beginning remote subtitle downloading

This commit is contained in:
Luke Pulverenti
2014-05-06 22:28:19 -04:00
parent e1dd361c7b
commit 0d025f7fb6
49 changed files with 1035 additions and 299 deletions

View File

@@ -108,6 +108,7 @@
<Compile Include="MediaInfo\FFProbeHelpers.cs" />
<Compile Include="MediaInfo\FFProbeProvider.cs" />
<Compile Include="MediaInfo\FFProbeVideoInfo.cs" />
<Compile Include="MediaInfo\SubtitleDownloader.cs" />
<Compile Include="Movies\MovieDbTrailerProvider.cs" />
<Compile Include="Movies\MovieExternalIds.cs" />
<Compile Include="Movies\TrailerMetadataService.cs" />
@@ -187,6 +188,7 @@
<Compile Include="Studios\StudiosImageProvider.cs" />
<Compile Include="Studios\StudioMetadataService.cs" />
<Compile Include="Subtitles\OpenSubtitleDownloader.cs" />
<Compile Include="Subtitles\SubtitleManager.cs" />
<Compile Include="TV\EpisodeLocalImageProvider.cs" />
<Compile Include="TV\EpisodeMetadataService.cs" />
<Compile Include="TV\EpisodeXmlProvider.cs" />

View File

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

View File

@@ -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;

View 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;
}
}
}

View File

@@ -1,8 +1,10 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Providers;
using OpenSubtitlesHandler;
using System;
using System.Collections.Generic;
@@ -20,9 +22,9 @@ namespace MediaBrowser.Providers.Subtitles
private readonly IHttpClient _httpClient;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
public OpenSubtitleDownloader(ILogger logger, IHttpClient httpClient)
public OpenSubtitleDownloader(ILogManager logManager, IHttpClient httpClient)
{
_logger = logger;
_logger = logManager.GetLogger(GetType().Name);
_httpClient = httpClient;
}
@@ -36,39 +38,71 @@ namespace MediaBrowser.Providers.Subtitles
get { return new[] { SubtitleMediaType.Episode, SubtitleMediaType.Movie }; }
}
public Task<SubtitleResponse> GetSubtitles(SubtitleRequest request, CancellationToken cancellationToken)
public Task<SubtitleResponse> GetSubtitles(string id, CancellationToken cancellationToken)
{
return GetSubtitlesInternal(request, cancellationToken);
return GetSubtitlesInternal(id, cancellationToken);
}
private async Task<SubtitleResponse> GetSubtitlesInternal(SubtitleRequest request,
private async Task<SubtitleResponse> GetSubtitlesInternal(string id,
CancellationToken cancellationToken)
{
var response = new SubtitleResponse();
if (string.IsNullOrWhiteSpace(id))
{
throw new ArgumentNullException("id");
}
var idParts = id.Split(new[] { '-' }, 3);
var format = idParts[0];
var language = idParts[1];
var ossId = idParts[2];
var downloadsList = new[] { int.Parse(ossId, _usCulture) };
var resultDownLoad = OpenSubtitles.DownloadSubtitles(downloadsList);
if (!(resultDownLoad is MethodResponseSubtitleDownload))
{
throw new ApplicationException("Invalid response type");
}
var res = ((MethodResponseSubtitleDownload)resultDownLoad).Results.First();
var data = Convert.FromBase64String(res.Data);
return new SubtitleResponse
{
Format = format,
Language = language,
Stream = new MemoryStream(Utilities.Decompress(new MemoryStream(data)))
};
}
public async Task<IEnumerable<RemoteSubtitleInfo>> SearchSubtitles(SubtitleSearchRequest request, CancellationToken cancellationToken)
{
var imdbIdText = request.GetProviderId(MetadataProviders.Imdb);
long imdbId;
if (string.IsNullOrWhiteSpace(imdbIdText) ||
long.TryParse(imdbIdText.TrimStart('t'), NumberStyles.Any, _usCulture, out imdbId))
!long.TryParse(imdbIdText.TrimStart('t'), NumberStyles.Any, _usCulture, out imdbId))
{
return response;
_logger.Debug("Imdb id missing");
return new List<RemoteSubtitleInfo>();
}
switch (request.ContentType)
{
case SubtitleMediaType.Episode:
if (!request.IndexNumber.HasValue || !request.ParentIndexNumber.HasValue || string.IsNullOrEmpty(request.SeriesName))
{
_logger.Debug("Information Missing");
return response;
_logger.Debug("Episode information missing");
return new List<RemoteSubtitleInfo>();
}
break;
case SubtitleMediaType.Movie:
if (string.IsNullOrEmpty(request.Name))
{
_logger.Debug("Information Missing");
return response;
_logger.Debug("Movie name missing");
return new List<RemoteSubtitleInfo>();
}
break;
}
@@ -76,16 +110,18 @@ namespace MediaBrowser.Providers.Subtitles
if (string.IsNullOrEmpty(request.MediaPath))
{
_logger.Debug("Path Missing");
return response;
return new List<RemoteSubtitleInfo>();
}
Utilities.HttpClient = _httpClient;
OpenSubtitles.SetUserAgent("OS Test User Agent");
var loginResponse = OpenSubtitles.LogIn("", "", "en");
var loginResponse = await OpenSubtitles.LogInAsync("", "", "en", cancellationToken).ConfigureAwait(false);
if (!(loginResponse is MethodResponseLogIn))
{
_logger.Debug("Login error");
return response;
return new List<RemoteSubtitleInfo>();
}
var subLanguageId = request.Language;
@@ -105,54 +141,42 @@ namespace MediaBrowser.Providers.Subtitles
var result = OpenSubtitles.SearchSubtitles(parms.ToArray());
if (!(result is MethodResponseSubtitleSearch))
{
_logger.Debug("invalid response type");
return null;
_logger.Debug("Invalid response type");
return new List<RemoteSubtitleInfo>();
}
Predicate<SubtitleSearchResult> mediaFilter =
x =>
request.ContentType == SubtitleMediaType.Episode
? int.Parse(x.SeriesSeason) == request.ParentIndexNumber && int.Parse(x.SeriesEpisode) == request.IndexNumber
: long.Parse(x.IDMovieImdb) == imdbId;
? int.Parse(x.SeriesSeason, _usCulture) == request.ParentIndexNumber && int.Parse(x.SeriesEpisode, _usCulture) == request.IndexNumber
: long.Parse(x.IDMovieImdb, _usCulture) == imdbId;
var results = ((MethodResponseSubtitleSearch)result).Results;
var bestResult = results.Where(x => x.SubBad == "0" && mediaFilter(x))
// Avoid implicitly captured closure
var hasCopy = hash;
return results.Where(x => x.SubBad == "0" && mediaFilter(x))
.OrderBy(x => x.MovieHash == hash)
.ThenBy(x => Math.Abs(long.Parse(x.MovieByteSize) - movieByteSize))
.ThenByDescending(x => int.Parse(x.SubDownloadsCnt))
.ThenByDescending(x => double.Parse(x.SubRating))
.ToList();
.ThenBy(x => Math.Abs(long.Parse(x.MovieByteSize, _usCulture) - movieByteSize))
.ThenByDescending(x => int.Parse(x.SubDownloadsCnt, _usCulture))
.ThenByDescending(x => double.Parse(x.SubRating, _usCulture))
.Select(i => new RemoteSubtitleInfo
{
Author = i.UserNickName,
Comment = i.SubAuthorComment,
CommunityRating = float.Parse(i.SubRating, _usCulture),
DownloadCount = int.Parse(i.SubDownloadsCnt, _usCulture),
Format = i.SubFormat,
ProviderName = Name,
Language = i.SubLanguageID,
if (!bestResult.Any())
{
_logger.Debug("No Subtitles");
return response;
}
Id = i.SubFormat + "-" + i.SubLanguageID + "-" + i.IDSubtitle,
_logger.Debug("Found " + bestResult.Count + " subtitles.");
var subtitle = bestResult.First();
var downloadsList = new[] { int.Parse(subtitle.IDSubtitleFile) };
var resultDownLoad = OpenSubtitles.DownloadSubtitles(downloadsList);
if (!(resultDownLoad is MethodResponseSubtitleDownload))
{
_logger.Debug("invalid response type");
return response;
}
if (!((MethodResponseSubtitleDownload)resultDownLoad).Results.Any())
{
_logger.Debug("No Subtitle Downloads");
return response;
}
var res = ((MethodResponseSubtitleDownload)resultDownLoad).Results.First();
var data = Convert.FromBase64String(res.Data);
response.HasContent = true;
response.Format = subtitle.SubFormat.ToUpper();
response.Stream = new MemoryStream(Utilities.Decompress(new MemoryStream(data)));
return response;
Name = i.SubFileName,
DateCreated = DateTime.Parse(i.SubAddDate, _usCulture),
IsHashMatch = i.MovieHash == hasCopy
});
}
}
}

View File

@@ -0,0 +1,141 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Providers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Providers.Subtitles
{
public class SubtitleManager : ISubtitleManager
{
private ISubtitleProvider[] _subtitleProviders;
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly ILibraryMonitor _monitor;
public SubtitleManager(ILogger logger, IFileSystem fileSystem, ILibraryMonitor monitor)
{
_logger = logger;
_fileSystem = fileSystem;
_monitor = monitor;
}
public void AddParts(IEnumerable<ISubtitleProvider> subtitleProviders)
{
_subtitleProviders = subtitleProviders.ToArray();
}
public async Task<IEnumerable<RemoteSubtitleInfo>> SearchSubtitles(SubtitleSearchRequest request, CancellationToken cancellationToken)
{
var providers = _subtitleProviders
.Where(i => i.SupportedMediaTypes.Contains(request.ContentType))
.ToList();
var tasks = providers.Select(async i =>
{
try
{
return await i.SearchSubtitles(request, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.ErrorException("Error downloading subtitles from {0}", ex, i.Name);
return new List<RemoteSubtitleInfo>();
}
});
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
return results.SelectMany(i => i);
}
public async Task DownloadSubtitles(Video video,
string subtitleId,
string providerName,
CancellationToken cancellationToken)
{
var provider = _subtitleProviders.First(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase));
var response = await provider.GetSubtitles(subtitleId, cancellationToken).ConfigureAwait(false);
using (var stream = response.Stream)
{
var savePath = Path.Combine(Path.GetDirectoryName(video.Path),
Path.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLower() + "." + response.Format.ToLower());
_logger.Info("Saving subtitles to {0}", savePath);
_monitor.ReportFileSystemChangeBeginning(savePath);
try
{
using (var fs = _fileSystem.GetFileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await stream.CopyToAsync(fs).ConfigureAwait(false);
}
}
finally
{
_monitor.ReportFileSystemChangeComplete(savePath, false);
}
}
}
public Task<IEnumerable<RemoteSubtitleInfo>> SearchSubtitles(Video video, string language, CancellationToken cancellationToken)
{
if (video.LocationType != LocationType.FileSystem ||
video.VideoType != VideoType.VideoFile)
{
return Task.FromResult<IEnumerable<RemoteSubtitleInfo>>(new List<RemoteSubtitleInfo>());
}
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 Task.FromResult<IEnumerable<RemoteSubtitleInfo>>(new List<RemoteSubtitleInfo>());
}
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;
}
return SearchSubtitles(request, cancellationToken);
}
}
}