You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Radarr/NzbDrone.Core/Providers/MediaFileProvider.cs

265 lines
9.9 KiB

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();
}
}
}