diff --git a/src/NzbDrone.Api/EpisodeFiles/EpisodeFileModule.cs b/src/NzbDrone.Api/EpisodeFiles/EpisodeFileModule.cs index c2044bda3..d89a0068c 100644 --- a/src/NzbDrone.Api/EpisodeFiles/EpisodeFileModule.cs +++ b/src/NzbDrone.Api/EpisodeFiles/EpisodeFileModule.cs @@ -11,6 +11,7 @@ using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Tv; using NzbDrone.Core.DecisionEngine; using NzbDrone.SignalR; +using System; namespace NzbDrone.Api.EpisodeFiles { @@ -47,24 +48,26 @@ namespace NzbDrone.Api.EpisodeFiles private EpisodeFileResource GetEpisodeFile(int id) { - var episodeFile = _mediaFileService.Get(id); - var series = _seriesService.GetSeries(episodeFile.SeriesId); + throw new NotImplementedException(); + //var episodeFile = _mediaFileService.Get(id); + //var series = _seriesService.GetSeries(episodeFile.SeriesId); - return episodeFile.ToResource(series, _qualityUpgradableSpecification); + //return episodeFile.ToResource(series, _qualityUpgradableSpecification); } private List GetEpisodeFiles() { - if (!Request.Query.SeriesId.HasValue) - { - throw new BadRequestException("seriesId is missing"); - } + throw new NotImplementedException(); + //if (!Request.Query.SeriesId.HasValue) + //{ + // 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) @@ -76,14 +79,15 @@ namespace NzbDrone.Api.EpisodeFiles private void DeleteEpisodeFile(int id) { - var episodeFile = _mediaFileService.Get(id); - var series = _seriesService.GetSeries(episodeFile.SeriesId); - var fullPath = Path.Combine(series.Path, episodeFile.RelativePath); - var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath)); + throw new NotImplementedException(); + //var episodeFile = _mediaFileService.Get(id); + //var series = _seriesService.GetSeries(episodeFile.SeriesId); + //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); - _recycleBinProvider.DeleteFile(fullPath, subfolder); - _mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual); + //_logger.Info("Deleting episode file: {0}", fullPath); + //_recycleBinProvider.DeleteFile(fullPath, subfolder); + //_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual); } public void Handle(EpisodeFileAddedEvent message) diff --git a/src/NzbDrone.Api/Music/ArtistModule.cs b/src/NzbDrone.Api/Music/ArtistModule.cs index d7ef5fed3..61acceb0e 100644 --- a/src/NzbDrone.Api/Music/ArtistModule.cs +++ b/src/NzbDrone.Api/Music/ArtistModule.cs @@ -144,14 +144,14 @@ namespace NzbDrone.Api.Music 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) { 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) diff --git a/src/NzbDrone.Core/Download/CompletedDownloadService.cs b/src/NzbDrone.Core/Download/CompletedDownloadService.cs index 4e46b3729..d9a48965c 100644 --- a/src/NzbDrone.Core/Download/CompletedDownloadService.cs +++ b/src/NzbDrone.Core/Download/CompletedDownloadService.cs @@ -13,6 +13,7 @@ using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Tv; +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.Download { @@ -130,7 +131,7 @@ namespace NzbDrone.Core.Download { var statusMessages = importResults .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(); trackedDownload.Warn(statusMessages); diff --git a/src/NzbDrone.Core/Extras/ExtraService.cs b/src/NzbDrone.Core/Extras/ExtraService.cs index 811d3ebea..7447e162e 100644 --- a/src/NzbDrone.Core/Extras/ExtraService.cs +++ b/src/NzbDrone.Core/Extras/ExtraService.cs @@ -16,6 +16,7 @@ using NzbDrone.Core.Tv; 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 { void ImportExtraFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly); @@ -136,16 +137,17 @@ namespace NzbDrone.Core.Extras private List GetEpisodeFiles(int seriesId) { - var episodeFiles = _mediaFileService.GetFilesBySeries(seriesId); - var episodes = _episodeService.GetEpisodeBySeries(seriesId); + //var episodeFiles = _mediaFileService.GetFilesBySeries(seriesId); + //var episodes = _episodeService.GetEpisodeBySeries(seriesId); - foreach (var episodeFile in episodeFiles) - { - var localEpisodeFile = episodeFile; - episodeFile.Episodes = new LazyList(episodes.Where(e => e.EpisodeFileId == localEpisodeFile.Id)); - } + //foreach (var episodeFile in episodeFiles) + //{ + // var localEpisodeFile = episodeFile; + // episodeFile.Episodes = new LazyList(episodes.Where(e => e.EpisodeFileId == localEpisodeFile.Id)); + //} - return episodeFiles; + //return episodeFiles; + return new List(); } } } diff --git a/src/NzbDrone.Core/MediaFiles/Commands/DownloadedEpisodesScanCommand.cs b/src/NzbDrone.Core/MediaFiles/Commands/DownloadedEpisodesScanCommand.cs index ab2f80480..70befbb18 100644 --- a/src/NzbDrone.Core/MediaFiles/Commands/DownloadedEpisodesScanCommand.cs +++ b/src/NzbDrone.Core/MediaFiles/Commands/DownloadedEpisodesScanCommand.cs @@ -1,4 +1,5 @@ using NzbDrone.Core.MediaFiles.EpisodeImport; +using NzbDrone.Core.MediaFiles.TrackImport; using NzbDrone.Core.Messaging.Commands; namespace NzbDrone.Core.MediaFiles.Commands diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs index 60c929956..773b94519 100644 --- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -18,12 +18,12 @@ using NzbDrone.Core.Tv; using NzbDrone.Core.Tv.Events; using NzbDrone.Core.Music; using NzbDrone.Core.Music.Events; +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.MediaFiles { public interface IDiskScanService { - void Scan(Series series); void Scan(Artist artist); string[] GetVideoFiles(string path, bool allDirectories = true); string[] GetNonVideoFiles(string path, bool allDirectories = true); @@ -32,14 +32,12 @@ namespace NzbDrone.Core.MediaFiles public class DiskScanService : IDiskScanService, - IHandle, - IExecute, IHandle, IExecute { private readonly IDiskProvider _diskProvider; private readonly IMakeImportDecision _importDecisionMaker; - private readonly IImportApprovedEpisodes _importApprovedEpisodes; + private readonly IImportApprovedTracks _importApprovedTracks; private readonly IConfigService _configService; private readonly ISeriesService _seriesService; private readonly IArtistService _artistService; @@ -49,7 +47,7 @@ namespace NzbDrone.Core.MediaFiles public DiskScanService(IDiskProvider diskProvider, IMakeImportDecision importDecisionMaker, - IImportApprovedEpisodes importApprovedEpisodes, + IImportApprovedTracks importApprovedTracks, IConfigService configService, ISeriesService seriesService, IArtistService artistService, @@ -59,7 +57,7 @@ namespace NzbDrone.Core.MediaFiles { _diskProvider = diskProvider; _importDecisionMaker = importDecisionMaker; - _importApprovedEpisodes = importApprovedEpisodes; + _importApprovedTracks = importApprovedTracks; _configService = configService; _seriesService = seriesService; _artistService = artistService; @@ -123,76 +121,18 @@ namespace NzbDrone.Core.MediaFiles 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()); - 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 mediaFileList) - { - _logger.Debug("{0} Cleaning up media files in DB", series); - _mediaFileTableCleanupService.Clean(series, mediaFileList); - } - + private void CleanMediaFiles(Artist artist, List mediaFileList) { _logger.Debug("{0} Cleaning up media files in DB", artist); _mediaFileTableCleanupService.Clean(artist, mediaFileList); } - private void CompletedScanning(Series series) - { - _logger.Info("Completed scanning disk for {0}", series.Title); - _eventAggregator.PublishEvent(new SeriesScannedEvent(series)); - } + //private void CompletedScanning(Series series) + //{ + // _logger.Info("Completed scanning disk for {0}", series.Title); + // _eventAggregator.PublishEvent(new SeriesScannedEvent(series)); + //} 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) { 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) { if (message.ArtistId.IsNotNullOrWhiteSpace()) diff --git a/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesCommandService.cs b/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesCommandService.cs index 2f5e19a41..f3ded84b2 100644 --- a/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesCommandService.cs +++ b/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesCommandService.cs @@ -9,6 +9,7 @@ using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.MediaFiles.Commands; using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.MediaFiles { diff --git a/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesImportService.cs b/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesImportService.cs index febc267a8..d5caf8fd2 100644 --- a/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesImportService.cs +++ b/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesImportService.cs @@ -9,6 +9,7 @@ using NzbDrone.Core.Parser; using NzbDrone.Core.Tv; using NzbDrone.Core.Download; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.MediaFiles { @@ -59,7 +60,7 @@ namespace NzbDrone.Core.MediaFiles 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); results.AddRange(fileResults); @@ -100,7 +101,7 @@ namespace NzbDrone.Core.MediaFiles 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"); foreach (var videoFile in videoFiles) @@ -152,48 +153,50 @@ namespace NzbDrone.Core.MediaFiles private List ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem) { - if (_seriesService.SeriesPathExists(directoryInfo.FullName)) - { - _logger.Warn("Unable to process folder that is mapped to an existing show"); - return new List(); - } - - var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); - var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name); - - if (folderInfo != null) - { - _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality); - } - - var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName); - - if (downloadClientItem == null) - { - foreach (var videoFile in videoFiles) - { - if (_diskProvider.IsFileLocked(videoFile)) - { - return new List - { - FileIsLockedResult(videoFile) - }; - } - } - } - - var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, folderInfo, true); - var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode); - - if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) && - importResults.Any(i => i.Result == ImportResultType.Imported) && - ShouldDeleteFolder(directoryInfo, series)) - { - _logger.Debug("Deleting folder after importing valid files"); - _diskProvider.DeleteFolder(directoryInfo.FullName, true); - } - - return importResults; + throw new System.NotImplementedException("Will be removed"); + + //if (_seriesService.SeriesPathExists(directoryInfo.FullName)) + //{ + // _logger.Warn("Unable to process folder that is mapped to an existing show"); + // return new List(); + //} + + //var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); + //var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name); + + //if (folderInfo != null) + //{ + // _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality); + //} + + //var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName); + + //if (downloadClientItem == null) + //{ + // foreach (var videoFile in videoFiles) + // { + // if (_diskProvider.IsFileLocked(videoFile)) + // { + // return new List + // { + // FileIsLockedResult(videoFile) + // }; + // } + // } + //} + + //var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, folderInfo, true); + //var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode); + + //if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) && + // importResults.Any(i => i.Result == ImportResultType.Imported) && + // ShouldDeleteFolder(directoryInfo, series)) + //{ + // _logger.Debug("Deleting folder after importing valid files"); + // _diskProvider.DeleteFolder(directoryInfo.FullName, true); + //} + + //return importResults; } private List ProcessFile(FileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem) @@ -215,30 +218,31 @@ namespace NzbDrone.Core.MediaFiles private List ProcessFile(FileInfo fileInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem) { - if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._")) - { - _logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName); - - return new List - { - new ImportResult(new ImportDecision(new LocalEpisode { Path = fileInfo.FullName }, new Rejection("Invalid video file, filename starts with '._'")), "Invalid video file, filename starts with '._'") - }; - } - - if (downloadClientItem == null) - { - if (_diskProvider.IsFileLocked(fileInfo.FullName)) - { - return new List - { - FileIsLockedResult(fileInfo.FullName) - }; - } - } - - var decisions = _importDecisionMaker.GetImportDecisions(new List() { fileInfo.FullName }, series, null, true); - - return _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode); + throw new System.NotImplementedException("Will be removed"); + //if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._")) + //{ + // _logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName); + + // return new List + // { + // 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 (_diskProvider.IsFileLocked(fileInfo.FullName)) + // { + // return new List + // { + // FileIsLockedResult(fileInfo.FullName) + // }; + // } + //} + + //var decisions = _importDecisionMaker.GetImportDecisions(new List() { fileInfo.FullName }, series, null, true); + + //return _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode); } private string GetCleanedUpFolderName(string folder) @@ -251,15 +255,17 @@ namespace NzbDrone.Core.MediaFiles private ImportResult FileIsLockedResult(string videoFile) { - _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"); + throw new System.NotImplementedException("Will be removed"); + //_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) { - 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); } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/IImportDecisionEngineSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/IImportDecisionEngineSpecification.cs index 86abb87b7..50f491ca6 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/IImportDecisionEngineSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/IImportDecisionEngineSpecification.cs @@ -6,5 +6,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport public interface IImportDecisionEngineSpecification { Decision IsSatisfiedBy(LocalEpisode localEpisode); + Decision IsSatisfiedBy(LocalTrack localTrack); } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs index cdfd289db..f3cc3404a 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs @@ -12,7 +12,7 @@ using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Download; using NzbDrone.Core.Extras; - +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.MediaFiles.EpisodeImport { @@ -47,105 +47,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport public List Import(List decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto) { - var qualifiedImports = decisions.Where(c => c.Approved) - .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(); - - 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(); - - 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; + throw new NotImplementedException("This will be removed"); } private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode) diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecision.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecision.cs deleted file mode 100644 index 5e4e2ede2..000000000 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecision.cs +++ /dev/null @@ -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 Rejections { get; private set; } - - public bool Approved => Rejections.Empty(); - - public ImportDecision(LocalEpisode localEpisode, params Rejection[] rejections) - { - LocalEpisode = localEpisode; - Rejections = rejections.ToList(); - } - } -} diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs index 23924686c..4209e98c7 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs @@ -12,6 +12,7 @@ using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.Music; +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.MediaFiles.EpisodeImport { @@ -94,7 +95,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport 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; @@ -109,11 +110,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport _logger.Debug("Size: {0}", localTrack.Size); - //TODO: make it so media info doesn't ruin the import process of a new series - if (sceneSource) - { - localTrack.MediaInfo = _videoFileInfoReader.GetMediaInfo(file); - } + //TODO: make it so media info doesn't ruin the import process of a new artist if (localTrack.Tracks.Empty()) { @@ -137,19 +134,41 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport { _logger.Error(e, "Couldn't import file. {0}", file); - var localEpisode = new LocalEpisode { Path = file }; - decision = new ImportDecision(localEpisode, new Rejection("Unexpected error processing file")); + var localTrack = new LocalTrack { Path = file }; + decision = new ImportDecision(localTrack, new Rejection("Unexpected error processing file")); } 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); - 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) diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportCommand.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportCommand.cs index 38ed485b7..28168385f 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportCommand.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportCommand.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual { diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs index d85a2e119..a12c841ea 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs @@ -15,6 +15,7 @@ using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual { @@ -94,65 +95,67 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual private List ProcessFolder(string folder, string downloadId) { - var directoryInfo = new DirectoryInfo(folder); - var series = _parsingService.GetSeries(directoryInfo.Name); + throw new System.NotImplementedException("TODO: This will be rewritten for Music"); + //var directoryInfo = new DirectoryInfo(folder); + //var series = _parsingService.GetSeries(directoryInfo.Name); - if (series == null && downloadId.IsNotNullOrWhiteSpace()) - { - var trackedDownload = _trackedDownloadService.Find(downloadId); - series = trackedDownload.RemoteEpisode.Series; - } + //if (series == null && downloadId.IsNotNullOrWhiteSpace()) + //{ + // var trackedDownload = _trackedDownloadService.Find(downloadId); + // series = trackedDownload.RemoteEpisode.Series; + //} - if (series == null) - { - var files = _diskScanService.GetVideoFiles(folder); + //if (series == null) + //{ + // 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 seriesFiles = _diskScanService.GetVideoFiles(folder).ToList(); - var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, folderInfo, SceneSource(series, folder)); + //var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name); + //var seriesFiles = _diskScanService.GetVideoFiles(folder).ToList(); + //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) { - if (folder.IsNullOrWhiteSpace()) - { - folder = new FileInfo(file).Directory.FullName; - } + throw new System.NotImplementedException("TODO: This will be rewritten for Music"); + //if (folder.IsNullOrWhiteSpace()) + //{ + // 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) - { - series = _parsingService.GetSeries(relativeFile); - } + //if (series == null) + //{ + // series = _parsingService.GetSeries(relativeFile); + //} - if (series == null && downloadId.IsNotNullOrWhiteSpace()) - { - var trackedDownload = _trackedDownloadService.Find(downloadId); - series = trackedDownload.RemoteEpisode.Series; - } + //if (series == null && downloadId.IsNotNullOrWhiteSpace()) + //{ + // var trackedDownload = _trackedDownloadService.Find(downloadId); + // series = trackedDownload.RemoteEpisode.Series; + //} - if (series == null) - { - var localEpisode = new LocalEpisode(); - localEpisode.Path = file; - localEpisode.Quality = QualityParser.ParseQuality(file); - localEpisode.Size = _diskProvider.GetFileSize(file); + //if (series == null) + //{ + // var localEpisode = new LocalEpisode(); + // localEpisode.Path = file; + // localEpisode.Quality = QualityParser.ParseQuality(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 {file}, - series, null, SceneSource(series, folder)); + //var importDecisions = _importDecisionMaker.GetImportDecisions(new List {file}, + // 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) @@ -162,107 +165,109 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual private ManualImportItem MapItem(ImportDecision decision, string folder, string downloadId) { - var item = new ManualImportItem(); - - item.Path = decision.LocalEpisode.Path; - item.RelativePath = folder.GetRelativePath(decision.LocalEpisode.Path); - item.Name = Path.GetFileNameWithoutExtension(decision.LocalEpisode.Path); - item.DownloadId = downloadId; - - if (decision.LocalEpisode.Series != null) - { - item.Series = decision.LocalEpisode.Series; - } - - if (decision.LocalEpisode.Episodes.Any()) - { - item.SeasonNumber = decision.LocalEpisode.SeasonNumber; - item.Episodes = decision.LocalEpisode.Episodes; - } - - item.Quality = decision.LocalEpisode.Quality; - item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path); - item.Rejections = decision.Rejections; - - return item; + 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.Name = Path.GetFileNameWithoutExtension(decision.LocalEpisode.Path); + //item.DownloadId = downloadId; + + //if (decision.LocalEpisode.Series != null) + //{ + // item.Series = decision.LocalEpisode.Series; + //} + + //if (decision.LocalEpisode.Episodes.Any()) + //{ + // item.SeasonNumber = decision.LocalEpisode.SeasonNumber; + // item.Episodes = decision.LocalEpisode.Episodes; + //} + + //item.Quality = decision.LocalEpisode.Quality; + //item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path); + //item.Rejections = decision.Rejections; + + //return item; } public void Execute(ManualImportCommand message) { _logger.ProgressTrace("Manually importing {0} files using mode {1}", message.Files.Count, message.ImportMode); - - var imported = new List(); - var importedTrackedDownload = new List(); - - for (int i = 0; i < message.Files.Count; i++) - { - _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count); - - var file = message.Files[i]; - var series = _seriesService.GetSeries(file.SeriesId); - var episodes = _episodeService.GetEpisodes(file.EpisodeIds); - var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo(); - var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path); - var existingFile = series.Path.IsParentPath(file.Path); - - var localEpisode = new LocalEpisode - { - ExistingFile = false, - Episodes = episodes, - MediaInfo = mediaInfo, - ParsedEpisodeInfo = parsedEpisodeInfo, - Path = file.Path, - Quality = file.Quality, - Series = series, - Size = 0 - }; - - //TODO: Cleanup non-tracked downloads - - var importDecision = new ImportDecision(localEpisode); - - if (file.DownloadId.IsNullOrWhiteSpace()) - { - imported.AddRange(_importApprovedEpisodes.Import(new List { importDecision }, !existingFile, null, message.ImportMode)); - } - - else - { - var trackedDownload = _trackedDownloadService.Find(file.DownloadId); - var importResult = _importApprovedEpisodes.Import(new List { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First(); - - imported.Add(importResult); - - importedTrackedDownload.Add(new ManuallyImportedFile - { - TrackedDownload = trackedDownload, - ImportResult = importResult - }); - } - } - - _logger.ProgressTrace("Manually imported {0} files", imported.Count); - - foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList()) - { - var trackedDownload = groupedTrackedDownload.First().TrackedDownload; - - if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath)) - { - if (_downloadedEpisodesImportService.ShouldDeleteFolder( - new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath), - trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly) - { - _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)) - { - trackedDownload.State = TrackedDownloadStage.Imported; - _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload)); - } - } + throw new System.NotImplementedException("TODO: This will be rewritten for Music"); + + //var imported = new List(); + //var importedTrackedDownload = new List(); + + //for (int i = 0; i < message.Files.Count; i++) + //{ + // _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count); + + // var file = message.Files[i]; + // var series = _seriesService.GetSeries(file.SeriesId); + // var episodes = _episodeService.GetEpisodes(file.EpisodeIds); + // var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo(); + // var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path); + // var existingFile = series.Path.IsParentPath(file.Path); + + // var localEpisode = new LocalEpisode + // { + // ExistingFile = false, + // Episodes = episodes, + // MediaInfo = mediaInfo, + // ParsedEpisodeInfo = parsedEpisodeInfo, + // Path = file.Path, + // Quality = file.Quality, + // Series = series, + // Size = 0 + // }; + + // //TODO: Cleanup non-tracked downloads + + // var importDecision = new ImportDecision(localEpisode); + + // if (file.DownloadId.IsNullOrWhiteSpace()) + // { + // imported.AddRange(_importApprovedEpisodes.Import(new List { importDecision }, !existingFile, null, message.ImportMode)); + // } + + // else + // { + // var trackedDownload = _trackedDownloadService.Find(file.DownloadId); + // var importResult = _importApprovedEpisodes.Import(new List { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First(); + + // imported.Add(importResult); + + // importedTrackedDownload.Add(new ManuallyImportedFile + // { + // TrackedDownload = trackedDownload, + // ImportResult = importResult + // }); + // } + //} + + //_logger.ProgressTrace("Manually imported {0} files", imported.Count); + + //foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList()) + //{ + // var trackedDownload = groupedTrackedDownload.First().TrackedDownload; + + // if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath)) + // { + // if (_downloadedEpisodesImportService.ShouldDeleteFolder( + // new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath), + // trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly) + // { + // _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)) + // { + // trackedDownload.State = TrackedDownloadStage.Imported; + // _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload)); + // } + //} } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManuallyImportedFile.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManuallyImportedFile.cs index 32f904e4d..4780240e2 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManuallyImportedFile.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManuallyImportedFile.cs @@ -1,4 +1,5 @@ using NzbDrone.Core.Download.TrackedDownloads; +using NzbDrone.Core.MediaFiles.TrackImport; namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual { diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecification.cs index 490bdb941..6e9695d34 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecification.cs @@ -63,5 +63,48 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications 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(); + } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs index 7397c13e7..4357c07bc 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs @@ -1,4 +1,5 @@ -using NLog; +using System; +using NLog; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Parser.Model; @@ -13,6 +14,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications _logger = logger; } + public Decision IsSatisfiedBy(LocalTrack localTrack) + { + throw new NotImplementedException("Interface will be removed"); + } + public Decision IsSatisfiedBy(LocalEpisode localEpisode) { if (localEpisode.ParsedEpisodeInfo.FullSeason) diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecification.cs index 79ef96f88..b97c42f35 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecification.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using NLog; using NzbDrone.Core.DecisionEngine; @@ -14,6 +15,53 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications { _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) { if (localEpisode.ExistingFile) diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs index c7b61d802..e8eb664ec 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs @@ -1,4 +1,5 @@ -using NLog; +using System; +using NLog; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Parser.Model; @@ -16,6 +17,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications _logger = logger; } + public Decision IsSatisfiedBy(LocalTrack localTrack) + { + throw new NotImplementedException(); + } + public Decision IsSatisfiedBy(LocalEpisode localEpisode) { if (localEpisode.ExistingFile) diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs index 2260ed71a..7fe4bef26 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs @@ -56,5 +56,10 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications return Decision.Accept(); } + + public Decision IsSatisfiedBy(LocalTrack localTrack) + { + throw new NotImplementedException(); + } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/SameEpisodesImportSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/SameEpisodesImportSpecification.cs index ee6c02c53..8adb7416b 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/SameEpisodesImportSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/SameEpisodesImportSpecification.cs @@ -1,3 +1,4 @@ +using System; using NLog; using NzbDrone.Core.DecisionEngine; 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"); return Decision.Reject("Episode file on disk contains more episodes than this file contains"); } + + public Decision IsSatisfiedBy(LocalTrack localTrack) + { + throw new NotImplementedException(); + } } } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UnverifiedSceneNumberingSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UnverifiedSceneNumberingSpecification.cs index ce65eb304..95c39b1d6 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UnverifiedSceneNumberingSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UnverifiedSceneNumberingSpecification.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using NLog; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Parser.Model; @@ -13,6 +14,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications _logger = logger; } + public Decision IsSatisfiedBy(LocalTrack localTrack) + { + throw new NotImplementedException("This is not needed, Interface will be removed"); + } + public Decision IsSatisfiedBy(LocalEpisode localEpisode) { if (localEpisode.ExistingFile) diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UpgradeSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UpgradeSpecification.cs index 3d07306af..c0eaa6a92 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UpgradeSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UpgradeSpecification.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using NLog; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Parser.Model; @@ -15,6 +16,18 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications _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) { var qualityComparer = new QualityModelComparer(localEpisode.Series.Profile); diff --git a/src/NzbDrone.Core/MediaFiles/Events/TrackDownloadedEvent.cs b/src/NzbDrone.Core/MediaFiles/Events/TrackDownloadedEvent.cs new file mode 100644 index 000000000..82ea9f788 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/Events/TrackDownloadedEvent.cs @@ -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 OldFiles { get; private set; } + + public TrackDownloadedEvent(LocalTrack track, TrackFile trackFile, List oldFiles) + { + Track = track; + TrackFile = trackFile; + OldFiles = oldFiles; + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/MediaFileTableCleanupService.cs b/src/NzbDrone.Core/MediaFiles/MediaFileTableCleanupService.cs index 0b7b2cba3..a46844f54 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaFileTableCleanupService.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaFileTableCleanupService.cs @@ -5,81 +5,73 @@ using NLog; using NzbDrone.Common; using NzbDrone.Common.Extensions; using NzbDrone.Core.Tv; +using NzbDrone.Core.Music; namespace NzbDrone.Core.MediaFiles { public interface IMediaFileTableCleanupService { - void Clean(Series series, List filesOnDisk); + void Clean(Artist artist, List filesOnDisk); } public class MediaFileTableCleanupService : IMediaFileTableCleanupService { private readonly IMediaFileService _mediaFileService; - private readonly IEpisodeService _episodeService; + private readonly ITrackService _trackService; private readonly Logger _logger; public MediaFileTableCleanupService(IMediaFileService mediaFileService, - IEpisodeService episodeService, + ITrackService trackService, Logger logger) { _mediaFileService = mediaFileService; - _episodeService = episodeService; + _trackService = trackService; _logger = logger; } - public void Clean(Series series, List filesOnDisk) + public void Clean(Artist artist, List filesOnDisk) { - var seriesFiles = _mediaFileService.GetFilesBySeries(series.Id); - var episodes = _episodeService.GetEpisodeBySeries(series.Id); + var artistFiles = _mediaFileService.GetFilesByArtist(artist.SpotifyId); + var tracks = _trackService.GetTracksByArtist(artist.SpotifyId); var filesOnDiskKeys = new HashSet(filesOnDisk, PathEqualityComparer.Instance); - foreach (var seriesFile in seriesFiles) + foreach (var artistFile in artistFiles) { - var episodeFile = seriesFile; - var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath); + var trackFile = artistFile; + var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath); try { - if (!filesOnDiskKeys.Contains(episodeFilePath)) + if (!filesOnDiskKeys.Contains(trackFilePath)) { - _logger.Debug("File [{0}] no longer exists on disk, removing from db", episodeFilePath); - _mediaFileService.Delete(seriesFile, DeleteMediaFileReason.MissingFromDisk); + _logger.Debug("File [{0}] no longer exists on disk, removing from db", trackFilePath); + _mediaFileService.Delete(artistFile, DeleteMediaFileReason.MissingFromDisk); 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); - _mediaFileService.Delete(episodeFile, DeleteMediaFileReason.NoLinkedEpisodes); + _logger.Debug("File [{0}] is not assigned to any artist, removing from db", trackFilePath); + _mediaFileService.Delete(trackFile, DeleteMediaFileReason.NoLinkedEpisodes); 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) { - _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; - _episodeService.UpdateEpisode(episode); + track.TrackFileId = 0; + _trackService.UpdateTrack(track); } } } diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/UpdateMediaInfoService.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/UpdateMediaInfoService.cs index fb232f2f9..60cf5bf01 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaInfo/UpdateMediaInfoService.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/UpdateMediaInfoService.cs @@ -7,10 +7,11 @@ using NzbDrone.Core.Tv; using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Music; namespace NzbDrone.Core.MediaFiles.MediaInfo { - public class UpdateMediaInfoService : IHandle + public class UpdateMediaInfoService : IHandle { private readonly IDiskProvider _diskProvider; private readonly IMediaFileService _mediaFileService; @@ -33,11 +34,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo _logger = logger; } - private void UpdateMediaInfo(Series series, List mediaFiles) + private void UpdateMediaInfo(Artist artist, List 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)) { @@ -56,7 +57,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo } } - public void Handle(SeriesScannedEvent message) + public void Handle(ArtistScannedEvent message) { if (!_configService.EnableMediaInfo) { @@ -64,10 +65,10 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo 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(); - UpdateMediaInfo(message.Series, filteredMediaFiles); + UpdateMediaInfo(message.Artist, filteredMediaFiles); } } } diff --git a/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs b/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs index 4cfe84b37..d279b7289 100644 --- a/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs @@ -55,24 +55,28 @@ namespace NzbDrone.Core.MediaFiles public List GetRenamePreviews(int seriesId) { - var series = _seriesService.GetSeries(seriesId); - var episodes = _episodeService.GetEpisodeBySeries(seriesId); - var files = _mediaFileService.GetFilesBySeries(seriesId); - - return GetPreviews(series, episodes, files) - .OrderByDescending(e => e.SeasonNumber) - .ThenByDescending(e => e.EpisodeNumbers.First()) - .ToList(); + // TODO + throw new NotImplementedException(); + //var series = _seriesService.GetSeries(seriesId); + //var episodes = _episodeService.GetEpisodeBySeries(seriesId); + //var files = _mediaFileService.GetFilesBySeries(seriesId); + + //return GetPreviews(series, episodes, files) + // .OrderByDescending(e => e.SeasonNumber) + // .ThenByDescending(e => e.EpisodeNumbers.First()) + // .ToList(); } public List GetRenamePreviews(int seriesId, int seasonNumber) { - var series = _seriesService.GetSeries(seriesId); - var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber); - var files = _mediaFileService.GetFilesBySeason(seriesId, seasonNumber); - - return GetPreviews(series, episodes, files) - .OrderByDescending(e => e.EpisodeNumbers.First()).ToList(); + // TODO + throw new NotImplementedException(); + //var series = _seriesService.GetSeries(seriesId); + //var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber); + //var files = _mediaFileService.GetFilesBySeason(seriesId, seasonNumber); + + //return GetPreviews(series, episodes, files) + // .OrderByDescending(e => e.EpisodeNumbers.First()).ToList(); } private IEnumerable GetPreviews(Series series, List episodes, List files) @@ -110,62 +114,68 @@ namespace NzbDrone.Core.MediaFiles private void RenameFiles(List episodeFiles, Series series) { - var renamed = new List(); - - foreach (var episodeFile in episodeFiles) - { - var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath); - - try - { - _logger.Debug("Renaming episode file: {0}", episodeFile); - _episodeFileMover.MoveEpisodeFile(episodeFile, series); - - _mediaFileService.Update(episodeFile); - renamed.Add(episodeFile); - - _logger.Debug("Renamed episode file: {0}", episodeFile); - } - catch (SameFilenameException ex) - { - _logger.Debug("File not renamed, source and destination are the same: {0}", ex.Filename); - } - catch (Exception ex) - { - _logger.Error(ex, "Failed to rename file {0}", episodeFilePath); - } - } - - if (renamed.Any()) - { - _diskProvider.RemoveEmptySubfolders(series.Path); - - _eventAggregator.PublishEvent(new SeriesRenamedEvent(series)); - } + // TODO + throw new NotImplementedException(); + //var renamed = new List(); + + //foreach (var episodeFile in episodeFiles) + //{ + // var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath); + + // try + // { + // _logger.Debug("Renaming episode file: {0}", episodeFile); + // _episodeFileMover.MoveEpisodeFile(episodeFile, series); + + // _mediaFileService.Update(episodeFile); + // renamed.Add(episodeFile); + + // _logger.Debug("Renamed episode file: {0}", episodeFile); + // } + // catch (SameFilenameException ex) + // { + // _logger.Debug("File not renamed, source and destination are the same: {0}", ex.Filename); + // } + // catch (Exception ex) + // { + // _logger.Error(ex, "Failed to rename file {0}", episodeFilePath); + // } + //} + + //if (renamed.Any()) + //{ + // _diskProvider.RemoveEmptySubfolders(series.Path); + + // _eventAggregator.PublishEvent(new SeriesRenamedEvent(series)); + //} } public void Execute(RenameFilesCommand message) { - var series = _seriesService.GetSeries(message.SeriesId); - var episodeFiles = _mediaFileService.Get(message.Files); - - _logger.ProgressInfo("Renaming {0} files for {1}", episodeFiles.Count, series.Title); - RenameFiles(episodeFiles, series); - _logger.ProgressInfo("Selected episode files renamed for {0}", series.Title); + // TODO + throw new NotImplementedException(); + //var series = _seriesService.GetSeries(message.SeriesId); + //var episodeFiles = _mediaFileService.Get(message.Files); + + //_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) { - _logger.Debug("Renaming all files for selected series"); - var seriesToRename = _seriesService.GetSeries(message.SeriesIds); - - foreach (var series in seriesToRename) - { - var episodeFiles = _mediaFileService.GetFilesBySeries(series.Id); - _logger.ProgressInfo("Renaming all files in series: {0}", series.Title); - RenameFiles(episodeFiles, series); - _logger.ProgressInfo("All episode files renamed for {0}", series.Title); - } + // TODO + throw new NotImplementedException(); + //_logger.Debug("Renaming all files for selected series"); + //var seriesToRename = _seriesService.GetSeries(message.SeriesIds); + + //foreach (var series in seriesToRename) + //{ + // var episodeFiles = _mediaFileService.GetFilesBySeries(series.Id); + // _logger.ProgressInfo("Renaming all files in series: {0}", series.Title); + // RenameFiles(episodeFiles, series); + // _logger.ProgressInfo("All episode files renamed for {0}", series.Title); + //} } } } diff --git a/src/NzbDrone.Core/MediaFiles/TrackFileMoveResult.cs b/src/NzbDrone.Core/MediaFiles/TrackFileMoveResult.cs new file mode 100644 index 000000000..8b4b3d854 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/TrackFileMoveResult.cs @@ -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(); + } + + public TrackFile TrackFile { get; set; } + public List OldFiles { get; set; } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/TrackFileMovingService.cs b/src/NzbDrone.Core/MediaFiles/TrackFileMovingService.cs new file mode 100644 index 000000000..5500f6007 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/TrackFileMovingService.cs @@ -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 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); + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs new file mode 100644 index 000000000..09abac393 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs @@ -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 Import(List 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 Import(List 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(); + + 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(); + + 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; + //} + } +} diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportDecision.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportDecision.cs new file mode 100644 index 000000000..885ec60b0 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportDecision.cs @@ -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 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(); + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportMode.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportMode.cs similarity index 66% rename from src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportMode.cs rename to src/NzbDrone.Core/MediaFiles/TrackImport/ImportMode.cs index ffdf7eed8..43236bc86 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportMode.cs +++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportMode.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Core.MediaFiles.EpisodeImport +namespace NzbDrone.Core.MediaFiles.TrackImport { public enum ImportMode { diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResult.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportResult.cs similarity index 85% rename from src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResult.cs rename to src/NzbDrone.Core/MediaFiles/TrackImport/ImportResult.cs index a0d989335..64f60869b 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResult.cs +++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportResult.cs @@ -1,8 +1,10 @@ -using System.Collections.Generic; +using NzbDrone.Common.EnsureThat; +using System; +using System.Collections.Generic; using System.Linq; -using NzbDrone.Common.EnsureThat; +using System.Text; -namespace NzbDrone.Core.MediaFiles.EpisodeImport +namespace NzbDrone.Core.MediaFiles.TrackImport { public class ImportResult { diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResultType.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportResultType.cs similarity index 66% rename from src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResultType.cs rename to src/NzbDrone.Core/MediaFiles/TrackImport/ImportResultType.cs index 7c43332de..e4e3eaef8 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResultType.cs +++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportResultType.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Core.MediaFiles.EpisodeImport +namespace NzbDrone.Core.MediaFiles.TrackImport { public enum ImportResultType { diff --git a/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs b/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs index d6c270d2c..0e952a676 100644 --- a/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/UpgradeMediaFileService.cs @@ -9,7 +9,8 @@ namespace NzbDrone.Core.MediaFiles { 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 @@ -17,35 +18,36 @@ namespace NzbDrone.Core.MediaFiles private readonly IRecycleBinProvider _recycleBinProvider; private readonly IMediaFileService _mediaFileService; private readonly IMoveEpisodeFiles _episodeFileMover; + private readonly IMoveTrackFiles _trackFileMover; private readonly IDiskProvider _diskProvider; private readonly Logger _logger; public UpgradeMediaFileService(IRecycleBinProvider recycleBinProvider, IMediaFileService mediaFileService, - IMoveEpisodeFiles episodeFileMover, + IMoveTrackFiles trackFileMover, IDiskProvider diskProvider, Logger logger) { _recycleBinProvider = recycleBinProvider; _mediaFileService = mediaFileService; - _episodeFileMover = episodeFileMover; + _trackFileMover = trackFileMover; _diskProvider = diskProvider; _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 existingFiles = localEpisode.Episodes - .Where(e => e.EpisodeFileId > 0) - .Select(e => e.EpisodeFile.Value) + var moveFileResult = new TrackFileMoveResult(); + var existingFiles = localTrack.Tracks + .Where(e => e.TrackFileId > 0) + .Select(e => e.TrackFile.Value) .GroupBy(e => e.Id); foreach (var existingFile in existingFiles) { var file = existingFile.First(); - var episodeFilePath = Path.Combine(localEpisode.Series.Path, file.RelativePath); - var subfolder = _diskProvider.GetParentFolder(localEpisode.Series.Path).GetRelativePath(_diskProvider.GetParentFolder(episodeFilePath)); + var episodeFilePath = Path.Combine(localTrack.Artist.Path, file.RelativePath); + var subfolder = _diskProvider.GetParentFolder(localTrack.Artist.Path).GetRelativePath(_diskProvider.GetParentFolder(episodeFilePath)); if (_diskProvider.FileExists(episodeFilePath)) { @@ -59,11 +61,11 @@ namespace NzbDrone.Core.MediaFiles if (copyOnly) { - moveFileResult.EpisodeFile = _episodeFileMover.CopyEpisodeFile(episodeFile, localEpisode); + moveFileResult.TrackFile = _trackFileMover.CopyTrackFile(trackFile, localTrack); } else { - moveFileResult.EpisodeFile = _episodeFileMover.MoveEpisodeFile(episodeFile, localEpisode); + moveFileResult.TrackFile = _trackFileMover.MoveTrackFile(trackFile, localTrack); } return moveFileResult; diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs index 5a76a4c8e..d2db40331 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs @@ -205,7 +205,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook var lowerTitle = title.ToLowerInvariant(); 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(); diff --git a/src/NzbDrone.Core/Music/TrackService.cs b/src/NzbDrone.Core/Music/TrackService.cs index cf09139e5..7b57b7749 100644 --- a/src/NzbDrone.Core/Music/TrackService.cs +++ b/src/NzbDrone.Core/Music/TrackService.cs @@ -55,11 +55,16 @@ namespace NzbDrone.Core.Music 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 GetTracksByArtist(string artistId) { return _trackRepository.GetTracks(artistId).ToList(); @@ -132,7 +137,7 @@ namespace NzbDrone.Core.Music _trackRepository.SetMonitoredByAlbum(artistId, albumId, monitored); } - public void UpdateEpisodes(List tracks) + public void UpdateTracks(List tracks) { _trackRepository.UpdateMany(tracks); } @@ -182,10 +187,5 @@ namespace NzbDrone.Core.Music _logger.Debug("Linking [{0}] > [{1}]", message.TrackFile.RelativePath, track); } } - - public void UpdateTracks(List tracks) - { - _trackRepository.UpdateMany(tracks); - } } } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 65494030b..e0793e352 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -725,7 +725,10 @@ - + + + + @@ -740,12 +743,10 @@ - - - + @@ -761,11 +762,14 @@ + + + @@ -789,6 +793,9 @@ + + + @@ -928,6 +935,7 @@ + diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index be6ed1da3..22e0e07be 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -380,33 +380,34 @@ namespace NzbDrone.Core.Parser if (result != null) { - if (result.FullSeason && title.ContainsIgnoreCase("Special")) - { - result.FullSeason = false; - result.Special = true; - } + //if (result.FullSeason && title.ContainsIgnoreCase("Special")) + //{ + // result.FullSeason = false; + // result.Special = true; + //} - result.Language = LanguageParser.ParseLanguage(title); - Logger.Debug("Language parsed: {0}", result.Language); + //result.Language = LanguageParser.ParseLanguage(title); + //Logger.Debug("Language parsed: {0}", result.Language); result.Quality = QualityParser.ParseQuality(title); 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); - if (!subGroup.IsNullOrWhiteSpace()) - { - result.ReleaseGroup = subGroup; - } + //var subGroup = GetSubGroup(match); + //if (!subGroup.IsNullOrWhiteSpace()) + //{ + // result.ReleaseGroup = subGroup; + //} - Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup); + //Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup); - result.ReleaseHash = GetReleaseHash(match); - if (!result.ReleaseHash.IsNullOrWhiteSpace()) - { - Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash); - } + //result.ReleaseHash = GetReleaseHash(match); + //if (!result.ReleaseHash.IsNullOrWhiteSpace()) + //{ + // Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash); + //} return result; } diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index 333848512..1c4ff67d0 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -457,7 +457,9 @@ namespace NzbDrone.Core.Parser 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) @@ -467,7 +469,7 @@ namespace NzbDrone.Core.Parser 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; } + public LocalTrack GetLocalTrack(string filename, Artist artist) { return GetLocalTrack(filename, artist, null); @@ -635,7 +638,60 @@ namespace NzbDrone.Core.Parser } return GetStandardEpisodes(artist, parsedTrackInfo, sceneSource, searchCriteria);*/ - return GetStandardTracks(artist, parsedTrackInfo, searchCriteria); + return GetStandardTracks(artist, parsedTrackInfo); + } + + private List GetStandardTracks(Artist artist, ParsedTrackInfo parsedTrackInfo) + { + var result = new List(); + //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(); + } + + 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; } } } \ No newline at end of file diff --git a/src/NzbDrone.Core/Tv/RefreshSeriesService.cs b/src/NzbDrone.Core/Tv/RefreshSeriesService.cs index f177b5857..39e32dbe7 100644 --- a/src/NzbDrone.Core/Tv/RefreshSeriesService.cs +++ b/src/NzbDrone.Core/Tv/RefreshSeriesService.cs @@ -176,7 +176,7 @@ namespace NzbDrone.Core.Tv try { _logger.Info("Skipping refresh of series: {0}", series.Title); - _diskScanService.Scan(series); + //_diskScanService.Scan(series); } catch (Exception e) {