mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-27 22:57:09 -04:00
New: Import subtitles from sub folders
This commit is contained in:
@@ -31,7 +31,6 @@ namespace NzbDrone.Core.Extras
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly List<IManageExtraFiles> _extraFileManagers;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ExtraService(IMediaFileService mediaFileService,
|
||||
IMovieService movieService,
|
||||
@@ -45,7 +44,6 @@ namespace NzbDrone.Core.Extras
|
||||
_diskProvider = diskProvider;
|
||||
_configService = configService;
|
||||
_extraFileManagers = extraFileManagers.OrderBy(e => e.Order).ToList();
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void ImportMovie(LocalMovie localMovie, MovieFile movieFile, bool isReadOnly)
|
||||
@@ -62,61 +60,42 @@ namespace NzbDrone.Core.Extras
|
||||
return;
|
||||
}
|
||||
|
||||
var sourcePath = localMovie.Path;
|
||||
var sourceFolder = _diskProvider.GetParentFolder(sourcePath);
|
||||
var sourceFileName = Path.GetFileNameWithoutExtension(sourcePath);
|
||||
var files = _diskProvider.GetFiles(sourceFolder, SearchOption.AllDirectories).Where(f => f != localMovie.Path);
|
||||
var folderSearchOption = localMovie.FolderMovieInfo == null
|
||||
? SearchOption.TopDirectoryOnly
|
||||
: SearchOption.AllDirectories;
|
||||
|
||||
var wantedExtensions = _configService.ExtraFileExtensions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(e => e.Trim(' ', '.'))
|
||||
.Select(e => e.Trim(' ', '.')
|
||||
.Insert(0, "."))
|
||||
.ToList();
|
||||
|
||||
var matchingFilenames = files.Where(f => Path.GetFileNameWithoutExtension(f).StartsWith(sourceFileName, StringComparison.InvariantCultureIgnoreCase)).ToList();
|
||||
var filteredFilenames = new List<string>();
|
||||
var hasNfo = false;
|
||||
var sourceFolder = _diskProvider.GetParentFolder(localMovie.Path);
|
||||
var files = _diskProvider.GetFiles(sourceFolder, folderSearchOption);
|
||||
var managedFiles = _extraFileManagers.Select((i) => new List<string>()).ToArray();
|
||||
|
||||
foreach (var matchingFilename in matchingFilenames)
|
||||
foreach (var file in files)
|
||||
{
|
||||
// Filter out duplicate NFO files
|
||||
if (matchingFilename.EndsWith(".nfo", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
if (hasNfo)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hasNfo = true;
|
||||
}
|
||||
|
||||
filteredFilenames.Add(matchingFilename);
|
||||
}
|
||||
|
||||
foreach (var matchingFilename in filteredFilenames)
|
||||
{
|
||||
var matchingExtension = wantedExtensions.FirstOrDefault(e => matchingFilename.EndsWith(e));
|
||||
var extension = Path.GetExtension(file);
|
||||
var matchingExtension = wantedExtensions.FirstOrDefault(e => e.Equals(extension));
|
||||
|
||||
if (matchingExtension == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
for (int i = 0; i < _extraFileManagers.Count; i++)
|
||||
{
|
||||
foreach (var extraFileManager in _extraFileManagers)
|
||||
if (_extraFileManagers[i].CanImportFile(localMovie, movieFile, file, extension, isReadOnly))
|
||||
{
|
||||
var extension = Path.GetExtension(matchingFilename);
|
||||
var extraFile = extraFileManager.Import(localMovie.Movie, movieFile, matchingFilename, extension, isReadOnly);
|
||||
|
||||
if (extraFile != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
managedFiles[i].Add(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Failed to import extra file: {0}", matchingFilename);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _extraFileManagers.Count; i++)
|
||||
{
|
||||
_extraFileManagers[i].ImportFiles(localMovie, movieFile, managedFiles[i], isReadOnly);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Files
|
||||
{
|
||||
@@ -19,7 +20,8 @@ namespace NzbDrone.Core.Extras.Files
|
||||
IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, MovieFile movieFile);
|
||||
IEnumerable<ExtraFile> CreateAfterMovieFolder(Movie movie, string movieFolder);
|
||||
IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles);
|
||||
ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly);
|
||||
bool CanImportFile(LocalMovie localMovie, MovieFile movieFile, string path, string extension, bool readOnly);
|
||||
IEnumerable<ExtraFile> ImportFiles(LocalMovie localMovie, MovieFile movieFile, List<string> files, bool isReadOnly);
|
||||
}
|
||||
|
||||
public abstract class ExtraFileManager<TExtraFile> : IManageExtraFiles
|
||||
@@ -47,7 +49,8 @@ namespace NzbDrone.Core.Extras.Files
|
||||
public abstract IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, MovieFile movieFile);
|
||||
public abstract IEnumerable<ExtraFile> CreateAfterMovieFolder(Movie movie, string movieFolder);
|
||||
public abstract IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles);
|
||||
public abstract ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly);
|
||||
public abstract bool CanImportFile(LocalMovie localMovie, MovieFile movieFile, string path, string extension, bool readOnly);
|
||||
public abstract IEnumerable<ExtraFile> ImportFiles(LocalMovie localMovie, MovieFile movieFile, List<string> files, bool isReadOnly);
|
||||
|
||||
protected TExtraFile ImportFile(Movie movie, MovieFile movieFile, string path, bool readOnly, string extension, string fileNameSuffix = null)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@ using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.Extras.Others;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
@@ -191,9 +192,14 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return movedFiles;
|
||||
}
|
||||
|
||||
public override ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly)
|
||||
public override bool CanImportFile(LocalMovie localMovie, MovieFile movieFile, string path, string extension, bool readOnly)
|
||||
{
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override IEnumerable<ExtraFile> ImportFiles(LocalMovie localMovie, MovieFile movieFile, List<string> files, bool isReadOnly)
|
||||
{
|
||||
return Enumerable.Empty<ExtraFile>();
|
||||
}
|
||||
|
||||
private List<MetadataFile> GetMetadataFilesForConsumer(IMetadata consumer, List<MetadataFile> movieMetadata)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
@@ -7,13 +9,16 @@ using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Others
|
||||
{
|
||||
public class OtherExtraService : ExtraFileManager<OtherExtraFile>
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IOtherExtraFileService _otherExtraFileService;
|
||||
private readonly IMediaFileAttributeService _mediaFileAttributeService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public OtherExtraService(IConfigService configService,
|
||||
IDiskProvider diskProvider,
|
||||
@@ -23,8 +28,10 @@ namespace NzbDrone.Core.Extras.Others
|
||||
Logger logger)
|
||||
: base(configService, diskProvider, diskTransferService, logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_otherExtraFileService = otherExtraFileService;
|
||||
_mediaFileAttributeService = mediaFileAttributeService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override int Order => 2;
|
||||
@@ -69,17 +76,79 @@ namespace NzbDrone.Core.Extras.Others
|
||||
return movedFiles;
|
||||
}
|
||||
|
||||
public override ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly)
|
||||
public override bool CanImportFile(LocalMovie localMovie, MovieFile movieFile, string path, string extension, bool readOnly)
|
||||
{
|
||||
var extraFile = ImportFile(movie, movieFile, path, readOnly, extension, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (extraFile != null)
|
||||
public override IEnumerable<ExtraFile> ImportFiles(LocalMovie localMovie, MovieFile movieFile, List<string> files, bool isReadOnly)
|
||||
{
|
||||
var importedFiles = new List<ExtraFile>();
|
||||
var filteredFiles = files.Where(f => CanImportFile(localMovie, movieFile, f, Path.GetExtension(f), isReadOnly)).ToList();
|
||||
var sourcePath = localMovie.Path;
|
||||
var sourceFolder = _diskProvider.GetParentFolder(sourcePath);
|
||||
var sourceFileName = Path.GetFileNameWithoutExtension(sourcePath);
|
||||
var matchingFiles = new List<string>();
|
||||
var hasNfo = false;
|
||||
|
||||
foreach (var file in filteredFiles)
|
||||
{
|
||||
_mediaFileAttributeService.SetFilePermissions(path);
|
||||
_otherExtraFileService.Upsert(extraFile);
|
||||
try
|
||||
{
|
||||
// Filter out duplicate NFO files
|
||||
if (file.EndsWith(".nfo", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
if (hasNfo)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hasNfo = true;
|
||||
}
|
||||
|
||||
// Filename match
|
||||
if (Path.GetFileNameWithoutExtension(file).StartsWith(sourceFileName, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
matchingFiles.Add(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Movie match
|
||||
var fileMovieInfo = Parser.Parser.ParseMoviePath(file) ?? new ParsedMovieInfo();
|
||||
|
||||
if (fileMovieInfo.MovieTitle == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileMovieInfo.MovieTitle == localMovie.FileMovieInfo.MovieTitle &&
|
||||
fileMovieInfo.Year.Equals(localMovie.FileMovieInfo.Year))
|
||||
{
|
||||
matchingFiles.Add(file);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Failed to import extra file: {0}", file);
|
||||
}
|
||||
}
|
||||
|
||||
return extraFile;
|
||||
foreach (string file in matchingFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var extraFile = ImportFile(localMovie.Movie, movieFile, file, isReadOnly, Path.GetExtension(file), null);
|
||||
_mediaFileAttributeService.SetFilePermissions(file);
|
||||
_otherExtraFileService.Upsert(extraFile);
|
||||
importedFiles.Add(extraFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Failed to import extra file: {0}", file);
|
||||
}
|
||||
}
|
||||
|
||||
return importedFiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -9,13 +10,17 @@ using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.MovieImport;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Subtitles
|
||||
{
|
||||
public class SubtitleService : ExtraFileManager<SubtitleFile>
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDetectSample _detectSample;
|
||||
private readonly ISubtitleFileService _subtitleFileService;
|
||||
private readonly IMediaFileAttributeService _mediaFileAttributeService;
|
||||
private readonly Logger _logger;
|
||||
@@ -23,11 +28,14 @@ namespace NzbDrone.Core.Extras.Subtitles
|
||||
public SubtitleService(IConfigService configService,
|
||||
IDiskProvider diskProvider,
|
||||
IDiskTransferService diskTransferService,
|
||||
IDetectSample detectSample,
|
||||
ISubtitleFileService subtitleFileService,
|
||||
IMediaFileAttributeService mediaFileAttributeService,
|
||||
Logger logger)
|
||||
: base(configService, diskProvider, diskTransferService, logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_detectSample = detectSample;
|
||||
_subtitleFileService = subtitleFileService;
|
||||
_mediaFileAttributeService = mediaFileAttributeService;
|
||||
_logger = logger;
|
||||
@@ -71,11 +79,6 @@ namespace NzbDrone.Core.Extras.Subtitles
|
||||
var groupCount = group.Count();
|
||||
var copy = 1;
|
||||
|
||||
if (groupCount > 1)
|
||||
{
|
||||
_logger.Warn("Multiple subtitle files found with the same language and extension for {0}", Path.Combine(movie.Path, movieFile.RelativePath));
|
||||
}
|
||||
|
||||
foreach (var subtitleFile in group)
|
||||
{
|
||||
var suffix = GetSuffix(subtitleFile.Language, copy, groupCount > 1);
|
||||
@@ -91,22 +94,129 @@ namespace NzbDrone.Core.Extras.Subtitles
|
||||
return movedFiles;
|
||||
}
|
||||
|
||||
public override ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly)
|
||||
public override bool CanImportFile(LocalMovie localEpisode, MovieFile movieFile, string path, string extension, bool readOnly)
|
||||
{
|
||||
if (SubtitleFileExtensions.Extensions.Contains(Path.GetExtension(path)))
|
||||
return SubtitleFileExtensions.Extensions.Contains(extension.ToLowerInvariant());
|
||||
}
|
||||
|
||||
public override IEnumerable<ExtraFile> ImportFiles(LocalMovie localMovie, MovieFile movieFile, List<string> files, bool isReadOnly)
|
||||
{
|
||||
var importedFiles = new List<SubtitleFile>();
|
||||
|
||||
var filteredFiles = files.Where(f => CanImportFile(localMovie, movieFile, f, Path.GetExtension(f), isReadOnly)).ToList();
|
||||
|
||||
var sourcePath = localMovie.Path;
|
||||
var sourceFolder = _diskProvider.GetParentFolder(sourcePath);
|
||||
var sourceFileName = Path.GetFileNameWithoutExtension(sourcePath);
|
||||
|
||||
var matchingFiles = new List<string>();
|
||||
|
||||
foreach (var file in filteredFiles)
|
||||
{
|
||||
var language = LanguageParser.ParseSubtitleLanguage(path);
|
||||
var suffix = GetSuffix(language, 1, false);
|
||||
var subtitleFile = ImportFile(movie, movieFile, path, readOnly, extension, suffix);
|
||||
subtitleFile.Language = language;
|
||||
try
|
||||
{
|
||||
// Filename match
|
||||
if (Path.GetFileNameWithoutExtension(file).StartsWith(sourceFileName, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
matchingFiles.Add(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
_mediaFileAttributeService.SetFilePermissions(path);
|
||||
_subtitleFileService.Upsert(subtitleFile);
|
||||
// Movie match
|
||||
var fileMovieInfo = Parser.Parser.ParseMoviePath(file) ?? new ParsedMovieInfo();
|
||||
|
||||
return subtitleFile;
|
||||
if (fileMovieInfo.MovieTitle == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileMovieInfo.MovieTitle == localMovie.FileMovieInfo.MovieTitle &&
|
||||
fileMovieInfo.Year.Equals(localMovie.FileMovieInfo.Year))
|
||||
{
|
||||
matchingFiles.Add(file);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Failed to import subtitle file: {0}", file);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
// Use any sub if only episode in folder
|
||||
if (matchingFiles.Count == 0 && filteredFiles.Count > 0)
|
||||
{
|
||||
var videoFiles = _diskProvider.GetFiles(sourceFolder, SearchOption.AllDirectories)
|
||||
.Where(file => MediaFileExtensions.Extensions.Contains(Path.GetExtension(file)))
|
||||
.ToList();
|
||||
|
||||
if (videoFiles.Count() > 2)
|
||||
{
|
||||
return importedFiles;
|
||||
}
|
||||
|
||||
// Filter out samples
|
||||
videoFiles = videoFiles.Where(file =>
|
||||
{
|
||||
var sample = _detectSample.IsSample(localMovie.Movie.MovieMetadata, file);
|
||||
|
||||
if (sample == DetectSampleResult.Sample)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}).ToList();
|
||||
|
||||
if (videoFiles.Count == 1)
|
||||
{
|
||||
matchingFiles.AddRange(filteredFiles);
|
||||
|
||||
_logger.Warn("Imported any available subtitle file for movie: {0}", localMovie);
|
||||
}
|
||||
}
|
||||
|
||||
var subtitleFiles = new List<Tuple<string, Language, string>>();
|
||||
|
||||
foreach (string file in matchingFiles)
|
||||
{
|
||||
var language = LanguageParser.ParseSubtitleLanguage(file);
|
||||
var extension = Path.GetExtension(file);
|
||||
subtitleFiles.Add(new Tuple<string, Language, string>(file, language, extension));
|
||||
}
|
||||
|
||||
var groupedSubtitleFiles = subtitleFiles.GroupBy(s => s.Item2 + s.Item3).ToList();
|
||||
|
||||
foreach (var group in groupedSubtitleFiles)
|
||||
{
|
||||
var groupCount = group.Count();
|
||||
var copy = 1;
|
||||
|
||||
foreach (var file in group)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = file.Item1;
|
||||
var language = file.Item2;
|
||||
var extension = file.Item3;
|
||||
var suffix = GetSuffix(language, copy, groupCount > 1);
|
||||
var subtitleFile = ImportFile(localMovie.Movie, movieFile, path, isReadOnly, extension, suffix);
|
||||
subtitleFile.Language = language;
|
||||
|
||||
_mediaFileAttributeService.SetFilePermissions(path);
|
||||
_subtitleFileService.Upsert(subtitleFile);
|
||||
|
||||
importedFiles.Add(subtitleFile);
|
||||
|
||||
copy++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Failed to import subtitle file: {0}", file.Item1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return importedFiles;
|
||||
}
|
||||
|
||||
private string GetSuffix(Language language, int copy, bool multipleCopies = false)
|
||||
|
||||
Reference in New Issue
Block a user