mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-17 13:10:28 +01:00
beginning remote subtitle downloading
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
@@ -10,15 +11,16 @@ using MediaBrowser.Controller.Localization;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Providers.MediaInfo
|
||||
{
|
||||
@@ -45,6 +47,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
private readonly IJsonSerializer _json;
|
||||
private readonly IEncodingManager _encodingManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ISubtitleManager _subtitleManager;
|
||||
|
||||
public string Name
|
||||
{
|
||||
@@ -96,7 +100,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
return FetchAudioInfo(item, cancellationToken);
|
||||
}
|
||||
|
||||
public FFProbeProvider(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem)
|
||||
public FFProbeProvider(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem, IServerConfigurationManager config, ISubtitleManager subtitleManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_isoManager = isoManager;
|
||||
@@ -108,6 +112,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
_json = json;
|
||||
_encodingManager = encodingManager;
|
||||
_fileSystem = fileSystem;
|
||||
_config = config;
|
||||
_subtitleManager = subtitleManager;
|
||||
}
|
||||
|
||||
private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.None);
|
||||
@@ -134,7 +140,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
return _cachedTask;
|
||||
}
|
||||
|
||||
var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager, _fileSystem);
|
||||
var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager, _fileSystem, _config, _subtitleManager);
|
||||
|
||||
return prober.ProbeVideo(item, directoryService, cancellationToken);
|
||||
}
|
||||
@@ -165,7 +171,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
|
||||
if (video != null && !video.IsPlaceHolder)
|
||||
{
|
||||
var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager, _fileSystem);
|
||||
var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager, _fileSystem, _config, _subtitleManager);
|
||||
|
||||
return !video.SubtitleFiles.SequenceEqual(prober.GetSubtitleFiles(video, directoryService).Select(i => i.FullName).OrderBy(i => i), StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Localization;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
@@ -35,10 +39,12 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
private readonly IJsonSerializer _json;
|
||||
private readonly IEncodingManager _encodingManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ISubtitleManager _subtitleManager;
|
||||
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
||||
public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem)
|
||||
public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem, IServerConfigurationManager config, ISubtitleManager subtitleManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_isoManager = isoManager;
|
||||
@@ -50,6 +56,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
_json = json;
|
||||
_encodingManager = encodingManager;
|
||||
_fileSystem = fileSystem;
|
||||
_config = config;
|
||||
_subtitleManager = subtitleManager;
|
||||
}
|
||||
|
||||
public async Task<ItemUpdateType> ProbeVideo<T>(T item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
||||
@@ -118,7 +126,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var idString = item.Id.ToString("N");
|
||||
var cachePath = Path.Combine(_appPaths.CachePath,
|
||||
var cachePath = Path.Combine(_appPaths.CachePath,
|
||||
"ffprobe-video",
|
||||
idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
|
||||
|
||||
@@ -200,7 +208,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
FetchBdInfo(video, chapters, mediaStreams, blurayInfo);
|
||||
}
|
||||
|
||||
AddExternalSubtitles(video, mediaStreams, directoryService);
|
||||
await AddExternalSubtitles(video, mediaStreams, directoryService, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
FetchWtvInfo(video, data);
|
||||
|
||||
@@ -247,7 +255,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
}
|
||||
}
|
||||
|
||||
info.StartPositionTicks = chapter.start/100;
|
||||
info.StartPositionTicks = chapter.start / 100;
|
||||
|
||||
return info;
|
||||
}
|
||||
@@ -450,11 +458,42 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
/// </summary>
|
||||
/// <param name="video">The video.</param>
|
||||
/// <param name="currentStreams">The current streams.</param>
|
||||
private void AddExternalSubtitles(Video video, List<MediaStream> currentStreams, IDirectoryService directoryService)
|
||||
private async Task AddExternalSubtitles(Video video, List<MediaStream> currentStreams, IDirectoryService directoryService, CancellationToken cancellationToken)
|
||||
{
|
||||
var externalSubtitleStreams = GetExternalSubtitleStreams(video, currentStreams.Count, directoryService).ToList();
|
||||
|
||||
if ((_config.Configuration.SubtitleOptions.DownloadEpisodeSubtitles &&
|
||||
video is Episode) ||
|
||||
(_config.Configuration.SubtitleOptions.DownloadMovieSubtitles &&
|
||||
video is Movie))
|
||||
{
|
||||
var downloadedLanguages = await new SubtitleDownloader(_logger,
|
||||
_subtitleManager)
|
||||
.DownloadSubtitles(video,
|
||||
currentStreams,
|
||||
externalSubtitleStreams,
|
||||
_config.Configuration.SubtitleOptions.RequireExternalSubtitles,
|
||||
_config.Configuration.SubtitleOptions.SubtitleDownloadLanguages,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Rescan
|
||||
if (downloadedLanguages.Count > 0)
|
||||
{
|
||||
externalSubtitleStreams = GetExternalSubtitleStreams(video, currentStreams.Count, directoryService).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
video.SubtitleFiles = externalSubtitleStreams.Select(i => i.Path).OrderBy(i => i).ToList();
|
||||
|
||||
currentStreams.AddRange(externalSubtitleStreams);
|
||||
}
|
||||
|
||||
private IEnumerable<MediaStream> GetExternalSubtitleStreams(Video video,
|
||||
int startIndex,
|
||||
IDirectoryService directoryService)
|
||||
{
|
||||
var files = GetSubtitleFiles(video, directoryService);
|
||||
|
||||
var startIndex = currentStreams.Count;
|
||||
var streams = new List<MediaStream>();
|
||||
|
||||
var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path);
|
||||
@@ -504,9 +543,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
}
|
||||
}
|
||||
|
||||
video.SubtitleFiles = streams.Select(i => i.Path).OrderBy(i => i).ToList();
|
||||
|
||||
currentStreams.AddRange(streams);
|
||||
return streams;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -627,7 +664,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
{
|
||||
var path = mount == null ? item.Path : mount.MountedPath;
|
||||
var dvd = new Dvd(path);
|
||||
|
||||
|
||||
var primaryTitle = dvd.Titles.OrderByDescending(GetRuntime).FirstOrDefault();
|
||||
|
||||
byte? titleNumber = null;
|
||||
|
||||
140
MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
Normal file
140
MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.MediaInfo
|
||||
{
|
||||
public class SubtitleDownloader
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ISubtitleManager _subtitleManager;
|
||||
|
||||
public SubtitleDownloader(ILogger logger, ISubtitleManager subtitleManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_subtitleManager = subtitleManager;
|
||||
}
|
||||
|
||||
public async Task<List<string>> DownloadSubtitles(Video video,
|
||||
List<MediaStream> internalSubtitleStreams,
|
||||
List<MediaStream> externalSubtitleStreams,
|
||||
bool forceExternal,
|
||||
IEnumerable<string> languages,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (video.LocationType != LocationType.FileSystem ||
|
||||
video.VideoType != VideoType.VideoFile)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
SubtitleMediaType mediaType;
|
||||
|
||||
if (video is Episode)
|
||||
{
|
||||
mediaType = SubtitleMediaType.Episode;
|
||||
}
|
||||
else if (video is Movie)
|
||||
{
|
||||
mediaType = SubtitleMediaType.Movie;
|
||||
}
|
||||
else
|
||||
{
|
||||
// These are the only supported types
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
var downloadedLanguages = new List<string>();
|
||||
|
||||
foreach (var lang in languages)
|
||||
{
|
||||
try
|
||||
{
|
||||
var downloaded = await DownloadSubtitles(video, internalSubtitleStreams, externalSubtitleStreams, forceExternal, lang, mediaType, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (downloaded)
|
||||
{
|
||||
downloadedLanguages.Add(lang);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error downloading subtitles", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return downloadedLanguages;
|
||||
}
|
||||
|
||||
private async Task<bool> DownloadSubtitles(Video video,
|
||||
IEnumerable<MediaStream> internalSubtitleStreams,
|
||||
IEnumerable<MediaStream> externalSubtitleStreams,
|
||||
bool forceExternal,
|
||||
string language,
|
||||
SubtitleMediaType mediaType,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// There's already subtitles for this language
|
||||
if (externalSubtitleStreams.Any(i => string.Equals(i.Language, language, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// There's an internal subtitle stream for this language
|
||||
if (!forceExternal && internalSubtitleStreams.Any(i => string.Equals(i.Language, language, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var request = new SubtitleSearchRequest
|
||||
{
|
||||
ContentType = mediaType,
|
||||
IndexNumber = video.IndexNumber,
|
||||
Language = language,
|
||||
MediaPath = video.Path,
|
||||
Name = video.Name,
|
||||
ParentIndexNumber = video.ParentIndexNumber,
|
||||
ProductionYear = video.ProductionYear,
|
||||
ProviderIds = video.ProviderIds
|
||||
};
|
||||
|
||||
var episode = video as Episode;
|
||||
|
||||
if (episode != null)
|
||||
{
|
||||
request.IndexNumberEnd = episode.IndexNumberEnd;
|
||||
request.SeriesName = episode.SeriesName;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var searchResults = await _subtitleManager.SearchSubtitles(request, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var result = searchResults.FirstOrDefault();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
await _subtitleManager.DownloadSubtitles(video, result.Id, result.ProviderName, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error downloading subtitles", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user