You've already forked Sonarr
							
							
				mirror of
				https://github.com/Sonarr/Sonarr.git
				synced 2025-10-31 00:07:55 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			265 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.IO;
 | |
| using System.Linq;
 | |
| using NLog;
 | |
| using NzbDrone.Core.Configuration;
 | |
| using NzbDrone.Core.Qualities;
 | |
| using NzbDrone.Core.Tv;
 | |
| using NzbDrone.Core.Helpers;
 | |
| using NzbDrone.Core.Providers.Core;
 | |
| using NzbDrone.Core.Repository;
 | |
| using PetaPoco;
 | |
| using NzbDrone.Common;
 | |
| 
 | |
| namespace NzbDrone.Core.Providers
 | |
| {
 | |
|     public class MediaFileProvider
 | |
|     {
 | |
|         private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
 | |
|         private readonly IConfigService _configService;
 | |
|         private readonly IDatabase _database;
 | |
|         private readonly IEpisodeService _episodeService;
 | |
| 
 | |
|         public MediaFileProvider(IEpisodeService episodeService, IConfigService configService, IDatabase database)
 | |
|         {
 | |
|             _episodeService = episodeService;
 | |
|             _configService = configService;
 | |
|             _database = database;
 | |
|         }
 | |
| 
 | |
|         public MediaFileProvider()
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         public virtual int Add(EpisodeFile episodeFile)
 | |
|         {
 | |
|             return Convert.ToInt32(_database.Insert(episodeFile));
 | |
|         }
 | |
| 
 | |
|         public virtual void Update(EpisodeFile episodeFile)
 | |
|         {
 | |
|             _database.Update(episodeFile);
 | |
|         }
 | |
| 
 | |
|         public virtual void Delete(int episodeFileId)
 | |
|         {
 | |
|             _database.Delete<EpisodeFile>(episodeFileId);
 | |
|         }
 | |
| 
 | |
|         public virtual bool Exists(string path)
 | |
|         {
 | |
|             return _database.Exists<EpisodeFile>("WHERE Path =@0", path.NormalizePath());
 | |
|         }
 | |
| 
 | |
|         public virtual EpisodeFile GetFileByPath(string path)
 | |
|         {
 | |
|             return _database.SingleOrDefault<EpisodeFile>("WHERE Path =@0", path.NormalizePath());
 | |
|         }
 | |
| 
 | |
|         public virtual EpisodeFile GetEpisodeFile(int episodeFileId)
 | |
|         {
 | |
|             return _database.Single<EpisodeFile>(episodeFileId);
 | |
|         }
 | |
| 
 | |
|         public virtual List<EpisodeFile> GetEpisodeFiles()
 | |
|         {
 | |
|             return _database.Fetch<EpisodeFile>();
 | |
|         }
 | |
| 
 | |
|         public virtual IList<EpisodeFile> GetSeriesFiles(int seriesId)
 | |
|         {
 | |
|             return _database.Fetch<EpisodeFile>("WHERE SeriesId= @0", seriesId);
 | |
|         }
 | |
| 
 | |
|         public virtual IList<EpisodeFile> GetSeasonFiles(int seriesId, int seasonNumber)
 | |
|         {
 | |
|             return _database.Fetch<EpisodeFile>("WHERE SeriesId= @0 AND SeasonNumber = @1", seriesId, seasonNumber);
 | |
|         }
 | |
| 
 | |
|         public virtual Tuple<int, int> GetEpisodeFilesCount(int seriesId)
 | |
|         {
 | |
|             var allEpisodes = _episodeService.GetEpisodeBySeries(seriesId).ToList();
 | |
| 
 | |
|             var episodeTotal = allEpisodes.Where(e => !e.Ignored && e.AirDate != null && e.AirDate <= DateTime.Today).ToList();
 | |
|             var avilableEpisodes = episodeTotal.Where(e => e.EpisodeFileId > 0).ToList();
 | |
| 
 | |
|             return new Tuple<int, int>(avilableEpisodes.Count, episodeTotal.Count);
 | |
|         }
 | |
| 
 | |
|         public virtual FileInfo CalculateFilePath(Series series, int seasonNumber, string fileName, string extention)
 | |
|         {
 | |
|             string path = series.Path;
 | |
|             if (series.SeasonFolder)
 | |
|             {
 | |
|                 var seasonFolder = _configService.SortingSeasonFolderFormat
 | |
|                     .Replace("%0s", seasonNumber.ToString("00"))
 | |
|                     .Replace("%s", seasonNumber.ToString());
 | |
| 
 | |
|                 path = Path.Combine(path, seasonFolder);
 | |
|             }
 | |
| 
 | |
|             path = Path.Combine(path, fileName + extention);
 | |
| 
 | |
|             return new FileInfo(path);
 | |
|         }
 | |
| 
 | |
|         public virtual void CleanUpDatabase()
 | |
|         {
 | |
|             Logger.Trace("Verifying Episode > Episode file relationships.");
 | |
| 
 | |
|             string updateString = "UPDATE Episodes SET EpisodeFileId = 0, GrabDate = NULL, PostDownloadStatus = 0";
 | |
| 
 | |
|             if (_configService.AutoIgnorePreviouslyDownloadedEpisodes)
 | |
|             {
 | |
|                 updateString += ", Ignored = 1";
 | |
|             }
 | |
| 
 | |
|             var updated = _database.Execute(updateString +
 | |
|                                                              @"WHERE EpisodeFileId IN
 | |
|                                                              (SELECT Episodes.EpisodeFileId FROM Episodes
 | |
|                                                              LEFT OUTER JOIN EpisodeFiles
 | |
|                                                              ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId
 | |
|                                                              WHERE Episodes.EpisodeFileId > 0 AND EpisodeFiles.EpisodeFileId IS NULL)");
 | |
| 
 | |
|             if (updated > 0)
 | |
|             {
 | |
|                 Logger.Debug("Removed {0} invalid links to episode files.", updated);
 | |
|             }
 | |
| 
 | |
|             Logger.Trace("Deleting orphan files.");
 | |
| 
 | |
|             updated = _database.Execute(@"DELETE FROM EpisodeFiles
 | |
|                                 WHERE EpisodeFileId IN
 | |
|                                 (SELECT EpisodeFiles.EpisodeFileId FROM EpisodeFiles
 | |
|                                 LEFT OUTER JOIN Episodes
 | |
|                                 ON EpisodeFiles.EpisodeFileId = Episodes.EpisodeFileId
 | |
|                                 WHERE Episodes.EpisodeFileId IS NULL)");
 | |
| 
 | |
|             if (updated > 0)
 | |
|             {
 | |
|                 Logger.Debug("Removed {0} orphan file(s) from database.", updated);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public virtual string GetNewFilename(IList<Episode> episodes, Series series, Quality quality, bool proper, EpisodeFile episodeFile)
 | |
|         {
 | |
|             if (_configService.SortingUseSceneName)
 | |
|             {
 | |
|                 Logger.Trace("Attempting to use scene name");
 | |
|                 if (String.IsNullOrWhiteSpace(episodeFile.SceneName))
 | |
|                 {
 | |
|                     var name = Path.GetFileNameWithoutExtension(episodeFile.Path);
 | |
|                     Logger.Trace("Unable to use scene name, because it is null, sticking with current name: {0}", name);
 | |
| 
 | |
|                     return name;
 | |
|                 }
 | |
| 
 | |
|                 return episodeFile.SceneName;
 | |
|             }
 | |
| 
 | |
|             var sortedEpisodes = episodes.OrderBy(e => e.EpisodeNumber);
 | |
| 
 | |
|             var separatorStyle = EpisodeSortingHelper.GetSeparatorStyle(_configService.SortingSeparatorStyle);
 | |
|             var numberStyle = EpisodeSortingHelper.GetNumberStyle(_configService.SortingNumberStyle);
 | |
| 
 | |
|             var episodeNames = new List<String>();
 | |
| 
 | |
|             episodeNames.Add(Parser.CleanupEpisodeTitle(sortedEpisodes.First().Title));
 | |
| 
 | |
|             string result = String.Empty;
 | |
| 
 | |
|             if (_configService.SortingIncludeSeriesName)
 | |
|             {
 | |
|                 result += series.Title + separatorStyle.Pattern;
 | |
|             }
 | |
| 
 | |
|             if (series.SeriesType == SeriesType.Standard)
 | |
|             {
 | |
|                 result += numberStyle.Pattern.Replace("%0e",
 | |
|                                                       String.Format("{0:00}", sortedEpisodes.First().EpisodeNumber));
 | |
| 
 | |
|                 if(episodes.Count > 1)
 | |
|                 {
 | |
|                     var multiEpisodeStyle =
 | |
|                             EpisodeSortingHelper.GetMultiEpisodeStyle(_configService.SortingMultiEpisodeStyle);
 | |
| 
 | |
|                     foreach(var episode in sortedEpisodes.Skip(1))
 | |
|                     {
 | |
|                         if(multiEpisodeStyle.Name == "Duplicate")
 | |
|                         {
 | |
|                             result += separatorStyle.Pattern + numberStyle.Pattern;
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             result += multiEpisodeStyle.Pattern;
 | |
|                         }
 | |
| 
 | |
|                         result = result.Replace("%0e", String.Format("{0:00}", episode.EpisodeNumber));
 | |
|                         episodeNames.Add(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", separatorStyle.Pattern);
 | |
|             }
 | |
| 
 | |
|             else
 | |
|             {
 | |
|                 if(episodes.First().AirDate.HasValue)
 | |
|                     result += episodes.First().AirDate.Value.ToString("yyyy-MM-dd");
 | |
| 
 | |
|                 else
 | |
|                     result += "Unknown";
 | |
|             }
 | |
| 
 | |
|             if (_configService.SortingIncludeEpisodeTitle)
 | |
|             {
 | |
|                 if (episodeNames.Distinct().Count() == 1)
 | |
|                     result += separatorStyle.Pattern + episodeNames.First();
 | |
| 
 | |
|                 else
 | |
|                     result += separatorStyle.Pattern + String.Join(" + ", episodeNames.Distinct());
 | |
|             }
 | |
| 
 | |
|             if (_configService.SortingAppendQuality)
 | |
|             {
 | |
|                 result += String.Format(" [{0}]", quality);
 | |
| 
 | |
|                 if (proper)
 | |
|                     result += " [Proper]";
 | |
|             }
 | |
| 
 | |
|             if (_configService.SortingReplaceSpaces)
 | |
|                 result = result.Replace(' ', '.');
 | |
| 
 | |
|             Logger.Trace("New File Name is: [{0}]", result.Trim());
 | |
|             return CleanFilename(result.Trim());
 | |
|         }
 | |
| 
 | |
|         public virtual void ChangeQuality(int episodeFileId, Quality quality)
 | |
|         {
 | |
|             _database.Execute("UPDATE EpisodeFiles SET Quality = @quality WHERE EpisodeFileId = @episodeFileId", new { episodeFileId, quality });
 | |
|         }
 | |
| 
 | |
|         public virtual void ChangeQuality(int seriesId, int seasonNumber, Quality quality)
 | |
|         {
 | |
|             _database.Execute("UPDATE EpisodeFiles SET Quality = @quality WHERE SeriesId = @seriesId AND SeasonNumber = @seasonNumber", new { seriesId, seasonNumber, quality });
 | |
|         }
 | |
| 
 | |
|         public static string CleanFilename(string name)
 | |
|         {
 | |
|             string result = name;
 | |
|             string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" };
 | |
|             string[] goodCharacters = { "+", "+", "{", "}", "!", "@", "-", "#", "`" };
 | |
| 
 | |
|             for (int i = 0; i < badCharacters.Length; i++)
 | |
|                 result = result.Replace(badCharacters[i], goodCharacters[i]);
 | |
| 
 | |
|             return result.Trim();
 | |
|         }
 | |
|     }
 | |
| } |