diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs index 0c8a0aaa63..87084e415a 100644 --- a/MediaBrowser.Api/AppThemeService.cs +++ b/MediaBrowser.Api/AppThemeService.cs @@ -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); } } } diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 727ee6fbcc..1af7054d95 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -97,24 +97,6 @@ namespace MediaBrowser.Api return session; } - /// - /// To the cached result. - /// - /// - /// The cache key. - /// The last date modified. - /// Duration of the cache. - /// The factory fn. - /// Type of the content. - /// The response headers. - /// System.Object. - /// cacheKey - protected object ToCachedResult(Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType, IDictionary responseHeaders = null) - where T : class - { - return ResultFactory.GetCachedResult(Request, cacheKey, lastDateModified, cacheDuration, factoryFn, contentType, responseHeaders); - } - /// /// To the static file result. /// diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 43e9ad3efe..2213a5af1b 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -361,7 +361,7 @@ namespace MediaBrowser.Api.Images /// System.Object. 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 GetImageResult(IHasImages item, + private async Task GetImageResult(IHasImages item, ImageRequest request, ItemImageInfo image, List enhancers, string contentType, TimeSpan? cacheDuration, - IDictionary headers, + IDictionary 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) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index a0a8ee61ea..31a81de731 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -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); } diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index 0d90e37395..2e9b9d36fe 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -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; - } - } - /// /// Called when [begin request]. /// diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index d8255bd290..997cc7ca4b 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -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 { diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index b13403bbf8..25d41565ae 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -38,6 +38,7 @@ namespace MediaBrowser.Controller.Entities.Audio Tags = new List(); } + [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. /// /// The type of the media. + [IgnoreDataMember] public override string MediaType { get diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 2eeec9715a..dc9f83b3c9 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -22,6 +22,7 @@ namespace MediaBrowser.Controller.Entities.Audio AlbumArtists = new List(); } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return true; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index de527b68b3..070572b9b2 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -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; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index f1dc56ac68..928eb64630 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -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; } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index fd7a33ddf4..26b28ec72b 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -53,6 +53,7 @@ namespace MediaBrowser.Controller.Entities public List ImageInfos { get; set; } + [IgnoreDataMember] public virtual bool SupportsAddingToPlaylist { get @@ -192,6 +193,7 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] public virtual bool SupportsLocalMetadata { get diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 1f38de9a31..367db5dcb5 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Entities Taglines = new List(); } + [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); diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index b82a400fe8..6804b29b73 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -29,6 +29,7 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return true; } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 856ed4fdf2..d3b95eb0c6 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -39,6 +39,7 @@ namespace MediaBrowser.Controller.Entities.TV DisplaySpecialsWithSeasons = true; } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return true; } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index ea530272dd..492a4a02f9 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -58,6 +58,7 @@ namespace MediaBrowser.Controller.Entities LinkedAlternateVersions = new List(); } + [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. /// /// The type of the media. + [IgnoreDataMember] public override string MediaType { get diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index aeeaae073b..6a78fa5d9f 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -214,6 +214,7 @@ + diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index f0cfbbcfae..526bf4be2e 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.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); /// - /// Gets the static file result. + /// Gets the static result. /// /// The request context. - /// The path. - /// The file share. - /// The response headers. - /// if set to true [is head request]. + /// The options. /// System.Object. - object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary responseHeaders = null, bool isHeadRequest = false); + object GetStaticResult(IRequest requestContext, StaticResultOptions options); /// /// Gets the static file result. /// /// The request context. /// The path. - /// Type of the content. - /// The cache curation. /// The file share. - /// The response headers. - /// if set to true [is head request]. - /// if set to true [throttle]. - /// The throttle limit. /// System.Object. - object GetStaticFileResult(IRequest requestContext, - string path, - string contentType, - TimeSpan? cacheCuration = null, - FileShare fileShare = FileShare.Read, - IDictionary responseHeaders = null, - bool isHeadRequest = false, - bool throttle = false, - long throttleLimit = 0); - + object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read); + /// - /// Gets the optimized serialized result using cache. + /// Gets the static file result. /// - /// - /// The request. - /// The result. + /// The request context. + /// The options. /// System.Object. - object GetOptimizedSerializedResultUsingCache(IRequest request, T result) - where T : class; + object GetStaticFileResult(IRequest requestContext, + StaticFileResultOptions options); } } diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs new file mode 100644 index 0000000000..fde08c269d --- /dev/null +++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs @@ -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> ContentFactory { get; set; } + + public bool IsHeadRequest { get; set; } + + public IDictionary ResponseHeaders { get; set; } + + public bool Throttle { get; set; } + public long ThrottleLimit { get; set; } + public long MinThrottlePosition { get; set; } + + public StaticResultOptions() + { + ResponseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + } + + public class StaticFileResultOptions : StaticResultOptions + { + public string Path { get; set; } + + public FileShare FileShare { get; set; } + + public StaticFileResultOptions() + { + FileShare = FileShare.Read; + } + } +} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index df22b5e1f7..87d706a16a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -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(outputPath, extractedFormat); @@ -477,13 +477,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// The input files. /// The protocol. /// Index of the subtitle stream. - /// if set to true, copy stream instead of converting. + /// The output codec. /// The output path. /// The cancellation token. /// Task. /// Must use inputPath list overload 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 } } - /// - /// Extracts the text subtitle. - /// - /// The input path. - /// Index of the subtitle stream. - /// if set to true, copy stream instead of converting. - /// The output path. - /// The cancellation token. - /// Task. - /// inputPath - /// or - /// outputPath - /// or - /// cancellationToken - /// 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 { diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 360d2d8621..ec5a26eee1 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -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; } + /// /// Gets a value indicating whether this instance can resume. /// diff --git a/MediaBrowser.Providers/Photos/PhotoProvider.cs b/MediaBrowser.Providers/Photos/PhotoProvider.cs index 123c91d075..b298c62e74 100644 --- a/MediaBrowser.Providers/Photos/PhotoProvider.cs +++ b/MediaBrowser.Providers/Photos/PhotoProvider.cs @@ -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; diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 61517ce6ef..922287f6ee 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -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) diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index be3e5f0051..9997cfbdb0 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -289,41 +289,28 @@ namespace MediaBrowser.Server.Implementations.HttpServer return null; } - /// - /// Gets the static file result. - /// - /// The request context. - /// The path. - /// The file share. - /// The response headers. - /// if set to true [is head request]. - /// System.Object. - /// path - /// path public object GetStaticFileResult(IRequest requestContext, string path, - FileShare fileShare = FileShare.Read, - IDictionary 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 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); } /// @@ -352,21 +346,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, fileShare, true); } - /// - /// Gets the static result. - /// - /// The request context. - /// The cache key. - /// The last date modified. - /// Duration of the cache. - /// Type of the content. - /// The factory fn. - /// The response headers. - /// if set to true [is head request]. - /// System.Object. - /// cacheKey - /// or - /// factoryFn public object GetStaticResult(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, @@ -376,39 +355,37 @@ namespace MediaBrowser.Server.Implementations.HttpServer IDictionary 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> factoryFn, - IDictionary 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(); + 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(); - } - // 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 /// private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// - /// Gets the static result. - /// - /// The request context. - /// The response headers. - /// Type of the content. - /// The factory fn. - /// if set to true [compress]. - /// if set to true [is head request]. - /// if set to true [throttle]. - /// The throttle limit. - /// Task{IHasOptions}. - private async Task GetStaticResult(IRequest requestContext, IDictionary responseHeaders, string contentType, Func> factoryFn, bool compress, bool isHeadRequest, bool throttle, long throttleLimit = 0) + private async Task 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(IRequest request, T result) - where T : class - { - var json = _jsonSerializer.SerializeToString(result); - var cacheKey = json.GetMD5(); - - return GetOptimizedResultUsingCache(request, cacheKey, null, null, () => result); - } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs index 5fd43aa76b..657545069a 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer public bool Throttle { get; set; } public long ThrottleLimit { get; set; } + public long MinThrottlePosition; /// /// 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); diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs index f1112ae0b3..28fc094f7d 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs @@ -38,7 +38,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer public bool Throttle { get; set; } public long ThrottleLimit { get; set; } - + public long MinThrottlePosition; + /// /// Initializes a new instance of the class. /// @@ -84,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer { responseStream = new ThrottledStream(responseStream, ThrottleLimit) { - MinThrottlePosition = ThrottleLimit * 180 + MinThrottlePosition = MinThrottlePosition }; } var task = WriteToAsync(responseStream);