mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-11-15 18:08:53 -07:00
Adjust transcoding throttling
This commit is contained in:
parent
6a9dbf6ae8
commit
33c6c37316
@ -94,7 +94,7 @@ namespace MediaBrowser.Api
|
||||
|
||||
var contentType = MimeTypes.GetMimeType(info.Path);
|
||||
|
||||
return ToCachedResult(cacheGuid, info.DateModified, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType);
|
||||
return ResultFactory.GetCachedResult(Request, cacheGuid, null, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,24 +97,6 @@ namespace MediaBrowser.Api
|
||||
return session;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To the cached result.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey">The cache key.</param>
|
||||
/// <param name="lastDateModified">The last date modified.</param>
|
||||
/// <param name="cacheDuration">Duration of the cache.</param>
|
||||
/// <param name="factoryFn">The factory fn.</param>
|
||||
/// <param name="contentType">Type of the content.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">cacheKey</exception>
|
||||
protected object ToCachedResult<T>(Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn, string contentType, IDictionary<string,string> responseHeaders = null)
|
||||
where T : class
|
||||
{
|
||||
return ResultFactory.GetCachedResult(Request, cacheKey, lastDateModified, cacheDuration, factoryFn, contentType, responseHeaders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To the static file result.
|
||||
/// </summary>
|
||||
|
@ -361,7 +361,7 @@ namespace MediaBrowser.Api.Images
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetItemImage request)
|
||||
{
|
||||
var item = string.IsNullOrEmpty(request.Id) ?
|
||||
var item = string.IsNullOrEmpty(request.Id) ?
|
||||
_libraryManager.RootFolder :
|
||||
_libraryManager.GetItemById(request.Id);
|
||||
|
||||
@ -542,24 +542,24 @@ namespace MediaBrowser.Api.Images
|
||||
{"realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"}
|
||||
};
|
||||
|
||||
return GetImageResult(item,
|
||||
request,
|
||||
imageInfo,
|
||||
supportedImageEnhancers,
|
||||
contentType,
|
||||
return GetImageResult(item,
|
||||
request,
|
||||
imageInfo,
|
||||
supportedImageEnhancers,
|
||||
contentType,
|
||||
cacheDuration,
|
||||
responseHeaders,
|
||||
isHeadRequest)
|
||||
.Result;
|
||||
}
|
||||
|
||||
private async Task<object> GetImageResult(IHasImages item,
|
||||
private async Task<object> GetImageResult(IHasImages item,
|
||||
ImageRequest request,
|
||||
ItemImageInfo image,
|
||||
List<IImageEnhancer> enhancers,
|
||||
string contentType,
|
||||
TimeSpan? cacheDuration,
|
||||
IDictionary<string,string> headers,
|
||||
IDictionary<string, string> headers,
|
||||
bool isHeadRequest)
|
||||
{
|
||||
var cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art;
|
||||
@ -590,7 +590,14 @@ namespace MediaBrowser.Api.Images
|
||||
|
||||
var file = await _imageProcessor.ProcessImage(options).ConfigureAwait(false);
|
||||
|
||||
return ResultFactory.GetStaticFileResult(Request, file, contentType, cacheDuration, FileShare.Read, headers, isHeadRequest);
|
||||
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
||||
{
|
||||
CacheDuration = cacheDuration,
|
||||
ResponseHeaders = headers,
|
||||
ContentType = contentType,
|
||||
IsHeadRequest = isHeadRequest,
|
||||
Path = file
|
||||
});
|
||||
}
|
||||
|
||||
private string GetMimeType(ImageOutputFormat format, string path)
|
||||
|
@ -348,14 +348,16 @@ namespace MediaBrowser.Api.Playback
|
||||
var profileScore = 0;
|
||||
|
||||
string crf;
|
||||
var qmin = "0";
|
||||
var qmax = "50";
|
||||
|
||||
switch (qualitySetting)
|
||||
{
|
||||
case EncodingQuality.HighSpeed:
|
||||
crf = "12";
|
||||
crf = "10";
|
||||
break;
|
||||
case EncodingQuality.HighQuality:
|
||||
crf = "8";
|
||||
crf = "6";
|
||||
break;
|
||||
case EncodingQuality.MaxQuality:
|
||||
crf = "4";
|
||||
@ -371,11 +373,13 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
// Max of 2
|
||||
profileScore = Math.Min(profileScore, 2);
|
||||
|
||||
|
||||
// http://www.webmproject.org/docs/encoder-parameters/
|
||||
param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1}",
|
||||
param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}",
|
||||
profileScore.ToString(UsCulture),
|
||||
crf);
|
||||
crf,
|
||||
qmin,
|
||||
qmax);
|
||||
}
|
||||
|
||||
else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
@ -789,7 +793,7 @@ namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo)
|
||||
{
|
||||
var url = "http://localhost:8096/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
|
||||
var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
|
||||
|
||||
return string.Format("\"{0}\"", url);
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ using ServiceStack;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Hls
|
||||
@ -79,14 +78,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
return ResultFactory.GetStaticFileResult(Request, file);
|
||||
}
|
||||
|
||||
protected override bool SupportsThrottling
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [begin request].
|
||||
/// </summary>
|
||||
|
@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using ServiceStack.Web;
|
||||
@ -26,7 +27,8 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
protected readonly IImageProcessor ImageProcessor;
|
||||
protected readonly IHttpClient HttpClient;
|
||||
|
||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient)
|
||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
||||
{
|
||||
ImageProcessor = imageProcessor;
|
||||
HttpClient = httpClient;
|
||||
@ -52,23 +54,23 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
if (isVideoRequest)
|
||||
{
|
||||
var videoCodec = state.VideoRequest.VideoCodec;
|
||||
|
||||
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ".ts";
|
||||
}
|
||||
if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ".ogv";
|
||||
}
|
||||
if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ".webm";
|
||||
}
|
||||
if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ".asf";
|
||||
}
|
||||
|
||||
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ".ts";
|
||||
}
|
||||
if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ".ogv";
|
||||
}
|
||||
if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ".webm";
|
||||
}
|
||||
if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ".asf";
|
||||
}
|
||||
}
|
||||
|
||||
// Try to infer based on the desired audio codec
|
||||
@ -153,7 +155,20 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
{
|
||||
var throttleLimit = state.InputBitrate.HasValue ? (state.InputBitrate.Value / 8) : 0;
|
||||
|
||||
return ResultFactory.GetStaticFileResult(Request, state.MediaPath, contentType, null, FileShare.Read, responseHeaders, isHeadRequest, request.Throttle, throttleLimit);
|
||||
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
||||
{
|
||||
ResponseHeaders = responseHeaders,
|
||||
ContentType = contentType,
|
||||
IsHeadRequest = isHeadRequest,
|
||||
Path = state.MediaPath,
|
||||
Throttle = request.Throttle,
|
||||
|
||||
// Pad by 20% to play it safe
|
||||
ThrottleLimit = Convert.ToInt64(1.2 * throttleLimit),
|
||||
|
||||
// Three minutes
|
||||
MinThrottlePosition = throttleLimit * 180
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +179,13 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
|
||||
try
|
||||
{
|
||||
return ResultFactory.GetStaticFileResult(Request, outputPath, contentType, null, FileShare.Read, responseHeaders, isHeadRequest);
|
||||
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
||||
{
|
||||
ResponseHeaders = responseHeaders,
|
||||
ContentType = contentType,
|
||||
IsHeadRequest = isHeadRequest,
|
||||
Path = outputPath
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -38,6 +38,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
|
||||
@ -118,6 +119,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// Gets the type of the media.
|
||||
/// </summary>
|
||||
/// <value>The type of the media.</value>
|
||||
[IgnoreDataMember]
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
|
@ -22,6 +22,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
AlbumArtists = new List<string>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return true; }
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MediaBrowser.Common.Progress;
|
||||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
@ -26,6 +27,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return true; }
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
@ -18,6 +19,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return "MusicGenre-" + Name;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return true; }
|
||||
|
@ -53,6 +53,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public List<ItemImageInfo> ImageInfos { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual bool SupportsAddingToPlaylist
|
||||
{
|
||||
get
|
||||
@ -192,6 +193,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual bool SupportsLocalMetadata
|
||||
{
|
||||
get
|
||||
|
@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
Taglines = new List<string>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsLocalMetadata
|
||||
{
|
||||
get
|
||||
@ -25,6 +26,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
@ -35,6 +37,16 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override Folder LatestItemsIndexContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
return Album;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[IgnoreDataMember]
|
||||
public PhotoAlbum Album
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -53,6 +65,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
public double? Aperture { get; set; }
|
||||
public double? ShutterSpeed { get; set; }
|
||||
|
||||
public double? Latitude { get; set; }
|
||||
public double? Longitude { get; set; }
|
||||
public double? Altitude { get; set; }
|
||||
public int? IsoSpeedRating { get; set; }
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserConfiguration config)
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||
|
@ -29,6 +29,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return true; }
|
||||
|
@ -39,6 +39,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
DisplaySpecialsWithSeasons = true;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return true; }
|
||||
|
@ -58,6 +58,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
LinkedAlternateVersions = new List<LinkedChild>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
|
||||
@ -238,6 +239,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Gets the type of the media.
|
||||
/// </summary>
|
||||
/// <value>The type of the media.</value>
|
||||
[IgnoreDataMember]
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
|
@ -214,6 +214,7 @@
|
||||
<Compile Include="Net\IRestfulService.cs" />
|
||||
<Compile Include="Net\ISessionContext.cs" />
|
||||
<Compile Include="Net\LoggedAttribute.cs" />
|
||||
<Compile Include="Net\StaticResultOptions.cs" />
|
||||
<Compile Include="News\INewsService.cs" />
|
||||
<Compile Include="Notifications\INotificationManager.cs" />
|
||||
<Compile Include="Notifications\INotificationService.cs" />
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using ServiceStack.Web;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
@ -89,47 +89,29 @@ namespace MediaBrowser.Controller.Net
|
||||
bool isHeadRequest = false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the static file result.
|
||||
/// Gets the static result.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="fileShare">The file share.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary<string, string> responseHeaders = null, bool isHeadRequest = false);
|
||||
object GetStaticResult(IRequest requestContext, StaticResultOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the static file result.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="contentType">Type of the content.</param>
|
||||
/// <param name="cacheCuration">The cache curation.</param>
|
||||
/// <param name="fileShare">The file share.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <param name="throttle">if set to <c>true</c> [throttle].</param>
|
||||
/// <param name="throttleLimit">The throttle limit.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the static file result.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
object GetStaticFileResult(IRequest requestContext,
|
||||
string path,
|
||||
string contentType,
|
||||
TimeSpan? cacheCuration = null,
|
||||
FileShare fileShare = FileShare.Read,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false,
|
||||
bool throttle = false,
|
||||
long throttleLimit = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the optimized serialized result using cache.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
object GetOptimizedSerializedResultUsingCache<T>(IRequest request, T result)
|
||||
where T : class;
|
||||
StaticFileResultOptions options);
|
||||
}
|
||||
}
|
||||
|
42
MediaBrowser.Controller/Net/StaticResultOptions.cs
Normal file
42
MediaBrowser.Controller/Net/StaticResultOptions.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public class StaticResultOptions
|
||||
{
|
||||
public string ContentType { get; set; }
|
||||
public TimeSpan? CacheDuration { get; set; }
|
||||
public DateTime? DateLastModified { get; set; }
|
||||
public Guid CacheKey { get; set; }
|
||||
|
||||
public Func<Task<Stream>> ContentFactory { get; set; }
|
||||
|
||||
public bool IsHeadRequest { get; set; }
|
||||
|
||||
public IDictionary<string, string> ResponseHeaders { get; set; }
|
||||
|
||||
public bool Throttle { get; set; }
|
||||
public long ThrottleLimit { get; set; }
|
||||
public long MinThrottlePosition { get; set; }
|
||||
|
||||
public StaticResultOptions()
|
||||
{
|
||||
ResponseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
public class StaticFileResultOptions : StaticResultOptions
|
||||
{
|
||||
public string Path { get; set; }
|
||||
|
||||
public FileShare FileShare { get; set; }
|
||||
|
||||
public StaticFileResultOptions()
|
||||
{
|
||||
FileShare = FileShare.Read;
|
||||
}
|
||||
}
|
||||
}
|
@ -201,7 +201,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
// Extract
|
||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat);
|
||||
|
||||
await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, false, outputPath, cancellationToken)
|
||||
await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, "srt", outputPath, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return new Tuple<string, string>(outputPath, extractedFormat);
|
||||
@ -477,13 +477,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
|
||||
/// <param name="copySubtitleStream">if set to true, copy stream instead of converting.</param>
|
||||
/// <param name="outputCodec">The output codec.</param>
|
||||
/// <param name="outputPath">The output path.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentException">Must use inputPath list overload</exception>
|
||||
private async Task ExtractTextSubtitle(string[] inputFiles, MediaProtocol protocol, int subtitleStreamIndex,
|
||||
bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
|
||||
string outputCodec, string outputPath, CancellationToken cancellationToken)
|
||||
{
|
||||
var semaphore = GetLock(outputPath);
|
||||
|
||||
@ -494,7 +494,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
if (!File.Exists(outputPath))
|
||||
{
|
||||
await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex,
|
||||
copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false);
|
||||
outputCodec, outputPath, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@ -503,23 +503,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the text subtitle.
|
||||
/// </summary>
|
||||
/// <param name="inputPath">The input path.</param>
|
||||
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
|
||||
/// <param name="copySubtitleStream">if set to true, copy stream instead of converting.</param>
|
||||
/// <param name="outputPath">The output path.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">inputPath
|
||||
/// or
|
||||
/// outputPath
|
||||
/// or
|
||||
/// cancellationToken</exception>
|
||||
/// <exception cref="System.ApplicationException"></exception>
|
||||
private async Task ExtractTextSubtitleInternal(string inputPath, int subtitleStreamIndex,
|
||||
bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
|
||||
string outputCodec, string outputPath, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(inputPath))
|
||||
{
|
||||
@ -533,14 +518,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||
|
||||
var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s srt \"{2}\"", inputPath,
|
||||
subtitleStreamIndex, outputPath);
|
||||
|
||||
if (copySubtitleStream)
|
||||
{
|
||||
processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s copy \"{2}\"", inputPath,
|
||||
subtitleStreamIndex, outputPath);
|
||||
}
|
||||
var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath,
|
||||
subtitleStreamIndex, outputCodec, outputPath);
|
||||
|
||||
var process = new Process
|
||||
{
|
||||
|
@ -732,7 +732,11 @@ namespace MediaBrowser.Model.Dto
|
||||
public ImageOrientation? ImageOrientation { get; set; }
|
||||
public double? Aperture { get; set; }
|
||||
public double? ShutterSpeed { get; set; }
|
||||
|
||||
public double? Latitude { get; set; }
|
||||
public double? Longitude { get; set; }
|
||||
public double? Altitude { get; set; }
|
||||
public int? IsoSpeedRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance can resume.
|
||||
/// </summary>
|
||||
|
@ -123,6 +123,19 @@ namespace MediaBrowser.Providers.Photos
|
||||
|
||||
item.ExposureTime = image.ImageTag.ExposureTime;
|
||||
item.FocalLength = image.ImageTag.FocalLength;
|
||||
|
||||
item.Latitude = image.ImageTag.Latitude;
|
||||
item.Longitude = image.ImageTag.Longitude;
|
||||
item.Altitude = image.ImageTag.Altitude;
|
||||
|
||||
if (image.ImageTag.ISOSpeedRatings.HasValue)
|
||||
{
|
||||
item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.IsoSpeedRating = null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -145,7 +158,7 @@ namespace MediaBrowser.Providers.Photos
|
||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
||||
{
|
||||
// Moved to plural AlbumArtists
|
||||
if (date < new DateTime(2014, 8, 28))
|
||||
if (date < new DateTime(2014, 8, 29))
|
||||
{
|
||||
// Revamped vaptured metadata
|
||||
return true;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
@ -369,6 +368,19 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
dto.ImageOrientation = item.Orientation;
|
||||
dto.Aperture = item.Aperture;
|
||||
dto.ShutterSpeed = item.ShutterSpeed;
|
||||
|
||||
dto.Latitude = item.Latitude;
|
||||
dto.Longitude = item.Longitude;
|
||||
dto.Altitude = item.Altitude;
|
||||
dto.IsoSpeedRating = item.IsoSpeedRating;
|
||||
|
||||
var album = item.Album;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
dto.Album = item.Name;
|
||||
dto.AlbumId = item.Id.ToString("N");
|
||||
}
|
||||
}
|
||||
|
||||
private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
|
||||
|
@ -289,41 +289,28 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the static file result.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="fileShare">The file share.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
/// <exception cref="ArgumentNullException">path</exception>
|
||||
/// <exception cref="System.ArgumentNullException">path</exception>
|
||||
public object GetStaticFileResult(IRequest requestContext,
|
||||
string path,
|
||||
FileShare fileShare = FileShare.Read,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false)
|
||||
FileShare fileShare = FileShare.Read)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
}
|
||||
|
||||
return GetStaticFileResult(requestContext, path, MimeTypes.GetMimeType(path), null, fileShare, responseHeaders, isHeadRequest);
|
||||
return GetStaticFileResult(requestContext, new StaticFileResultOptions
|
||||
{
|
||||
Path = path,
|
||||
FileShare = fileShare
|
||||
});
|
||||
}
|
||||
|
||||
public object GetStaticFileResult(IRequest requestContext,
|
||||
string path,
|
||||
string contentType,
|
||||
TimeSpan? cacheCuration = null,
|
||||
FileShare fileShare = FileShare.Read,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false,
|
||||
bool throttle = false,
|
||||
long throttleLimit = 0)
|
||||
StaticFileResultOptions options)
|
||||
{
|
||||
var path = options.Path;
|
||||
var fileShare = options.FileShare;
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
@ -334,11 +321,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
throw new ArgumentException("FileShare must be either Read or ReadWrite");
|
||||
}
|
||||
|
||||
var dateModified = _fileSystem.GetLastWriteTimeUtc(path);
|
||||
if (string.IsNullOrWhiteSpace(options.ContentType))
|
||||
{
|
||||
options.ContentType = MimeTypes.GetMimeType(path);
|
||||
}
|
||||
|
||||
var cacheKey = path + dateModified.Ticks;
|
||||
options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path);
|
||||
var cacheKey = path + options.DateLastModified.Value.Ticks;
|
||||
|
||||
return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, cacheCuration, contentType, () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest, throttle, throttleLimit);
|
||||
options.CacheKey = cacheKey.GetMD5();
|
||||
options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare));
|
||||
|
||||
return GetStaticResult(requestContext, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -352,21 +346,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, fileShare, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the static result.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <param name="cacheKey">The cache key.</param>
|
||||
/// <param name="lastDateModified">The last date modified.</param>
|
||||
/// <param name="cacheDuration">Duration of the cache.</param>
|
||||
/// <param name="contentType">Type of the content.</param>
|
||||
/// <param name="factoryFn">The factory fn.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">cacheKey
|
||||
/// or
|
||||
/// factoryFn</exception>
|
||||
public object GetStaticResult(IRequest requestContext,
|
||||
Guid cacheKey,
|
||||
DateTime? lastDateModified,
|
||||
@ -376,39 +355,37 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false)
|
||||
{
|
||||
return GetStaticResult(requestContext, cacheKey, lastDateModified, cacheDuration, contentType, factoryFn,
|
||||
responseHeaders, isHeadRequest, false, 0);
|
||||
return GetStaticResult(requestContext, new StaticResultOptions
|
||||
{
|
||||
CacheDuration = cacheDuration,
|
||||
CacheKey = cacheKey,
|
||||
ContentFactory = factoryFn,
|
||||
ContentType = contentType,
|
||||
DateLastModified = lastDateModified,
|
||||
IsHeadRequest = isHeadRequest,
|
||||
ResponseHeaders = responseHeaders
|
||||
});
|
||||
}
|
||||
|
||||
public object GetStaticResult(IRequest requestContext,
|
||||
Guid cacheKey,
|
||||
DateTime? lastDateModified,
|
||||
TimeSpan? cacheDuration,
|
||||
string contentType,
|
||||
Func<Task<Stream>> factoryFn,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false,
|
||||
bool throttle = false,
|
||||
long throttleLimit = 0)
|
||||
public object GetStaticResult(IRequest requestContext, StaticResultOptions options)
|
||||
{
|
||||
var cacheKey = options.CacheKey;
|
||||
options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>();
|
||||
var contentType = options.ContentType;
|
||||
|
||||
if (cacheKey == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("cacheKey");
|
||||
}
|
||||
if (factoryFn == null)
|
||||
if (options.ContentFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException("factoryFn");
|
||||
}
|
||||
|
||||
var key = cacheKey.ToString("N");
|
||||
|
||||
if (responseHeaders == null)
|
||||
{
|
||||
responseHeaders = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
// See if the result is already cached in the browser
|
||||
var result = GetCachedResult(requestContext, responseHeaders, cacheKey, key, lastDateModified, cacheDuration, contentType);
|
||||
var result = GetCachedResult(requestContext, options.ResponseHeaders, cacheKey, key, options.DateLastModified, options.CacheDuration, contentType);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
@ -416,8 +393,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
}
|
||||
|
||||
var compress = ShouldCompressResponse(requestContext, contentType);
|
||||
var hasOptions = GetStaticResult(requestContext, responseHeaders, contentType, factoryFn, compress, isHeadRequest, throttle, throttleLimit).Result;
|
||||
AddResponseHeaders(hasOptions, responseHeaders);
|
||||
var hasOptions = GetStaticResult(requestContext, options, compress).Result;
|
||||
AddResponseHeaders(hasOptions, options.ResponseHeaders);
|
||||
|
||||
return hasOptions;
|
||||
}
|
||||
@ -473,20 +450,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
/// </summary>
|
||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the static result.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="contentType">Type of the content.</param>
|
||||
/// <param name="factoryFn">The factory fn.</param>
|
||||
/// <param name="compress">if set to <c>true</c> [compress].</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <param name="throttle">if set to <c>true</c> [throttle].</param>
|
||||
/// <param name="throttleLimit">The throttle limit.</param>
|
||||
/// <returns>Task{IHasOptions}.</returns>
|
||||
private async Task<IHasOptions> GetStaticResult(IRequest requestContext, IDictionary<string, string> responseHeaders, string contentType, Func<Task<Stream>> factoryFn, bool compress, bool isHeadRequest, bool throttle, long throttleLimit = 0)
|
||||
private async Task<IHasOptions> GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress)
|
||||
{
|
||||
var isHeadRequest = options.IsHeadRequest;
|
||||
var factoryFn = options.ContentFactory;
|
||||
var contentType = options.ContentType;
|
||||
var responseHeaders = options.ResponseHeaders;
|
||||
|
||||
var requestedCompressionType = requestContext.GetCompressionType();
|
||||
|
||||
if (!compress || string.IsNullOrEmpty(requestedCompressionType))
|
||||
@ -499,8 +469,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
{
|
||||
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest)
|
||||
{
|
||||
Throttle = throttle,
|
||||
ThrottleLimit = throttleLimit
|
||||
Throttle = options.Throttle,
|
||||
ThrottleLimit = options.ThrottleLimit,
|
||||
MinThrottlePosition = options.MinThrottlePosition
|
||||
};
|
||||
}
|
||||
|
||||
@ -515,8 +486,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
|
||||
return new StreamWriter(stream, contentType, _logger)
|
||||
{
|
||||
Throttle = throttle,
|
||||
ThrottleLimit = throttleLimit
|
||||
Throttle = options.Throttle,
|
||||
ThrottleLimit = options.ThrottleLimit,
|
||||
MinThrottlePosition = options.MinThrottlePosition
|
||||
};
|
||||
}
|
||||
|
||||
@ -746,14 +718,5 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
public object GetOptimizedSerializedResultUsingCache<T>(IRequest request, T result)
|
||||
where T : class
|
||||
{
|
||||
var json = _jsonSerializer.SerializeToString(result);
|
||||
var cacheKey = json.GetMD5();
|
||||
|
||||
return GetOptimizedResultUsingCache(request, cacheKey, null, null, () => result);
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
|
||||
public bool Throttle { get; set; }
|
||||
public long ThrottleLimit { get; set; }
|
||||
public long MinThrottlePosition;
|
||||
|
||||
/// <summary>
|
||||
/// The _options
|
||||
@ -166,7 +167,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
{
|
||||
responseStream = new ThrottledStream(responseStream, ThrottleLimit)
|
||||
{
|
||||
MinThrottlePosition = ThrottleLimit * 180
|
||||
MinThrottlePosition = MinThrottlePosition
|
||||
};
|
||||
}
|
||||
var task = WriteToAsync(responseStream);
|
||||
|
@ -38,7 +38,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
|
||||
public bool Throttle { get; set; }
|
||||
public long ThrottleLimit { get; set; }
|
||||
|
||||
public long MinThrottlePosition;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
|
||||
/// </summary>
|
||||
@ -84,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
{
|
||||
responseStream = new ThrottledStream(responseStream, ThrottleLimit)
|
||||
{
|
||||
MinThrottlePosition = ThrottleLimit * 180
|
||||
MinThrottlePosition = MinThrottlePosition
|
||||
};
|
||||
}
|
||||
var task = WriteToAsync(responseStream);
|
||||
|
Loading…
Reference in New Issue
Block a user