using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using NLog; using NzbDrone.Core.Helpers; 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 readonly IExtenalNotificationProvider _externalNotificationProvider; 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, IExtenalNotificationProvider extenalNotificationProvider) { _seriesProvider = seriesProvider; _seasonProvider = seasonProvider; _episodeProvider = episodeProvider; _mediaFileProvider = mediaFileProvider; _diskProvider = diskProvider; _configProvider = configProvider; _externalNotificationProvider = extenalNotificationProvider; } #region IRenameProvider Members public void RenameAll() { //Get a list of all episode files/episodes and rename them foreach (var episodeFile in _mediaFileProvider.GetEpisodeFiles()) { var series = _seriesProvider.GetSeries(episodeFile.SeriesId); var erm = new EpisodeRenameModel(); erm.SeriesName = series.Title; erm.Folder = series.Path; if (series.SeasonFolder) erm.Folder += Path.DirectorySeparatorChar + EpisodeRenameHelper.GetSeasonFolder(episodeFile.Episodes[0].SeasonNumber, _configProvider.GetValue("Sorting_SeasonFolderFormat", "Season %s", true)); erm.EpisodeFile = episodeFile; _epsToRename.Add(erm); StartRename(); } } public void RenameSeries(int seriesId) { //Get a list of all applicable episode files/episodes and rename them var series = _seriesProvider.GetSeries(seriesId); foreach (var episodeFile in _mediaFileProvider.GetEpisodeFiles().Where(s => s.SeriesId == seriesId)) { var erm = new EpisodeRenameModel(); erm.SeriesName = series.Title; erm.Folder = series.Path; if (series.SeasonFolder) erm.Folder += Path.DirectorySeparatorChar + EpisodeRenameHelper.GetSeasonFolder(episodeFile.Episodes[0].SeasonNumber, _configProvider.GetValue("Sorting_SeasonFolderFormat", "Season %s", true)); erm.EpisodeFile = episodeFile; _epsToRename.Add(erm); 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); foreach (var episodeFile in _mediaFileProvider.GetEpisodeFiles().Where(s => s.Episodes[0].SeasonId == seasonId)) { var erm = new EpisodeRenameModel(); erm.SeriesName = series.Title; erm.Folder = series.Path; if (series.SeasonFolder) erm.Folder += Path.DirectorySeparatorChar + EpisodeRenameHelper.GetSeasonFolder(episodeFile.Episodes[0].SeasonNumber, _configProvider.GetValue("Sorting_SeasonFolderFormat", "Season %s", true)); erm.EpisodeFile = episodeFile; _epsToRename.Add(erm); StartRename(); } } public void RenameEpisode(int episodeId) { //This will properly rename multi-episode files if asked to rename either of the episode var episode = _episodeProvider.GetEpisode(episodeId); var series = _seriesProvider.GetSeries(episode.SeriesId); var episodeFile = _mediaFileProvider.GetEpisodeFiles().Where(s => s.Episodes.Contains(episode)).FirstOrDefault(); var erm = new EpisodeRenameModel(); erm.SeriesName = series.Title; erm.Folder = series.Path; if (series.SeasonFolder) erm.Folder += Path.DirectorySeparatorChar + EpisodeRenameHelper.GetSeasonFolder(episodeFile.Episodes[0].SeasonNumber, _configProvider.GetValue("Sorting_SeasonFolderFormat", "Season %s", true)); erm.EpisodeFile = episodeFile; _epsToRename.Add(erm); StartRename(); } public void RenameEpisodeFile(int episodeFileId, bool newDownload) { //This will properly rename multi-episode files if asked to rename either of the episode var episodeFile = _mediaFileProvider.GetEpisodeFile(episodeFileId); var series = _seriesProvider.GetSeries(episodeFile.Series.SeriesId); var erm = new EpisodeRenameModel(); erm.SeriesName = series.Title; erm.Folder = series.Path; if (series.SeasonFolder) erm.Folder += Path.DirectorySeparatorChar + EpisodeRenameHelper.GetSeasonFolder(episodeFile.Episodes[0].SeasonNumber, _configProvider.GetValue("Sorting_SeasonFolderFormat", "Season %s", true)); erm.EpisodeFile = episodeFile; _epsToRename.Add(erm); 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 erm) { try { //Update EpisodeFile if successful Logger.Debug("Renaming Episode: {0}", Path.GetFileName(erm.EpisodeFile.Path)); var newName = EpisodeRenameHelper.GetNewName(erm); var ext = Path.GetExtension(erm.EpisodeFile.Path); var newFilename = erm.Folder + Path.DirectorySeparatorChar + newName + ext; if (!_diskProvider.FolderExists(erm.Folder)) _diskProvider.CreateDirectory(erm.Folder); if (erm.EpisodeFile.Path == newFilename) return; _diskProvider.RenameFile(erm.EpisodeFile.Path, newFilename); erm.EpisodeFile.Path = newFilename; _mediaFileProvider.Update(erm.EpisodeFile); if (erm.NewDownload) _externalNotificationProvider.OnDownload(erm); else _externalNotificationProvider.OnRename(erm); } catch (Exception ex) { Logger.DebugException(ex.Message, ex); Logger.Warn("Unable to Rename Episode: {0}", Path.GetFileName(erm.EpisodeFile.Path)); } } } }