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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user