diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 7b6e5ed19e..ce6ca015de 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -122,53 +122,12 @@ namespace MediaBrowser.Api return ToOptimizedResult(result); } - const string XbmcMetadata = "Xbmc Nfo"; - const string MediaBrowserMetadata = "Media Browser Xml"; - public void Post(AutoSetMetadataOptions request) { - var service = AutoDetectMetadataService(); - - Logger.Info("Setting preferred metadata format to " + service); - - var serviceToDisable = string.Equals(service, XbmcMetadata) ? - MediaBrowserMetadata : - XbmcMetadata; - - _configurationManager.DisableMetadataService(serviceToDisable); + _configurationManager.DisableMetadataService("Media Browser Xml"); _configurationManager.SaveConfiguration(); } - private string AutoDetectMetadataService() - { - try - { - var paths = _libraryManager.GetDefaultVirtualFolders() - .SelectMany(i => i.Locations) - .Distinct(StringComparer.OrdinalIgnoreCase) - .Select(i => new DirectoryInfo(i)) - .ToList(); - - if (paths.SelectMany(i => i.EnumerateFiles("*.xml", SearchOption.AllDirectories)) - .Any()) - { - return XbmcMetadata; - } - - if (paths.SelectMany(i => i.EnumerateFiles("*.xml", SearchOption.AllDirectories)) - .Any(i => string.Equals(i.Name, "series.xml", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "movie.xml", StringComparison.OrdinalIgnoreCase))) - { - return MediaBrowserMetadata; - } - } - catch (Exception) - { - - } - - return XbmcMetadata; - } - /// /// Posts the specified configuraiton. /// diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 7289ac0862..ed777cafe0 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1978,6 +1978,7 @@ namespace MediaBrowser.Api.Playback state.TargetPacketLength, state.TargetTimestamp, state.IsTargetAnamorphic, + state.IsTargetCabac, state.TargetRefFrames); if (mediaProfile != null) @@ -2067,6 +2068,7 @@ namespace MediaBrowser.Api.Playback state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, + state.IsTargetCabac, state.TargetRefFrames ).FirstOrDefault() ?? string.Empty; diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 30ba25ae47..97565cdc3d 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -501,7 +501,7 @@ namespace MediaBrowser.Api.Playback.Hls private void AppendPlaylist(StringBuilder builder, string url, int bitrate, string subtitleGroup) { - var header = "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + bitrate.ToString(UsCulture); + var header = "#EXT-X-STREAM-INF:BANDWIDTH=" + bitrate.ToString(UsCulture); if (!string.IsNullOrWhiteSpace(subtitleGroup)) { diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index 6e77e5eabd..35f714cb18 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -1,5 +1,4 @@ -using System.Threading; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Model.Logging; using ServiceStack.Web; using System; @@ -49,9 +48,7 @@ namespace MediaBrowser.Api.Playback.Progressive /// The response stream. public void WriteTo(Stream responseStream) { - var task = WriteToAsync(responseStream); - - Task.WaitAll(task); + WriteToInternal(responseStream); } /// @@ -59,12 +56,12 @@ namespace MediaBrowser.Api.Playback.Progressive /// /// The response stream. /// Task. - public async Task WriteToAsync(Stream responseStream) + private void WriteToInternal(Stream responseStream) { try { - await new ProgressiveFileCopier(_fileSystem, _job) - .StreamFile(Path, responseStream).ConfigureAwait(false); + new ProgressiveFileCopier(_fileSystem, _job) + .StreamFile(Path, responseStream); } catch (Exception ex) { @@ -95,16 +92,16 @@ namespace MediaBrowser.Api.Playback.Progressive _job = job; } - public async Task StreamFile(string path, Stream outputStream) + public void StreamFile(string path, Stream outputStream) { var eofCount = 0; long position = 0; - using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) + using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, false)) { while (eofCount < 15) { - await CopyToAsyncInternal(fs, outputStream, 81920, CancellationToken.None).ConfigureAwait(false); + CopyToInternal(fs, outputStream, 81920); var fsPosition = fs.Position; @@ -118,7 +115,8 @@ namespace MediaBrowser.Api.Playback.Progressive { eofCount++; } - await Task.Delay(100).ConfigureAwait(false); + var task = Task.Delay(100); + Task.WaitAll(task); } else { @@ -130,13 +128,13 @@ namespace MediaBrowser.Api.Playback.Progressive } } - private async Task CopyToAsyncInternal(Stream source, Stream destination, int bufferSize, CancellationToken cancellationToken) + private void CopyToInternal(Stream source, Stream destination, int bufferSize) { byte[] array = new byte[bufferSize]; int count; - while ((count = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) + while ((count = source.Read(array, 0, array.Length)) != 0) { - await destination.WriteAsync(array, 0, count, cancellationToken).ConfigureAwait(false); + destination.Write(array, 0, count); _bytesWritten += count; diff --git a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs index 8f9fa11db1..ada2a98a15 100644 --- a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs +++ b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs @@ -2,7 +2,6 @@ using ServiceStack.Web; using System.Collections.Generic; using System.IO; -using System.Threading.Tasks; namespace MediaBrowser.Api.Playback { @@ -41,22 +40,7 @@ namespace MediaBrowser.Api.Playback /// The response stream. public void WriteTo(Stream responseStream) { - var task = WriteToAsync(responseStream); - - Task.WaitAll(task); - } - - /// - /// Writes to async. - /// - /// The response stream. - /// Task. - public async Task WriteToAsync(Stream responseStream) - { - using (_response) - { - await _response.Content.CopyToAsync(responseStream, 819200).ConfigureAwait(false); - } + _response.Content.CopyTo(responseStream, 819200); } } } diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 8f45c95daa..832eb3ca87 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -418,5 +418,18 @@ namespace MediaBrowser.Api.Playback return false; } } + + public bool? IsTargetCabac + { + get + { + if (Request.Static) + { + return VideoStream == null ? null : VideoStream.IsCabac; + } + + return true; + } + } } } diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 093b904f1f..43db03b428 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -434,21 +434,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager throw exception; } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + options.Url, ex); - - throw new HttpException(ex.Message, ex); - } - catch (WebException ex) - { - throw GetException(ex, options); - } catch (Exception ex) { - _logger.ErrorException("Error getting response from " + options.Url, ex); - - throw; + throw GetException(ex, options); } finally { @@ -636,21 +624,10 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return GetResponseInfo(httpResponse, tempFile, contentLength); } } - catch (OperationCanceledException ex) - { - throw GetTempFileException(ex, options, tempFile); - } - catch (HttpRequestException ex) - { - throw GetTempFileException(ex, options, tempFile); - } - catch (WebException ex) - { - throw GetTempFileException(ex, options, tempFile); - } catch (Exception ex) { - throw GetTempFileException(ex, options, tempFile); + DeleteTempFile(tempFile); + throw GetException(ex, options); } finally { @@ -675,45 +652,26 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// - /// Handles the temp file exception. - /// - /// The ex. - /// The options. - /// The temp file. - /// Task. - /// - private Exception GetTempFileException(Exception ex, HttpRequestOptions options, string tempFile) + private Exception GetException(Exception ex, HttpRequestOptions options) { - var operationCanceledException = ex as OperationCanceledException; + var webException = ex as WebException + ?? ex.InnerException as WebException; + + if (webException != null) + { + return GetException(webException, options); + } + + var operationCanceledException = ex as OperationCanceledException + ?? ex.InnerException as OperationCanceledException; if (operationCanceledException != null) { - // Cleanup - DeleteTempFile(tempFile); - return GetCancellationException(options.Url, options.CancellationToken, operationCanceledException); } _logger.ErrorException("Error getting response from " + options.Url, ex); - // Cleanup - DeleteTempFile(tempFile); - - var httpRequestException = ex as HttpRequestException; - - if (httpRequestException != null) - { - return new HttpException(ex.Message, ex); - } - - var webException = ex as WebException; - - if (webException != null) - { - throw GetException(webException, options); - } - return ex; } diff --git a/MediaBrowser.Controller/Connect/UserLinkResult.cs b/MediaBrowser.Controller/Connect/UserLinkResult.cs index 4ed57cfc2d..16ebfc70a3 100644 --- a/MediaBrowser.Controller/Connect/UserLinkResult.cs +++ b/MediaBrowser.Controller/Connect/UserLinkResult.cs @@ -4,5 +4,7 @@ namespace MediaBrowser.Controller.Connect public class UserLinkResult { public bool IsPending { get; set; } + public bool IsNewUserInvitation { get; set; } + public string GuestDisplayName { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 4b90741c09..a10742f01e 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -74,7 +74,8 @@ namespace MediaBrowser.Controller.Entities { FileInfo = new DirectoryInfo(path), Path = path, - Parent = Parent + Parent = Parent, + CollectionType = CollectionType }; // Gather child folder and files diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 4614f2f8a3..4abdde8ddd 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -736,7 +736,9 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. protected virtual IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { - return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), directoryService, this); + var collectionType = LibraryManager.FindCollectionType(this); + + return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), directoryService, this, collectionType); } /// @@ -745,7 +747,16 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. protected IEnumerable GetCachedChildren() { - return ItemRepository.GetChildren(Id).Select(RetrieveChild).Where(i => i != null); + var childrenItems = ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null); + + //var children = ItemRepository.GetChildren(Id).Select(RetrieveChild).Where(i => i != null).ToList(); + + //if (children.Count != childrenItems.Count) + //{ + // var b = this; + //} + + return childrenItems; } /// @@ -770,6 +781,29 @@ namespace MediaBrowser.Controller.Entities return item; } + private BaseItem RetrieveChild(BaseItem child) + { + var item = LibraryManager.GetMemoryItemById(child.Id); + + if (item != null) + { + if (item is IByReferenceItem) + { + return LibraryManager.GetOrAddByReferenceItem(item); + } + + item.Parent = this; + } + else + { + child.Parent = this; + LibraryManager.RegisterItem(child); + item = child; + } + + return item; + } + public virtual Task> GetItems(InternalItemsQuery query) { var user = query.User; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 951513962c..f935648822 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -17,30 +17,14 @@ namespace MediaBrowser.Controller.Library /// public interface ILibraryManager { - /// - /// Resolves the item. - /// - /// The args. - /// BaseItem. - BaseItem ResolveItem(ItemResolveArgs args); - - /// - /// Resolves a path into a BaseItem - /// - /// The file info. - /// The directory service. - /// The parent. - /// BaseItem. - /// - BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null); - /// /// Resolves the path. /// /// The file information. /// The parent. + /// Type of the collection. /// BaseItem. - BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null); + BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null, string collectionType = null); /// /// Resolves a set of files into a list of BaseItem @@ -49,8 +33,9 @@ namespace MediaBrowser.Controller.Library /// The files. /// The directory service. /// The parent. + /// Type of the collection. /// List{``0}. - List ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent) + List ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, string collectionType = null) where T : BaseItem; /// @@ -151,6 +136,13 @@ namespace MediaBrowser.Controller.Library /// BaseItem. BaseItem GetItemById(Guid id); + /// + /// Gets the memory item by identifier. + /// + /// The identifier. + /// BaseItem. + BaseItem GetMemoryItemById(Guid id); + /// /// Gets the intros. /// diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index c1fcdc9feb..d1692aabf0 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -229,22 +229,6 @@ namespace MediaBrowser.Controller.Library return null; } - /// - /// Gets the name of the meta file by. - /// - /// The name. - /// FileSystemInfo. - /// - public FileSystemInfo GetMetaFileByName(string name) - { - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentNullException(); - } - - return GetFileSystemEntryByName(name); - } - /// /// Determines whether [contains meta file by name] [the specified name]. /// @@ -252,7 +236,12 @@ namespace MediaBrowser.Controller.Library /// true if [contains meta file by name] [the specified name]; otherwise, false. public bool ContainsMetaFileByName(string name) { - return GetMetaFileByName(name) != null; + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(); + } + + return GetFileSystemEntryByName(name) != null; } /// @@ -265,20 +254,13 @@ namespace MediaBrowser.Controller.Library return GetFileSystemEntryByName(name) != null; } - private bool _collectionTypeDiscovered; - private string _collectionType; - public string GetCollectionType() { - if (!_collectionTypeDiscovered) - { - _collectionType = Parent == null ? null : _libraryManager.FindCollectionType(Parent); - _collectionTypeDiscovered = true; - } - - return _collectionType; + return CollectionType; } + public string CollectionType { get; set; } + #region Equality Overrides /// diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs index 34486182b7..c85a8f3354 100644 --- a/MediaBrowser.Controller/Library/TVUtils.cs +++ b/MediaBrowser.Controller/Library/TVUtils.cs @@ -284,7 +284,7 @@ namespace MediaBrowser.Controller.Library { if (IsSeasonFolder(child.FullName, directoryService, fileSystem)) { - logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName); + //logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName); return true; } diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 02bca739f4..edaa15c9df 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Persistence /// The cancellation token. /// Task. Task DeleteItem(Guid id, CancellationToken cancellationToken); - + /// /// Gets the critic reviews. /// @@ -41,6 +41,13 @@ namespace MediaBrowser.Controller.Persistence /// Task{IEnumerable{ItemReview}}. IEnumerable GetCriticReviews(Guid itemId); + /// + /// Gets the children items. + /// + /// The parent identifier. + /// IEnumerable<BaseItem>. + IEnumerable GetChildrenItems(Guid parentId); + /// /// Saves the critic reviews. /// @@ -101,7 +108,7 @@ namespace MediaBrowser.Controller.Persistence /// The type. /// IEnumerable{Guid}. IEnumerable GetItemsOfType(Type type); - + /// /// Saves the children. /// diff --git a/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs b/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs index 7d9c9d8769..5b40073226 100644 --- a/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs +++ b/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs @@ -246,7 +246,7 @@ namespace MediaBrowser.Controller.Resolvers if (config.UseFileCreationTimeForDateAdded) { - item.DateModified = fileSystem.GetCreationTimeUtc(info); + item.DateCreated = fileSystem.GetCreationTimeUtc(info); } else { diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 53a8d5a7cb..d8a2464d64 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -80,6 +80,12 @@ namespace MediaBrowser.Controller.Session /// The last activity date. public DateTime LastActivityDate { get; set; } + /// + /// Gets or sets the last playback check in. + /// + /// The last playback check in. + public DateTime LastPlaybackCheckIn { get; set; } + /// /// Gets or sets the name of the device. /// diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 912612d299..5e08d80311 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -149,6 +149,7 @@ namespace MediaBrowser.Dlna.Didl streamInfo.TargetPacketLength, streamInfo.TranscodeSeekInfo, streamInfo.IsTargetAnamorphic, + streamInfo.IsTargetCabac, streamInfo.TargetRefFrames); foreach (var contentFeature in contentFeatureList) @@ -270,6 +271,7 @@ namespace MediaBrowser.Dlna.Didl streamInfo.TargetPacketLength, streamInfo.TargetTimestamp, streamInfo.IsTargetAnamorphic, + streamInfo.IsTargetCabac, streamInfo.TargetRefFrames); var filename = url.Substring(0, url.IndexOf('?')); diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index 7d06185740..1989c437aa 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -452,19 +452,9 @@ namespace MediaBrowser.Dlna.PlayTo private void AddItemFromId(Guid id, List list) { var item = _libraryManager.GetItemById(id); - if (item.IsFolder) + if (item.MediaType == MediaType.Audio || item.MediaType == MediaType.Video) { - foreach (var childId in _itemRepository.GetChildren(item.Id)) - { - AddItemFromId(childId, list); - } - } - else - { - if (item.MediaType == MediaType.Audio || item.MediaType == MediaType.Video) - { - list.Add(item); - } + list.Add(item); } } @@ -537,6 +527,7 @@ namespace MediaBrowser.Dlna.PlayTo streamInfo.TargetPacketLength, streamInfo.TranscodeSeekInfo, streamInfo.IsTargetAnamorphic, + streamInfo.IsTargetCabac, streamInfo.TargetRefFrames); return list.FirstOrDefault(); diff --git a/MediaBrowser.Dlna/Profiles/Xml/Android.xml b/MediaBrowser.Dlna/Profiles/Xml/Android.xml index 6cc20db406..0b4f9f7b18 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Android.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Android.xml @@ -51,6 +51,7 @@ + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml index b056e31278..90a4ef55d4 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml @@ -29,8 +29,8 @@ DMS-1.50 http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_HD_50_AC3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMA_BASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMA_FULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-matroska:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AC3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_1080i_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_HP_HD_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_LPCM;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_ASP_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_SP_L6_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_NDSD;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_LPCM_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000 40 - true - true + false + false false false diff --git a/MediaBrowser.MediaInfo/MediaInfoLib.cs b/MediaBrowser.MediaInfo/MediaInfoLib.cs index 64842edcbe..fa644aee0a 100644 --- a/MediaBrowser.MediaInfo/MediaInfoLib.cs +++ b/MediaBrowser.MediaInfo/MediaInfoLib.cs @@ -24,6 +24,12 @@ namespace MediaBrowser.MediaInfo result.IsInterlaced = text.IndexOf("interlac", StringComparison.OrdinalIgnoreCase) != -1; } + text = GetValue(lib, videoStreamIndex, new[] { "Format_Settings_CABAC", "Format_Settings_CABAC/String" }); + if (!string.IsNullOrWhiteSpace(text)) + { + result.IsCabac = string.Equals(text, "yes", StringComparison.OrdinalIgnoreCase); + } + int bitDepth; text = GetValue(lib, videoStreamIndex, new[] { "BitDepth", "BitDepth/String" }); @@ -51,6 +57,7 @@ namespace MediaBrowser.MediaInfo public class MediaInfoResult { + public bool? IsCabac { get; set; } public bool? IsInterlaced { get; set; } public int? BitDepth { get; set; } public int? RefFrames { get; set; } diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 45e761f0aa..5c117e6054 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -1088,9 +1088,6 @@ Users\AuthenticationResult.cs - - Weather\WeatherUnits.cs - Properties\SharedVersion.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index f261ac42d7..34fcd819ae 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -1047,9 +1047,6 @@ Users\AuthenticationResult.cs - - Weather\WeatherUnits.cs - Properties\SharedVersion.cs diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 4fedb36d6e..e0a8e239e1 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -19,6 +19,7 @@ namespace MediaBrowser.Model.Dlna int? packetLength, TransportStreamTimestamp? timestamp, bool? isAnamorphic, + bool? isCabac, int? refFrames) { switch (condition.Property) @@ -31,6 +32,8 @@ namespace MediaBrowser.Model.Dlna return true; case ProfileConditionValue.IsAnamorphic: return IsConditionSatisfied(condition, isAnamorphic); + case ProfileConditionValue.IsCabac: + return IsConditionSatisfied(condition, isCabac); case ProfileConditionValue.VideoFramerate: return IsConditionSatisfied(condition, videoFramerate); case ProfileConditionValue.VideoLevel: diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index 5ded415aa5..a3eeecff2f 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -116,6 +116,7 @@ namespace MediaBrowser.Model.Dlna int? packetLength, TranscodeSeekInfo transcodeSeekInfo, bool? isAnamorphic, + bool? isCabac, int? refFrames) { // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none @@ -156,6 +157,7 @@ namespace MediaBrowser.Model.Dlna packetLength, timestamp, isAnamorphic, + isCabac, refFrames); List orgPnValues = new List(); diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 94de34a282..66f5936158 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -281,6 +281,7 @@ namespace MediaBrowser.Model.Dlna int? packetLength, TransportStreamTimestamp timestamp, bool? isAnamorphic, + bool? isCabac, int? refFrames) { container = StringHelper.TrimStart((container ?? string.Empty), '.'); @@ -315,7 +316,7 @@ namespace MediaBrowser.Model.Dlna var anyOff = false; foreach (ProfileCondition c in i.Conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(c, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames)) + if (!conditionProcessor.IsVideoConditionSatisfied(c, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames)) { anyOff = true; break; diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs index 27abf9878e..ae6dc74c8c 100644 --- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs +++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs @@ -16,6 +16,7 @@ VideoProfile = 11, VideoTimestamp = 12, IsAnamorphic = 13, - RefFrames = 14 + RefFrames = 14, + IsCabac = 15 } } \ No newline at end of file diff --git a/MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs b/MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs index 1f27e5991c..04b4a808d4 100644 --- a/MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs +++ b/MediaBrowser.Model/Dlna/Profiles/AndroidProfile.cs @@ -114,7 +114,8 @@ namespace MediaBrowser.Model.Dlna.Profiles new ProfileCondition(ProfileConditionType.LessThanEqual, ProfileConditionValue.Width, "1920"), new ProfileCondition(ProfileConditionType.LessThanEqual, ProfileConditionValue.Height, "1080"), new ProfileCondition(ProfileConditionType.LessThanEqual, ProfileConditionValue.VideoBitDepth, "8"), - new ProfileCondition(ProfileConditionType.NotEquals, ProfileConditionValue.IsAnamorphic, "true") + new ProfileCondition(ProfileConditionType.NotEquals, ProfileConditionValue.IsAnamorphic, "true"), + new ProfileCondition(ProfileConditionType.Equals, ProfileConditionValue.IsCabac, "true") } }, diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 227fb3ad6e..792e6de912 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -419,6 +419,7 @@ namespace MediaBrowser.Model.Dlna string videoProfile = videoStream == null ? null : videoStream.Profile; float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate; bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic; + bool? isCabac = videoStream == null ? null : videoStream.IsCabac; int? audioBitrate = audioStream == null ? null : audioStream.BitRate; int? audioChannels = audioStream == null ? null : audioStream.Channels; @@ -431,7 +432,7 @@ namespace MediaBrowser.Model.Dlna // Check container conditions foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames)) + if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames)) { return null; } @@ -458,7 +459,7 @@ namespace MediaBrowser.Model.Dlna foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames)) + if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames)) { return null; } @@ -647,6 +648,7 @@ namespace MediaBrowser.Model.Dlna } case ProfileConditionValue.AudioProfile: case ProfileConditionValue.IsAnamorphic: + case ProfileConditionValue.IsCabac: case ProfileConditionValue.Has64BitOffsets: case ProfileConditionValue.PacketLength: case ProfileConditionValue.VideoTimestamp: diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 58848ff50e..4c03201f16 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -456,6 +456,19 @@ namespace MediaBrowser.Model.Dlna } } + public bool? IsTargetCabac + { + get + { + if (IsDirectStream) + { + return TargetVideoStream == null ? null : TargetVideoStream.IsCabac; + } + + return true; + } + } + public int? TargetWidth { get diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index b71f68d183..4a9b765c23 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -175,5 +175,11 @@ namespace MediaBrowser.Model.Entities /// /// true if this instance is anamorphic; otherwise, false. public bool? IsAnamorphic { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is cabac. + /// + /// null if [is cabac] contains no value, true if [is cabac]; otherwise, false. + public bool? IsCabac { get; set; } } } diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index bb6f94b110..32f655ae75 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -402,7 +402,6 @@ - diff --git a/MediaBrowser.Model/Querying/ItemsResult.cs b/MediaBrowser.Model/Querying/ItemsResult.cs index b3f771e4b4..3b9c59733c 100644 --- a/MediaBrowser.Model/Querying/ItemsResult.cs +++ b/MediaBrowser.Model/Querying/ItemsResult.cs @@ -5,26 +5,7 @@ namespace MediaBrowser.Model.Querying /// /// Represents the result of a query for items /// - public class ItemsResult + public class ItemsResult : QueryResult { - /// - /// The set of items returned based on sorting, paging, etc - /// - /// The items. - public BaseItemDto[] Items { get; set; } - - /// - /// The total number of records available - /// - /// The total record count. - public int TotalRecordCount { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public ItemsResult() - { - Items = new BaseItemDto[] { }; - } } } diff --git a/MediaBrowser.Model/Weather/WeatherUnits.cs b/MediaBrowser.Model/Weather/WeatherUnits.cs deleted file mode 100644 index d27982e956..0000000000 --- a/MediaBrowser.Model/Weather/WeatherUnits.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace MediaBrowser.Model.Weather -{ - /// - /// Enum WeatherUnits - /// - public enum WeatherUnits - { - /// - /// The fahrenheit - /// - Fahrenheit, - /// - /// The celsius - /// - Celsius - } -} \ No newline at end of file diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index ee7ce7f26b..8e6fff38cc 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -286,6 +286,7 @@ namespace MediaBrowser.Providers.MediaInfo { var result = new MediaInfoLib().GetVideoInfo(video.Path); + videoStream.IsCabac = result.IsCabac ?? videoStream.IsCabac; videoStream.IsInterlaced = result.IsInterlaced ?? videoStream.IsInterlaced; videoStream.BitDepth = result.BitDepth ?? videoStream.BitDepth; videoStream.RefFrames = result.RefFrames; diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs index 0c78136719..2936fec0ec 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Movies { class FanartMovieUpdatesPostScanTask : ILibraryPostScanTask { - private const string UpdatesUrl = "http://api.fanart.tv/webservice/newmovies/{0}/{1}/"; + private const string UpdatesUrl = "http://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}"; /// /// The _HTTP client @@ -118,11 +118,26 @@ namespace MediaBrowser.Providers.Movies return new List(); } - var updates = _jsonSerializer.DeserializeFromString>(json); + var updates = _jsonSerializer.DeserializeFromString>(json); var existingDictionary = existingIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - return updates.Select(i => i.id).Where(existingDictionary.ContainsKey); + return updates.SelectMany(i => + { + var list = new List(); + + if (!string.IsNullOrWhiteSpace(i.imdb_id)) + { + list.Add(i.imdb_id); + } + if (!string.IsNullOrWhiteSpace(i.tmdb_id)) + { + list.Add(i.tmdb_id); + } + + return list; + + }).Where(existingDictionary.ContainsKey); } } } @@ -136,7 +151,7 @@ namespace MediaBrowser.Providers.Movies { _logger.Info("Updating movie " + id); - await FanartMovieImageProvider.Current.DownloadMovieXml(id, cancellationToken).ConfigureAwait(false); + await FanartMovieImageProvider.Current.DownloadMovieJson(id, cancellationToken).ConfigureAwait(false); numComplete++; double percent = numComplete; @@ -157,9 +172,10 @@ namespace MediaBrowser.Providers.Movies return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds; } - public class FanArtUpdate + public class RootObject { - public string id { get; set; } + public string tmdb_id { get; set; } + public string imdb_id { get; set; } public string name { get; set; } public string new_images { get; set; } public string total_images { get; set; } diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index 9af0b17b78..1d47ee9b92 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -1,25 +1,22 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Channels; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; +using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Music; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Xml; namespace MediaBrowser.Providers.Movies { @@ -29,16 +26,19 @@ namespace MediaBrowser.Providers.Movies private readonly IServerConfigurationManager _config; private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; + private readonly IJsonSerializer _json; - private const string FanArtBaseUrl = "http://api.fanart.tv/webservice/movie/{0}/{1}/xml/all/1/1"; + private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3/movies/{1}?api_key={0}"; + // &client_key=52c813aa7b8c8b3bb87f4797532a2f8c internal static FanartMovieImageProvider Current; - public FanartMovieImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem) + public FanartMovieImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json) { _config = config; _httpClient = httpClient; _fileSystem = fileSystem; + _json = json; Current = this; } @@ -88,13 +88,13 @@ namespace MediaBrowser.Providers.Movies if (!string.IsNullOrEmpty(movieId)) { - await EnsureMovieXml(movieId, cancellationToken).ConfigureAwait(false); + await EnsureMovieJson(movieId, cancellationToken).ConfigureAwait(false); - var xmlPath = GetFanartXmlPath(movieId); + var path = GetFanartJsonPath(movieId); try { - AddImages(list, xmlPath, cancellationToken); + AddImages(list, path, cancellationToken); } catch (FileNotFoundException) { @@ -130,198 +130,63 @@ namespace MediaBrowser.Providers.Movies .ThenByDescending(i => i.CommunityRating ?? 0); } - private void AddImages(List list, string xmlPath, CancellationToken cancellationToken) + private void AddImages(List list, string path, CancellationToken cancellationToken) { - using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8)) - { - // Use XmlReader for best performance - using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings - { - CheckCharacters = false, - IgnoreProcessingInstructions = true, - IgnoreComments = true, - ValidationType = ValidationType.None - })) - { - reader.MoveToContent(); + var root = _json.DeserializeFromFile(path); - // Loop through each element - while (reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "movie": - { - using (var subReader = reader.ReadSubtree()) - { - AddImages(list, subReader, cancellationToken); - } - break; - } - - default: - reader.Skip(); - break; - } - } - } - } - } + AddImages(list, root, cancellationToken); } - private void AddImages(List list, XmlReader reader, CancellationToken cancellationToken) + private void AddImages(List list, RootObject obj, CancellationToken cancellationToken) { - reader.MoveToContent(); - - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "hdmoviecleararts": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 1000, 562); - } - break; - } - case "hdmovielogos": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 800, 310); - } - break; - } - case "moviediscs": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Disc, 1000, 1000); - } - break; - } - case "movieposters": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Primary, 1000, 1426); - } - break; - } - case "movielogos": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 400, 155); - } - break; - } - case "moviearts": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 500, 281); - } - break; - } - case "moviethumbs": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 1000, 562); - } - break; - } - case "moviebanners": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Banner, 1000, 185); - } - break; - } - case "moviebackgrounds": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080); - } - break; - } - default: - { - using (reader.ReadSubtree()) - { - } - break; - } - } - } - } + PopulateImages(list, obj.hdmovieclearart, ImageType.Art, 1000, 562); + PopulateImages(list, obj.hdmovielogo, ImageType.Logo, 800, 310); + PopulateImages(list, obj.moviedisc, ImageType.Disc, 1000, 1000); + PopulateImages(list, obj.movieposter, ImageType.Primary, 1000, 1426); + PopulateImages(list, obj.movielogo, ImageType.Logo, 400, 155); + PopulateImages(list, obj.movieart, ImageType.Art, 500, 281); + PopulateImages(list, obj.moviethumb, ImageType.Thumb, 1000, 562); + PopulateImages(list, obj.moviebanner, ImageType.Banner, 1000, 185); + PopulateImages(list, obj.moviebackground, ImageType.Backdrop, 1920, 1080); } - private void PopulateImageCategory(List list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height) + private void PopulateImages(List list, List images, ImageType type, int width, int height) { - reader.MoveToContent(); - - while (reader.Read()) + if (images == null) { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "hdmovielogo": - case "moviedisc": - case "hdmovieclearart": - case "movieposter": - case "movielogo": - case "movieart": - case "moviethumb": - case "moviebanner": - case "moviebackground": - { - var url = reader.GetAttribute("url"); - - if (!string.IsNullOrEmpty(url)) - { - var likesString = reader.GetAttribute("likes"); - int likes; - - var info = new RemoteImageInfo - { - RatingType = RatingType.Likes, - Type = type, - Width = width, - Height = height, - ProviderName = Name, - Url = url, - Language = reader.GetAttribute("lang") - }; - - if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes)) - { - info.CommunityRating = likes; - } - - list.Add(info); - } - break; - } - default: - reader.Skip(); - break; - } - } + return; } + + list.AddRange(images.Select(i => + { + var url = i.url; + + if (!string.IsNullOrEmpty(url)) + { + var likesString = i.likes; + int likes; + + var info = new RemoteImageInfo + { + RatingType = RatingType.Likes, + Type = type, + Width = width, + Height = height, + ProviderName = Name, + Url = url, + Language = i.lang + }; + + if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes)) + { + info.CommunityRating = likes; + } + + return info; + } + + return null; + }).Where(i => i != null)); } public int Order @@ -347,13 +212,17 @@ namespace MediaBrowser.Providers.Movies } var id = item.GetProviderId(MetadataProviders.Tmdb); + if (string.IsNullOrEmpty(id)) + { + id = item.GetProviderId(MetadataProviders.Imdb); + } if (!string.IsNullOrEmpty(id)) { // Process images - var xmlPath = GetFanartXmlPath(id); + var path = GetFanartJsonPath(id); - var fileInfo = new FileInfo(xmlPath); + var fileInfo = new FileInfo(path); return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date; } @@ -364,12 +233,12 @@ namespace MediaBrowser.Providers.Movies /// /// Gets the movie data path. /// - /// The app paths. - /// The TMDB id. + /// The application paths. + /// The identifier. /// System.String. - internal static string GetMovieDataPath(IApplicationPaths appPaths, string tmdbId) + internal static string GetMovieDataPath(IApplicationPaths appPaths, string id) { - var dataPath = Path.Combine(GetMoviesDataPath(appPaths), tmdbId); + var dataPath = Path.Combine(GetMoviesDataPath(appPaths), id); return dataPath; } @@ -386,27 +255,27 @@ namespace MediaBrowser.Providers.Movies return dataPath; } - public string GetFanartXmlPath(string tmdbId) + public string GetFanartJsonPath(string id) { - var movieDataPath = GetMovieDataPath(_config.ApplicationPaths, tmdbId); - return Path.Combine(movieDataPath, "fanart.xml"); + var movieDataPath = GetMovieDataPath(_config.ApplicationPaths, id); + return Path.Combine(movieDataPath, "fanart.json"); } /// - /// Downloads the movie XML. + /// Downloads the movie json. /// - /// The TMDB id. + /// The identifier. /// The cancellation token. /// Task. - internal async Task DownloadMovieXml(string tmdbId, CancellationToken cancellationToken) + internal async Task DownloadMovieJson(string id, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - var url = string.Format(FanArtBaseUrl, FanartArtistProvider.ApiKey, tmdbId); + var url = string.Format(FanArtBaseUrl, FanartArtistProvider.ApiKey, id); - var xmlPath = GetFanartXmlPath(tmdbId); + var path = GetFanartJsonPath(id); - Directory.CreateDirectory(Path.GetDirectoryName(xmlPath)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); using (var response = await _httpClient.Get(new HttpRequestOptions { @@ -416,17 +285,17 @@ namespace MediaBrowser.Providers.Movies }).ConfigureAwait(false)) { - using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true)) + using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { - await response.CopyToAsync(xmlFileStream).ConfigureAwait(false); + await response.CopyToAsync(fileStream).ConfigureAwait(false); } } } private readonly Task _cachedTask = Task.FromResult(true); - internal Task EnsureMovieXml(string tmdbId, CancellationToken cancellationToken) + internal Task EnsureMovieJson(string id, CancellationToken cancellationToken) { - var path = GetFanartXmlPath(tmdbId); + var path = GetFanartJsonPath(id); var fileInfo = _fileSystem.GetFileSystemInfo(path); @@ -438,7 +307,31 @@ namespace MediaBrowser.Providers.Movies } } - return DownloadMovieXml(tmdbId, cancellationToken); + return DownloadMovieJson(id, cancellationToken); + } + + public class Image + { + public string id { get; set; } + public string url { get; set; } + public string lang { get; set; } + public string likes { get; set; } + } + + public class RootObject + { + public string name { get; set; } + public string tmdb_id { get; set; } + public string imdb_id { get; set; } + public List hdmovielogo { get; set; } + public List moviedisc { get; set; } + public List movielogo { get; set; } + public List movieposter { get; set; } + public List hdmovieclearart { get; set; } + public List movieart { get; set; } + public List moviebackground { get; set; } + public List moviebanner { get; set; } + public List moviethumb { get; set; } } } } diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs index 5bc58af915..47c73abbbe 100644 --- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs @@ -7,16 +7,15 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; +using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Music; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Xml; namespace MediaBrowser.Providers.TV { @@ -26,12 +25,14 @@ namespace MediaBrowser.Providers.TV private readonly IServerConfigurationManager _config; private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; + private readonly IJsonSerializer _json; - public FanArtSeasonProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem) + public FanArtSeasonProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json) { _config = config; _httpClient = httpClient; _fileSystem = fileSystem; + _json = json; } public string Name @@ -71,14 +72,14 @@ namespace MediaBrowser.Providers.TV if (!string.IsNullOrEmpty(id) && season.IndexNumber.HasValue) { - await FanartSeriesProvider.Current.EnsureSeriesXml(id, cancellationToken).ConfigureAwait(false); + await FanartSeriesProvider.Current.EnsureSeriesJson(id, cancellationToken).ConfigureAwait(false); - var xmlPath = FanartSeriesProvider.Current.GetFanartXmlPath(id); + var path = FanartSeriesProvider.Current.GetFanartJsonPath(id); try { int seasonNumber = AdjustForSeriesOffset(series, season.IndexNumber.Value); - AddImages(list, seasonNumber, xmlPath, cancellationToken); + AddImages(list, seasonNumber, path, cancellationToken); } catch (FileNotFoundException) { @@ -125,142 +126,67 @@ namespace MediaBrowser.Providers.TV return seasonNumber; } - private void AddImages(List list, int seasonNumber, string xmlPath, CancellationToken cancellationToken) + private void AddImages(List list, int seasonNumber, string path, CancellationToken cancellationToken) { - using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8)) - { - // Use XmlReader for best performance - using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings - { - CheckCharacters = false, - IgnoreProcessingInstructions = true, - IgnoreComments = true, - ValidationType = ValidationType.None - })) - { - reader.MoveToContent(); + var root = _json.DeserializeFromFile(path); - // Loop through each element - while (reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "series": - { - using (var subReader = reader.ReadSubtree()) - { - AddImages(list, subReader, seasonNumber, cancellationToken); - } - break; - } - - default: - reader.Skip(); - break; - } - } - } - } - } + AddImages(list, root, seasonNumber, cancellationToken); } - private void AddImages(List list, XmlReader reader, int seasonNumber, CancellationToken cancellationToken) + private void AddImages(List list, FanartSeriesProvider.RootObject obj, int seasonNumber, CancellationToken cancellationToken) { - reader.MoveToContent(); - - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "seasonthumbs": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281, seasonNumber); - } - break; - } - case "showbackgrounds": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080, seasonNumber); - } - break; - } - default: - { - using (reader.ReadSubtree()) - { - } - break; - } - } - } - } + PopulateImages(list, obj.seasonthumb, ImageType.Thumb, 500, 281, seasonNumber); + PopulateImages(list, obj.showbackground, ImageType.Backdrop, 1920, 1080, seasonNumber); } - private void PopulateImageCategory(List list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, int seasonNumber) + private void PopulateImages(List list, + List images, + ImageType type, + int width, + int height, + int seasonNumber) { - reader.MoveToContent(); - - while (reader.Read()) + if (images == null) { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "seasonthumb": - case "showbackground": - { - var url = reader.GetAttribute("url"); - var season = reader.GetAttribute("season"); - - int imageSeasonNumber; - - if (!string.IsNullOrEmpty(url) && - !string.IsNullOrEmpty(season) && - int.TryParse(season, NumberStyles.Any, _usCulture, out imageSeasonNumber) && - seasonNumber == imageSeasonNumber) - { - var likesString = reader.GetAttribute("likes"); - int likes; - - var info = new RemoteImageInfo - { - RatingType = RatingType.Likes, - Type = type, - Width = width, - Height = height, - ProviderName = Name, - Url = url, - Language = reader.GetAttribute("lang") - }; - - if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes)) - { - info.CommunityRating = likes; - } - - list.Add(info); - } - - break; - } - default: - reader.Skip(); - break; - } - } + return; } + + list.AddRange(images.Select(i => + { + var url = i.url; + var season = i.season; + + int imageSeasonNumber; + + if (!string.IsNullOrEmpty(url) && + !string.IsNullOrEmpty(season) && + int.TryParse(season, NumberStyles.Any, _usCulture, out imageSeasonNumber) && + seasonNumber == imageSeasonNumber) + { + var likesString = i.likes; + int likes; + + var info = new RemoteImageInfo + { + RatingType = RatingType.Likes, + Type = type, + Width = width, + Height = height, + ProviderName = Name, + Url = url, + Language = i.lang + }; + + if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes)) + { + info.CommunityRating = likes; + } + + return info; + } + + return null; + }).Where(i => i != null)); } public int Order @@ -298,9 +224,9 @@ namespace MediaBrowser.Providers.TV if (!String.IsNullOrEmpty(tvdbId)) { // Process images - var imagesXmlPath = FanartSeriesProvider.Current.GetFanartXmlPath(tvdbId); + var imagesFilePath = FanartSeriesProvider.Current.GetFanartJsonPath(tvdbId); - var fileInfo = new FileInfo(imagesXmlPath); + var fileInfo = new FileInfo(imagesFilePath); return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date; } diff --git a/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs b/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs index 33100db730..13920d942d 100644 --- a/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs +++ b/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.TV { class FanArtTvUpdatesPostScanTask : ILibraryPostScanTask { - private const string UpdatesUrl = "http://api.fanart.tv/webservice/newtv/{0}/{1}/"; + private const string UpdatesUrl = "http://webservice.fanart.tv/v3/tv/latest?api_key={0}&date={1}"; /// /// The _HTTP client @@ -150,7 +150,7 @@ namespace MediaBrowser.Providers.TV { _logger.Info("Updating series " + id); - await FanartSeriesProvider.Current.DownloadSeriesXml(id, cancellationToken).ConfigureAwait(false); + await FanartSeriesProvider.Current.DownloadSeriesJson(id, cancellationToken).ConfigureAwait(false); numComplete++; double percent = numComplete; diff --git a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs index 57427ece7c..56945106ad 100644 --- a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs @@ -8,16 +8,15 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; +using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Music; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Xml; namespace MediaBrowser.Providers.TV { @@ -27,16 +26,19 @@ namespace MediaBrowser.Providers.TV private readonly IServerConfigurationManager _config; private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; + private readonly IJsonSerializer _json; - protected string FanArtBaseUrl = "http://api.fanart.tv/webservice/series/{0}/{1}/xml/all/1/1"; + private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3/tv/{1}?api_key={0}"; + // &client_key=52c813aa7b8c8b3bb87f4797532a2f8c internal static FanartSeriesProvider Current { get; private set; } - public FanartSeriesProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem) + public FanartSeriesProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json) { _config = config; _httpClient = httpClient; _fileSystem = fileSystem; + _json = json; Current = this; } @@ -79,13 +81,13 @@ namespace MediaBrowser.Providers.TV if (!string.IsNullOrEmpty(id)) { - await EnsureSeriesXml(id, cancellationToken).ConfigureAwait(false); + await EnsureSeriesJson(id, cancellationToken).ConfigureAwait(false); - var xmlPath = GetFanartXmlPath(id); + var path = GetFanartJsonPath(id); try { - AddImages(list, xmlPath, cancellationToken); + AddImages(list, path, cancellationToken); } catch (FileNotFoundException) { @@ -122,203 +124,72 @@ namespace MediaBrowser.Providers.TV .ThenByDescending(i => i.VoteCount ?? 0); } - private void AddImages(List list, string xmlPath, CancellationToken cancellationToken) + private void AddImages(List list, string path, CancellationToken cancellationToken) { - using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8)) - { - // Use XmlReader for best performance - using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings - { - CheckCharacters = false, - IgnoreProcessingInstructions = true, - IgnoreComments = true, - ValidationType = ValidationType.None - })) - { - reader.MoveToContent(); + var root = _json.DeserializeFromFile(path); - // Loop through each element - while (reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "series": - { - using (var subReader = reader.ReadSubtree()) - { - AddImages(list, subReader, cancellationToken); - } - break; - } - - default: - reader.Skip(); - break; - } - } - } - } - } + AddImages(list, root, cancellationToken); } - private void AddImages(List list, XmlReader reader, CancellationToken cancellationToken) + private void AddImages(List list, RootObject obj, CancellationToken cancellationToken) { - reader.MoveToContent(); - - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "hdtvlogos": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 800, 310); - } - break; - } - case "hdcleararts": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 1000, 562); - } - break; - } - case "clearlogos": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 400, 155); - } - break; - } - case "cleararts": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 500, 281); - } - break; - } - case "showbackgrounds": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080, true); - } - break; - } - case "seasonthumbs": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281); - } - break; - } - case "tvthumbs": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281); - } - break; - } - case "tvbanners": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Banner, 1000, 185); - } - break; - } - case "tvposters": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Primary, 1000, 1426); - } - break; - } - default: - { - using (reader.ReadSubtree()) - { - } - break; - } - } - } - } + PopulateImages(list, obj.hdtvlogo, ImageType.Logo, 800, 310); + PopulateImages(list, obj.hdclearart, ImageType.Art, 1000, 562); + PopulateImages(list, obj.clearlogo, ImageType.Logo, 400, 155); + PopulateImages(list, obj.clearart, ImageType.Art, 500, 281); + PopulateImages(list, obj.showbackground, ImageType.Backdrop, 1920, 1080, true); + PopulateImages(list, obj.seasonthumb, ImageType.Thumb, 500, 281); + PopulateImages(list, obj.tvthumb, ImageType.Thumb, 500, 281); + PopulateImages(list, obj.tvbanner, ImageType.Banner, 1000, 185); + PopulateImages(list, obj.tvposter, ImageType.Primary, 1000, 1426); } - private void PopulateImageCategory(List list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, bool allowSeasonAll = false) + private void PopulateImages(List list, + List images, + ImageType type, + int width, + int height, + bool allowSeasonAll = false) { - reader.MoveToContent(); - - while (reader.Read()) + if (images == null) { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "hdtvlogo": - case "hdclearart": - case "clearlogo": - case "clearart": - case "showbackground": - case "seasonthumb": - case "tvthumb": - case "tvbanner": - case "tvposter": - { - var url = reader.GetAttribute("url"); - var season = reader.GetAttribute("season"); - - var isSeasonValid = string.IsNullOrEmpty(season) || - (allowSeasonAll && string.Equals(season, "all", StringComparison.OrdinalIgnoreCase)); - - if (!string.IsNullOrEmpty(url) && isSeasonValid) - { - var likesString = reader.GetAttribute("likes"); - int likes; - - var info = new RemoteImageInfo - { - RatingType = RatingType.Likes, - Type = type, - Width = width, - Height = height, - ProviderName = Name, - Url = url, - Language = reader.GetAttribute("lang") - }; - - if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes)) - { - info.CommunityRating = likes; - } - - list.Add(info); - } - - break; - } - default: - reader.Skip(); - break; - } - } + return; } + + list.AddRange(images.Select(i => + { + var url = i.url; + var season = i.season; + + var isSeasonValid = string.IsNullOrEmpty(season) || + (allowSeasonAll && string.Equals(season, "all", StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrEmpty(url) && isSeasonValid) + { + var likesString = i.likes; + int likes; + + var info = new RemoteImageInfo + { + RatingType = RatingType.Likes, + Type = type, + Width = width, + Height = height, + ProviderName = Name, + Url = url, + Language = i.lang + }; + + if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes)) + { + info.CommunityRating = likes; + } + + return info; + } + + return null; + }).Where(i => i != null)); } public int Order @@ -361,23 +232,23 @@ namespace MediaBrowser.Providers.TV return dataPath; } - public string GetFanartXmlPath(string tvdbId) + public string GetFanartJsonPath(string tvdbId) { var dataPath = GetSeriesDataPath(_config.ApplicationPaths, tvdbId); - return Path.Combine(dataPath, "fanart.xml"); + return Path.Combine(dataPath, "fanart.json"); } private readonly SemaphoreSlim _ensureSemaphore = new SemaphoreSlim(1, 1); - internal async Task EnsureSeriesXml(string tvdbId, CancellationToken cancellationToken) + internal async Task EnsureSeriesJson(string tvdbId, CancellationToken cancellationToken) { - var xmlPath = GetFanartXmlPath(tvdbId); + var path = GetFanartJsonPath(tvdbId); // Only allow one thread in here at a time since every season will be calling this method, possibly concurrently await _ensureSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { - var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath); + var fileInfo = _fileSystem.GetFileSystemInfo(path); if (fileInfo.Exists) { @@ -387,7 +258,7 @@ namespace MediaBrowser.Providers.TV } } - await DownloadSeriesXml(tvdbId, cancellationToken).ConfigureAwait(false); + await DownloadSeriesJson(tvdbId, cancellationToken).ConfigureAwait(false); } finally { @@ -396,20 +267,20 @@ namespace MediaBrowser.Providers.TV } /// - /// Downloads the series XML. + /// Downloads the series json. /// - /// The TVDB id. + /// The TVDB identifier. /// The cancellation token. /// Task. - internal async Task DownloadSeriesXml(string tvdbId, CancellationToken cancellationToken) + internal async Task DownloadSeriesJson(string tvdbId, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var url = string.Format(FanArtBaseUrl, FanartArtistProvider.ApiKey, tvdbId); - var xmlPath = GetFanartXmlPath(tvdbId); + var path = GetFanartJsonPath(tvdbId); - Directory.CreateDirectory(Path.GetDirectoryName(xmlPath)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); using (var response = await _httpClient.Get(new HttpRequestOptions { @@ -419,9 +290,9 @@ namespace MediaBrowser.Providers.TV }).ConfigureAwait(false)) { - using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true)) + using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { - await response.CopyToAsync(xmlFileStream).ConfigureAwait(false); + await response.CopyToAsync(fileStream).ConfigureAwait(false); } } } @@ -438,14 +309,41 @@ namespace MediaBrowser.Providers.TV if (!String.IsNullOrEmpty(tvdbId)) { // Process images - var imagesXmlPath = GetFanartXmlPath(tvdbId); + var imagesFilePath = GetFanartJsonPath(tvdbId); - var fileInfo = new FileInfo(imagesXmlPath); + var fileInfo = new FileInfo(imagesFilePath); return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date; } return false; } + + public class Image + { + public string id { get; set; } + public string url { get; set; } + public string lang { get; set; } + public string likes { get; set; } + public string season { get; set; } + } + + public class RootObject + { + public string name { get; set; } + public string thetvdb_id { get; set; } + public List clearlogo { get; set; } + public List hdtvlogo { get; set; } + public List clearart { get; set; } + public List showbackground { get; set; } + public List tvthumb { get; set; } + public List seasonposter { get; set; } + public List seasonthumb { get; set; } + public List hdclearart { get; set; } + public List tvbanner { get; set; } + public List characterart { get; set; } + public List tvposter { get; set; } + public List seasonbanner { get; set; } + } } } diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs index 1370b2bf29..4abe56acae 100644 --- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -3,6 +3,8 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.Implementations.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Model.Configuration; @@ -214,6 +216,11 @@ namespace MediaBrowser.Server.Implementations.Configuration DisableMetadataService(typeof(Movie), Configuration, service); DisableMetadataService(typeof(Episode), Configuration, service); DisableMetadataService(typeof(Series), Configuration, service); + DisableMetadataService(typeof(Season), Configuration, service); + DisableMetadataService(typeof(MusicArtist), Configuration, service); + DisableMetadataService(typeof(MusicAlbum), Configuration, service); + DisableMetadataService(typeof(MusicVideo), Configuration, service); + DisableMetadataService(typeof(Video), Configuration, service); } private void DisableMetadataService(Type type, ServerConfiguration config, string service) diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index 88f934d25f..f468606ed0 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -141,6 +141,8 @@ namespace MediaBrowser.Server.Implementations.Connect try { + var localAddress = _appHost.GetSystemInfo().LocalAddress; + var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) && !string.IsNullOrWhiteSpace(ConnectAccessKey); @@ -150,11 +152,12 @@ namespace MediaBrowser.Server.Implementations.Connect { try { - await UpdateServerRegistration(wanApiAddress).ConfigureAwait(false); + await UpdateServerRegistration(wanApiAddress, localAddress).ConfigureAwait(false); } catch (HttpException ex) { - if (!ex.StatusCode.HasValue || !new[] { HttpStatusCode.NotFound, HttpStatusCode.Unauthorized }.Contains(ex.StatusCode.Value)) + if (!ex.StatusCode.HasValue || + !new[] { HttpStatusCode.NotFound, HttpStatusCode.Unauthorized }.Contains(ex.StatusCode.Value)) { throw; } @@ -165,7 +168,7 @@ namespace MediaBrowser.Server.Implementations.Connect if (createNewRegistration) { - await CreateServerRegistration(wanApiAddress).ConfigureAwait(false); + await CreateServerRegistration(wanApiAddress, localAddress).ConfigureAwait(false); } await RefreshAuthorizationsInternal(true, CancellationToken.None).ConfigureAwait(false); @@ -176,7 +179,7 @@ namespace MediaBrowser.Server.Implementations.Connect } } - private async Task CreateServerRegistration(string wanApiAddress) + private async Task CreateServerRegistration(string wanApiAddress, string localAddress) { var url = "Servers"; url = GetConnectUrl(url); @@ -188,6 +191,11 @@ namespace MediaBrowser.Server.Implementations.Connect {"systemId", _appHost.SystemId} }; + if (!string.IsNullOrWhiteSpace(localAddress)) + { + postData["localAddress"] = localAddress; + } + using (var stream = await _httpClient.Post(url, postData, CancellationToken.None).ConfigureAwait(false)) { var data = _json.DeserializeFromStream(stream); @@ -199,24 +207,31 @@ namespace MediaBrowser.Server.Implementations.Connect } } - private async Task UpdateServerRegistration(string wanApiAddress) + private async Task UpdateServerRegistration(string wanApiAddress, string localAddress) { var url = "Servers"; url = GetConnectUrl(url); url += "?id=" + ConnectServerId; + var postData = new Dictionary + { + {"name", _appHost.FriendlyName}, + {"url", wanApiAddress}, + {"systemId", _appHost.SystemId} + }; + + if (!string.IsNullOrWhiteSpace(localAddress)) + { + postData["localAddress"] = localAddress; + } + var options = new HttpRequestOptions { Url = url, CancellationToken = CancellationToken.None }; - options.SetPostData(new Dictionary - { - {"name", _appHost.FriendlyName}, - {"url", wanApiAddress}, - {"systemId", _appHost.SystemId} - }); + options.SetPostData(postData); SetServerAccessToken(options); @@ -405,15 +420,46 @@ namespace MediaBrowser.Server.Implementations.Connect throw new ArgumentNullException("connectUsername"); } - var connectUser = await GetConnectUser(new ConnectUserQuery - { - Name = connectUsername + string connectUserId = null; + var result = new UserLinkResult(); - }, CancellationToken.None).ConfigureAwait(false); - - if (!connectUser.IsActive) + try { - throw new ArgumentException("The Media Browser account has been disabled."); + var connectUser = await GetConnectUser(new ConnectUserQuery + { + Name = connectUsername + + }, CancellationToken.None).ConfigureAwait(false); + + if (!connectUser.IsActive) + { + throw new ArgumentException("The Media Browser account has been disabled."); + } + + connectUserId = connectUser.Id; + result.GuestDisplayName = connectUser.Name; + } + catch (HttpException ex) + { + if (!ex.StatusCode.HasValue || + ex.StatusCode.Value != HttpStatusCode.NotFound || + !Validator.EmailIsValid(connectUsername)) + { + throw; + } + } + + var sendingUser = GetUser(sendingUserId); + var requesterUserName = sendingUser.ConnectUserName; + + if (string.IsNullOrWhiteSpace(requesterUserName)) + { + requesterUserName = sendingUser.Name; + } + + if (string.IsNullOrWhiteSpace(connectUserId)) + { + return await SendNewUserInvitation(requesterUserName, connectUsername).ConfigureAwait(false); } var url = GetConnectUrl("ServerAuthorizations"); @@ -425,18 +471,11 @@ namespace MediaBrowser.Server.Implementations.Connect }; var accessToken = Guid.NewGuid().ToString("N"); - var sendingUser = GetUser(sendingUserId); - - var requesterUserName = sendingUser.ConnectUserName; - if (string.IsNullOrWhiteSpace(requesterUserName)) - { - requesterUserName = sendingUser.Name; - } var postData = new Dictionary { {"serverId", ConnectServerId}, - {"userId", connectUser.Id}, + {"userId", connectUserId}, {"userType", "Guest"}, {"accessToken", accessToken}, {"requesterUserName", requesterUserName} @@ -446,8 +485,6 @@ namespace MediaBrowser.Server.Implementations.Connect SetServerAccessToken(options); - var result = new UserLinkResult(); - // No need to examine the response using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content) { @@ -461,6 +498,36 @@ namespace MediaBrowser.Server.Implementations.Connect return result; } + private async Task SendNewUserInvitation(string fromName, string email) + { + var url = GetConnectUrl("users/invite"); + + var options = new HttpRequestOptions + { + Url = url, + CancellationToken = CancellationToken.None + }; + + var postData = new Dictionary + { + {"email", email}, + {"requesterUserName", fromName} + }; + + options.SetPostData(postData); + + // No need to examine the response + using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content) + { + } + + return new UserLinkResult + { + IsNewUserInvitation = true, + GuestDisplayName = email + }; + } + public Task RemoveConnect(string userId) { var user = GetUser(userId); @@ -586,6 +653,9 @@ namespace MediaBrowser.Server.Implementations.Connect if (connectEntry == null) { + var deleteUser = user.ConnectLinkType.HasValue && + user.ConnectLinkType.Value == UserLinkType.Guest; + user.ConnectUserId = null; user.ConnectAccessKey = null; user.ConnectUserName = null; @@ -593,7 +663,7 @@ namespace MediaBrowser.Server.Implementations.Connect await _userManager.UpdateUser(user).ConfigureAwait(false); - if (user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest) + if (deleteUser) { _logger.Debug("Deleting guest user {0}", user.Name); await _userManager.DeleteUser(user).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Connect/Validator.cs b/MediaBrowser.Server.Implementations/Connect/Validator.cs new file mode 100644 index 0000000000..b217da32ac --- /dev/null +++ b/MediaBrowser.Server.Implementations/Connect/Validator.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Connect +{ + public static class Validator + { + static Regex ValidEmailRegex = CreateValidEmailRegex(); + + /// + /// Taken from http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx + /// + /// + private static Regex CreateValidEmailRegex() + { + string validEmailPattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|" + + @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(? - /// Resolves a path into a BaseItem - /// - /// The file info. - /// The directory service. - /// The parent. - /// BaseItem. - /// fileInfo - public BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null) + public BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null) { if (fileInfo == null) { @@ -554,7 +546,8 @@ namespace MediaBrowser.Server.Implementations.Library { Parent = parent, Path = fileInfo.FullName, - FileInfo = fileInfo + FileInfo = fileInfo, + CollectionType = collectionType }; // Return null if ignore rules deem that we should do so @@ -622,15 +615,7 @@ namespace MediaBrowser.Server.Implementations.Library return !args.ContainsFileSystemEntryByName(".ignore"); } - /// - /// Resolves a set of files into a list of BaseItem - /// - /// - /// The files. - /// The directory service. - /// The parent. - /// List{``0}. - public List ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent) + public List ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, string collectionType = null) where T : BaseItem { var list = new List(); @@ -639,7 +624,7 @@ namespace MediaBrowser.Server.Implementations.Library { try { - var item = ResolvePath(f, directoryService, parent) as T; + var item = ResolvePath(f, directoryService, parent, collectionType) as T; if (item != null) { @@ -1190,6 +1175,20 @@ namespace MediaBrowser.Server.Implementations.Library return item; } + public BaseItem GetMemoryItemById(Guid id) + { + if (id == Guid.Empty) + { + throw new ArgumentNullException("id"); + } + + BaseItem item; + + LibraryItemsCache.TryGetValue(id, out item); + + return item; + } + /// /// Gets the intros. /// @@ -1497,14 +1496,10 @@ namespace MediaBrowser.Server.Implementations.Library return null; } - var collectionTypes = _userManager.Users - .Select(i => i.RootFolder) - .Distinct() - .SelectMany(i => i.Children) + var collectionTypes = GetUserRootFolder().Children .OfType() - .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path)) + .Where(i => !string.IsNullOrEmpty(i.CollectionType) && (string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path))) .Select(i => i.CollectionType) - .Where(i => !string.IsNullOrEmpty(i)) .Distinct() .ToList(); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 7f15dce2d1..231b807d8e 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -82,29 +82,29 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { if (string.Equals(collectionType, CollectionType.Trailers, StringComparison.OrdinalIgnoreCase)) { - return FindMovie(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false); + return FindMovie(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false, collectionType); } if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false); + return FindMovie(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false, collectionType); } if (string.Equals(collectionType, CollectionType.AdultVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie