mirror of https://github.com/jellyfin/jellyfin.git
sync updates
This commit is contained in:
parent
eaf70589ae
commit
a025f4eefa
|
@ -73,6 +73,17 @@ namespace MediaBrowser.Api
|
||||||
return ResultFactory.GetOptimizedResultUsingCache(Request, cacheKey, lastDateModified, cacheDuration, factoryFn);
|
return ResultFactory.GetOptimizedResultUsingCache(Request, cacheKey, lastDateModified, cacheDuration, factoryFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Infers the server address from the url
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected string GetServerAddress()
|
||||||
|
{
|
||||||
|
var index = Request.AbsoluteUri.IndexOf(Request.PathInfo, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
return Request.AbsoluteUri.Substring(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
protected void AssertCanUpdateUser(IUserManager userManager, string userId)
|
protected void AssertCanUpdateUser(IUserManager userManager, string userId)
|
||||||
{
|
{
|
||||||
var auth = AuthorizationContext.GetAuthorizationInfo(Request);
|
var auth = AuthorizationContext.GetAuthorizationInfo(Request);
|
||||||
|
|
|
@ -699,7 +699,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
||||||
{
|
{
|
||||||
var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath);
|
var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.MediaSource.Protocol, CancellationToken.None).Result;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(charenc))
|
if (!string.IsNullOrEmpty(charenc))
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,6 +59,9 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
[ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
[ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||||
public string MediaSourceId { get; set; }
|
public string MediaSourceId { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "LiveStreamId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||||
|
public string LiveStreamId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveStreams/Open", "POST", Summary = "Opens a media source")]
|
[Route("/LiveStreams/Open", "POST", Summary = "Opens a media source")]
|
||||||
|
@ -142,7 +145,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
public async Task<object> Post(GetPostedPlaybackInfo request)
|
public async Task<object> Post(GetPostedPlaybackInfo request)
|
||||||
{
|
{
|
||||||
var info = await GetPlaybackInfo(request.Id, request.UserId, request.MediaSourceId).ConfigureAwait(false);
|
var info = await GetPlaybackInfo(request.Id, request.UserId, request.MediaSourceId, request.LiveStreamId).ConfigureAwait(false);
|
||||||
var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
|
var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
|
||||||
|
|
||||||
var profile = request.DeviceProfile;
|
var profile = request.DeviceProfile;
|
||||||
|
@ -164,12 +167,13 @@ namespace MediaBrowser.Api.Playback
|
||||||
return ToOptimizedResult(info);
|
return ToOptimizedResult(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string mediaSourceId = null)
|
private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string mediaSourceId = null, string liveStreamId = null)
|
||||||
{
|
{
|
||||||
var result = new PlaybackInfoResponse();
|
var result = new PlaybackInfoResponse();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(liveStreamId))
|
||||||
|
{
|
||||||
IEnumerable<MediaSourceInfo> mediaSources;
|
IEnumerable<MediaSourceInfo> mediaSources;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false);
|
mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
@ -188,6 +192,13 @@ namespace MediaBrowser.Api.Playback
|
||||||
.Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase))
|
.Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var mediaSource = await _mediaSourceManager.GetLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
result.MediaSources = new List<MediaSourceInfo> { mediaSource };
|
||||||
|
}
|
||||||
|
|
||||||
if (result.MediaSources.Count == 0)
|
if (result.MediaSources.Count == 0)
|
||||||
{
|
{
|
||||||
|
@ -236,6 +247,8 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
var streamBuilder = new StreamBuilder();
|
var streamBuilder = new StreamBuilder();
|
||||||
|
|
||||||
|
var baseUrl = GetServerAddress();
|
||||||
|
|
||||||
var options = new VideoOptions
|
var options = new VideoOptions
|
||||||
{
|
{
|
||||||
MediaSources = new List<MediaSourceInfo> { mediaSource },
|
MediaSources = new List<MediaSourceInfo> { mediaSource },
|
||||||
|
@ -275,7 +288,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
if (streamInfo != null)
|
if (streamInfo != null)
|
||||||
{
|
{
|
||||||
SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token);
|
SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, baseUrl, auth.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +306,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
if (streamInfo != null)
|
if (streamInfo != null)
|
||||||
{
|
{
|
||||||
SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token);
|
SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, baseUrl, auth.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,21 +320,22 @@ namespace MediaBrowser.Api.Playback
|
||||||
if (streamInfo != null && streamInfo.PlayMethod == PlayMethod.Transcode)
|
if (streamInfo != null && streamInfo.PlayMethod == PlayMethod.Transcode)
|
||||||
{
|
{
|
||||||
streamInfo.StartPositionTicks = startTimeTicks;
|
streamInfo.StartPositionTicks = startTimeTicks;
|
||||||
mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).TrimStart('-');
|
mediaSource.TranscodingUrl = streamInfo.ToUrl(baseUrl, auth.Token);
|
||||||
mediaSource.TranscodingContainer = streamInfo.Container;
|
mediaSource.TranscodingContainer = streamInfo.Container;
|
||||||
mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol;
|
mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streamInfo != null)
|
if (streamInfo != null)
|
||||||
{
|
{
|
||||||
SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token);
|
SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, baseUrl, auth.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetDeviceSpecificSubtitleInfo(StreamInfo info, MediaSourceInfo mediaSource, string accessToken)
|
private void SetDeviceSpecificSubtitleInfo(StreamInfo info, MediaSourceInfo mediaSource, string baseUrl, string accessToken)
|
||||||
{
|
{
|
||||||
var profiles = info.GetSubtitleProfiles(false, "-", accessToken);
|
var profiles = info.GetSubtitleProfiles(false, baseUrl, accessToken);
|
||||||
|
mediaSource.DefaultSubtitleStreamIndex = info.SubtitleStreamIndex;
|
||||||
|
|
||||||
foreach (var profile in profiles)
|
foreach (var profile in profiles)
|
||||||
{
|
{
|
||||||
|
@ -333,7 +347,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
if (profile.DeliveryMethod == SubtitleDeliveryMethod.External)
|
if (profile.DeliveryMethod == SubtitleDeliveryMethod.External)
|
||||||
{
|
{
|
||||||
stream.DeliveryUrl = profile.Url.TrimStart('-');
|
stream.DeliveryUrl = profile.Url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
var options = GetOptions();
|
var options = GetOptions();
|
||||||
|
|
||||||
if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdSeconds))
|
if (/*options.EnableThrottling &&*/ IsThrottleAllowed(_job, options.ThrottleThresholdSeconds))
|
||||||
{
|
{
|
||||||
PauseTranscoding();
|
PauseTranscoding();
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,6 +304,14 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var user = _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
|
if (!request.IsPlayed.HasValue)
|
||||||
|
{
|
||||||
|
if (user.Configuration.HidePlayedInLatest)
|
||||||
|
{
|
||||||
|
request.IsPlayed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var list = _userViewManager.GetLatestItems(new LatestItemsQuery
|
var list = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||||
{
|
{
|
||||||
GroupItems = request.GroupItems,
|
GroupItems = request.GroupItems,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -47,8 +48,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// Gets the subtitle language encoding parameter.
|
/// Gets the subtitle language encoding parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
|
/// <param name="protocol">The protocol.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
string GetSubtitleFileCharacterSet(string path);
|
Task<string> GetSubtitleFileCharacterSet(string path, MediaProtocol protocol, CancellationToken cancellationToken);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages)
|
streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var full = streams.Where(s => !s.IsForced);
|
|
||||||
|
|
||||||
MediaStream stream = null;
|
MediaStream stream = null;
|
||||||
|
|
||||||
if (mode == SubtitlePlaybackMode.None)
|
if (mode == SubtitlePlaybackMode.None)
|
||||||
|
@ -55,13 +53,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
// if the audio language is not understood by the user, load their preferred subs, if there are any
|
// if the audio language is not understood by the user, load their preferred subs, if there are any
|
||||||
if (!ContainsOrdinal(preferredLanguages, audioTrackLanguage))
|
if (!ContainsOrdinal(preferredLanguages, audioTrackLanguage))
|
||||||
{
|
{
|
||||||
stream = full.FirstOrDefault(s => ContainsOrdinal(preferredLanguages, s.Language));
|
stream = streams.Where(s => !s.IsForced).FirstOrDefault(s => ContainsOrdinal(preferredLanguages, s.Language));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mode == SubtitlePlaybackMode.Always)
|
else if (mode == SubtitlePlaybackMode.Always)
|
||||||
{
|
{
|
||||||
// always load the most suitable full subtitles
|
// always load the most suitable full subtitles
|
||||||
stream = full.FirstOrDefault();
|
stream = streams.FirstOrDefault(s => !s.IsForced);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load forced subs if we have found no suitable full subtitles
|
// load forced subs if we have found no suitable full subtitles
|
||||||
|
@ -97,6 +95,77 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
.ThenBy(i => i.Index);
|
.ThenBy(i => i.Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetSubtitleStreamScores(List<MediaStream> streams,
|
||||||
|
List<string> preferredLanguages,
|
||||||
|
SubtitlePlaybackMode mode,
|
||||||
|
string audioTrackLanguage)
|
||||||
|
{
|
||||||
|
if (mode == SubtitlePlaybackMode.None)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var filteredStreams = new List<MediaStream>();
|
||||||
|
|
||||||
|
if (mode == SubtitlePlaybackMode.Default)
|
||||||
|
{
|
||||||
|
// if the audio language is not understood by the user, load their preferred subs, if there are any
|
||||||
|
if (!ContainsOrdinal(preferredLanguages, audioTrackLanguage))
|
||||||
|
{
|
||||||
|
filteredStreams = streams.Where(s => !s.IsForced && ContainsOrdinal(preferredLanguages, s.Language))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mode == SubtitlePlaybackMode.Always)
|
||||||
|
{
|
||||||
|
// always load the most suitable full subtitles
|
||||||
|
filteredStreams = streams.Where(s => !s.IsForced)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// load forced subs if we have found no suitable full subtitles
|
||||||
|
if (filteredStreams.Count == 0)
|
||||||
|
{
|
||||||
|
filteredStreams = streams
|
||||||
|
.Where(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var stream in filteredStreams)
|
||||||
|
{
|
||||||
|
stream.Score = GetSubtitleScore(stream, preferredLanguages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetSubtitleScore(MediaStream stream, List<string> languagePreferences)
|
||||||
|
{
|
||||||
|
var values = new List<int>();
|
||||||
|
|
||||||
|
var index = languagePreferences.FindIndex(l => string.Equals(stream.Language, l, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
values.Add(index == -1 ? 0 : 100 - index);
|
||||||
|
|
||||||
|
values.Add(stream.IsDefault ? 1 : 0);
|
||||||
|
values.Add(stream.SupportsExternalStream ? 1 : 0);
|
||||||
|
values.Add(stream.IsTextSubtitleStream ? 1 : 0);
|
||||||
|
values.Add(stream.IsExternal ? 1 : 0);
|
||||||
|
|
||||||
|
values.Reverse();
|
||||||
|
var scale = 1;
|
||||||
|
var score = 0;
|
||||||
|
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
score += scale * (value + 1);
|
||||||
|
scale *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
private static int GetBooleanOrderBy(bool value)
|
private static int GetBooleanOrderBy(bool value)
|
||||||
{
|
{
|
||||||
return value ? 0 : 1;
|
return value ? 0 : 1;
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
{
|
{
|
||||||
if (streamInfo == null)
|
if (streamInfo == null)
|
||||||
{
|
{
|
||||||
var sources = _user == null ? video.GetMediaSources(true).ToList() : _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
|
var sources = _user == null ? _mediaSourceManager.GetStaticMediaSources(video, true).ToList() : _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
|
||||||
|
|
||||||
streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions
|
streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions
|
||||||
{
|
{
|
||||||
|
@ -351,7 +351,7 @@ namespace MediaBrowser.Dlna.Didl
|
||||||
|
|
||||||
if (streamInfo == null)
|
if (streamInfo == null)
|
||||||
{
|
{
|
||||||
var sources = _user == null ? audio.GetMediaSources(true).ToList() : _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
|
var sources = _user == null ? _mediaSourceManager.GetStaticMediaSources(audio, true).ToList() : _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
|
||||||
|
|
||||||
streamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
|
streamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
|
||||||
{
|
{
|
||||||
|
|
|
@ -470,7 +470,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
var hasMediaSources = item as IHasMediaSources;
|
var hasMediaSources = item as IHasMediaSources;
|
||||||
var mediaSources = hasMediaSources != null
|
var mediaSources = hasMediaSources != null
|
||||||
? (user == null ? hasMediaSources.GetMediaSources(true) : _mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList()
|
? (user == null ? _mediaSourceManager.GetStaticMediaSources(hasMediaSources, true) : _mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList()
|
||||||
: new List<MediaSourceInfo>();
|
: new List<MediaSourceInfo>();
|
||||||
|
|
||||||
var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
|
var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
|
||||||
|
|
|
@ -951,7 +951,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
||||||
{
|
{
|
||||||
var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath);
|
var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.MediaSource.Protocol, CancellationToken.None).Result;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(charenc))
|
if (!string.IsNullOrEmpty(charenc))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
@ -29,8 +30,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IJsonSerializer _json;
|
private readonly IJsonSerializer _json;
|
||||||
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
|
|
||||||
public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IJsonSerializer json)
|
public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IJsonSerializer json, IHttpClient httpClient, IMediaSourceManager mediaSourceManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -38,6 +41,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_json = json;
|
_json = json;
|
||||||
|
_httpClient = httpClient;
|
||||||
|
_mediaSourceManager = mediaSourceManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SubtitleCachePath
|
private string SubtitleCachePath
|
||||||
|
@ -127,9 +132,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
int subtitleStreamIndex,
|
int subtitleStreamIndex,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var item = (Video)_libraryManager.GetItemById(new Guid(itemId));
|
var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(itemId, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var mediaSource = item.GetMediaSources(false)
|
var mediaSource = mediaSources
|
||||||
.First(i => string.Equals(i.Id, mediaSourceId));
|
.First(i => string.Equals(i.Id, mediaSourceId));
|
||||||
|
|
||||||
var subtitleStream = mediaSource.MediaStreams
|
var subtitleStream = mediaSource.MediaStreams
|
||||||
|
@ -149,20 +154,20 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
|
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var stream = await GetSubtitleStream(fileInfo.Item1, fileInfo.Item3).ConfigureAwait(false);
|
var stream = await GetSubtitleStream(fileInfo.Item1, fileInfo.Item2, fileInfo.Item4, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return new Tuple<Stream, string>(stream, fileInfo.Item2);
|
return new Tuple<Stream, string>(stream, fileInfo.Item3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Stream> GetSubtitleStream(string path, bool requiresCharset)
|
private async Task<Stream> GetSubtitleStream(string path, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (requiresCharset)
|
if (requiresCharset)
|
||||||
{
|
{
|
||||||
var charset = GetSubtitleFileCharacterSet(path);
|
var charset = await GetSubtitleFileCharacterSet(path, protocol, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(charset))
|
if (!string.IsNullOrEmpty(charset))
|
||||||
{
|
{
|
||||||
using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
using (var fs = await GetStream(path, protocol, cancellationToken).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
using (var reader = new StreamReader(fs, GetEncoding(charset)))
|
using (var reader = new StreamReader(fs, GetEncoding(charset)))
|
||||||
{
|
{
|
||||||
|
@ -196,7 +201,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Tuple<string, string, bool>> GetReadableFile(string mediaPath,
|
private async Task<Tuple<string, MediaProtocol, string, bool>> GetReadableFile(string mediaPath,
|
||||||
string[] inputFiles,
|
string[] inputFiles,
|
||||||
MediaProtocol protocol,
|
MediaProtocol protocol,
|
||||||
MediaStream subtitleStream,
|
MediaStream subtitleStream,
|
||||||
|
@ -228,12 +233,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract
|
// Extract
|
||||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + outputFormat);
|
var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, "." + outputFormat);
|
||||||
|
|
||||||
await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, outputCodec, outputPath, cancellationToken)
|
await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, outputCodec, outputPath, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return new Tuple<string, string, bool>(outputPath, outputFormat, false);
|
return new Tuple<string, MediaProtocol, string, bool>(outputPath, MediaProtocol.File, outputFormat, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec)
|
var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec)
|
||||||
|
@ -242,14 +247,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
if (GetReader(currentFormat, false) == null)
|
if (GetReader(currentFormat, false) == null)
|
||||||
{
|
{
|
||||||
// Convert
|
// Convert
|
||||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".srt");
|
var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, ".srt");
|
||||||
|
|
||||||
await ConvertTextSubtitleToSrt(subtitleStream.Path, outputPath, cancellationToken).ConfigureAwait(false);
|
await ConvertTextSubtitleToSrt(subtitleStream.Path, protocol, outputPath, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return new Tuple<string, string, bool>(outputPath, "srt", true);
|
return new Tuple<string, MediaProtocol, string, bool>(outputPath, MediaProtocol.File, "srt", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tuple<string, string, bool>(subtitleStream.Path, currentFormat, true);
|
return new Tuple<string, MediaProtocol, string, bool>(subtitleStream.Path, protocol, currentFormat, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<SubtitleTrackInfo> GetTrackInfo(Stream stream,
|
private async Task<SubtitleTrackInfo> GetTrackInfo(Stream stream,
|
||||||
|
@ -336,10 +341,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
/// Converts the text subtitle to SRT.
|
/// Converts the text subtitle to SRT.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputPath">The input path.</param>
|
/// <param name="inputPath">The input path.</param>
|
||||||
|
/// <param name="inputProtocol">The input protocol.</param>
|
||||||
/// <param name="outputPath">The output path.</param>
|
/// <param name="outputPath">The output path.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public async Task ConvertTextSubtitleToSrt(string inputPath, string outputPath, CancellationToken cancellationToken)
|
private async Task ConvertTextSubtitleToSrt(string inputPath, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var semaphore = GetLock(outputPath);
|
var semaphore = GetLock(outputPath);
|
||||||
|
|
||||||
|
@ -349,7 +355,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
{
|
{
|
||||||
if (!File.Exists(outputPath))
|
if (!File.Exists(outputPath))
|
||||||
{
|
{
|
||||||
await ConvertTextSubtitleToSrtInternal(inputPath, outputPath).ConfigureAwait(false);
|
await ConvertTextSubtitleToSrtInternal(inputPath, inputProtocol, outputPath, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@ -362,13 +368,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
/// Converts the text subtitle to SRT internal.
|
/// Converts the text subtitle to SRT internal.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputPath">The input path.</param>
|
/// <param name="inputPath">The input path.</param>
|
||||||
|
/// <param name="inputProtocol">The input protocol.</param>
|
||||||
/// <param name="outputPath">The output path.</param>
|
/// <param name="outputPath">The output path.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException">inputPath
|
/// <exception cref="System.ArgumentNullException">
|
||||||
|
/// inputPath
|
||||||
/// or
|
/// or
|
||||||
/// outputPath</exception>
|
/// outputPath
|
||||||
|
/// </exception>
|
||||||
/// <exception cref="System.ApplicationException"></exception>
|
/// <exception cref="System.ApplicationException"></exception>
|
||||||
private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string outputPath)
|
private async Task ConvertTextSubtitleToSrtInternal(string inputPath, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(inputPath))
|
if (string.IsNullOrEmpty(inputPath))
|
||||||
{
|
{
|
||||||
|
@ -382,7 +392,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||||
|
|
||||||
var encodingParam = GetSubtitleFileCharacterSet(inputPath);
|
var encodingParam = await GetSubtitleFileCharacterSet(inputPath, inputProtocol, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(encodingParam))
|
if (!string.IsNullOrEmpty(encodingParam))
|
||||||
{
|
{
|
||||||
|
@ -688,7 +698,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetSubtitleCachePath(string mediaPath, int subtitleStreamIndex, string outputSubtitleExtension)
|
private string GetSubtitleCachePath(string mediaPath, MediaProtocol protocol, int subtitleStreamIndex, string outputSubtitleExtension)
|
||||||
|
{
|
||||||
|
if (protocol == MediaProtocol.File)
|
||||||
{
|
{
|
||||||
var ticksParam = string.Empty;
|
var ticksParam = string.Empty;
|
||||||
|
|
||||||
|
@ -700,20 +712,27 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
return Path.Combine(SubtitleCachePath, prefix, filename);
|
return Path.Combine(SubtitleCachePath, prefix, filename);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var filename = (mediaPath + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5() + outputSubtitleExtension;
|
||||||
|
|
||||||
/// <summary>
|
var prefix = filename.Substring(0, 1);
|
||||||
/// Gets the subtitle language encoding param.
|
|
||||||
/// </summary>
|
return Path.Combine(SubtitleCachePath, prefix, filename);
|
||||||
/// <param name="path">The path.</param>
|
}
|
||||||
/// <returns>System.String.</returns>
|
}
|
||||||
public string GetSubtitleFileCharacterSet(string path)
|
|
||||||
|
public async Task<string> GetSubtitleFileCharacterSet(string path, MediaProtocol protocol, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (protocol == MediaProtocol.File)
|
||||||
{
|
{
|
||||||
if (GetFileEncoding(path).Equals(Encoding.UTF8))
|
if (GetFileEncoding(path).Equals(Encoding.UTF8))
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var charset = DetectCharset(path);
|
var charset = await DetectCharset(path, protocol, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(charset))
|
if (!string.IsNullOrWhiteSpace(charset))
|
||||||
{
|
{
|
||||||
|
@ -769,11 +788,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string DetectCharset(string path)
|
private async Task<string> DetectCharset(string path, MediaProtocol protocol, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var file = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
using (var file = await GetStream(path, protocol, cancellationToken).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
var detector = new CharsetDetector();
|
var detector = new CharsetDetector();
|
||||||
detector.Feed(file);
|
detector.Feed(file);
|
||||||
|
@ -819,5 +838,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
// It's ok - anything aside from utf is ok since that's what we're looking for
|
// It's ok - anything aside from utf is ok since that's what we're looking for
|
||||||
return Encoding.Default;
|
return Encoding.Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Stream> GetStream(string path, MediaProtocol protocol, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (protocol == MediaProtocol.Http)
|
||||||
|
{
|
||||||
|
return await _httpClient.Get(path, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
if (protocol == MediaProtocol.File)
|
||||||
|
{
|
||||||
|
return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentOutOfRangeException("protocol");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace MediaBrowser.Model.Configuration
|
||||||
public string[] LatestItemsExcludes { get; set; }
|
public string[] LatestItemsExcludes { get; set; }
|
||||||
|
|
||||||
public bool HasMigratedToPolicy { get; set; }
|
public bool HasMigratedToPolicy { get; set; }
|
||||||
|
public bool HidePlayedInLatest { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UserConfiguration" /> class.
|
/// Initializes a new instance of the <see cref="UserConfiguration" /> class.
|
||||||
|
|
|
@ -282,6 +282,49 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return playMethods;
|
return playMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
|
||||||
|
{
|
||||||
|
int highestScore = -1;
|
||||||
|
|
||||||
|
foreach (MediaStream stream in item.MediaStreams)
|
||||||
|
{
|
||||||
|
if (stream.Type == MediaStreamType.Subtitle && stream.Score.HasValue)
|
||||||
|
{
|
||||||
|
if (stream.Score.Value > highestScore)
|
||||||
|
{
|
||||||
|
highestScore = stream.Score.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MediaStream> topStreams = new List<MediaStream>();
|
||||||
|
foreach (MediaStream stream in item.MediaStreams)
|
||||||
|
{
|
||||||
|
if (stream.Type == MediaStreamType.Subtitle && stream.Score.HasValue && stream.Score.Value == highestScore)
|
||||||
|
{
|
||||||
|
topStreams.Add(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If multiple streams have an equal score, try to pick the most efficient one
|
||||||
|
if (topStreams.Count > 1)
|
||||||
|
{
|
||||||
|
foreach (MediaStream stream in topStreams)
|
||||||
|
{
|
||||||
|
foreach (SubtitleProfile profile in subtitleProfiles)
|
||||||
|
{
|
||||||
|
if (profile.Method == SubtitleDeliveryMethod.External && StringHelper.EqualsIgnoreCase(profile.Format, stream.Codec))
|
||||||
|
{
|
||||||
|
return stream.Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no optimization panned out, just use the original default
|
||||||
|
return item.DefaultSubtitleStreamIndex;
|
||||||
|
}
|
||||||
|
|
||||||
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options)
|
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options)
|
||||||
{
|
{
|
||||||
StreamInfo playlistItem = new StreamInfo
|
StreamInfo playlistItem = new StreamInfo
|
||||||
|
@ -294,7 +337,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
DeviceProfile = options.Profile
|
DeviceProfile = options.Profile
|
||||||
};
|
};
|
||||||
|
|
||||||
playlistItem.SubtitleStreamIndex = options.SubtitleStreamIndex ?? item.DefaultSubtitleStreamIndex;
|
playlistItem.SubtitleStreamIndex = options.SubtitleStreamIndex ?? GetDefaultSubtitleStreamIndex(item, options.Profile.SubtitleProfiles);
|
||||||
MediaStream subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null;
|
MediaStream subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null;
|
||||||
|
|
||||||
MediaStream audioStream = item.GetDefaultAudioStream(options.AudioStreamIndex ?? item.DefaultAudioStreamIndex);
|
MediaStream audioStream = item.GetDefaultAudioStream(options.AudioStreamIndex ?? item.DefaultAudioStreamIndex);
|
||||||
|
@ -618,6 +661,8 @@ namespace MediaBrowser.Model.Dlna
|
||||||
// Look for an external profile that matches the stream type (text/graphical)
|
// Look for an external profile that matches the stream type (text/graphical)
|
||||||
foreach (SubtitleProfile profile in subtitleProfiles)
|
foreach (SubtitleProfile profile in subtitleProfiles)
|
||||||
{
|
{
|
||||||
|
bool requiresConversion = !StringHelper.EqualsIgnoreCase(subtitleStream.Codec, profile.Format);
|
||||||
|
|
||||||
if (!profile.SupportsLanguage(subtitleStream.Language))
|
if (!profile.SupportsLanguage(subtitleStream.Language))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -625,6 +670,11 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
if (profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
|
if (profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
|
||||||
{
|
{
|
||||||
|
if (!requiresConversion)
|
||||||
|
{
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
if (subtitleStream.SupportsExternalStream)
|
if (subtitleStream.SupportsExternalStream)
|
||||||
{
|
{
|
||||||
return profile;
|
return profile;
|
||||||
|
@ -640,6 +690,8 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
foreach (SubtitleProfile profile in subtitleProfiles)
|
foreach (SubtitleProfile profile in subtitleProfiles)
|
||||||
{
|
{
|
||||||
|
bool requiresConversion = !StringHelper.EqualsIgnoreCase(subtitleStream.Codec, profile.Format);
|
||||||
|
|
||||||
if (!profile.SupportsLanguage(subtitleStream.Language))
|
if (!profile.SupportsLanguage(subtitleStream.Language))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -647,6 +699,11 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
if (profile.Method == SubtitleDeliveryMethod.Embed && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
|
if (profile.Method == SubtitleDeliveryMethod.Embed && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
|
||||||
{
|
{
|
||||||
|
if (!requiresConversion)
|
||||||
|
{
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,9 +217,9 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SubtitleStreamInfo> GetExternalSubtitles(bool includeSelectedTrackOnly, string baseUrl, string accessToken)
|
public List<SubtitleStreamInfo> GetExternalSubtitles(bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken)
|
||||||
{
|
{
|
||||||
List<SubtitleStreamInfo> list = GetSubtitleProfiles(includeSelectedTrackOnly, baseUrl, accessToken);
|
List<SubtitleStreamInfo> list = GetSubtitleProfiles(includeSelectedTrackOnly, enableAllProfiles, baseUrl, accessToken);
|
||||||
List<SubtitleStreamInfo> newList = new List<SubtitleStreamInfo>();
|
List<SubtitleStreamInfo> newList = new List<SubtitleStreamInfo>();
|
||||||
|
|
||||||
// First add the selected track
|
// First add the selected track
|
||||||
|
@ -235,6 +235,11 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SubtitleStreamInfo> GetSubtitleProfiles(bool includeSelectedTrackOnly, string baseUrl, string accessToken)
|
public List<SubtitleStreamInfo> GetSubtitleProfiles(bool includeSelectedTrackOnly, string baseUrl, string accessToken)
|
||||||
|
{
|
||||||
|
return GetSubtitleProfiles(includeSelectedTrackOnly, false, baseUrl, accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SubtitleStreamInfo> GetSubtitleProfiles(bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken)
|
||||||
{
|
{
|
||||||
List<SubtitleStreamInfo> list = new List<SubtitleStreamInfo>();
|
List<SubtitleStreamInfo> list = new List<SubtitleStreamInfo>();
|
||||||
|
|
||||||
|
@ -250,9 +255,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (stream.Type == MediaStreamType.Subtitle && stream.Index == SubtitleStreamIndex.Value)
|
if (stream.Type == MediaStreamType.Subtitle && stream.Index == SubtitleStreamIndex.Value)
|
||||||
{
|
{
|
||||||
SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks);
|
AddSubtitleProfiles(list, stream, enableAllProfiles, baseUrl, accessToken, startPositionTicks);
|
||||||
|
|
||||||
list.Add(info);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,9 +266,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (stream.Type == MediaStreamType.Subtitle && (!SubtitleStreamIndex.HasValue || stream.Index != SubtitleStreamIndex.Value))
|
if (stream.Type == MediaStreamType.Subtitle && (!SubtitleStreamIndex.HasValue || stream.Index != SubtitleStreamIndex.Value))
|
||||||
{
|
{
|
||||||
SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks);
|
AddSubtitleProfiles(list, stream, enableAllProfiles, baseUrl, accessToken, startPositionTicks);
|
||||||
|
|
||||||
list.Add(info);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,17 +274,41 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubtitleStreamInfo GetSubtitleStreamInfo(MediaStream stream, string baseUrl, string accessToken, long startPositionTicks)
|
private void AddSubtitleProfiles(List<SubtitleStreamInfo> list, MediaStream stream, bool enableAllProfiles, string baseUrl, string accessToken, long startPositionTicks)
|
||||||
{
|
{
|
||||||
SubtitleStreamInfo info = GetSubtitleStreamInfo(stream);
|
if (enableAllProfiles)
|
||||||
|
{
|
||||||
|
foreach (SubtitleProfile profile in DeviceProfile.SubtitleProfiles)
|
||||||
|
{
|
||||||
|
SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, new[] { profile });
|
||||||
|
|
||||||
|
list.Add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, DeviceProfile.SubtitleProfiles);
|
||||||
|
|
||||||
|
list.Add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SubtitleStreamInfo GetSubtitleStreamInfo(MediaStream stream, string baseUrl, string accessToken, long startPositionTicks, SubtitleProfile[] subtitleProfiles)
|
||||||
|
{
|
||||||
|
SubtitleProfile subtitleProfile = StreamBuilder.GetSubtitleProfile(stream, subtitleProfiles, Context);
|
||||||
|
SubtitleStreamInfo info = new SubtitleStreamInfo
|
||||||
|
{
|
||||||
|
IsForced = stream.IsForced,
|
||||||
|
Language = stream.Language,
|
||||||
|
Name = stream.Language ?? "Unknown",
|
||||||
|
Format = subtitleProfile.Format,
|
||||||
|
Index = stream.Index,
|
||||||
|
DeliveryMethod = subtitleProfile.Method
|
||||||
|
};
|
||||||
|
|
||||||
if (info.DeliveryMethod == SubtitleDeliveryMethod.External)
|
if (info.DeliveryMethod == SubtitleDeliveryMethod.External)
|
||||||
{
|
{
|
||||||
if (MediaSource.Protocol == MediaProtocol.Http)
|
if (MediaSource.Protocol == MediaProtocol.File || !StringHelper.EqualsIgnoreCase(stream.Codec, subtitleProfile.Format))
|
||||||
{
|
|
||||||
info.Url = stream.Path;
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrEmpty(baseUrl))
|
|
||||||
{
|
{
|
||||||
info.Url = string.Format("{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}",
|
info.Url = string.Format("{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
|
@ -291,28 +316,17 @@ namespace MediaBrowser.Model.Dlna
|
||||||
MediaSourceId,
|
MediaSourceId,
|
||||||
StringHelper.ToStringCultureInvariant(stream.Index),
|
StringHelper.ToStringCultureInvariant(stream.Index),
|
||||||
StringHelper.ToStringCultureInvariant(startPositionTicks),
|
StringHelper.ToStringCultureInvariant(startPositionTicks),
|
||||||
SubtitleFormat);
|
subtitleProfile.Format);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info.Url = stream.Path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubtitleStreamInfo GetSubtitleStreamInfo(MediaStream stream)
|
|
||||||
{
|
|
||||||
SubtitleProfile subtitleProfile = StreamBuilder.GetSubtitleProfile(stream, DeviceProfile.SubtitleProfiles, Context);
|
|
||||||
|
|
||||||
return new SubtitleStreamInfo
|
|
||||||
{
|
|
||||||
IsForced = stream.IsForced,
|
|
||||||
Language = stream.Language,
|
|
||||||
Name = stream.Language ?? "Unknown",
|
|
||||||
Format = SubtitleFormat,
|
|
||||||
Index = stream.Index,
|
|
||||||
DeliveryMethod = subtitleProfile.Method
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the audio stream that will be used
|
/// Returns the audio stream that will be used
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -130,6 +130,12 @@ namespace MediaBrowser.Model.Entities
|
||||||
/// <value>The index.</value>
|
/// <value>The index.</value>
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the score.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The score.</value>
|
||||||
|
public int? Score { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether this instance is external.
|
/// Gets or sets a value indicating whether this instance is external.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -6,15 +6,14 @@ using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Subtitles;
|
using MediaBrowser.Controller.Subtitles;
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Providers;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Providers;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.MediaInfo
|
namespace MediaBrowser.Providers.MediaInfo
|
||||||
{
|
{
|
||||||
|
@ -23,14 +22,16 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly ISubtitleManager _subtitleManager;
|
private readonly ISubtitleManager _subtitleManager;
|
||||||
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public SubtitleScheduledTask(ILibraryManager libraryManager, IServerConfigurationManager config, ISubtitleManager subtitleManager, ILogger logger)
|
public SubtitleScheduledTask(ILibraryManager libraryManager, IServerConfigurationManager config, ISubtitleManager subtitleManager, ILogger logger, IMediaSourceManager mediaSourceManager)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
_subtitleManager = subtitleManager;
|
_subtitleManager = subtitleManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_mediaSourceManager = mediaSourceManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
|
@ -107,7 +108,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
(options.DownloadMovieSubtitles &&
|
(options.DownloadMovieSubtitles &&
|
||||||
video is Movie))
|
video is Movie))
|
||||||
{
|
{
|
||||||
var mediaStreams = video.GetMediaSources(false).First().MediaStreams;
|
var mediaStreams = _mediaSourceManager.GetStaticMediaSources(video, false).First().MediaStreams;
|
||||||
|
|
||||||
var downloadedLanguages = await new SubtitleDownloader(_logger,
|
var downloadedLanguages = await new SubtitleDownloader(_logger,
|
||||||
_subtitleManager)
|
_subtitleManager)
|
||||||
|
|
|
@ -261,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
dto.MediaSources = hasMediaSources.GetMediaSources(true).ToList();
|
dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1280,7 +1280,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mediaStreams = iHasMediaSources.GetMediaSources(true).First().MediaStreams;
|
mediaStreams = _mediaSourceManager().GetStaticMediaSources(iHasMediaSources, true).First().MediaStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
dto.MediaStreams = mediaStreams;
|
dto.MediaStreams = mediaStreams;
|
||||||
|
@ -1453,7 +1453,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
var tvChannel = item as LiveTvChannel;
|
var tvChannel = item as LiveTvChannel;
|
||||||
if (tvChannel != null)
|
if (tvChannel != null)
|
||||||
{
|
{
|
||||||
dto.MediaSources = tvChannel.GetMediaSources(true).ToList();
|
dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(tvChannel, true).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
var channelItem = item as IChannelItem;
|
var channelItem = item as IChannelItem;
|
||||||
|
|
|
@ -135,6 +135,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
IEnumerable<MediaSourceInfo> mediaSources;
|
IEnumerable<MediaSourceInfo> mediaSources;
|
||||||
|
|
||||||
var hasMediaSources = (IHasMediaSources)item;
|
var hasMediaSources = (IHasMediaSources)item;
|
||||||
|
User user = null;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(userId))
|
if (string.IsNullOrWhiteSpace(userId))
|
||||||
{
|
{
|
||||||
|
@ -142,7 +143,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(userId);
|
user = _userManager.GetUserById(userId);
|
||||||
mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
|
mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +155,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
|
|
||||||
foreach (var source in dynamicMediaSources)
|
foreach (var source in dynamicMediaSources)
|
||||||
{
|
{
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
SetUserProperties(source, user);
|
||||||
|
}
|
||||||
if (source.Protocol == MediaProtocol.File)
|
if (source.Protocol == MediaProtocol.File)
|
||||||
{
|
{
|
||||||
source.SupportsDirectStream = File.Exists(source.Path);
|
source.SupportsDirectStream = File.Exists(source.Path);
|
||||||
|
@ -225,6 +230,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken);
|
return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution)
|
||||||
|
{
|
||||||
|
return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution)
|
public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution)
|
||||||
{
|
{
|
||||||
if (item == null)
|
if (item == null)
|
||||||
|
@ -288,6 +298,9 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
preferredSubs,
|
preferredSubs,
|
||||||
user.Configuration.SubtitleMode,
|
user.Configuration.SubtitleMode,
|
||||||
audioLangage);
|
audioLangage);
|
||||||
|
|
||||||
|
MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs,
|
||||||
|
user.Configuration.SubtitleMode, audioLangage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<MediaSourceInfo> SortMediaSources(IEnumerable<MediaSourceInfo> sources)
|
private IEnumerable<MediaSourceInfo> SortMediaSources(IEnumerable<MediaSourceInfo> sources)
|
||||||
|
@ -311,11 +324,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution)
|
|
||||||
{
|
|
||||||
return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, LiveStreamInfo> _openStreams = new ConcurrentDictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase);
|
private readonly ConcurrentDictionary<string, LiveStreamInfo> _openStreams = new ConcurrentDictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase);
|
||||||
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
|
@ -427,10 +435,17 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
LiveStreamInfo current;
|
||||||
|
if (_openStreams.TryGetValue(id, out current))
|
||||||
|
{
|
||||||
|
if (current.MediaSource.RequiresClosing)
|
||||||
{
|
{
|
||||||
var tuple = GetProvider(id);
|
var tuple = GetProvider(id);
|
||||||
|
|
||||||
await tuple.Item1.CloseMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
|
await tuple.Item1.CloseMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LiveStreamInfo removed;
|
LiveStreamInfo removed;
|
||||||
if (_openStreams.TryRemove(id, out removed))
|
if (_openStreams.TryRemove(id, out removed))
|
||||||
|
|
|
@ -215,7 +215,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
if (request.IsPlayed.HasValue)
|
if (request.IsPlayed.HasValue)
|
||||||
{
|
{
|
||||||
var val = request.IsPlayed.Value;
|
var val = request.IsPlayed.Value;
|
||||||
if (i.IsPlayed(currentUser) != val)
|
if (i is Video && i.IsPlayed(currentUser) != val)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
private readonly ILiveTvManager _liveTvManager;
|
private readonly ILiveTvManager _liveTvManager;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
|
|
||||||
public LiveTvMediaSourceProvider(ILiveTvManager liveTvManager, IJsonSerializer jsonSerializer, ILogManager logManager)
|
public LiveTvMediaSourceProvider(ILiveTvManager liveTvManager, IJsonSerializer jsonSerializer, ILogManager logManager, IMediaSourceManager mediaSourceManager)
|
||||||
{
|
{
|
||||||
_liveTvManager = liveTvManager;
|
_liveTvManager = liveTvManager;
|
||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
_logger = logManager.GetLogger(GetType().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +65,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
{
|
{
|
||||||
var hasMediaSources = (IHasMediaSources)item;
|
var hasMediaSources = (IHasMediaSources)item;
|
||||||
|
|
||||||
sources = hasMediaSources.GetMediaSources(false)
|
sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
"HeaderAddUser": "Add User",
|
"HeaderAddUser": "Add User",
|
||||||
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
|
"LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Emby Connect from their user profile page.",
|
||||||
"LabelPinCode": "Pin code:",
|
"LabelPinCode": "Pin code:",
|
||||||
|
"OptionHideWatchedContentFromLatestMedia": "Hide watched content from latest media",
|
||||||
"ButtonOk": "Ok",
|
"ButtonOk": "Ok",
|
||||||
"ButtonCancel": "Cancel",
|
"ButtonCancel": "Cancel",
|
||||||
"ButtonExit": "Exit",
|
"ButtonExit": "Exit",
|
||||||
|
|
|
@ -198,8 +198,7 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||||
var maxAudioChannels = supportsAc3 || supportsDca ? "5" : "2";
|
var maxAudioChannels = supportsAc3 || supportsDca ? "5" : "2";
|
||||||
codecProfiles.Add(new CodecProfile
|
codecProfiles.Add(new CodecProfile
|
||||||
{
|
{
|
||||||
Type = CodecType.Audio,
|
Type = CodecType.VideoAudio,
|
||||||
Codec = "mpeg4",
|
|
||||||
Conditions = new[]
|
Conditions = new[]
|
||||||
{
|
{
|
||||||
new ProfileCondition
|
new ProfileCondition
|
||||||
|
@ -207,7 +206,7 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.AudioChannels,
|
Property = ProfileConditionValue.AudioChannels,
|
||||||
Value = maxAudioChannels,
|
Value = maxAudioChannels,
|
||||||
IsRequired = false
|
IsRequired = true
|
||||||
},
|
},
|
||||||
new ProfileCondition
|
new ProfileCondition
|
||||||
{
|
{
|
||||||
|
|
|
@ -495,7 +495,7 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||||
// No sense creating external subs if we're already burning one into the video
|
// No sense creating external subs if we're already burning one into the video
|
||||||
var externalSubs = streamInfo.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode ?
|
var externalSubs = streamInfo.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode ?
|
||||||
new List<SubtitleStreamInfo>() :
|
new List<SubtitleStreamInfo>() :
|
||||||
streamInfo.GetExternalSubtitles(false, null, null);
|
streamInfo.GetExternalSubtitles(false, true, null, null);
|
||||||
|
|
||||||
// Mark as requiring conversion if transcoding the video, or if any subtitles need to be extracted
|
// Mark as requiring conversion if transcoding the video, or if any subtitles need to be extracted
|
||||||
var requiresVideoTranscoding = streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting;
|
var requiresVideoTranscoding = streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting;
|
||||||
|
@ -823,7 +823,7 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||||
|
|
||||||
var hasMediaSources = item as IHasMediaSources;
|
var hasMediaSources = item as IHasMediaSources;
|
||||||
|
|
||||||
var mediaSources = hasMediaSources.GetMediaSources(false).ToList();
|
var mediaSources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false).ToList();
|
||||||
|
|
||||||
var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
|
var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
|
||||||
? new string[] { }
|
? new string[] { }
|
||||||
|
|
|
@ -530,7 +530,7 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
|
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
|
||||||
RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager));
|
RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager));
|
||||||
|
|
||||||
SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer);
|
SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager);
|
||||||
RegisterSingleInstance(SubtitleEncoder);
|
RegisterSingleInstance(SubtitleEncoder);
|
||||||
|
|
||||||
await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false);
|
await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false);
|
||||||
|
|
Loading…
Reference in New Issue