1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-27 22:57:09 -04:00

Added: Importing extra files from downloaded movies and generate metadata such as .nfo (#2506)

Fixes #121, Fixes #167, Fixes #2262 and Fixes #1104
This commit is contained in:
Qstick
2018-02-15 13:39:01 +01:00
committed by Leonardo Galli
parent b40423f3a3
commit e7e9e2b154
78 changed files with 1381 additions and 1759 deletions
+10 -4
View File
@@ -1,16 +1,22 @@
using System;
using System;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Extras.Files
{
public abstract class ExtraFile : ModelBase
{
public int SeriesId { get; set; }
public int? EpisodeFileId { get; set; }
public int? SeasonNumber { get; set; }
public int MovieId { get; set; }
public int? MovieFileId { get; set; }
public string RelativePath { get; set; }
public DateTime Added { get; set; }
public DateTime LastUpdated { get; set; }
public string Extension { get; set; }
}
public enum ExtraFileType
{
Subtitle = 0,
Metadata = 1,
Other = 2
}
}
@@ -1,5 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
@@ -11,11 +14,10 @@ namespace NzbDrone.Core.Extras.Files
public interface IManageExtraFiles
{
int Order { get; }
IEnumerable<ExtraFile> CreateAfterSeriesScan(Series series, List<EpisodeFile> episodeFiles);
IEnumerable<ExtraFile> CreateAfterEpisodeImport(Series series, EpisodeFile episodeFile);
IEnumerable<ExtraFile> CreateAfterEpisodeImport(Series series, string seriesFolder, string seasonFolder);
IEnumerable<ExtraFile> MoveFilesAfterRename(Series series, List<EpisodeFile> episodeFiles);
ExtraFile Import(Series series, EpisodeFile episodeFile, string path, string extension, bool readOnly);
IEnumerable<ExtraFile> CreateAfterMovieScan(Movie movie, List<MovieFile> movieFiles);
IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, MovieFile movieFile);
IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles);
ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly);
}
public abstract class ExtraFileManager<TExtraFile> : IManageExtraFiles
@@ -23,29 +25,40 @@ namespace NzbDrone.Core.Extras.Files
{
private readonly IConfigService _configService;
private readonly IDiskProvider _diskProvider;
private readonly IDiskTransferService _diskTransferService;
private readonly IExtraFileService<TExtraFile> _extraFileService;
private readonly Logger _logger;
public ExtraFileManager(IConfigService configService,
IDiskProvider diskProvider,
IDiskTransferService diskTransferService,
IExtraFileService<TExtraFile> extraFileService)
Logger logger)
{
_configService = configService;
_diskProvider = diskProvider;
_diskTransferService = diskTransferService;
_extraFileService = extraFileService;
_logger = logger;
}
public abstract int Order { get; }
public abstract IEnumerable<ExtraFile> CreateAfterSeriesScan(Series series, List<EpisodeFile> episodeFiles);
public abstract IEnumerable<ExtraFile> CreateAfterEpisodeImport(Series series, EpisodeFile episodeFile);
public abstract IEnumerable<ExtraFile> CreateAfterEpisodeImport(Series series, string seriesFolder, string seasonFolder);
public abstract IEnumerable<ExtraFile> MoveFilesAfterRename(Series series, List<EpisodeFile> episodeFiles);
public abstract ExtraFile Import(Series series, EpisodeFile episodeFile, string path, string extension, bool readOnly);
public abstract IEnumerable<ExtraFile> CreateAfterMovieScan(Movie movie, List<MovieFile> movieFiles);
public abstract IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, MovieFile movieFile);
public abstract IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles);
public abstract ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly);
protected TExtraFile ImportFile(Series series, EpisodeFile episodeFile, string path, string extension, bool readOnly)
protected TExtraFile ImportFile(Movie movie, MovieFile movieFile, string path, bool readOnly, string extension, string fileNameSuffix = null)
{
var newFileName = Path.Combine(series.Path, Path.ChangeExtension(episodeFile.RelativePath, extension));
var newFolder = Path.GetDirectoryName(Path.Combine(movie.Path, movieFile.RelativePath));
var filenameBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(movieFile.RelativePath));
if (fileNameSuffix.IsNotNullOrWhiteSpace())
{
filenameBuilder.Append(fileNameSuffix);
}
filenameBuilder.Append(extension);
var newFileName = Path.Combine(newFolder, filenameBuilder.ToString());
var transferMode = TransferMode.Move;
if (readOnly)
@@ -57,12 +70,45 @@ namespace NzbDrone.Core.Extras.Files
return new TExtraFile
{
SeriesId = series.Id,
SeasonNumber = episodeFile.SeasonNumber,
EpisodeFileId = episodeFile.Id,
RelativePath = series.Path.GetRelativePath(newFileName),
Extension = Path.GetExtension(path)
MovieId = movie.Id,
MovieFileId = movieFile.Id,
RelativePath = movie.Path.GetRelativePath(newFileName),
Extension = extension
};
}
protected TExtraFile MoveFile(Movie movie, MovieFile movieFile, TExtraFile extraFile, string fileNameSuffix = null)
{
var newFolder = Path.GetDirectoryName(Path.Combine(movie.Path, movieFile.RelativePath));
var filenameBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(movieFile.RelativePath));
if (fileNameSuffix.IsNotNullOrWhiteSpace())
{
filenameBuilder.Append(fileNameSuffix);
}
filenameBuilder.Append(extraFile.Extension);
var existingFileName = Path.Combine(movie.Path, extraFile.RelativePath);
var newFileName = Path.Combine(newFolder, filenameBuilder.ToString());
if (newFileName.PathNotEquals(existingFileName))
{
try
{
_diskProvider.MoveFile(existingFileName, newFileName);
extraFile.RelativePath = movie.Path.GetRelativePath(newFileName);
return extraFile;
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to move file after rename: {0}", existingFileName);
}
}
return null;
}
}
}
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
@@ -7,12 +7,10 @@ namespace NzbDrone.Core.Extras.Files
{
public interface IExtraFileRepository<TExtraFile> : IBasicRepository<TExtraFile> where TExtraFile : ExtraFile, new()
{
void DeleteForSeries(int seriesId);
void DeleteForSeason(int seriesId, int seasonNumber);
void DeleteForEpisodeFile(int episodeFileId);
List<TExtraFile> GetFilesBySeries(int seriesId);
List<TExtraFile> GetFilesBySeason(int seriesId, int seasonNumber);
List<TExtraFile> GetFilesByEpisodeFile(int episodeFileId);
void DeleteForMovie(int movieId);
void DeleteForMovieFile(int movieFileId);
List<TExtraFile> GetFilesByMovie(int movieId);
List<TExtraFile> GetFilesByMovieFile(int movieFileId);
TExtraFile FindByPath(string path);
}
@@ -24,34 +22,24 @@ namespace NzbDrone.Core.Extras.Files
{
}
public void DeleteForSeries(int seriesId)
public void DeleteForMovie(int movieId)
{
Delete(c => c.SeriesId == seriesId);
Delete(c => c.MovieId == movieId);
}
public void DeleteForSeason(int seriesId, int seasonNumber)
public void DeleteForMovieFile(int movieFileId)
{
Delete(c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber);
Delete(c => c.MovieFileId == movieFileId);
}
public void DeleteForEpisodeFile(int episodeFileId)
public List<TExtraFile> GetFilesByMovie(int movieId)
{
Delete(c => c.EpisodeFileId == episodeFileId);
return Query.Where(c => c.MovieId == movieId);
}
public List<TExtraFile> GetFilesBySeries(int seriesId)
public List<TExtraFile> GetFilesByMovieFile(int movieFileId)
{
return Query.Where(c => c.SeriesId == seriesId);
}
public List<TExtraFile> GetFilesBySeason(int seriesId, int seasonNumber)
{
return Query.Where(c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber);
}
public List<TExtraFile> GetFilesByEpisodeFile(int episodeFileId)
{
return Query.Where(c => c.EpisodeFileId == episodeFileId);
return Query.Where(c => c.MovieFileId == movieFileId);
}
public TExtraFile FindByPath(string path)
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -15,8 +15,8 @@ namespace NzbDrone.Core.Extras.Files
public interface IExtraFileService<TExtraFile>
where TExtraFile : ExtraFile, new()
{
List<TExtraFile> GetFilesBySeries(int seriesId);
List<TExtraFile> GetFilesByEpisodeFile(int episodeFileId);
List<TExtraFile> GetFilesByMovie(int movieId);
List<TExtraFile> GetFilesByMovieFile(int movieFileId);
TExtraFile FindByPath(string path);
void Upsert(TExtraFile extraFile);
void Upsert(List<TExtraFile> extraFiles);
@@ -25,24 +25,24 @@ namespace NzbDrone.Core.Extras.Files
}
public abstract class ExtraFileService<TExtraFile> : IExtraFileService<TExtraFile>,
IHandleAsync<SeriesDeletedEvent>,
IHandleAsync<EpisodeFileDeletedEvent>
IHandleAsync<MovieDeletedEvent>,
IHandleAsync<MovieFileDeletedEvent>
where TExtraFile : ExtraFile, new()
{
private readonly IExtraFileRepository<TExtraFile> _repository;
private readonly ISeriesService _seriesService;
private readonly IMovieService _movieService;
private readonly IDiskProvider _diskProvider;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly Logger _logger;
public ExtraFileService(IExtraFileRepository<TExtraFile> repository,
ISeriesService seriesService,
IMovieService movieService,
IDiskProvider diskProvider,
IRecycleBinProvider recycleBinProvider,
Logger logger)
{
_repository = repository;
_seriesService = seriesService;
_movieService = movieService;
_diskProvider = diskProvider;
_recycleBinProvider = recycleBinProvider;
_logger = logger;
@@ -50,14 +50,14 @@ namespace NzbDrone.Core.Extras.Files
public virtual bool PermanentlyDelete => false;
public List<TExtraFile> GetFilesBySeries(int seriesId)
public List<TExtraFile> GetFilesByMovie(int movieId)
{
return _repository.GetFilesBySeries(seriesId);
return _repository.GetFilesByMovie(movieId);
}
public List<TExtraFile> GetFilesByEpisodeFile(int episodeFileId)
public List<TExtraFile> GetFilesByMovieFile(int movieFileId)
{
return _repository.GetFilesByEpisodeFile(episodeFileId);
return _repository.GetFilesByMovieFile(movieFileId);
}
public TExtraFile FindByPath(string path)
@@ -96,28 +96,28 @@ namespace NzbDrone.Core.Extras.Files
_repository.DeleteMany(ids);
}
public void HandleAsync(SeriesDeletedEvent message)
public void HandleAsync(MovieDeletedEvent message)
{
_logger.Debug("Deleting Extra from database for series: {0}", message.Series);
_repository.DeleteForSeries(message.Series.Id);
_logger.Debug("Deleting Extra from database for movie: {0}", message.Movie);
_repository.DeleteForMovie(message.Movie.Id);
}
public void HandleAsync(EpisodeFileDeletedEvent message)
public void HandleAsync(MovieFileDeletedEvent message)
{
var episodeFile = message.EpisodeFile;
var movieFile = message.MovieFile;
if (message.Reason == DeleteMediaFileReason.NoLinkedEpisodes)
{
_logger.Debug("Removing episode file from DB as part of cleanup routine, not deleting extra files from disk.");
_logger.Debug("Removing movie file from DB as part of cleanup routine, not deleting extra files from disk.");
}
else
{
var series = _seriesService.GetSeries(message.EpisodeFile.SeriesId);
var movie = _movieService.GetMovie(message.MovieFile.MovieId);
foreach (var extra in _repository.GetFilesByEpisodeFile(episodeFile.Id))
foreach (var extra in _repository.GetFilesByMovieFile(movieFile.Id))
{
var path = Path.Combine(series.Path, extra.RelativePath);
var path = Path.Combine(movie.Path, extra.RelativePath);
if (_diskProvider.FileExists(path))
{
@@ -135,8 +135,8 @@ namespace NzbDrone.Core.Extras.Files
}
}
_logger.Debug("Deleting Extra from database for episode file: {0}", episodeFile);
_repository.DeleteForEpisodeFile(episodeFile.Id);
_logger.Debug("Deleting Extra from database for movie file: {0}", movieFile);
_repository.DeleteForMovieFile(movieFile.Id);
}
}
}