public void OnDownload(Series series, EpisodeFile episodeFile, string sourcePath, CustomScriptSettings settings) { var environmentVariables = new StringDictionary(); environmentVariables.Add("Sonarr_EventType", "Download"); environmentVariables.Add("Sonarr_Series_Id", series.Id.ToString()); environmentVariables.Add("Sonarr_Series_Title", series.Title); environmentVariables.Add("Sonarr_Series_Path", series.Path); environmentVariables.Add("Sonarr_Series_TvdbId", series.TvdbId.ToString()); environmentVariables.Add("Sonarr_EpisodeFile_Id", episodeFile.Id.ToString()); environmentVariables.Add("Sonarr_EpisodeFile_RelativePath", episodeFile.RelativePath); environmentVariables.Add("Sonarr_EpisodeFile_Path", Path.Combine(series.Path, episodeFile.RelativePath)); environmentVariables.Add("Sonarr_EpisodeFile_SeasonNumber", episodeFile.SeasonNumber.ToString()); environmentVariables.Add("Sonarr_EpisodeFile_EpisodeNumbers", string.Join(",", episodeFile.Episodes.Value.Select(e => e.EpisodeNumber))); environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDates", string.Join(",", episodeFile.Episodes.Value.Select(e => e.AirDate))); environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDatesUtc", string.Join(",", episodeFile.Episodes.Value.Select(e => e.AirDateUtc))); environmentVariables.Add("Sonarr_EpisodeFile_Quality", episodeFile.Quality.Quality.Name); environmentVariables.Add("Sonarr_EpisodeFile_QualityVersion", episodeFile.Quality.Revision.Version.ToString()); environmentVariables.Add("Sonarr_EpisodeFile_ReleaseGroup", episodeFile.ReleaseGroup ?? string.Empty); environmentVariables.Add("Sonarr_EpisodeFile_SceneName", episodeFile.SceneName ?? string.Empty); environmentVariables.Add("Sonarr_EpisodeFile_SourcePath", sourcePath); environmentVariables.Add("Sonarr_EpisodeFile_SourceFolder", Path.GetDirectoryName(sourcePath)); ExecuteScript(environmentVariables, settings); }
public EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode) { var moveFileResult = new EpisodeFileMoveResult(); var existingFiles = localEpisode.Episodes .Where(e => e.EpisodeFileId > 0) .Select(e => e.EpisodeFile.Value) .GroupBy(e => e.Id); foreach (var existingFile in existingFiles) { var file = existingFile.First(); if (_diskProvider.FileExists(file.Path)) { _logger.Debug("Removing existing episode file: {0}", file); _recycleBinProvider.DeleteFile(file.Path); } moveFileResult.OldFiles.Add(file); _mediaFileService.Delete(file, true); } moveFileResult.EpisodeFile = _episodeFileMover.MoveEpisodeFile(episodeFile, localEpisode); return moveFileResult; }
public string MoveEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode) { var newFileName = _buildFileNames.BuildFilename(localEpisode.Episodes, localEpisode.Series, episodeFile); var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path)); MoveFile(episodeFile, localEpisode.Series, filePath); return filePath; }
public string MoveEpisodeFile(EpisodeFile episodeFile, Series series) { var episodes = _episodeService.GetEpisodesByFileId(episodeFile.Id); var newFileName = _buildFileNames.BuildFilename(episodes, series, episodeFile); var filePath = _buildFileNames.BuildFilePath(series, episodes.First().SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path)); MoveFile(episodeFile, series, filePath); return filePath; }
public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode) { var newFileName = _buildFileNames.BuildFilename(localEpisode.Episodes, localEpisode.Series, episodeFile); var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path)); _logger.Trace("Moving episode file: {0} to {1}", episodeFile, filePath); return MoveFile(episodeFile, localEpisode.Series, filePath); }
public EpisodeFile CopyEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode) { var newFileName = _buildFileNames.BuildFilename(localEpisode.Episodes, localEpisode.Series, episodeFile); var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path)); _logger.Debug("Copying episode file: {0} to {1}", episodeFile, filePath); return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, true); }
public string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null) { if (namingConfig == null) { namingConfig = _namingConfigService.GetConfig(); } if (!namingConfig.RenameEpisodes) { return GetOriginalTitle(episodeFile); } if (namingConfig.StandardEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Standard) { throw new NamingFormatException("Standard episode format cannot be empty"); } if (namingConfig.DailyEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Daily) { throw new NamingFormatException("Daily episode format cannot be empty"); } if (namingConfig.AnimeEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Anime) { throw new NamingFormatException("Anime episode format cannot be empty"); } var pattern = namingConfig.StandardEpisodeFormat; var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance); episodes = episodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber).ToList(); if (series.SeriesType == SeriesTypes.Daily) { pattern = namingConfig.DailyEpisodeFormat; } if (series.SeriesType == SeriesTypes.Anime && episodes.All(e => e.AbsoluteEpisodeNumber.HasValue)) { pattern = namingConfig.AnimeEpisodeFormat; } pattern = AddSeasonEpisodeNumberingTokens(pattern, tokenHandlers, episodes, namingConfig); pattern = AddAbsoluteNumberingTokens(pattern, tokenHandlers, series, episodes, namingConfig); AddSeriesTokens(tokenHandlers, series); AddEpisodeTokens(tokenHandlers, episodes); AddEpisodeFileTokens(tokenHandlers, episodeFile); AddQualityTokens(tokenHandlers, series, episodeFile); AddMediaInfoTokens(tokenHandlers, episodeFile); var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim(); fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString()); fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty); return fileName; }
public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, Series series) { var episodes = _episodeService.GetEpisodesByFileId(episodeFile.Id); var newFileName = _buildFileNames.BuildFilename(episodes, series, episodeFile); var filePath = _buildFileNames.BuildFilePath(series, episodes.First().SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path)); _logger.Trace("Renaming episode file: {0} to {1}", episodeFile, filePath); return MoveFile(episodeFile, series, filePath); }
public FilenameSampleService(IBuildFileNames buildFileNames) { _buildFileNames = buildFileNames; _standardSeries = new Series { SeriesType = SeriesTypes.Standard, Title = "Series Title" }; _dailySeries = new Series { SeriesType = SeriesTypes.Daily, Title = "Series Title" }; _episode1 = new Episode { SeasonNumber = 1, EpisodeNumber = 1, Title = "Episode Title (1)", AirDate = "2013-10-30" }; _episode2 = new Episode { SeasonNumber = 1, EpisodeNumber = 2, Title = "Episode Title (2)" }; _singleEpisode = new List<Episode> { _episode1 }; _multiEpisodes = new List<Episode> { _episode1, _episode2 }; _singleEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p), Path = @"C:\Test\Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv", ReleaseGroup = "RlsGrp" }; _multiEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p), Path = @"C:\Test\Series.Title.S01E01-E02.720p.HDTV.x264-EVOLVE.mkv", ReleaseGroup = "RlsGrp" }; _dailyEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p), Path = @"C:\Test\Series.Title.2013.10.30.HDTV.x264-EVOLVE.mkv", ReleaseGroup = "RlsGrp" }; }
public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode) { 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 EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, Series series) { var episodes = _episodeService.GetEpisodesByFileId(episodeFile.Id); var newFileName = _buildFileNames.BuildFileName(episodes, series, episodeFile); var filePath = _buildFileNames.BuildFilePath(series, episodes.First().SeasonNumber, newFileName, Path.GetExtension(episodeFile.RelativePath)); EnsureEpisodeFolder(episodeFile, series, episodes.Select(v => v.SeasonNumber).First(), filePath); _logger.Debug("Renaming episode file: {0} to {1}", episodeFile, filePath); return TransferFile(episodeFile, series, episodes, filePath, TransferMode.Move); }
public EpisodeFile CopyEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode) { var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile); var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(localEpisode.Path)); 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); }
public void OnDownload(Series series, EpisodeFile episodeFile, WebhookSettings settings) { var payload = new WebhookPayload { EventType = "Download", Series = new WebhookSeries(series), Episodes = episodeFile.Episodes.Value.ConvertAll(x => new WebhookEpisode(x) { Quality = episodeFile.Quality.Quality.Name, QualityVersion = episodeFile.Quality.Revision.Version, ReleaseGroup = episodeFile.ReleaseGroup, SceneName = episodeFile.SceneName }) }; NotifyWebhook(payload, settings); }
private void MoveFile(EpisodeFile episodeFile, Series series, string destinationFilename) { if (!_diskProvider.FileExists(episodeFile.Path)) { throw new FileNotFoundException("Episode file path does not exist", episodeFile.Path); } if (episodeFile.Path.PathEquals(destinationFilename)) { throw new SameFilenameException("File not moved, source and destination are the same", episodeFile.Path); } _diskProvider.CreateFolder(new FileInfo(destinationFilename).DirectoryName); _logger.Debug("Moving [{0}] > [{1}]", episodeFile.Path, destinationFilename); _diskProvider.MoveFile(episodeFile.Path, destinationFilename); _logger.Trace("Setting last write time on series folder: {0}", series.Path); _diskProvider.SetFolderWriteTime(series.Path, episodeFile.DateAdded); if (series.SeasonFolder) { var seasonFolder = Path.GetDirectoryName(destinationFilename); _logger.Trace("Setting last write time on season folder: {0}", seasonFolder); _diskProvider.SetFolderWriteTime(seasonFolder, episodeFile.DateAdded); } //Wrapped in Try/Catch to prevent this from causing issues with remote NAS boxes, the move worked, which is more important. try { _diskProvider.InheritFolderPermissions(destinationFilename); } catch (UnauthorizedAccessException ex) { _logger.Debug("Unable to apply folder permissions to: ", destinationFilename); _logger.TraceException(ex.Message, ex); } }
public string UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode) { var existingFiles = localEpisode.Episodes .Where(e => e.EpisodeFileId > 0) .Select(e => e.EpisodeFile.Value) .GroupBy(e => e.Id); foreach (var existingFile in existingFiles) { var file = existingFile.First(); if (_diskProvider.FileExists(file.Path)) { _logger.Trace("Removing existing episode file: {0}", file); _recycleBinProvider.DeleteFile(file.Path); } _mediaFileService.Delete(file, true); } _logger.Trace("Moving episode file: {0}", episodeFile); return _episodeFileMover.MoveEpisodeFile(episodeFile, localEpisode); }
private string GetOriginalTitle(EpisodeFile episodeFile) { if (episodeFile.SceneName.IsNullOrWhiteSpace()) { return GetOriginalFileName(episodeFile); } return episodeFile.SceneName; }
private void AddMediaInfoTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, EpisodeFile episodeFile) { if (episodeFile.MediaInfo == null) return; string mediaInfoVideo; switch (episodeFile.MediaInfo.VideoCodec) { case "AVC": if (episodeFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(episodeFile.SceneName).Contains("h264")) { mediaInfoVideo = "h264"; } else { mediaInfoVideo = "x264"; } break; case "V_MPEGH/ISO/HEVC": if (episodeFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(episodeFile.SceneName).Contains("h265")) { mediaInfoVideo = "h265"; } else { mediaInfoVideo = "x265"; } break; default: mediaInfoVideo = episodeFile.MediaInfo.VideoCodec; break; } string mediaInfoAudio; switch (episodeFile.MediaInfo.AudioFormat) { case "AC-3": mediaInfoAudio = "AC3"; break; case "MPEG Audio": if (episodeFile.MediaInfo.AudioProfile == "Layer 3") { mediaInfoAudio = "MP3"; } else { mediaInfoAudio = episodeFile.MediaInfo.AudioFormat; } break; case "DTS": mediaInfoAudio = episodeFile.MediaInfo.AudioFormat; break; default: mediaInfoAudio = episodeFile.MediaInfo.AudioFormat; break; } var mediaInfoAudioLanguages = GetLanguagesToken(episodeFile.MediaInfo.AudioLanguages); if (!mediaInfoAudioLanguages.IsNullOrWhiteSpace()) { mediaInfoAudioLanguages = string.Format("[{0}]", mediaInfoAudioLanguages); } if (mediaInfoAudioLanguages == "[EN]") { mediaInfoAudioLanguages = string.Empty; } var mediaInfoSubtitleLanguages = GetLanguagesToken(episodeFile.MediaInfo.Subtitles); if (!mediaInfoSubtitleLanguages.IsNullOrWhiteSpace()) { mediaInfoSubtitleLanguages = string.Format("[{0}]", mediaInfoSubtitleLanguages); } tokenHandlers["{MediaInfo Video}"] = m => mediaInfoVideo; tokenHandlers["{MediaInfo Audio}"] = m => mediaInfoAudio; tokenHandlers["{MediaInfo Simple}"] = m => string.Format("{0} {1}", mediaInfoVideo, mediaInfoAudio); tokenHandlers["{MediaInfo Full}"] = m => string.Format("{0} {1}{2} {3}", mediaInfoVideo, mediaInfoAudio, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages); }
private void AddQualityTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Series series, EpisodeFile episodeFile) { var qualityTitle = _qualityDefinitionService.Get(episodeFile.Quality.Quality).Title; var qualityProper = GetQualityProper(series, episodeFile.Quality); var qualityReal = GetQualityReal(series, episodeFile.Quality); tokenHandlers["{Quality Full}"] = m => String.Format("{0} {1} {2}", qualityTitle, qualityProper, qualityReal); tokenHandlers["{Quality Title}"] = m => qualityTitle; tokenHandlers["{Quality Proper}"] = m => qualityProper; tokenHandlers["{Quality Real}"] = m => qualityReal; }
private void AddEpisodeFileTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, EpisodeFile episodeFile) { tokenHandlers["{Original Title}"] = m => GetOriginalTitle(episodeFile); tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(episodeFile); tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? "Sonarr"; }
public FileNameSampleService(IBuildFileNames buildFileNames) { _buildFileNames = buildFileNames; _standardSeries = new Series { SeriesType = SeriesTypes.Standard, Title = "Series Title (2010)" }; _dailySeries = new Series { SeriesType = SeriesTypes.Daily, Title = "Series Title (2010)" }; _animeSeries = new Series { SeriesType = SeriesTypes.Anime, Title = "Series Title (2010)" }; _episode1 = new Episode { SeasonNumber = 1, EpisodeNumber = 1, Title = "Episode Title (1)", AirDate = "2013-10-30", AbsoluteEpisodeNumber = 1, }; _episode2 = new Episode { SeasonNumber = 1, EpisodeNumber = 2, Title = "Episode Title (2)", AbsoluteEpisodeNumber = 2 }; _episode3 = new Episode { SeasonNumber = 1, EpisodeNumber = 3, Title = "Episode Title (3)", AbsoluteEpisodeNumber = 3 }; _singleEpisode = new List<Episode> { _episode1 }; _multiEpisodes = new List<Episode> { _episode1, _episode2, _episode3 }; var mediaInfo = new MediaInfoModel() { VideoCodec = "AVC", AudioFormat = "DTS", AudioLanguages = "English", Subtitles = "English/German" }; var mediaInfoAnime = new MediaInfoModel() { VideoCodec = "AVC", AudioFormat = "DTS", AudioLanguages = "Japanese", Subtitles = "Japanese/English" }; _singleEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p, new Revision(2)), RelativePath = "Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv", SceneName = "Series.Title.S01E01.720p.HDTV.x264-EVOLVE", ReleaseGroup = "RlsGrp", MediaInfo = mediaInfo }; _multiEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p, new Revision(2)), RelativePath = "Series.Title.S01E01-E03.720p.HDTV.x264-EVOLVE.mkv", SceneName = "Series.Title.S01E01-E03.720p.HDTV.x264-EVOLVE", ReleaseGroup = "RlsGrp", MediaInfo = mediaInfo, }; _dailyEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p, new Revision(2)), RelativePath = "Series.Title.2013.10.30.HDTV.x264-EVOLVE.mkv", SceneName = "Series.Title.2013.10.30.HDTV.x264-EVOLVE", ReleaseGroup = "RlsGrp", MediaInfo = mediaInfo }; _animeEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p, new Revision(2)), RelativePath = "[RlsGroup] Series Title - 001 [720p].mkv", SceneName = "[RlsGroup] Series Title - 001 [720p]", ReleaseGroup = "RlsGrp", MediaInfo = mediaInfoAnime }; _animeMultiEpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p, new Revision(2)), RelativePath = "[RlsGroup] Series Title - 001 - 103 [720p].mkv", SceneName = "[RlsGroup] Series Title - 001 - 103 [720p]", ReleaseGroup = "RlsGrp", MediaInfo = mediaInfoAnime }; }
private void AddMediaInfoTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, EpisodeFile episodeFile) { if (episodeFile.MediaInfo == null) return; string videoCodec; switch (episodeFile.MediaInfo.VideoCodec) { case "AVC": if (episodeFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(episodeFile.SceneName).Contains("h264")) { videoCodec = "h264"; } else { videoCodec = "x264"; } break; case "V_MPEGH/ISO/HEVC": if (episodeFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(episodeFile.SceneName).Contains("h265")) { videoCodec = "h265"; } else { videoCodec = "x265"; } break; case "MPEG-2 Video": videoCodec = "MPEG2"; break; default: videoCodec = episodeFile.MediaInfo.VideoCodec; break; } string audioCodec; switch (episodeFile.MediaInfo.AudioFormat) { case "AC-3": audioCodec = "AC3"; break; case "E-AC-3": audioCodec = "EAC3"; break; case "MPEG Audio": if (episodeFile.MediaInfo.AudioProfile == "Layer 3") { audioCodec = "MP3"; } else { audioCodec = episodeFile.MediaInfo.AudioFormat; } break; case "DTS": audioCodec = episodeFile.MediaInfo.AudioFormat; break; default: audioCodec = episodeFile.MediaInfo.AudioFormat; break; } var mediaInfoAudioLanguages = GetLanguagesToken(episodeFile.MediaInfo.AudioLanguages); if (!mediaInfoAudioLanguages.IsNullOrWhiteSpace()) { mediaInfoAudioLanguages = string.Format("[{0}]", mediaInfoAudioLanguages); } if (mediaInfoAudioLanguages == "[EN]") { mediaInfoAudioLanguages = string.Empty; } var mediaInfoSubtitleLanguages = GetLanguagesToken(episodeFile.MediaInfo.Subtitles); if (!mediaInfoSubtitleLanguages.IsNullOrWhiteSpace()) { mediaInfoSubtitleLanguages = string.Format("[{0}]", mediaInfoSubtitleLanguages); } var videoBitDepth = episodeFile.MediaInfo.VideoBitDepth > 0 ? episodeFile.MediaInfo.VideoBitDepth.ToString() : string.Empty; var audioChannels = episodeFile.MediaInfo.FormattedAudioChannels > 0 ? episodeFile.MediaInfo.FormattedAudioChannels.ToString("F1", CultureInfo.InvariantCulture) : string.Empty; tokenHandlers["{MediaInfo Video}"] = m => videoCodec; tokenHandlers["{MediaInfo VideoCodec}"] = m => videoCodec; tokenHandlers["{MediaInfo VideoBitDepth}"] = m => videoBitDepth; tokenHandlers["{MediaInfo Audio}"] = m => audioCodec; tokenHandlers["{MediaInfo AudioCodec}"] = m => audioCodec; tokenHandlers["{MediaInfo AudioChannels}"] = m => audioChannels; tokenHandlers["{MediaInfo Simple}"] = m => string.Format("{0} {1}", videoCodec, audioCodec); tokenHandlers["{MediaInfo Full}"] = m => string.Format("{0} {1}{2} {3}", videoCodec, audioCodec, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages); }
private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List<Episode> episodes, string destinationFilePath, TransferMode mode) { 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); _updateEpisodeFileService.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, 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); } }
public string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile episodeFile) { var nameSpec = _namingConfigService.GetConfig(); return BuildFilename(episodes, series, episodeFile, nameSpec); }
private string GetOriginalFileName(EpisodeFile episodeFile) { if (episodeFile.RelativePath.IsNullOrWhiteSpace()) { return Path.GetFileNameWithoutExtension(episodeFile.Path); } return Path.GetFileNameWithoutExtension(episodeFile.RelativePath); }
public string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig) { if (!namingConfig.RenameEpisodes) { if (String.IsNullOrWhiteSpace(episodeFile.SceneName)) { return Path.GetFileNameWithoutExtension(episodeFile.Path); } return episodeFile.SceneName; } if (String.IsNullOrWhiteSpace(namingConfig.StandardEpisodeFormat) && series.SeriesType == SeriesTypes.Standard) { throw new NamingFormatException("Standard episode format cannot be null"); } if (String.IsNullOrWhiteSpace(namingConfig.DailyEpisodeFormat) && series.SeriesType == SeriesTypes.Daily) { throw new NamingFormatException("Daily episode format cannot be null"); } var sortedEpisodes = episodes.OrderBy(e => e.EpisodeNumber).ToList(); var pattern = namingConfig.StandardEpisodeFormat; var episodeTitles = new List<string> { sortedEpisodes.First().Title.TrimEnd(EpisodeTitleTrimCharaters) }; var tokenValues = new Dictionary<string, string>(FilenameBuilderTokenEqualityComparer.Instance); tokenValues.Add("{Series Title}", series.Title); tokenValues.Add("{Original Title}", episodeFile.SceneName); tokenValues.Add("{Release Group}", episodeFile.ReleaseGroup); if (series.SeriesType == SeriesTypes.Daily) { pattern = namingConfig.DailyEpisodeFormat; if (!String.IsNullOrWhiteSpace(episodes.First().AirDate)) { tokenValues.Add("{Air Date}", episodes.First().AirDate.Replace('-', ' ')); } else { tokenValues.Add("{Air Date}", "Unknown"); } } var episodeFormat = GetEpisodeFormat(pattern); if (episodeFormat != null) { pattern = pattern.Replace(episodeFormat.SeasonEpisodePattern, "{Season Episode}"); var seasonEpisodePattern = episodeFormat.SeasonEpisodePattern; foreach (var episode in sortedEpisodes.Skip(1)) { switch ((MultiEpisodeStyle)namingConfig.MultiEpisodeStyle) { case MultiEpisodeStyle.Duplicate: seasonEpisodePattern += episodeFormat.Separator + episodeFormat.SeasonEpisodePattern; break; case MultiEpisodeStyle.Repeat: seasonEpisodePattern += episodeFormat.EpisodeSeparator + episodeFormat.EpisodePattern; break; case MultiEpisodeStyle.Scene: seasonEpisodePattern += "-" + episodeFormat.EpisodeSeparator + episodeFormat.EpisodePattern; break; //MultiEpisodeStyle.Extend default: seasonEpisodePattern += "-" + episodeFormat.EpisodePattern; break; } episodeTitles.Add(episode.Title.TrimEnd(EpisodeTitleTrimCharaters)); } seasonEpisodePattern = ReplaceNumberTokens(seasonEpisodePattern, sortedEpisodes); tokenValues.Add("{Season Episode}", seasonEpisodePattern); } tokenValues.Add("{Episode Title}", GetEpisodeTitle(episodeTitles)); tokenValues.Add("{Quality Title}", GetQualityTitle(episodeFile.Quality)); var filename = ReplaceTokens(pattern, tokenValues).Trim(); filename = FilenameCleanupRegex.Replace(filename, match => match.Captures[0].Value[0].ToString() ); return CleanFilename(filename); }
public void Update(EpisodeFile episodeFile) { _mediaFileRepository.Update(episodeFile); }
private EpisodeFile MoveFile(EpisodeFile episodeFile, Series series, List <Episode> episodes, string destinationFilename) { Ensure.That(episodeFile, () => episodeFile).IsNotNull(); Ensure.That(series, () => series).IsNotNull(); Ensure.That(destinationFilename, () => destinationFilename).IsValidPath(); if (!_diskProvider.FileExists(episodeFile.Path)) { throw new FileNotFoundException("Episode file path does not exist", episodeFile.Path); } if (episodeFile.Path.PathEquals(destinationFilename)) { throw new SameFilenameException("File not moved, source and destination are the same", episodeFile.Path); } var directoryName = new FileInfo(destinationFilename).DirectoryName; if (!_diskProvider.FolderExists(directoryName)) { try { _diskProvider.CreateFolder(directoryName); } catch (IOException ex) { _logger.ErrorException("Unable to create directory: " + directoryName, ex); } SetFolderPermissions(directoryName); if (!directoryName.PathEquals(series.Path)) { SetFolderPermissions(series.Path); } } _logger.Debug("Moving [{0}] > [{1}]", episodeFile.Path, destinationFilename); _diskProvider.MoveFile(episodeFile.Path, destinationFilename); episodeFile.Path = destinationFilename; _updateEpisodeFileService.ChangeFileDateForFile(episodeFile, series, episodes); try { _logger.Debug("Setting last write time on series folder: {0}", series.Path); _diskProvider.FolderSetLastWriteTimeUtc(series.Path, episodeFile.DateAdded); if (series.SeasonFolder) { var seasonFolder = Path.GetDirectoryName(destinationFilename); _logger.Debug("Setting last write time on season folder: {0}", seasonFolder); _diskProvider.FolderSetLastWriteTimeUtc(seasonFolder, episodeFile.DateAdded); } } catch (Exception ex) { _logger.WarnException("Unable to set last write time", ex); } //We should only run this on Windows if (OsInfo.IsWindows) { //Wrapped in Try/Catch to prevent this from causing issues with remote NAS boxes, the move worked, which is more important. try { _diskProvider.InheritFolderPermissions(destinationFilename); } catch (Exception ex) { if (ex is UnauthorizedAccessException || ex is InvalidOperationException) { _logger.Debug("Unable to apply folder permissions to: ", destinationFilename); _logger.DebugException(ex.Message, ex); } else { throw; } } } else { SetPermissions(destinationFilename, _configService.FileChmod); } return(episodeFile); }
private void EnsureEpisodeFolder(EpisodeFile episodeFile, LocalEpisode localEpisode, string filePath) { EnsureEpisodeFolder(episodeFile, localEpisode.Series, localEpisode.SeasonNumber, filePath); }
public string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig nameSpec) { if (!nameSpec.RenameEpisodes) { if (String.IsNullOrWhiteSpace(episodeFile.SceneName)) { return Path.GetFileNameWithoutExtension(episodeFile.Path); } return episodeFile.SceneName; } var sortedEpisodes = episodes.OrderBy(e => e.EpisodeNumber); var numberStyle = GetNumberStyle(nameSpec.NumberStyle); var episodeNames = new List<string> { Parser.Parser.CleanupEpisodeTitle(sortedEpisodes.First().Title) }; var result = String.Empty; if (nameSpec.IncludeSeriesTitle) { result += series.Title + nameSpec.Separator; } if (series.SeriesType == SeriesTypes.Standard) { result += numberStyle.Pattern.Replace("%0e", String.Format("{0:00}", sortedEpisodes.First().EpisodeNumber)); if (episodes.Count > 1) { var multiEpisodeStyle = GetMultiEpisodeStyle(nameSpec.MultiEpisodeStyle); foreach (var episode in sortedEpisodes.Skip(1)) { if (multiEpisodeStyle.Name == "Duplicate") { result += nameSpec.Separator + numberStyle.Pattern; } else { result += multiEpisodeStyle.Pattern; } result = result.Replace("%0e", String.Format("{0:00}", episode.EpisodeNumber)); episodeNames.Add(Parser.Parser.CleanupEpisodeTitle(episode.Title)); } } result = result .Replace("%s", String.Format("{0}", episodes.First().SeasonNumber)) .Replace("%0s", String.Format("{0:00}", episodes.First().SeasonNumber)) .Replace("%x", numberStyle.EpisodeSeparator) .Replace("%p", nameSpec.Separator); } else { if (!String.IsNullOrEmpty(episodes.First().AirDate)) result += episodes.First().AirDate; else result += "Unknown"; } if (nameSpec.IncludeEpisodeTitle) { if (episodeNames.Distinct().Count() == 1) result += nameSpec.Separator + episodeNames.First(); else result += nameSpec.Separator + String.Join(" + ", episodeNames.Distinct()); } if (nameSpec.IncludeQuality) { result += String.Format(" [{0}]", episodeFile.Quality.Quality); if (episodeFile.Quality.Proper) result += " [Proper]"; } if (nameSpec.ReplaceSpaces) result = result.Replace(' ', '.'); _logger.Trace("New File Name is: [{0}]", result.Trim()); return CleanFilename(result.Trim()); }
private EpisodeFile MoveFile(EpisodeFile episodeFile, Series series, string destinationFilename) { Ensure.That(episodeFile, () => episodeFile).IsNotNull(); Ensure.That(series,() => series).IsNotNull(); Ensure.That(destinationFilename, () => destinationFilename).IsValidPath(); if (!_diskProvider.FileExists(episodeFile.Path)) { throw new FileNotFoundException("Episode file path does not exist", episodeFile.Path); } if (episodeFile.Path.PathEquals(destinationFilename)) { throw new SameFilenameException("File not moved, source and destination are the same", episodeFile.Path); } var directoryName = new FileInfo(destinationFilename).DirectoryName; if (!_diskProvider.FolderExists(directoryName)) { try { _diskProvider.CreateFolder(directoryName); } catch (IOException ex) { _logger.ErrorException("Unable to create directory: " + directoryName, ex); } SetFolderPermissions(directoryName); if (!directoryName.PathEquals(series.Path)) { SetFolderPermissions(series.Path); } } _logger.Debug("Moving [{0}] > [{1}]", episodeFile.Path, destinationFilename); _diskProvider.MoveFile(episodeFile.Path, destinationFilename); episodeFile.Path = destinationFilename; try { _logger.Trace("Setting last write time on series folder: {0}", series.Path); _diskProvider.FolderSetLastWriteTimeUtc(series.Path, episodeFile.DateAdded); if (series.SeasonFolder) { var seasonFolder = Path.GetDirectoryName(destinationFilename); _logger.Trace("Setting last write time on season folder: {0}", seasonFolder); _diskProvider.FolderSetLastWriteTimeUtc(seasonFolder, episodeFile.DateAdded); } } catch (Exception ex) { _logger.WarnException("Unable to set last write time", ex); } //We should only run this on Windows if (OsInfo.IsWindows) { //Wrapped in Try/Catch to prevent this from causing issues with remote NAS boxes, the move worked, which is more important. try { _diskProvider.InheritFolderPermissions(destinationFilename); } catch (Exception ex) { if (ex is UnauthorizedAccessException || ex is InvalidOperationException) { _logger.Debug("Unable to apply folder permissions to: ", destinationFilename); _logger.TraceException(ex.Message, ex); } else { throw; } } } else { SetPermissions(destinationFilename, _configService.FileChmod); } return episodeFile; }
private string BuildSample(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig nameSpec) { try { return _buildFileNames.BuildFilename(episodes, series, episodeFile, nameSpec); } catch (NamingFormatException) { return String.Empty; } }
public void ChangeFileDateForFile(EpisodeFile episodeFile, Series series, List <Episode> episodes) { ChangeFileDate(episodeFile, series, episodes); }