At a point where we can build. Many TODOs and existing Series-based APIs need to be removed. No track code actually works.

pull/7/head
Joseph Milazzo 8 years ago
parent 235e753b93
commit 1024555f75

@ -11,6 +11,7 @@ using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.SignalR; using NzbDrone.SignalR;
using System;
namespace NzbDrone.Api.EpisodeFiles namespace NzbDrone.Api.EpisodeFiles
{ {
@ -47,24 +48,26 @@ namespace NzbDrone.Api.EpisodeFiles
private EpisodeFileResource GetEpisodeFile(int id) private EpisodeFileResource GetEpisodeFile(int id)
{ {
var episodeFile = _mediaFileService.Get(id); throw new NotImplementedException();
var series = _seriesService.GetSeries(episodeFile.SeriesId); //var episodeFile = _mediaFileService.Get(id);
//var series = _seriesService.GetSeries(episodeFile.SeriesId);
return episodeFile.ToResource(series, _qualityUpgradableSpecification); //return episodeFile.ToResource(series, _qualityUpgradableSpecification);
} }
private List<EpisodeFileResource> GetEpisodeFiles() private List<EpisodeFileResource> GetEpisodeFiles()
{ {
if (!Request.Query.SeriesId.HasValue) throw new NotImplementedException();
{ //if (!Request.Query.SeriesId.HasValue)
throw new BadRequestException("seriesId is missing"); //{
} // throw new BadRequestException("seriesId is missing");
//}
var seriesId = (int)Request.Query.SeriesId; //var seriesId = (int)Request.Query.SeriesId;
var series = _seriesService.GetSeries(seriesId); //var series = _seriesService.GetSeries(seriesId);
return _mediaFileService.GetFilesBySeries(seriesId).ConvertAll(f => f.ToResource(series, _qualityUpgradableSpecification)); //return _mediaFileService.GetFilesBySeries(seriesId).ConvertAll(f => f.ToResource(series, _qualityUpgradableSpecification));
} }
private void SetQuality(EpisodeFileResource episodeFileResource) private void SetQuality(EpisodeFileResource episodeFileResource)
@ -76,14 +79,15 @@ namespace NzbDrone.Api.EpisodeFiles
private void DeleteEpisodeFile(int id) private void DeleteEpisodeFile(int id)
{ {
var episodeFile = _mediaFileService.Get(id); throw new NotImplementedException();
var series = _seriesService.GetSeries(episodeFile.SeriesId); //var episodeFile = _mediaFileService.Get(id);
var fullPath = Path.Combine(series.Path, episodeFile.RelativePath); //var series = _seriesService.GetSeries(episodeFile.SeriesId);
var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath)); //var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
//var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath));
_logger.Info("Deleting episode file: {0}", fullPath); //_logger.Info("Deleting episode file: {0}", fullPath);
_recycleBinProvider.DeleteFile(fullPath, subfolder); //_recycleBinProvider.DeleteFile(fullPath, subfolder);
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual); //_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
} }
public void Handle(EpisodeFileAddedEvent message) public void Handle(EpisodeFileAddedEvent message)

@ -144,14 +144,14 @@ namespace NzbDrone.Api.Music
public void Handle(TrackImportedEvent message) public void Handle(TrackImportedEvent message)
{ {
BroadcastResourceChange(ModelAction.Updated, message.ImportedTrack.ItunesTrackId); BroadcastResourceChange(ModelAction.Updated, message.ImportedTrack.Id); // TODO: Ensure we can pass DB ID instead of Metadata ID (SpotifyID)
} }
public void Handle(TrackFileDeletedEvent message) public void Handle(TrackFileDeletedEvent message)
{ {
if (message.Reason == DeleteMediaFileReason.Upgrade) return; if (message.Reason == DeleteMediaFileReason.Upgrade) return;
BroadcastResourceChange(ModelAction.Updated, message.TrackFile.ItunesTrackId); BroadcastResourceChange(ModelAction.Updated, message.TrackFile.Id); // TODO: Ensure we can pass DB ID instead of Metadata ID (SpotifyID)
} }
public void Handle(ArtistUpdatedEvent message) public void Handle(ArtistUpdatedEvent message)

@ -13,6 +13,7 @@ using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.Download namespace NzbDrone.Core.Download
{ {
@ -130,7 +131,7 @@ namespace NzbDrone.Core.Download
{ {
var statusMessages = importResults var statusMessages = importResults
.Where(v => v.Result != ImportResultType.Imported) .Where(v => v.Result != ImportResultType.Imported)
.Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.LocalEpisode.Path), v.Errors)) .Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.LocalTrack.Path), v.Errors))
.ToArray(); .ToArray();
trackedDownload.Warn(statusMessages); trackedDownload.Warn(statusMessages);

@ -16,6 +16,7 @@ using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Extras namespace NzbDrone.Core.Extras
{ {
// NOTE: Majora: ExtraService can be reserved for Music Videos, lyric files, etc for Plex. TODO: Implement Extras for Music
public interface IExtraService public interface IExtraService
{ {
void ImportExtraFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly); void ImportExtraFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly);
@ -136,16 +137,17 @@ namespace NzbDrone.Core.Extras
private List<EpisodeFile> GetEpisodeFiles(int seriesId) private List<EpisodeFile> GetEpisodeFiles(int seriesId)
{ {
var episodeFiles = _mediaFileService.GetFilesBySeries(seriesId); //var episodeFiles = _mediaFileService.GetFilesBySeries(seriesId);
var episodes = _episodeService.GetEpisodeBySeries(seriesId); //var episodes = _episodeService.GetEpisodeBySeries(seriesId);
foreach (var episodeFile in episodeFiles) //foreach (var episodeFile in episodeFiles)
{ //{
var localEpisodeFile = episodeFile; // var localEpisodeFile = episodeFile;
episodeFile.Episodes = new LazyList<Episode>(episodes.Where(e => e.EpisodeFileId == localEpisodeFile.Id)); // episodeFile.Episodes = new LazyList<Episode>(episodes.Where(e => e.EpisodeFileId == localEpisodeFile.Id));
} //}
return episodeFiles; //return episodeFiles;
return new List<EpisodeFile>();
} }
} }
} }

@ -1,4 +1,5 @@
using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.MediaFiles.TrackImport;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.MediaFiles.Commands namespace NzbDrone.Core.MediaFiles.Commands

@ -18,12 +18,12 @@ using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events; using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.Music; using NzbDrone.Core.Music;
using NzbDrone.Core.Music.Events; using NzbDrone.Core.Music.Events;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.MediaFiles namespace NzbDrone.Core.MediaFiles
{ {
public interface IDiskScanService public interface IDiskScanService
{ {
void Scan(Series series);
void Scan(Artist artist); void Scan(Artist artist);
string[] GetVideoFiles(string path, bool allDirectories = true); string[] GetVideoFiles(string path, bool allDirectories = true);
string[] GetNonVideoFiles(string path, bool allDirectories = true); string[] GetNonVideoFiles(string path, bool allDirectories = true);
@ -32,14 +32,12 @@ namespace NzbDrone.Core.MediaFiles
public class DiskScanService : public class DiskScanService :
IDiskScanService, IDiskScanService,
IHandle<SeriesUpdatedEvent>,
IExecute<RescanSeriesCommand>,
IHandle<ArtistUpdatedEvent>, IHandle<ArtistUpdatedEvent>,
IExecute<RescanArtistCommand> IExecute<RescanArtistCommand>
{ {
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IMakeImportDecision _importDecisionMaker; private readonly IMakeImportDecision _importDecisionMaker;
private readonly IImportApprovedEpisodes _importApprovedEpisodes; private readonly IImportApprovedTracks _importApprovedTracks;
private readonly IConfigService _configService; private readonly IConfigService _configService;
private readonly ISeriesService _seriesService; private readonly ISeriesService _seriesService;
private readonly IArtistService _artistService; private readonly IArtistService _artistService;
@ -49,7 +47,7 @@ namespace NzbDrone.Core.MediaFiles
public DiskScanService(IDiskProvider diskProvider, public DiskScanService(IDiskProvider diskProvider,
IMakeImportDecision importDecisionMaker, IMakeImportDecision importDecisionMaker,
IImportApprovedEpisodes importApprovedEpisodes, IImportApprovedTracks importApprovedTracks,
IConfigService configService, IConfigService configService,
ISeriesService seriesService, ISeriesService seriesService,
IArtistService artistService, IArtistService artistService,
@ -59,7 +57,7 @@ namespace NzbDrone.Core.MediaFiles
{ {
_diskProvider = diskProvider; _diskProvider = diskProvider;
_importDecisionMaker = importDecisionMaker; _importDecisionMaker = importDecisionMaker;
_importApprovedEpisodes = importApprovedEpisodes; _importApprovedTracks = importApprovedTracks;
_configService = configService; _configService = configService;
_seriesService = seriesService; _seriesService = seriesService;
_artistService = artistService; _artistService = artistService;
@ -123,76 +121,18 @@ namespace NzbDrone.Core.MediaFiles
CompletedScanning(artist); CompletedScanning(artist);
} }
public void Scan(Series series)
{
var rootFolder = _diskProvider.GetParentFolder(series.Path);
if (!_diskProvider.FolderExists(rootFolder))
{
_logger.Warn("Series' root folder ({0}) doesn't exist.", rootFolder);
_eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderDoesNotExist));
return;
}
if (_diskProvider.GetDirectories(rootFolder).Empty())
{
_logger.Warn("Series' root folder ({0}) is empty.", rootFolder);
_eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderIsEmpty));
return;
}
_logger.ProgressInfo("Scanning disk for {0}", series.Title);
if (!_diskProvider.FolderExists(series.Path))
{
if (_configService.CreateEmptySeriesFolders)
{
_logger.Debug("Creating missing series folder: {0}", series.Path);
_diskProvider.CreateFolder(series.Path);
SetPermissions(series.Path);
}
else
{
_logger.Debug("Series folder doesn't exist: {0}", series.Path);
}
CleanMediaFiles(series, new List<string>());
CompletedScanning(series);
return;
}
var videoFilesStopwatch = Stopwatch.StartNew();
var mediaFileList = FilterFiles(series, GetVideoFiles(series.Path)).ToList();
videoFilesStopwatch.Stop();
_logger.Trace("Finished getting episode files for: {0} [{1}]", series, videoFilesStopwatch.Elapsed);
CleanMediaFiles(series, mediaFileList);
var decisionsStopwatch = Stopwatch.StartNew();
var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, series);
decisionsStopwatch.Stop();
_logger.Trace("Import decisions complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed);
_importApprovedEpisodes.Import(decisions, false);
CompletedScanning(series);
}
private void CleanMediaFiles(Series series, List<string> mediaFileList)
{
_logger.Debug("{0} Cleaning up media files in DB", series);
_mediaFileTableCleanupService.Clean(series, mediaFileList);
}
private void CleanMediaFiles(Artist artist, List<string> mediaFileList) private void CleanMediaFiles(Artist artist, List<string> mediaFileList)
{ {
_logger.Debug("{0} Cleaning up media files in DB", artist); _logger.Debug("{0} Cleaning up media files in DB", artist);
_mediaFileTableCleanupService.Clean(artist, mediaFileList); _mediaFileTableCleanupService.Clean(artist, mediaFileList);
} }
private void CompletedScanning(Series series) //private void CompletedScanning(Series series)
{ //{
_logger.Info("Completed scanning disk for {0}", series.Title); // _logger.Info("Completed scanning disk for {0}", series.Title);
_eventAggregator.PublishEvent(new SeriesScannedEvent(series)); // _eventAggregator.PublishEvent(new SeriesScannedEvent(series));
} //}
private void CompletedScanning(Artist artist) private void CompletedScanning(Artist artist)
{ {
@ -280,35 +220,11 @@ namespace NzbDrone.Core.MediaFiles
} }
} }
public void Handle(SeriesUpdatedEvent message)
{
Scan(message.Series);
}
public void Handle(ArtistUpdatedEvent message) public void Handle(ArtistUpdatedEvent message)
{ {
Scan(message.Artist); Scan(message.Artist);
} }
public void Execute(RescanSeriesCommand message)
{
if (message.SeriesId.HasValue)
{
var series = _seriesService.GetSeries(message.SeriesId.Value);
Scan(series);
}
else
{
var allSeries = _seriesService.GetAllSeries();
foreach (var series in allSeries)
{
Scan(series);
}
}
}
public void Execute(RescanArtistCommand message) public void Execute(RescanArtistCommand message)
{ {
if (message.ArtistId.IsNotNullOrWhiteSpace()) if (message.ArtistId.IsNotNullOrWhiteSpace())

@ -9,6 +9,7 @@ using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.MediaFiles.Commands; using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.MediaFiles namespace NzbDrone.Core.MediaFiles
{ {

@ -9,6 +9,7 @@ using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.MediaFiles namespace NzbDrone.Core.MediaFiles
{ {
@ -59,7 +60,7 @@ namespace NzbDrone.Core.MediaFiles
results.AddRange(folderResults); results.AddRange(folderResults);
} }
foreach (var videoFile in _diskScanService.GetVideoFiles(directoryInfo.FullName, false)) foreach (var videoFile in _diskScanService.GetNonVideoFiles(directoryInfo.FullName, false))
{ {
var fileResults = ProcessFile(new FileInfo(videoFile), ImportMode.Auto, null); var fileResults = ProcessFile(new FileInfo(videoFile), ImportMode.Auto, null);
results.AddRange(fileResults); results.AddRange(fileResults);
@ -100,7 +101,7 @@ namespace NzbDrone.Core.MediaFiles
public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Series series) public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Series series)
{ {
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName); var videoFiles = _diskScanService.GetNonVideoFiles(directoryInfo.FullName);
var rarFiles = _diskProvider.GetFiles(directoryInfo.FullName, SearchOption.AllDirectories).Where(f => Path.GetExtension(f) == ".rar"); var rarFiles = _diskProvider.GetFiles(directoryInfo.FullName, SearchOption.AllDirectories).Where(f => Path.GetExtension(f) == ".rar");
foreach (var videoFile in videoFiles) foreach (var videoFile in videoFiles)
@ -152,48 +153,50 @@ namespace NzbDrone.Core.MediaFiles
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem) private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem)
{ {
if (_seriesService.SeriesPathExists(directoryInfo.FullName)) throw new System.NotImplementedException("Will be removed");
{
_logger.Warn("Unable to process folder that is mapped to an existing show"); //if (_seriesService.SeriesPathExists(directoryInfo.FullName))
return new List<ImportResult>(); //{
} // _logger.Warn("Unable to process folder that is mapped to an existing show");
// return new List<ImportResult>();
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); //}
var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
//var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
if (folderInfo != null) //var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
{
_logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality); //if (folderInfo != null)
} //{
// _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName); //}
if (downloadClientItem == null) //var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
{
foreach (var videoFile in videoFiles) //if (downloadClientItem == null)
{ //{
if (_diskProvider.IsFileLocked(videoFile)) // foreach (var videoFile in videoFiles)
{ // {
return new List<ImportResult> // if (_diskProvider.IsFileLocked(videoFile))
{ // {
FileIsLockedResult(videoFile) // return new List<ImportResult>
}; // {
} // FileIsLockedResult(videoFile)
} // };
} // }
// }
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, folderInfo, true); //}
var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);
//var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, folderInfo, true);
if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) && //var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);
importResults.Any(i => i.Result == ImportResultType.Imported) &&
ShouldDeleteFolder(directoryInfo, series)) //if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) &&
{ // importResults.Any(i => i.Result == ImportResultType.Imported) &&
_logger.Debug("Deleting folder after importing valid files"); // ShouldDeleteFolder(directoryInfo, series))
_diskProvider.DeleteFolder(directoryInfo.FullName, true); //{
} // _logger.Debug("Deleting folder after importing valid files");
// _diskProvider.DeleteFolder(directoryInfo.FullName, true);
return importResults; //}
//return importResults;
} }
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem) private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
@ -215,30 +218,31 @@ namespace NzbDrone.Core.MediaFiles
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem) private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem)
{ {
if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._")) throw new System.NotImplementedException("Will be removed");
{ //if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._"))
_logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName); //{
// _logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName);
return new List<ImportResult>
{ // return new List<ImportResult>
new ImportResult(new ImportDecision(new LocalEpisode { Path = fileInfo.FullName }, new Rejection("Invalid video file, filename starts with '._'")), "Invalid video file, filename starts with '._'") // {
}; // new ImportResult(new ImportDecision(new LocalTrack { Path = fileInfo.FullName }, new Rejection("Invalid music file, filename starts with '._'")), "Invalid music file, filename starts with '._'")
} // };
//}
if (downloadClientItem == null)
{ //if (downloadClientItem == null)
if (_diskProvider.IsFileLocked(fileInfo.FullName)) //{
{ // if (_diskProvider.IsFileLocked(fileInfo.FullName))
return new List<ImportResult> // {
{ // return new List<ImportResult>
FileIsLockedResult(fileInfo.FullName) // {
}; // FileIsLockedResult(fileInfo.FullName)
} // };
} // }
//}
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, null, true);
//var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, null, true);
return _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);
//return _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);
} }
private string GetCleanedUpFolderName(string folder) private string GetCleanedUpFolderName(string folder)
@ -251,15 +255,17 @@ namespace NzbDrone.Core.MediaFiles
private ImportResult FileIsLockedResult(string videoFile) private ImportResult FileIsLockedResult(string videoFile)
{ {
_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile); throw new System.NotImplementedException("Will be removed");
return new ImportResult(new ImportDecision(new LocalEpisode { Path = videoFile }, new Rejection("Locked file, try again later")), "Locked file, try again later"); //_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
//return new ImportResult(new ImportDecision(new LocalEpisode { Path = videoFile }, new Rejection("Locked file, try again later")), "Locked file, try again later");
} }
private ImportResult UnknownSeriesResult(string message, string videoFile = null) private ImportResult UnknownSeriesResult(string message, string videoFile = null)
{ {
var localEpisode = videoFile == null ? null : new LocalEpisode { Path = videoFile }; throw new System.NotImplementedException("Will be removed");
//var localEpisode = videoFile == null ? null : new LocalEpisode { Path = videoFile };
return new ImportResult(new ImportDecision(localEpisode, new Rejection("Unknown Series")), message); //return new ImportResult(new ImportDecision(localEpisode, new Rejection("Unknown Series")), message);
} }
} }
} }

@ -6,5 +6,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
public interface IImportDecisionEngineSpecification public interface IImportDecisionEngineSpecification
{ {
Decision IsSatisfiedBy(LocalEpisode localEpisode); Decision IsSatisfiedBy(LocalEpisode localEpisode);
Decision IsSatisfiedBy(LocalTrack localTrack);
} }
} }

@ -12,7 +12,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Extras; using NzbDrone.Core.Extras;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.MediaFiles.EpisodeImport namespace NzbDrone.Core.MediaFiles.EpisodeImport
{ {
@ -47,105 +47,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto) public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto)
{ {
var qualifiedImports = decisions.Where(c => c.Approved) throw new NotImplementedException("This will be removed");
.GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s
.OrderByDescending(c => c.LocalEpisode.Quality, new QualityModelComparer(s.First().LocalEpisode.Series.Profile))
.ThenByDescending(c => c.LocalEpisode.Size))
.SelectMany(c => c)
.ToList();
var importResults = new List<ImportResult>();
foreach (var importDecision in qualifiedImports.OrderBy(e => e.LocalEpisode.Episodes.Select(episode => episode.EpisodeNumber).MinOrDefault())
.ThenByDescending(e => e.LocalEpisode.Size))
{
var localEpisode = importDecision.LocalEpisode;
var oldFiles = new List<EpisodeFile>();
try
{
//check if already imported
if (importResults.SelectMany(r => r.ImportDecision.LocalEpisode.Episodes)
.Select(e => e.Id)
.Intersect(localEpisode.Episodes.Select(e => e.Id))
.Any())
{
importResults.Add(new ImportResult(importDecision, "Episode has already been imported"));
continue;
}
var episodeFile = new EpisodeFile();
episodeFile.DateAdded = DateTime.UtcNow;
episodeFile.SeriesId = localEpisode.Series.Id;
episodeFile.Path = localEpisode.Path.CleanFilePath();
episodeFile.Size = _diskProvider.GetFileSize(localEpisode.Path);
episodeFile.Quality = localEpisode.Quality;
episodeFile.MediaInfo = localEpisode.MediaInfo;
episodeFile.SeasonNumber = localEpisode.SeasonNumber;
episodeFile.Episodes = localEpisode.Episodes;
episodeFile.ReleaseGroup = localEpisode.ParsedEpisodeInfo.ReleaseGroup;
bool copyOnly;
switch (importMode)
{
default:
case ImportMode.Auto:
copyOnly = downloadClientItem != null && downloadClientItem.IsReadOnly;
break;
case ImportMode.Move:
copyOnly = false;
break;
case ImportMode.Copy:
copyOnly = true;
break;
}
if (newDownload)
{
episodeFile.SceneName = GetSceneName(downloadClientItem, localEpisode);
var moveResult = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly);
oldFiles = moveResult.OldFiles;
}
else
{
episodeFile.RelativePath = localEpisode.Series.Path.GetRelativePath(episodeFile.Path);
}
_mediaFileService.Add(episodeFile);
importResults.Add(new ImportResult(importDecision));
if (newDownload)
{
_extraService.ImportExtraFiles(localEpisode, episodeFile, copyOnly);
}
if (downloadClientItem != null)
{
_eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId, downloadClientItem.IsReadOnly));
}
else
{
_eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload));
}
if (newDownload)
{
_eventAggregator.PublishEvent(new EpisodeDownloadedEvent(localEpisode, episodeFile, oldFiles));
}
}
catch (Exception e)
{
_logger.Warn(e, "Couldn't import episode " + localEpisode);
importResults.Add(new ImportResult(importDecision, "Failed to import episode"));
}
}
//Adding all the rejected decisions
importResults.AddRange(decisions.Where(c => !c.Approved)
.Select(d => new ImportResult(d, d.Rejections.Select(r => r.Reason).ToArray())));
return importResults;
} }
private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode) private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode)

@ -1,22 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
public class ImportDecision
{
public LocalEpisode LocalEpisode { get; private set; }
public IEnumerable<Rejection> Rejections { get; private set; }
public bool Approved => Rejections.Empty();
public ImportDecision(LocalEpisode localEpisode, params Rejection[] rejections)
{
LocalEpisode = localEpisode;
Rejections = rejections.ToList();
}
}
}

@ -12,6 +12,7 @@ using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Music; using NzbDrone.Core.Music;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.MediaFiles.EpisodeImport namespace NzbDrone.Core.MediaFiles.EpisodeImport
{ {
@ -94,7 +95,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
return decisions; return decisions;
} }
private ImportDecision GetDecision(string file, Artist artist, ParsedTrackInfo folderInfo, bool sceneSource, bool shouldUseFolderName) private ImportDecision GetDecision(string file, Artist artist, ParsedTrackInfo folderInfo, bool shouldUseFolderName)
{ {
ImportDecision decision = null; ImportDecision decision = null;
@ -109,11 +110,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
_logger.Debug("Size: {0}", localTrack.Size); _logger.Debug("Size: {0}", localTrack.Size);
//TODO: make it so media info doesn't ruin the import process of a new series //TODO: make it so media info doesn't ruin the import process of a new artist
if (sceneSource)
{
localTrack.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
}
if (localTrack.Tracks.Empty()) if (localTrack.Tracks.Empty())
{ {
@ -137,19 +134,41 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{ {
_logger.Error(e, "Couldn't import file. {0}", file); _logger.Error(e, "Couldn't import file. {0}", file);
var localEpisode = new LocalEpisode { Path = file }; var localTrack = new LocalTrack { Path = file };
decision = new ImportDecision(localEpisode, new Rejection("Unexpected error processing file")); decision = new ImportDecision(localTrack, new Rejection("Unexpected error processing file"));
} }
return decision; return decision;
} }
private ImportDecision GetDecision(LocalEpisode localEpisode) private ImportDecision GetDecision(LocalTrack localTrack)
{ {
var reasons = _specifications.Select(c => EvaluateSpec(c, localEpisode)) var reasons = _specifications.Select(c => EvaluateSpec(c, localTrack))
.Where(c => c != null); .Where(c => c != null);
return new ImportDecision(localEpisode, reasons.ToArray()); return new ImportDecision(localTrack, reasons.ToArray());
}
private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalTrack localTrack)
{
try
{
var result = spec.IsSatisfiedBy(localTrack);
if (!result.Accepted)
{
return new Rejection(result.Reason);
}
}
catch (Exception e)
{
//e.Data.Add("report", remoteEpisode.Report.ToJson());
//e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson());
_logger.Error(e, "Couldn't evaluate decision on {0}", localTrack.Path);
return new Rejection($"{spec.GetType().Name}: {e.Message}");
}
return null;
} }
private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalEpisode localEpisode) private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalEpisode localEpisode)

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
{ {

@ -15,6 +15,7 @@ using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
{ {
@ -94,65 +95,67 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
private List<ManualImportItem> ProcessFolder(string folder, string downloadId) private List<ManualImportItem> ProcessFolder(string folder, string downloadId)
{ {
var directoryInfo = new DirectoryInfo(folder); throw new System.NotImplementedException("TODO: This will be rewritten for Music");
var series = _parsingService.GetSeries(directoryInfo.Name); //var directoryInfo = new DirectoryInfo(folder);
//var series = _parsingService.GetSeries(directoryInfo.Name);
if (series == null && downloadId.IsNotNullOrWhiteSpace()) //if (series == null && downloadId.IsNotNullOrWhiteSpace())
{ //{
var trackedDownload = _trackedDownloadService.Find(downloadId); // var trackedDownload = _trackedDownloadService.Find(downloadId);
series = trackedDownload.RemoteEpisode.Series; // series = trackedDownload.RemoteEpisode.Series;
} //}
if (series == null) //if (series == null)
{ //{
var files = _diskScanService.GetVideoFiles(folder); // var files = _diskScanService.GetVideoFiles(folder);
return files.Select(file => ProcessFile(file, downloadId, folder)).Where(i => i != null).ToList(); // return files.Select(file => ProcessFile(file, downloadId, folder)).Where(i => i != null).ToList();
} //}
var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name); //var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
var seriesFiles = _diskScanService.GetVideoFiles(folder).ToList(); //var seriesFiles = _diskScanService.GetVideoFiles(folder).ToList();
var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, folderInfo, SceneSource(series, folder)); //var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, folderInfo, SceneSource(series, folder));
return decisions.Select(decision => MapItem(decision, folder, downloadId)).ToList(); //return decisions.Select(decision => MapItem(decision, folder, downloadId)).ToList();
} }
private ManualImportItem ProcessFile(string file, string downloadId, string folder = null) private ManualImportItem ProcessFile(string file, string downloadId, string folder = null)
{ {
if (folder.IsNullOrWhiteSpace()) throw new System.NotImplementedException("TODO: This will be rewritten for Music");
{ //if (folder.IsNullOrWhiteSpace())
folder = new FileInfo(file).Directory.FullName; //{
} // folder = new FileInfo(file).Directory.FullName;
//}
var relativeFile = folder.GetRelativePath(file); //var relativeFile = folder.GetRelativePath(file);
var series = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]); //var series = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]);
if (series == null) //if (series == null)
{ //{
series = _parsingService.GetSeries(relativeFile); // series = _parsingService.GetSeries(relativeFile);
} //}
if (series == null && downloadId.IsNotNullOrWhiteSpace()) //if (series == null && downloadId.IsNotNullOrWhiteSpace())
{ //{
var trackedDownload = _trackedDownloadService.Find(downloadId); // var trackedDownload = _trackedDownloadService.Find(downloadId);
series = trackedDownload.RemoteEpisode.Series; // series = trackedDownload.RemoteEpisode.Series;
} //}
if (series == null) //if (series == null)
{ //{
var localEpisode = new LocalEpisode(); // var localEpisode = new LocalEpisode();
localEpisode.Path = file; // localEpisode.Path = file;
localEpisode.Quality = QualityParser.ParseQuality(file); // localEpisode.Quality = QualityParser.ParseQuality(file);
localEpisode.Size = _diskProvider.GetFileSize(file); // localEpisode.Size = _diskProvider.GetFileSize(file);
return MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), folder, downloadId); // return MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), folder, downloadId);
} //}
var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> {file}, //var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> {file},
series, null, SceneSource(series, folder)); // series, null, SceneSource(series, folder));
return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null; //return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null;
} }
private bool SceneSource(Series series, string folder) private bool SceneSource(Series series, string folder)
@ -162,107 +165,109 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
private ManualImportItem MapItem(ImportDecision decision, string folder, string downloadId) private ManualImportItem MapItem(ImportDecision decision, string folder, string downloadId)
{ {
var item = new ManualImportItem(); throw new System.NotImplementedException("TODO: This will be rewritten for Music");
//var item = new ManualImportItem();
item.Path = decision.LocalEpisode.Path;
item.RelativePath = folder.GetRelativePath(decision.LocalEpisode.Path); //item.Path = decision.LocalEpisode.Path;
item.Name = Path.GetFileNameWithoutExtension(decision.LocalEpisode.Path); //item.RelativePath = folder.GetRelativePath(decision.LocalEpisode.Path);
item.DownloadId = downloadId; //item.Name = Path.GetFileNameWithoutExtension(decision.LocalEpisode.Path);
//item.DownloadId = downloadId;
if (decision.LocalEpisode.Series != null)
{ //if (decision.LocalEpisode.Series != null)
item.Series = decision.LocalEpisode.Series; //{
} // item.Series = decision.LocalEpisode.Series;
//}
if (decision.LocalEpisode.Episodes.Any())
{ //if (decision.LocalEpisode.Episodes.Any())
item.SeasonNumber = decision.LocalEpisode.SeasonNumber; //{
item.Episodes = decision.LocalEpisode.Episodes; // item.SeasonNumber = decision.LocalEpisode.SeasonNumber;
} // item.Episodes = decision.LocalEpisode.Episodes;
//}
item.Quality = decision.LocalEpisode.Quality;
item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path); //item.Quality = decision.LocalEpisode.Quality;
item.Rejections = decision.Rejections; //item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path);
//item.Rejections = decision.Rejections;
return item;
//return item;
} }
public void Execute(ManualImportCommand message) public void Execute(ManualImportCommand message)
{ {
_logger.ProgressTrace("Manually importing {0} files using mode {1}", message.Files.Count, message.ImportMode); _logger.ProgressTrace("Manually importing {0} files using mode {1}", message.Files.Count, message.ImportMode);
throw new System.NotImplementedException("TODO: This will be rewritten for Music");
var imported = new List<ImportResult>();
var importedTrackedDownload = new List<ManuallyImportedFile>(); //var imported = new List<ImportResult>();
//var importedTrackedDownload = new List<ManuallyImportedFile>();
for (int i = 0; i < message.Files.Count; i++)
{ //for (int i = 0; i < message.Files.Count; i++)
_logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count); //{
// _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count);
var file = message.Files[i];
var series = _seriesService.GetSeries(file.SeriesId); // var file = message.Files[i];
var episodes = _episodeService.GetEpisodes(file.EpisodeIds); // var series = _seriesService.GetSeries(file.SeriesId);
var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo(); // var episodes = _episodeService.GetEpisodes(file.EpisodeIds);
var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path); // var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo();
var existingFile = series.Path.IsParentPath(file.Path); // var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path);
// var existingFile = series.Path.IsParentPath(file.Path);
var localEpisode = new LocalEpisode
{ // var localEpisode = new LocalEpisode
ExistingFile = false, // {
Episodes = episodes, // ExistingFile = false,
MediaInfo = mediaInfo, // Episodes = episodes,
ParsedEpisodeInfo = parsedEpisodeInfo, // MediaInfo = mediaInfo,
Path = file.Path, // ParsedEpisodeInfo = parsedEpisodeInfo,
Quality = file.Quality, // Path = file.Path,
Series = series, // Quality = file.Quality,
Size = 0 // Series = series,
}; // Size = 0
// };
//TODO: Cleanup non-tracked downloads
// //TODO: Cleanup non-tracked downloads
var importDecision = new ImportDecision(localEpisode);
// var importDecision = new ImportDecision(localEpisode);
if (file.DownloadId.IsNullOrWhiteSpace())
{ // if (file.DownloadId.IsNullOrWhiteSpace())
imported.AddRange(_importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode)); // {
} // imported.AddRange(_importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode));
// }
else
{ // else
var trackedDownload = _trackedDownloadService.Find(file.DownloadId); // {
var importResult = _importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First(); // var trackedDownload = _trackedDownloadService.Find(file.DownloadId);
// var importResult = _importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First();
imported.Add(importResult);
// imported.Add(importResult);
importedTrackedDownload.Add(new ManuallyImportedFile
{ // importedTrackedDownload.Add(new ManuallyImportedFile
TrackedDownload = trackedDownload, // {
ImportResult = importResult // TrackedDownload = trackedDownload,
}); // ImportResult = importResult
} // });
} // }
//}
_logger.ProgressTrace("Manually imported {0} files", imported.Count);
//_logger.ProgressTrace("Manually imported {0} files", imported.Count);
foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList())
{ //foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList())
var trackedDownload = groupedTrackedDownload.First().TrackedDownload; //{
// var trackedDownload = groupedTrackedDownload.First().TrackedDownload;
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
{ // if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
if (_downloadedEpisodesImportService.ShouldDeleteFolder( // {
new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath), // if (_downloadedEpisodesImportService.ShouldDeleteFolder(
trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly) // new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
{ // trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly)
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true); // {
} // _diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true);
} // }
// }
if (groupedTrackedDownload.Select(c => c.ImportResult).Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, trackedDownload.RemoteEpisode.Episodes.Count))
{ // if (groupedTrackedDownload.Select(c => c.ImportResult).Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, trackedDownload.RemoteEpisode.Episodes.Count))
trackedDownload.State = TrackedDownloadStage.Imported; // {
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload)); // trackedDownload.State = TrackedDownloadStage.Imported;
} // _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
} // }
//}
} }
} }
} }

@ -1,4 +1,5 @@
using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.MediaFiles.TrackImport;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
{ {

@ -63,5 +63,48 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
return Decision.Accept(); return Decision.Accept();
} }
public Decision IsSatisfiedBy(LocalTrack localTrack)
{
if (_configService.SkipFreeSpaceCheckWhenImporting)
{
_logger.Debug("Skipping free space check when importing");
return Decision.Accept();
}
try
{
if (localTrack.ExistingFile)
{
_logger.Debug("Skipping free space check for existing episode");
return Decision.Accept();
}
var path = Directory.GetParent(localTrack.Artist.Path);
var freeSpace = _diskProvider.GetAvailableSpace(path.FullName);
if (!freeSpace.HasValue)
{
_logger.Debug("Free space check returned an invalid result for: {0}", path);
return Decision.Accept();
}
if (freeSpace < localTrack.Size + 100.Megabytes())
{
_logger.Warn("Not enough free space ({0}) to import: {1} ({2})", freeSpace, localTrack, localTrack.Size);
return Decision.Reject("Not enough free space");
}
}
catch (DirectoryNotFoundException ex)
{
_logger.Error(ex, "Unable to check free disk space while importing.");
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to check free disk space while importing. {0}", localTrack.Path);
}
return Decision.Accept();
}
} }
} }

@ -1,4 +1,5 @@
using NLog; using System;
using NLog;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -13,6 +14,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger = logger; _logger = logger;
} }
public Decision IsSatisfiedBy(LocalTrack localTrack)
{
throw new NotImplementedException("Interface will be removed");
}
public Decision IsSatisfiedBy(LocalEpisode localEpisode) public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{ {
if (localEpisode.ParsedEpisodeInfo.FullSeason) if (localEpisode.ParsedEpisodeInfo.FullSeason)

@ -1,4 +1,5 @@
using System.IO; using System;
using System.IO;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
@ -14,6 +15,53 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
{ {
_logger = logger; _logger = logger;
} }
public Decision IsSatisfiedBy(LocalTrack localTrack)
{
if (localTrack.ExistingFile)
{
return Decision.Accept();
}
var dirInfo = new FileInfo(localTrack.Path).Directory;
if (dirInfo == null)
{
return Decision.Accept();
}
throw new System.NotImplementedException("Needs to be implemented");
//var folderInfo = Parser.Parser.ParseTitle(dirInfo.Name);
//if (folderInfo == null)
//{
// return Decision.Accept();
//}
//if (!folderInfo.TrackNumbers.Any())
//{
// return Decision.Accept();
//}
//var unexpected = localTrack.ParsedTrackInfo.TrackNumbers.Where(f => !folderInfo.TrackNumbers.Contains(f)).ToList();
//// TODO: Implement MatchesFolderSpecification
//if (unexpected.Any())
//{
// _logger.Debug("Unexpected track number(s) in file: {0}", string.Join(", ", unexpected));
// if (unexpected.Count == 1)
// {
// return Decision.Reject("Track Number {0} was unexpected considering the {1} folder name", unexpected.First(), dirInfo.Name);
// }
// return Decision.Reject("Episode Numbers {0} were unexpected considering the {1} folder name", string.Join(", ", unexpected), dirInfo.Name);
//}
return Decision.Accept();
}
public Decision IsSatisfiedBy(LocalEpisode localEpisode) public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{ {
if (localEpisode.ExistingFile) if (localEpisode.ExistingFile)

@ -1,4 +1,5 @@
using NLog; using System;
using NLog;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -16,6 +17,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger = logger; _logger = logger;
} }
public Decision IsSatisfiedBy(LocalTrack localTrack)
{
throw new NotImplementedException();
}
public Decision IsSatisfiedBy(LocalEpisode localEpisode) public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{ {
if (localEpisode.ExistingFile) if (localEpisode.ExistingFile)

@ -56,5 +56,10 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
return Decision.Accept(); return Decision.Accept();
} }
public Decision IsSatisfiedBy(LocalTrack localTrack)
{
throw new NotImplementedException();
}
} }
} }

@ -1,3 +1,4 @@
using System;
using NLog; using NLog;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -27,5 +28,10 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger.Debug("Episode file on disk contains more episodes than this file contains"); _logger.Debug("Episode file on disk contains more episodes than this file contains");
return Decision.Reject("Episode file on disk contains more episodes than this file contains"); return Decision.Reject("Episode file on disk contains more episodes than this file contains");
} }
public Decision IsSatisfiedBy(LocalTrack localTrack)
{
throw new NotImplementedException();
}
} }
} }

@ -1,4 +1,5 @@
using System.Linq; using System;
using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -13,6 +14,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger = logger; _logger = logger;
} }
public Decision IsSatisfiedBy(LocalTrack localTrack)
{
throw new NotImplementedException("This is not needed, Interface will be removed");
}
public Decision IsSatisfiedBy(LocalEpisode localEpisode) public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{ {
if (localEpisode.ExistingFile) if (localEpisode.ExistingFile)

@ -1,4 +1,5 @@
using System.Linq; using System;
using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -15,6 +16,18 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger = logger; _logger = logger;
} }
public Decision IsSatisfiedBy(LocalTrack localTrack)
{
var qualityComparer = new QualityModelComparer(localTrack.Artist.Profile);
if (localTrack.Tracks.Any(e => e.TrackFileId != 0 && qualityComparer.Compare(e.TrackFile.Value.Quality, localTrack.Quality) > 0))
{
_logger.Debug("This file isn't an upgrade for all tracks. Skipping {0}", localTrack.Path);
return Decision.Reject("Not an upgrade for existing track file(s)");
}
return Decision.Accept();
}
public Decision IsSatisfiedBy(LocalEpisode localEpisode) public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{ {
var qualityComparer = new QualityModelComparer(localEpisode.Series.Profile); var qualityComparer = new QualityModelComparer(localEpisode.Series.Profile);

@ -0,0 +1,23 @@
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Parser.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.MediaFiles.Events
{
public class TrackDownloadedEvent : IEvent
{
public LocalTrack Track { get; private set; }
public TrackFile TrackFile { get; private set; }
public List<TrackFile> OldFiles { get; private set; }
public TrackDownloadedEvent(LocalTrack track, TrackFile trackFile, List<TrackFile> oldFiles)
{
Track = track;
TrackFile = trackFile;
OldFiles = oldFiles;
}
}
}

@ -5,81 +5,73 @@ using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Music;
namespace NzbDrone.Core.MediaFiles namespace NzbDrone.Core.MediaFiles
{ {
public interface IMediaFileTableCleanupService public interface IMediaFileTableCleanupService
{ {
void Clean(Series series, List<string> filesOnDisk); void Clean(Artist artist, List<string> filesOnDisk);
} }
public class MediaFileTableCleanupService : IMediaFileTableCleanupService public class MediaFileTableCleanupService : IMediaFileTableCleanupService
{ {
private readonly IMediaFileService _mediaFileService; private readonly IMediaFileService _mediaFileService;
private readonly IEpisodeService _episodeService; private readonly ITrackService _trackService;
private readonly Logger _logger; private readonly Logger _logger;
public MediaFileTableCleanupService(IMediaFileService mediaFileService, public MediaFileTableCleanupService(IMediaFileService mediaFileService,
IEpisodeService episodeService, ITrackService trackService,
Logger logger) Logger logger)
{ {
_mediaFileService = mediaFileService; _mediaFileService = mediaFileService;
_episodeService = episodeService; _trackService = trackService;
_logger = logger; _logger = logger;
} }
public void Clean(Series series, List<string> filesOnDisk) public void Clean(Artist artist, List<string> filesOnDisk)
{ {
var seriesFiles = _mediaFileService.GetFilesBySeries(series.Id); var artistFiles = _mediaFileService.GetFilesByArtist(artist.SpotifyId);
var episodes = _episodeService.GetEpisodeBySeries(series.Id); var tracks = _trackService.GetTracksByArtist(artist.SpotifyId);
var filesOnDiskKeys = new HashSet<string>(filesOnDisk, PathEqualityComparer.Instance); var filesOnDiskKeys = new HashSet<string>(filesOnDisk, PathEqualityComparer.Instance);
foreach (var seriesFile in seriesFiles) foreach (var artistFile in artistFiles)
{ {
var episodeFile = seriesFile; var trackFile = artistFile;
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath); var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
try try
{ {
if (!filesOnDiskKeys.Contains(episodeFilePath)) if (!filesOnDiskKeys.Contains(trackFilePath))
{ {
_logger.Debug("File [{0}] no longer exists on disk, removing from db", episodeFilePath); _logger.Debug("File [{0}] no longer exists on disk, removing from db", trackFilePath);
_mediaFileService.Delete(seriesFile, DeleteMediaFileReason.MissingFromDisk); _mediaFileService.Delete(artistFile, DeleteMediaFileReason.MissingFromDisk);
continue; continue;
} }
if (episodes.None(e => e.EpisodeFileId == episodeFile.Id)) if (tracks.None(e => e.TrackFileId == trackFile.Id))
{ {
_logger.Debug("File [{0}] is not assigned to any episodes, removing from db", episodeFilePath); _logger.Debug("File [{0}] is not assigned to any artist, removing from db", trackFilePath);
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.NoLinkedEpisodes); _mediaFileService.Delete(trackFile, DeleteMediaFileReason.NoLinkedEpisodes);
continue; continue;
} }
// var localEpsiode = _parsingService.GetLocalEpisode(episodeFile.Path, series);
//
// if (localEpsiode == null || episodes.Count != localEpsiode.Episodes.Count)
// {
// _logger.Debug("File [{0}] parsed episodes has changed, removing from db", episodeFile.Path);
// _mediaFileService.Delete(episodeFile);
// continue;
// }
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to cleanup EpisodeFile in DB: {0}", episodeFile.Id); _logger.Error(ex, "Unable to cleanup EpisodeFile in DB: {0}", trackFile.Id);
} }
} }
foreach (var e in episodes) foreach (var t in tracks)
{ {
var episode = e; var track = t;
if (episode.EpisodeFileId > 0 && seriesFiles.None(f => f.Id == episode.EpisodeFileId)) if (track.TrackFileId > 0 && artistFiles.None(f => f.Id == track.TrackFileId))
{ {
episode.EpisodeFileId = 0; track.TrackFileId = 0;
_episodeService.UpdateEpisode(episode); _trackService.UpdateTrack(track);
} }
} }
} }

@ -7,10 +7,11 @@ using NzbDrone.Core.Tv;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Music;
namespace NzbDrone.Core.MediaFiles.MediaInfo namespace NzbDrone.Core.MediaFiles.MediaInfo
{ {
public class UpdateMediaInfoService : IHandle<SeriesScannedEvent> public class UpdateMediaInfoService : IHandle<ArtistScannedEvent>
{ {
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IMediaFileService _mediaFileService; private readonly IMediaFileService _mediaFileService;
@ -33,11 +34,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
_logger = logger; _logger = logger;
} }
private void UpdateMediaInfo(Series series, List<EpisodeFile> mediaFiles) private void UpdateMediaInfo(Artist artist, List<TrackFile> mediaFiles)
{ {
foreach (var mediaFile in mediaFiles) foreach (var mediaFile in mediaFiles)
{ {
var path = Path.Combine(series.Path, mediaFile.RelativePath); var path = Path.Combine(artist.Path, mediaFile.RelativePath);
if (!_diskProvider.FileExists(path)) if (!_diskProvider.FileExists(path))
{ {
@ -56,7 +57,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
} }
} }
public void Handle(SeriesScannedEvent message) public void Handle(ArtistScannedEvent message)
{ {
if (!_configService.EnableMediaInfo) if (!_configService.EnableMediaInfo)
{ {
@ -64,10 +65,10 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
return; return;
} }
var allMediaFiles = _mediaFileService.GetFilesBySeries(message.Series.Id); var allMediaFiles = _mediaFileService.GetFilesByArtist(message.Artist.SpotifyId);
var filteredMediaFiles = allMediaFiles.Where(c => c.MediaInfo == null || c.MediaInfo.SchemaRevision < CURRENT_MEDIA_INFO_SCHEMA_REVISION).ToList(); var filteredMediaFiles = allMediaFiles.Where(c => c.MediaInfo == null || c.MediaInfo.SchemaRevision < CURRENT_MEDIA_INFO_SCHEMA_REVISION).ToList();
UpdateMediaInfo(message.Series, filteredMediaFiles); UpdateMediaInfo(message.Artist, filteredMediaFiles);
} }
} }
} }

@ -55,24 +55,28 @@ namespace NzbDrone.Core.MediaFiles
public List<RenameEpisodeFilePreview> GetRenamePreviews(int seriesId) public List<RenameEpisodeFilePreview> GetRenamePreviews(int seriesId)
{ {
var series = _seriesService.GetSeries(seriesId); // TODO
var episodes = _episodeService.GetEpisodeBySeries(seriesId); throw new NotImplementedException();
var files = _mediaFileService.GetFilesBySeries(seriesId); //var series = _seriesService.GetSeries(seriesId);
//var episodes = _episodeService.GetEpisodeBySeries(seriesId);
return GetPreviews(series, episodes, files) //var files = _mediaFileService.GetFilesBySeries(seriesId);
.OrderByDescending(e => e.SeasonNumber)
.ThenByDescending(e => e.EpisodeNumbers.First()) //return GetPreviews(series, episodes, files)
.ToList(); // .OrderByDescending(e => e.SeasonNumber)
// .ThenByDescending(e => e.EpisodeNumbers.First())
// .ToList();
} }
public List<RenameEpisodeFilePreview> GetRenamePreviews(int seriesId, int seasonNumber) public List<RenameEpisodeFilePreview> GetRenamePreviews(int seriesId, int seasonNumber)
{ {
var series = _seriesService.GetSeries(seriesId); // TODO
var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber); throw new NotImplementedException();
var files = _mediaFileService.GetFilesBySeason(seriesId, seasonNumber); //var series = _seriesService.GetSeries(seriesId);
//var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber);
return GetPreviews(series, episodes, files) //var files = _mediaFileService.GetFilesBySeason(seriesId, seasonNumber);
.OrderByDescending(e => e.EpisodeNumbers.First()).ToList();
//return GetPreviews(series, episodes, files)
// .OrderByDescending(e => e.EpisodeNumbers.First()).ToList();
} }
private IEnumerable<RenameEpisodeFilePreview> GetPreviews(Series series, List<Episode> episodes, List<EpisodeFile> files) private IEnumerable<RenameEpisodeFilePreview> GetPreviews(Series series, List<Episode> episodes, List<EpisodeFile> files)
@ -110,62 +114,68 @@ namespace NzbDrone.Core.MediaFiles
private void RenameFiles(List<EpisodeFile> episodeFiles, Series series) private void RenameFiles(List<EpisodeFile> episodeFiles, Series series)
{ {
var renamed = new List<EpisodeFile>(); // TODO
throw new NotImplementedException();
foreach (var episodeFile in episodeFiles) //var renamed = new List<EpisodeFile>();
{
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath); //foreach (var episodeFile in episodeFiles)
//{
try // var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
{
_logger.Debug("Renaming episode file: {0}", episodeFile); // try
_episodeFileMover.MoveEpisodeFile(episodeFile, series); // {
// _logger.Debug("Renaming episode file: {0}", episodeFile);
_mediaFileService.Update(episodeFile); // _episodeFileMover.MoveEpisodeFile(episodeFile, series);
renamed.Add(episodeFile);
// _mediaFileService.Update(episodeFile);
_logger.Debug("Renamed episode file: {0}", episodeFile); // renamed.Add(episodeFile);
}
catch (SameFilenameException ex) // _logger.Debug("Renamed episode file: {0}", episodeFile);
{ // }
_logger.Debug("File not renamed, source and destination are the same: {0}", ex.Filename); // catch (SameFilenameException ex)
} // {
catch (Exception ex) // _logger.Debug("File not renamed, source and destination are the same: {0}", ex.Filename);
{ // }
_logger.Error(ex, "Failed to rename file {0}", episodeFilePath); // catch (Exception ex)
} // {
} // _logger.Error(ex, "Failed to rename file {0}", episodeFilePath);
// }
if (renamed.Any()) //}
{
_diskProvider.RemoveEmptySubfolders(series.Path); //if (renamed.Any())
//{
_eventAggregator.PublishEvent(new SeriesRenamedEvent(series)); // _diskProvider.RemoveEmptySubfolders(series.Path);
}
// _eventAggregator.PublishEvent(new SeriesRenamedEvent(series));
//}
} }
public void Execute(RenameFilesCommand message) public void Execute(RenameFilesCommand message)
{ {
var series = _seriesService.GetSeries(message.SeriesId); // TODO
var episodeFiles = _mediaFileService.Get(message.Files); throw new NotImplementedException();
//var series = _seriesService.GetSeries(message.SeriesId);
_logger.ProgressInfo("Renaming {0} files for {1}", episodeFiles.Count, series.Title); //var episodeFiles = _mediaFileService.Get(message.Files);
RenameFiles(episodeFiles, series);
_logger.ProgressInfo("Selected episode files renamed for {0}", series.Title); //_logger.ProgressInfo("Renaming {0} files for {1}", episodeFiles.Count, series.Title);
//RenameFiles(episodeFiles, series);
//_logger.ProgressInfo("Selected episode files renamed for {0}", series.Title);
} }
public void Execute(RenameSeriesCommand message) public void Execute(RenameSeriesCommand message)
{ {
_logger.Debug("Renaming all files for selected series"); // TODO
var seriesToRename = _seriesService.GetSeries(message.SeriesIds); throw new NotImplementedException();
//_logger.Debug("Renaming all files for selected series");
foreach (var series in seriesToRename) //var seriesToRename = _seriesService.GetSeries(message.SeriesIds);
{
var episodeFiles = _mediaFileService.GetFilesBySeries(series.Id); //foreach (var series in seriesToRename)
_logger.ProgressInfo("Renaming all files in series: {0}", series.Title); //{
RenameFiles(episodeFiles, series); // var episodeFiles = _mediaFileService.GetFilesBySeries(series.Id);
_logger.ProgressInfo("All episode files renamed for {0}", series.Title); // _logger.ProgressInfo("Renaming all files in series: {0}", series.Title);
} // RenameFiles(episodeFiles, series);
// _logger.ProgressInfo("All episode files renamed for {0}", series.Title);
//}
} }
} }
} }

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.MediaFiles
{
public class TrackFileMoveResult
{
public TrackFileMoveResult()
{
OldFiles = new List<TrackFile>();
}
public TrackFile TrackFile { get; set; }
public List<TrackFile> OldFiles { get; set; }
}
}

@ -0,0 +1,226 @@
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Music;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.MediaFiles
{
public interface IMoveTrackFiles
{
TrackFile MoveTrackFile(TrackFile trackFile, Artist artist);
TrackFile MoveTrackFile(TrackFile trackFile, LocalTrack localTrack);
TrackFile CopyTrackFile(TrackFile trackFile, LocalTrack localTrack);
}
public class TrackFileMovingService : IMoveTrackFiles
{
private readonly ITrackService _trackService;
//private readonly IUpdateTrackFileService _updateTrackFileService;
private readonly IBuildFileNames _buildFileNames;
private readonly IDiskTransferService _diskTransferService;
private readonly IDiskProvider _diskProvider;
private readonly IMediaFileAttributeService _mediaFileAttributeService;
private readonly IEventAggregator _eventAggregator;
private readonly IConfigService _configService;
private readonly Logger _logger;
public TrackFileMovingService(ITrackService episodeService,
//IUpdateEpisodeFileService updateEpisodeFileService,
IBuildFileNames buildFileNames,
IDiskTransferService diskTransferService,
IDiskProvider diskProvider,
IMediaFileAttributeService mediaFileAttributeService,
IEventAggregator eventAggregator,
IConfigService configService,
Logger logger)
{
_trackService = episodeService;
//_updateTrackFileService = updateEpisodeFileService;
_buildFileNames = buildFileNames;
_diskTransferService = diskTransferService;
_diskProvider = diskProvider;
_mediaFileAttributeService = mediaFileAttributeService;
_eventAggregator = eventAggregator;
_configService = configService;
_logger = logger;
}
public TrackFile MoveTrackFile(TrackFile trackFile, Artist artist)
{
throw new System.NotImplementedException();
// TODO
//var tracks = _trackService.GetTracksByFileId(trackFile.Id);
//var newFileName = _buildFileNames.BuildFileName(tracks, artist, trackFile);
//var filePath = _buildFileNames.BuildFilePath(artist, tracks.First(), trackFile.AlbumId, newFileName, Path.GetExtension(trackFile.RelativePath));
//EnsureAlbumFolder(trackFile, artist, tracks.Select(v => v.Album).First(), filePath);
//_logger.Debug("Renaming track file: {0} to {1}", trackFile, filePath);
//return TransferFile(trackFile, artist, tracks, filePath, TransferMode.Move);
}
public TrackFile MoveTrackFile(TrackFile trackFile, LocalTrack localTrack)
{
// TODO
throw new System.NotImplementedException();
//var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile);
//var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(localEpisode.Path));
//EnsureEpisodeFolder(episodeFile, localEpisode, filePath);
//_logger.Debug("Moving episode file: {0} to {1}", episodeFile.Path, filePath);
//return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.Move);
}
public TrackFile CopyTrackFile(TrackFile trackFile, LocalTrack localTrack)
{
// TODO
throw new System.NotImplementedException();
//var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile);
//var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(localEpisode.Path));
//EnsureEpisodeFolder(episodeFile, localEpisode, filePath);
//if (_configService.CopyUsingHardlinks)
//{
// _logger.Debug("Hardlinking episode file: {0} to {1}", episodeFile.Path, filePath);
// return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.HardLinkOrCopy);
//}
//_logger.Debug("Copying episode file: {0} to {1}", episodeFile.Path, filePath);
//return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.Copy);
}
private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List<Episode> episodes, string destinationFilePath, TransferMode mode)
{
// TODO
throw new System.NotImplementedException();
//Ensure.That(episodeFile, () => episodeFile).IsNotNull();
//Ensure.That(series, () => series).IsNotNull();
//Ensure.That(destinationFilePath, () => destinationFilePath).IsValidPath();
//var episodeFilePath = episodeFile.Path ?? Path.Combine(series.Path, episodeFile.RelativePath);
//if (!_diskProvider.FileExists(episodeFilePath))
//{
// throw new FileNotFoundException("Episode file path does not exist", episodeFilePath);
//}
//if (episodeFilePath == destinationFilePath)
//{
// throw new SameFilenameException("File not moved, source and destination are the same", episodeFilePath);
//}
//_diskTransferService.TransferFile(episodeFilePath, destinationFilePath, mode);
//episodeFile.RelativePath = series.Path.GetRelativePath(destinationFilePath);
//_updateTrackFileService.ChangeFileDateForFile(episodeFile, series, episodes);
//try
//{
// _mediaFileAttributeService.SetFolderLastWriteTime(series.Path, episodeFile.DateAdded);
// if (series.SeasonFolder)
// {
// var seasonFolder = Path.GetDirectoryName(destinationFilePath);
// _mediaFileAttributeService.SetFolderLastWriteTime(seasonFolder, episodeFile.DateAdded);
// }
//}
//catch (Exception ex)
//{
// _logger.Warn(ex, "Unable to set last write time");
//}
//_mediaFileAttributeService.SetFilePermissions(destinationFilePath);
//return episodeFile;
}
private void EnsureEpisodeFolder(EpisodeFile episodeFile, LocalEpisode localEpisode, string filePath)
{
EnsureEpisodeFolder(episodeFile, localEpisode.Series, localEpisode.SeasonNumber, filePath);
}
private void EnsureEpisodeFolder(EpisodeFile episodeFile, Series series, int seasonNumber, string filePath)
{
var episodeFolder = Path.GetDirectoryName(filePath);
var seasonFolder = _buildFileNames.BuildSeasonPath(series, seasonNumber);
var seriesFolder = series.Path;
var rootFolder = new OsPath(seriesFolder).Directory.FullPath;
if (!_diskProvider.FolderExists(rootFolder))
{
throw new DirectoryNotFoundException(string.Format("Root folder '{0}' was not found.", rootFolder));
}
var changed = false;
var newEvent = new EpisodeFolderCreatedEvent(series, episodeFile);
if (!_diskProvider.FolderExists(seriesFolder))
{
CreateFolder(seriesFolder);
newEvent.SeriesFolder = seriesFolder;
changed = true;
}
if (seriesFolder != seasonFolder && !_diskProvider.FolderExists(seasonFolder))
{
CreateFolder(seasonFolder);
newEvent.SeasonFolder = seasonFolder;
changed = true;
}
if (seasonFolder != episodeFolder && !_diskProvider.FolderExists(episodeFolder))
{
CreateFolder(episodeFolder);
newEvent.EpisodeFolder = episodeFolder;
changed = true;
}
if (changed)
{
_eventAggregator.PublishEvent(newEvent);
}
}
private void CreateFolder(string directoryName)
{
Ensure.That(directoryName, () => directoryName).IsNotNullOrWhiteSpace();
var parentFolder = new OsPath(directoryName).Directory.FullPath;
if (!_diskProvider.FolderExists(parentFolder))
{
CreateFolder(parentFolder);
}
try
{
_diskProvider.CreateFolder(directoryName);
}
catch (IOException ex)
{
_logger.Error(ex, "Unable to create directory: {0}", directoryName);
}
_mediaFileAttributeService.SetFolderPermissions(directoryName);
}
}
}

@ -0,0 +1,172 @@
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Qualities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.MediaFiles.TrackImport
{
public interface IImportApprovedTracks
{
List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto);
}
public class ImportApprovedTracks : IImportApprovedTracks
{
private readonly IUpgradeMediaFiles _trackFileUpgrader;
private readonly IMediaFileService _mediaFileService;
//private readonly IExtraService _extraService;
private readonly IDiskProvider _diskProvider;
private readonly IEventAggregator _eventAggregator;
private readonly Logger _logger;
public ImportApprovedTracks(IUpgradeMediaFiles episodeFileUpgrader,
IMediaFileService mediaFileService,
//IExtraService extraService,
IDiskProvider diskProvider,
IEventAggregator eventAggregator,
Logger logger)
{
_trackFileUpgrader = episodeFileUpgrader;
_mediaFileService = mediaFileService;
// _extraService = extraService;
_diskProvider = diskProvider;
_eventAggregator = eventAggregator;
_logger = logger;
}
public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto)
{
var qualifiedImports = decisions.Where(c => c.Approved)
.GroupBy(c => c.LocalTrack.Artist.Id, (i, s) => s
.OrderByDescending(c => c.LocalTrack.Quality, new QualityModelComparer(s.First().LocalTrack.Artist.Profile))
.ThenByDescending(c => c.LocalTrack.Size))
.SelectMany(c => c)
.ToList();
var importResults = new List<ImportResult>();
foreach (var importDecision in qualifiedImports.OrderBy(e => e.LocalTrack.Tracks.Select(track => track.TrackNumber).MinOrDefault())
.ThenByDescending(e => e.LocalTrack.Size))
{
var localTrack = importDecision.LocalTrack;
var oldFiles = new List<TrackFile>();
try
{
//check if already imported
if (importResults.SelectMany(r => r.ImportDecision.LocalTrack.Tracks)
.Select(e => e.Id)
.Intersect(localTrack.Tracks.Select(e => e.Id))
.Any())
{
importResults.Add(new ImportResult(importDecision, "Episode has already been imported"));
continue;
}
var trackFile = new TrackFile();
trackFile.DateAdded = DateTime.UtcNow;
trackFile.SpotifyTrackId = localTrack.Artist.SpotifyId;
trackFile.Path = localTrack.Path.CleanFilePath();
trackFile.Size = _diskProvider.GetFileSize(localTrack.Path);
trackFile.Quality = localTrack.Quality;
trackFile.MediaInfo = localTrack.MediaInfo;
//trackFile.AlbumId = localTrack.Album.ElementAt(0); // TODO: Implement ImportApprovedTracks Album Id
trackFile.Tracks = localTrack.Tracks;
trackFile.ReleaseGroup = localTrack.ParsedTrackInfo.ReleaseGroup;
bool copyOnly;
switch (importMode)
{
default:
case ImportMode.Auto:
copyOnly = downloadClientItem != null && downloadClientItem.IsReadOnly;
break;
case ImportMode.Move:
copyOnly = false;
break;
case ImportMode.Copy:
copyOnly = true;
break;
}
if (newDownload)
{
//trackFile.SceneName = GetSceneName(downloadClientItem, localTrack);
var moveResult = _trackFileUpgrader.UpgradeTrackFile(trackFile, localTrack, copyOnly);
oldFiles = moveResult.OldFiles;
}
else
{
trackFile.RelativePath = localTrack.Artist.Path.GetRelativePath(trackFile.Path);
}
_mediaFileService.Add(trackFile);
importResults.Add(new ImportResult(importDecision));
//if (newDownload)
//{
// _extraService.ImportExtraFiles(localTrack, trackFile, copyOnly); // TODO: Import Music Extras
//}
if (downloadClientItem != null)
{
_eventAggregator.PublishEvent(new TrackImportedEvent(localTrack, trackFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId, downloadClientItem.IsReadOnly));
}
else
{
_eventAggregator.PublishEvent(new TrackImportedEvent(localTrack, trackFile, newDownload));
}
if (newDownload)
{
_eventAggregator.PublishEvent(new TrackDownloadedEvent(localTrack, trackFile, oldFiles));
}
}
catch (Exception e)
{
_logger.Warn(e, "Couldn't import track " + localTrack);
importResults.Add(new ImportResult(importDecision, "Failed to import episode"));
}
}
//Adding all the rejected decisions
importResults.AddRange(decisions.Where(c => !c.Approved)
.Select(d => new ImportResult(d, d.Rejections.Select(r => r.Reason).ToArray())));
return importResults;
}
//private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode)
//{
// if (downloadClientItem != null)
// {
// var title = Parser.Parser.RemoveFileExtension(downloadClientItem.Title);
// var parsedTitle = Parser.Parser.ParseTitle(title);
// if (parsedTitle != null && !parsedTitle.FullSeason)
// {
// return title;
// }
// }
// var fileName = Path.GetFileNameWithoutExtension(localEpisode.Path.CleanFilePath());
// if (SceneChecker.IsSceneTitle(fileName))
// {
// return fileName;
// }
// return null;
//}
}
}

@ -0,0 +1,26 @@
using NzbDrone.Common.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.MediaFiles.TrackImport
{
public class ImportDecision
{
public LocalTrack LocalTrack { get; private set; }
public IEnumerable<Rejection> Rejections { get; private set; }
public bool Approved => Rejections.Empty();
public object LocalEpisode { get; internal set; }
public ImportDecision(LocalTrack localTrack, params Rejection[] rejections)
{
LocalTrack = localTrack;
Rejections = rejections.ToList();
}
}
}

@ -1,4 +1,4 @@
namespace NzbDrone.Core.MediaFiles.EpisodeImport namespace NzbDrone.Core.MediaFiles.TrackImport
{ {
public enum ImportMode public enum ImportMode
{ {

@ -1,8 +1,10 @@
using System.Collections.Generic; using NzbDrone.Common.EnsureThat;
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Common.EnsureThat; using System.Text;
namespace NzbDrone.Core.MediaFiles.EpisodeImport namespace NzbDrone.Core.MediaFiles.TrackImport
{ {
public class ImportResult public class ImportResult
{ {

@ -1,4 +1,4 @@
namespace NzbDrone.Core.MediaFiles.EpisodeImport namespace NzbDrone.Core.MediaFiles.TrackImport
{ {
public enum ImportResultType public enum ImportResultType
{ {

@ -9,7 +9,8 @@ namespace NzbDrone.Core.MediaFiles
{ {
public interface IUpgradeMediaFiles public interface IUpgradeMediaFiles
{ {
EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode, bool copyOnly = false); //EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode, bool copyOnly = false);
TrackFileMoveResult UpgradeTrackFile(TrackFile trackFile, LocalTrack localTrack, bool copyOnly = false);
} }
public class UpgradeMediaFileService : IUpgradeMediaFiles public class UpgradeMediaFileService : IUpgradeMediaFiles
@ -17,35 +18,36 @@ namespace NzbDrone.Core.MediaFiles
private readonly IRecycleBinProvider _recycleBinProvider; private readonly IRecycleBinProvider _recycleBinProvider;
private readonly IMediaFileService _mediaFileService; private readonly IMediaFileService _mediaFileService;
private readonly IMoveEpisodeFiles _episodeFileMover; private readonly IMoveEpisodeFiles _episodeFileMover;
private readonly IMoveTrackFiles _trackFileMover;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly Logger _logger; private readonly Logger _logger;
public UpgradeMediaFileService(IRecycleBinProvider recycleBinProvider, public UpgradeMediaFileService(IRecycleBinProvider recycleBinProvider,
IMediaFileService mediaFileService, IMediaFileService mediaFileService,
IMoveEpisodeFiles episodeFileMover, IMoveTrackFiles trackFileMover,
IDiskProvider diskProvider, IDiskProvider diskProvider,
Logger logger) Logger logger)
{ {
_recycleBinProvider = recycleBinProvider; _recycleBinProvider = recycleBinProvider;
_mediaFileService = mediaFileService; _mediaFileService = mediaFileService;
_episodeFileMover = episodeFileMover; _trackFileMover = trackFileMover;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_logger = logger; _logger = logger;
} }
public EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode, bool copyOnly = false) public TrackFileMoveResult UpgradeTrackFile(TrackFile trackFile, LocalTrack localTrack, bool copyOnly = false)
{ {
var moveFileResult = new EpisodeFileMoveResult(); var moveFileResult = new TrackFileMoveResult();
var existingFiles = localEpisode.Episodes var existingFiles = localTrack.Tracks
.Where(e => e.EpisodeFileId > 0) .Where(e => e.TrackFileId > 0)
.Select(e => e.EpisodeFile.Value) .Select(e => e.TrackFile.Value)
.GroupBy(e => e.Id); .GroupBy(e => e.Id);
foreach (var existingFile in existingFiles) foreach (var existingFile in existingFiles)
{ {
var file = existingFile.First(); var file = existingFile.First();
var episodeFilePath = Path.Combine(localEpisode.Series.Path, file.RelativePath); var episodeFilePath = Path.Combine(localTrack.Artist.Path, file.RelativePath);
var subfolder = _diskProvider.GetParentFolder(localEpisode.Series.Path).GetRelativePath(_diskProvider.GetParentFolder(episodeFilePath)); var subfolder = _diskProvider.GetParentFolder(localTrack.Artist.Path).GetRelativePath(_diskProvider.GetParentFolder(episodeFilePath));
if (_diskProvider.FileExists(episodeFilePath)) if (_diskProvider.FileExists(episodeFilePath))
{ {
@ -59,11 +61,11 @@ namespace NzbDrone.Core.MediaFiles
if (copyOnly) if (copyOnly)
{ {
moveFileResult.EpisodeFile = _episodeFileMover.CopyEpisodeFile(episodeFile, localEpisode); moveFileResult.TrackFile = _trackFileMover.CopyTrackFile(trackFile, localTrack);
} }
else else
{ {
moveFileResult.EpisodeFile = _episodeFileMover.MoveEpisodeFile(episodeFile, localEpisode); moveFileResult.TrackFile = _trackFileMover.MoveTrackFile(trackFile, localTrack);
} }
return moveFileResult; return moveFileResult;

@ -205,7 +205,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
var lowerTitle = title.ToLowerInvariant(); var lowerTitle = title.ToLowerInvariant();
Console.WriteLine("Searching for " + lowerTitle); Console.WriteLine("Searching for " + lowerTitle);
if (lowerTitle.StartsWith("itunes:") || lowerTitle.StartsWith("itunesid:")) if (lowerTitle.StartsWith("spotify:") || lowerTitle.StartsWith("spotifyid:"))
{ {
var slug = lowerTitle.Split(':')[1].Trim(); var slug = lowerTitle.Split(':')[1].Trim();

@ -55,11 +55,16 @@ namespace NzbDrone.Core.Music
return _trackRepository.Get(ids).ToList(); return _trackRepository.Get(ids).ToList();
} }
public Track FindTrack(string artistId, string albumId, int episodeNumber) public Track FindTrack(string artistId, string albumId, int trackNumber)
{ {
return _trackRepository.Find(artistId, albumId, episodeNumber); return _trackRepository.Find(artistId, albumId, trackNumber);
} }
//public Track FindTrack(string artistId, int trackNumber)
//{
// return _trackRepository.Find(artistId, trackNumber);
//}
public List<Track> GetTracksByArtist(string artistId) public List<Track> GetTracksByArtist(string artistId)
{ {
return _trackRepository.GetTracks(artistId).ToList(); return _trackRepository.GetTracks(artistId).ToList();
@ -132,7 +137,7 @@ namespace NzbDrone.Core.Music
_trackRepository.SetMonitoredByAlbum(artistId, albumId, monitored); _trackRepository.SetMonitoredByAlbum(artistId, albumId, monitored);
} }
public void UpdateEpisodes(List<Track> tracks) public void UpdateTracks(List<Track> tracks)
{ {
_trackRepository.UpdateMany(tracks); _trackRepository.UpdateMany(tracks);
} }
@ -182,10 +187,5 @@ namespace NzbDrone.Core.Music
_logger.Debug("Linking [{0}] > [{1}]", message.TrackFile.RelativePath, track); _logger.Debug("Linking [{0}] > [{1}]", message.TrackFile.RelativePath, track);
} }
} }
public void UpdateTracks(List<Track> tracks)
{
_trackRepository.UpdateMany(tracks);
}
} }
} }

@ -725,7 +725,10 @@
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" /> <Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" /> <Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" /> <Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportMode.cs" /> <Compile Include="MediaFiles\Events\TrackDownloadedEvent.cs" />
<Compile Include="MediaFiles\TrackFileMovingService.cs" />
<Compile Include="MediaFiles\TrackFileMoveResult.cs" />
<Compile Include="MediaFiles\TrackImport\ImportMode.cs" />
<Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" /> <Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" />
<Compile Include="MediaFiles\Commands\RenameSeriesCommand.cs" /> <Compile Include="MediaFiles\Commands\RenameSeriesCommand.cs" />
<Compile Include="MediaFiles\Commands\RescanSeriesCommand.cs" /> <Compile Include="MediaFiles\Commands\RescanSeriesCommand.cs" />
@ -740,12 +743,10 @@
<Compile Include="MediaFiles\EpisodeFile.cs" /> <Compile Include="MediaFiles\EpisodeFile.cs" />
<Compile Include="MediaFiles\EpisodeFileMoveResult.cs" /> <Compile Include="MediaFiles\EpisodeFileMoveResult.cs" />
<Compile Include="MediaFiles\EpisodeFileMovingService.cs" /> <Compile Include="MediaFiles\EpisodeFileMovingService.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportResult.cs" />
<Compile Include="MediaFiles\EpisodeImport\IImportDecisionEngineSpecification.cs" /> <Compile Include="MediaFiles\EpisodeImport\IImportDecisionEngineSpecification.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportApprovedEpisodes.cs" /> <Compile Include="MediaFiles\EpisodeImport\ImportApprovedEpisodes.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportDecision.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMaker.cs" /> <Compile Include="MediaFiles\EpisodeImport\ImportDecisionMaker.cs" />
<Compile Include="MediaFiles\EpisodeImport\ImportResultType.cs" /> <Compile Include="MediaFiles\TrackImport\ImportResultType.cs" />
<Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportFile.cs" /> <Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportFile.cs" />
<Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportCommand.cs" /> <Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportCommand.cs" />
<Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportItem.cs" /> <Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportItem.cs" />
@ -761,11 +762,14 @@
<Compile Include="MediaFiles\EpisodeImport\Specifications\UnverifiedSceneNumberingSpecification.cs" /> <Compile Include="MediaFiles\EpisodeImport\Specifications\UnverifiedSceneNumberingSpecification.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" /> <Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" />
<Compile Include="MediaFiles\Events\ArtistRenamedEvent.cs" /> <Compile Include="MediaFiles\Events\ArtistRenamedEvent.cs" />
<Compile Include="MediaFiles\Events\ArtistScannedEvent.cs" />
<Compile Include="MediaFiles\Events\ArtistScanSkippedEvent.cs" />
<Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" /> <Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" />
<Compile Include="MediaFiles\Events\EpisodeFileAddedEvent.cs" /> <Compile Include="MediaFiles\Events\EpisodeFileAddedEvent.cs" />
<Compile Include="MediaFiles\Events\EpisodeFileDeletedEvent.cs" /> <Compile Include="MediaFiles\Events\EpisodeFileDeletedEvent.cs" />
<Compile Include="MediaFiles\Events\EpisodeFolderCreatedEvent.cs" /> <Compile Include="MediaFiles\Events\EpisodeFolderCreatedEvent.cs" />
<Compile Include="MediaFiles\Events\EpisodeImportedEvent.cs" /> <Compile Include="MediaFiles\Events\EpisodeImportedEvent.cs" />
<Compile Include="MediaFiles\Commands\RescanArtistCommand.cs" />
<Compile Include="MediaFiles\Events\SeriesRenamedEvent.cs" /> <Compile Include="MediaFiles\Events\SeriesRenamedEvent.cs" />
<Compile Include="MediaFiles\Events\SeriesScanSkippedEvent.cs" /> <Compile Include="MediaFiles\Events\SeriesScanSkippedEvent.cs" />
<Compile Include="MediaFiles\Events\SeriesScannedEvent.cs" /> <Compile Include="MediaFiles\Events\SeriesScannedEvent.cs" />
@ -789,6 +793,9 @@
<Compile Include="MediaFiles\RenameEpisodeFileService.cs" /> <Compile Include="MediaFiles\RenameEpisodeFileService.cs" />
<Compile Include="MediaFiles\SameFilenameException.cs" /> <Compile Include="MediaFiles\SameFilenameException.cs" />
<Compile Include="MediaFiles\TrackFile.cs" /> <Compile Include="MediaFiles\TrackFile.cs" />
<Compile Include="MediaFiles\TrackImport\ImportApprovedTracks.cs" />
<Compile Include="MediaFiles\TrackImport\ImportDecision.cs" />
<Compile Include="MediaFiles\TrackImport\ImportResult.cs" />
<Compile Include="MediaFiles\UpdateEpisodeFileService.cs" /> <Compile Include="MediaFiles\UpdateEpisodeFileService.cs" />
<Compile Include="MediaFiles\UpgradeMediaFileService.cs" /> <Compile Include="MediaFiles\UpgradeMediaFileService.cs" />
<Compile Include="Messaging\Commands\BackendCommandAttribute.cs" /> <Compile Include="Messaging\Commands\BackendCommandAttribute.cs" />
@ -928,6 +935,7 @@
<Compile Include="Parser\IsoLanguage.cs" /> <Compile Include="Parser\IsoLanguage.cs" />
<Compile Include="Parser\IsoLanguages.cs" /> <Compile Include="Parser\IsoLanguages.cs" />
<Compile Include="Parser\LanguageParser.cs" /> <Compile Include="Parser\LanguageParser.cs" />
<Compile Include="Parser\Model\ArtistTitleInfo.cs" />
<Compile Include="Parser\Model\LocalTrack.cs" /> <Compile Include="Parser\Model\LocalTrack.cs" />
<Compile Include="Parser\Model\ParsedTrackInfo.cs" /> <Compile Include="Parser\Model\ParsedTrackInfo.cs" />
<Compile Include="Profiles\Delay\DelayProfile.cs" /> <Compile Include="Profiles\Delay\DelayProfile.cs" />

@ -380,33 +380,34 @@ namespace NzbDrone.Core.Parser
if (result != null) if (result != null)
{ {
if (result.FullSeason && title.ContainsIgnoreCase("Special")) //if (result.FullSeason && title.ContainsIgnoreCase("Special"))
{ //{
result.FullSeason = false; // result.FullSeason = false;
result.Special = true; // result.Special = true;
} //}
result.Language = LanguageParser.ParseLanguage(title); //result.Language = LanguageParser.ParseLanguage(title);
Logger.Debug("Language parsed: {0}", result.Language); //Logger.Debug("Language parsed: {0}", result.Language);
result.Quality = QualityParser.ParseQuality(title); result.Quality = QualityParser.ParseQuality(title);
Logger.Debug("Quality parsed: {0}", result.Quality); Logger.Debug("Quality parsed: {0}", result.Quality);
result.ReleaseGroup = ParseReleaseGroup(title); // Majora: We don't currently need Release Group for Music.
//result.ReleaseGroup = ParseReleaseGroup(title);
var subGroup = GetSubGroup(match); //var subGroup = GetSubGroup(match);
if (!subGroup.IsNullOrWhiteSpace()) //if (!subGroup.IsNullOrWhiteSpace())
{ //{
result.ReleaseGroup = subGroup; // result.ReleaseGroup = subGroup;
} //}
Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup); //Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup);
result.ReleaseHash = GetReleaseHash(match); //result.ReleaseHash = GetReleaseHash(match);
if (!result.ReleaseHash.IsNullOrWhiteSpace()) //if (!result.ReleaseHash.IsNullOrWhiteSpace())
{ //{
Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash); // Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash);
} //}
return result; return result;
} }

@ -457,7 +457,9 @@ namespace NzbDrone.Core.Parser
if (trackInfo == null) if (trackInfo == null)
{ {
trackInfo = _trackService.FindTrack(artist.SpotifyId, trackNumber); // TODO: [ParsingService]: FindTrack by artistID and trackNumber (or albumID and trackNumber if we change db schema to album as base)
_logger.Debug("TrackInfo is null, we will not add as FindTrack(artistId, trackNumber) is not implemented");
//trackInfo = _trackService.FindTrack(artist.SpotifyId, trackNumber);
} }
if (trackInfo != null) if (trackInfo != null)
@ -467,7 +469,7 @@ namespace NzbDrone.Core.Parser
else else
{ {
_logger.Debug("Unable to find {0}", parsedEpisodeInfo); _logger.Debug("Unable to find {0}", parsedTrackInfo);
} }
} }
@ -553,6 +555,7 @@ namespace NzbDrone.Core.Parser
return result; return result;
} }
public LocalTrack GetLocalTrack(string filename, Artist artist) public LocalTrack GetLocalTrack(string filename, Artist artist)
{ {
return GetLocalTrack(filename, artist, null); return GetLocalTrack(filename, artist, null);
@ -635,7 +638,60 @@ namespace NzbDrone.Core.Parser
} }
return GetStandardEpisodes(artist, parsedTrackInfo, sceneSource, searchCriteria);*/ return GetStandardEpisodes(artist, parsedTrackInfo, sceneSource, searchCriteria);*/
return GetStandardTracks(artist, parsedTrackInfo, searchCriteria); return GetStandardTracks(artist, parsedTrackInfo);
}
private List<Track> GetStandardTracks(Artist artist, ParsedTrackInfo parsedTrackInfo)
{
var result = new List<Track>();
//var seasonNumber = parsedEpisodeInfo.SeasonNumber;
//if (sceneSource)
//{
// var sceneMapping = _sceneMappingService.FindSceneMapping(parsedEpisodeInfo.SeriesTitle);
// if (sceneMapping != null && sceneMapping.SeasonNumber.HasValue && sceneMapping.SeasonNumber.Value >= 0 &&
// sceneMapping.SceneSeasonNumber == seasonNumber)
// {
// seasonNumber = sceneMapping.SeasonNumber.Value;
// }
//}
if (parsedTrackInfo.TrackNumbers == null)
{
return new List<Track>();
}
foreach (var trackNumber in parsedTrackInfo.TrackNumbers)
{
Track trackInfo = null;
//if (searchCriteria != null)
//{
// trackInfo = searchCriteria.Episodes.SingleOrDefault(e => e.SeasonNumber == seasonNumber && e.EpisodeNumber == trackNumber);
//}
if (trackInfo == null)
{
// TODO: [ParsingService]: FindTrack by artistID and trackNumber (or albumID and trackNumber if we change db schema to album as base)
_logger.Debug("TrackInfo is null, we will not add as FindTrack(artistId, trackNumber) is not implemented");
//trackInfo = _trackService.FindTrack(artist.SpotifyId, trackNumber); //series.Id, seasonNumber, trackNumber
}
if (trackInfo != null)
{
result.Add(trackInfo);
}
else
{
_logger.Debug("Unable to find {0}", parsedTrackInfo);
}
}
return result;
} }
} }
} }

@ -176,7 +176,7 @@ namespace NzbDrone.Core.Tv
try try
{ {
_logger.Info("Skipping refresh of series: {0}", series.Title); _logger.Info("Skipping refresh of series: {0}", series.Title);
_diskScanService.Scan(series); //_diskScanService.Scan(series);
} }
catch (Exception e) catch (Exception e)
{ {

Loading…
Cancel
Save