From 738700537e039bb557a33469e0163276d585d01c Mon Sep 17 00:00:00 2001 From: markus101 Date: Mon, 21 Feb 2011 22:22:40 -0800 Subject: [PATCH] Episode RenamingProvider created, allows renaming by Every Episode for Every Series, by Series, by Season, or individual Episodes. Currently uses Hard-Coded Naming Convention, Undecided on SAB or SB configuration style, SAB's is more robust (and flawless? -SP). --- NzbDrone.Core/CentralDispatch.cs | 3 +- NzbDrone.Core/Model/EpisodeRenameModel.cs | 18 ++ NzbDrone.Core/Providers/DiskProvider.cs | 5 + NzbDrone.Core/Providers/IDiskProvider.cs | 1 + NzbDrone.Core/Providers/IMediaFileProvider.cs | 2 + NzbDrone.Core/Providers/IRenameProvider.cs | 15 ++ NzbDrone.Core/Providers/MediaFileProvider.cs | 11 +- NzbDrone.Core/Providers/RenameProvider.cs | 190 ++++++++++++++++++ NzbDrone.Core/Providers/RssSyncProvider.cs | 2 +- 9 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 NzbDrone.Core/Model/EpisodeRenameModel.cs create mode 100644 NzbDrone.Core/Providers/IRenameProvider.cs create mode 100644 NzbDrone.Core/Providers/RenameProvider.cs diff --git a/NzbDrone.Core/CentralDispatch.cs b/NzbDrone.Core/CentralDispatch.cs index 5c51ac1d1..e9c669d29 100644 --- a/NzbDrone.Core/CentralDispatch.cs +++ b/NzbDrone.Core/CentralDispatch.cs @@ -66,7 +66,8 @@ namespace NzbDrone.Core _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); - _kernel.Bind().To().InSingletonScope(); ; + _kernel.Bind().To().InSingletonScope(); + _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); diff --git a/NzbDrone.Core/Model/EpisodeRenameModel.cs b/NzbDrone.Core/Model/EpisodeRenameModel.cs new file mode 100644 index 000000000..591865e46 --- /dev/null +++ b/NzbDrone.Core/Model/EpisodeRenameModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Core.Repository; + +namespace NzbDrone.Core.Model +{ + public class EpisodeRenameModel + { + public string SeriesName { get; set; } + public int SeasonNumber { get; set; } + public int EpisodeNumber { get; set; } + public string EpisodeName { get; set; } + public string Folder { get; set; } + public EpisodeFile EpisodeFile { get; set; } + } +} diff --git a/NzbDrone.Core/Providers/DiskProvider.cs b/NzbDrone.Core/Providers/DiskProvider.cs index f41c9e724..55ff77fea 100644 --- a/NzbDrone.Core/Providers/DiskProvider.cs +++ b/NzbDrone.Core/Providers/DiskProvider.cs @@ -42,6 +42,11 @@ namespace NzbDrone.Core.Providers File.Delete(path); } + public void RenameFile(string sourcePath, string destinationPath) + { + File.Move(sourcePath, destinationPath); + } + #endregion } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/IDiskProvider.cs b/NzbDrone.Core/Providers/IDiskProvider.cs index b15967fac..bf17cf1d1 100644 --- a/NzbDrone.Core/Providers/IDiskProvider.cs +++ b/NzbDrone.Core/Providers/IDiskProvider.cs @@ -12,5 +12,6 @@ namespace NzbDrone.Core.Providers bool FileExists(string path); long GetSize(string path); void DeleteFile(string path); + void RenameFile(string sourcePath, string destinationPath); } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/IMediaFileProvider.cs b/NzbDrone.Core/Providers/IMediaFileProvider.cs index da4c0404a..9a84dbd9f 100644 --- a/NzbDrone.Core/Providers/IMediaFileProvider.cs +++ b/NzbDrone.Core/Providers/IMediaFileProvider.cs @@ -15,5 +15,7 @@ namespace NzbDrone.Core.Providers string GenerateEpisodePath(EpisodeModel episode); void DeleteFromDb(int fileId); void DeleteFromDisk(int fileId, string path); + void Update(EpisodeFile episodeFile); + EpisodeFile GetEpisodeFile(int episodeFileId); } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/IRenameProvider.cs b/NzbDrone.Core/Providers/IRenameProvider.cs new file mode 100644 index 000000000..b45280860 --- /dev/null +++ b/NzbDrone.Core/Providers/IRenameProvider.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.Providers +{ + public interface IRenameProvider + { + void RenameAll(); + void RenameSeries(int seriesId); + void RenameSeason(int seasonId); + void RenameEpisode(int episodeId); + } +} diff --git a/NzbDrone.Core/Providers/MediaFileProvider.cs b/NzbDrone.Core/Providers/MediaFileProvider.cs index 030b35fdf..bb4b7b2ec 100644 --- a/NzbDrone.Core/Providers/MediaFileProvider.cs +++ b/NzbDrone.Core/Providers/MediaFileProvider.cs @@ -98,7 +98,6 @@ namespace NzbDrone.Core.Providers } } - public string GenerateEpisodePath(EpisodeModel episode) { var episodeNamePattern = _configProvider.EpisodeNameFormat; @@ -123,6 +122,16 @@ namespace NzbDrone.Core.Providers _repository.Delete(fileId); } + public void Update(EpisodeFile episodeFile) + { + _repository.Update(episodeFile); + } + + public EpisodeFile GetEpisodeFile(int episodeFileId) + { + return _repository.Single(episodeFileId); + } + private List GetMediaFileList(string path) { Logger.Debug("Scanning '{0}' for episodes", path); diff --git a/NzbDrone.Core/Providers/RenameProvider.cs b/NzbDrone.Core/Providers/RenameProvider.cs new file mode 100644 index 000000000..437d2e945 --- /dev/null +++ b/NzbDrone.Core/Providers/RenameProvider.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using NLog; +using NzbDrone.Core.Model; +using NzbDrone.Core.Repository; + +namespace NzbDrone.Core.Providers +{ + public class RenameProvider : IRenameProvider + { + private readonly ISeriesProvider _seriesProvider; + private readonly ISeasonProvider _seasonProvider; + private readonly IEpisodeProvider _episodeProvider; + private readonly IMediaFileProvider _mediaFileProvider; + private readonly IDiskProvider _diskProvider; + private readonly IConfigProvider _configProvider; + private Thread _renameThread; + private List _epsToRename = new List(); + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + public RenameProvider(ISeriesProvider seriesProvider, ISeasonProvider seasonProvider, + IEpisodeProvider episodeProvider, IMediaFileProvider mediaFileProvider, + IDiskProvider diskProvider, IConfigProvider configProvider) + { + _seriesProvider = seriesProvider; + _seasonProvider = seasonProvider; + _episodeProvider = episodeProvider; + _mediaFileProvider = mediaFileProvider; + _diskProvider = diskProvider; + _configProvider = configProvider; + } + + #region IRenameProvider Members + public void RenameAll() + { + //Get a list of all episode files/episodes and rename them + + var seasonFolder = _configProvider.GetValue("SeasonFolder", "Season %s", true); + + foreach (var series in _seriesProvider.GetAllSeries()) + { + foreach (var episode in series.Episodes) + { + var episodeRenameModel = new EpisodeRenameModel(); + episodeRenameModel.SeriesName = series.Title; + episodeRenameModel.SeasonNumber = episode.SeasonNumber; + episodeRenameModel.EpisodeNumber = episode.EpisodeNumber; + episodeRenameModel.EpisodeName = episode.Title; + episodeRenameModel.Folder = series.Path + Path.DirectorySeparatorChar + seasonFolder; + episodeRenameModel.EpisodeFile = episode.EpisodeFile; + + _epsToRename.Add(episodeRenameModel); + StartRename(); + } + } + } + + public void RenameSeries(int seriesId) + { + //Get a list of all applicable episode files/episodes and rename them + + var series = _seriesProvider.GetSeries(seriesId); + var seasonFolder = _configProvider.GetValue("SeasonFolder", "Season %s", true); + + foreach (var episode in series.Episodes) + { + var episodeRenameModel = new EpisodeRenameModel(); + episodeRenameModel.SeriesName = series.Title; + episodeRenameModel.SeasonNumber = episode.SeasonNumber; + episodeRenameModel.EpisodeNumber = episode.EpisodeNumber; + episodeRenameModel.EpisodeName = episode.Title; + episodeRenameModel.Folder = series.Path + Path.DirectorySeparatorChar + seasonFolder; + episodeRenameModel.EpisodeFile = episode.EpisodeFile; + + _epsToRename.Add(episodeRenameModel); + StartRename(); + } + } + + public void RenameSeason(int seasonId) + { + //Get a list of all applicable episode files/episodes and rename them + var season = _seasonProvider.GetSeason(seasonId); + var series = _seriesProvider.GetSeries(season.SeriesId); + var seasonFolder = _configProvider.GetValue("SeasonFolder", "Season %s", true); + + foreach (var episode in season.Episodes) + { + var episodeRenameModel = new EpisodeRenameModel(); + episodeRenameModel.SeriesName = series.Title; + episodeRenameModel.SeasonNumber = episode.SeasonNumber; + episodeRenameModel.EpisodeNumber = episode.EpisodeNumber; + episodeRenameModel.EpisodeName = episode.Title; + episodeRenameModel.Folder = series.Path + Path.DirectorySeparatorChar + seasonFolder; + episodeRenameModel.EpisodeFile = episode.EpisodeFile; + + _epsToRename.Add(episodeRenameModel); + StartRename(); + } + } + + public void RenameEpisode(int episodeId) + { + var episode = _episodeProvider.GetEpisode(episodeId); + var series = _seriesProvider.GetSeries(episode.SeriesId); + var seasonFolder = _configProvider.GetValue("SeasonFolder", "Season %s", true); + + var episodeRenameModel = new EpisodeRenameModel(); + episodeRenameModel.SeriesName = series.Title; + episodeRenameModel.SeasonNumber = episode.SeasonNumber; + episodeRenameModel.EpisodeNumber = episode.EpisodeNumber; + episodeRenameModel.EpisodeName = episode.Title; + episodeRenameModel.Folder = series.Path + Path.DirectorySeparatorChar + seasonFolder; + episodeRenameModel.EpisodeFile = episode.EpisodeFile; + + _epsToRename.Add(episodeRenameModel); + StartRename(); + } + + #endregion + + private void StartRename() + { + Logger.Debug("Episode Rename Starting"); + if (_renameThread == null || !_renameThread.IsAlive) + { + Logger.Debug("Initializing background rename of episodes"); + _renameThread = new Thread(RenameProcessor) + { + Name = "RenameEpisodes", + Priority = ThreadPriority.Lowest + }; + + _renameThread.Start(); + } + else + { + Logger.Warn("Episode renaming already in progress. Ignoring request."); + } + } + + private void RenameProcessor() + { + while (_epsToRename.Count > 0) + { + var ep = _epsToRename.First(); + _epsToRename.RemoveAt(0); + RenameFile(ep); + } + } + + private void RenameFile(EpisodeRenameModel episodeRenameModel) + { + try + { + //Update EpisodeFile if successful + Logger.Debug("Renaming Episode: {0}", Path.GetFileName(episodeRenameModel.EpisodeFile.Path)); + var newName = GetNewName(episodeRenameModel); + var newFilename = episodeRenameModel.Folder + Path.DirectorySeparatorChar + newName; + + if (!_diskProvider.FolderExists(episodeRenameModel.Folder)) + _diskProvider.CreateDirectory(episodeRenameModel.Folder); + + _diskProvider.RenameFile(episodeRenameModel.EpisodeFile.Path, newFilename); + episodeRenameModel.EpisodeFile.Path = newFilename; + _mediaFileProvider.Update(episodeRenameModel.EpisodeFile); + + } + catch (Exception ex) + { + Logger.DebugException(ex.Message, ex); + Logger.Warn("Unable to Rename Episode: {0}", Path.GetFileName(episodeRenameModel.EpisodeFile.Path)); + } + } + + private string GetNewName(EpisodeRenameModel episodeRenameModel) + { + //Todo: Get the users preferred naming convention instead of hard-coding it + return String.Format("{0} - S{1:00}E{2:00} - {3}", episodeRenameModel.SeriesName, + episodeRenameModel.SeasonNumber, episodeRenameModel.EpisodeNumber, + episodeRenameModel.EpisodeName); + //var fileString = _configProvider.GetValue("") + } + } +} diff --git a/NzbDrone.Core/Providers/RssSyncProvider.cs b/NzbDrone.Core/Providers/RssSyncProvider.cs index 7f4eba2ee..a06b13a20 100644 --- a/NzbDrone.Core/Providers/RssSyncProvider.cs +++ b/NzbDrone.Core/Providers/RssSyncProvider.cs @@ -55,7 +55,7 @@ namespace NzbDrone.Core.Providers Logger.Debug("Initializing background sync of RSS Feeds."); _rssSyncThread = new Thread(SyncWithRss) { - Name = "SyncUnmappedFolders", + Name = "RssSync", Priority = ThreadPriority.Lowest };