diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-10-23 00:26:01 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-10-23 00:26:01 -0400 |
| commit | 5a5b48feff3a0b0a660aaaa9bdfd04fd0fe711ed (patch) | |
| tree | 47079574a89158a371f91392992e9ebe9b7840ba | |
| parent | 35f40993b2b85efc6fbb677d373b337aebfe0465 (diff) | |
added new cabac value
56 files changed, 766 insertions, 873 deletions
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; - } - /// <summary> /// Posts the specified configuraiton. /// </summary> 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 /// <param name="responseStream">The response stream.</param> public void WriteTo(Stream responseStream) { - var task = WriteToAsync(responseStream); - - Task.WaitAll(task); + WriteToInternal(responseStream); } /// <summary> @@ -59,12 +56,12 @@ namespace MediaBrowser.Api.Playback.Progressive /// </summary> /// <param name="responseStream">The response stream.</param> /// <returns>Task.</returns> - 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 /// <param name="responseStream">The response stream.</param> public void WriteTo(Stream responseStream) { - var task = WriteToAsync(responseStream); - - Task.WaitAll(task); - } - - /// <summary> - /// Writes to async. - /// </summary> - /// <param name="responseStream">The response stream.</param> - /// <returns>Task.</returns> - 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,44 +652,25 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// <summary> - /// Handles the temp file exception. - /// </summary> - /// <param name="ex">The ex.</param> - /// <param name="options">The options.</param> - /// <param name="tempFile">The temp file.</param> - /// <returns>Task.</returns> - /// <exception cref="HttpException"></exception> - 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 (operationCanceledException != null) + if (webException != null) { - // Cleanup - DeleteTempFile(tempFile); - - return GetCancellationException(options.Url, options.CancellationToken, operationCanceledException); + return GetException(webException, options); } - _logger.ErrorException("Error getting response from " + options.Url, ex); - - // Cleanup - DeleteTempFile(tempFile); - - var httpRequestException = ex as HttpRequestException; + var operationCanceledException = ex as OperationCanceledException + ?? ex.InnerException as OperationCanceledException; - if (httpRequestException != null) + if (operationCanceledException != null) { - return new HttpException(ex.Message, ex); + return GetCancellationException(options.Url, options.CancellationToken, operationCanceledException); } - var webException = ex as WebException; - - if (webException != null) - { - throw GetException(webException, options); - } + _logger.ErrorException("Error getting response from " + options.Url, ex); 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 /// <returns>IEnumerable{BaseItem}.</returns> protected virtual IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService) { - return LibraryManager.ResolvePaths<BaseItem>(GetFileSystemChildren(directoryService), directoryService, this); + var collectionType = LibraryManager.FindCollectionType(this); + + return LibraryManager.ResolvePaths<BaseItem>(GetFileSystemChildren(directoryService), directoryService, this, collectionType); } /// <summary> @@ -745,7 +747,16 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{BaseItem}.</returns> protected IEnumerable<BaseItem> 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; } /// <summary> @@ -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<QueryResult<BaseItem>> 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 @@ -18,29 +18,13 @@ namespace MediaBrowser.Controller.Library public interface ILibraryManager { /// <summary> - /// Resolves the item. - /// </summary> - /// <param name="args">The args.</param> - /// <returns>BaseItem.</returns> - BaseItem ResolveItem(ItemResolveArgs args); - - /// <summary> - /// Resolves a path into a BaseItem - /// </summary> - /// <param name="fileInfo">The file info.</param> - /// <param name="directoryService">The directory service.</param> - /// <param name="parent">The parent.</param> - /// <returns>BaseItem.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null); - - /// <summary> /// Resolves the path. /// </summary> /// <param name="fileInfo">The file information.</param> /// <param name="parent">The parent.</param> + /// <param name="collectionType">Type of the collection.</param> /// <returns>BaseItem.</returns> - BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null); + BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null, string collectionType = null); /// <summary> /// Resolves a set of files into a list of BaseItem @@ -49,8 +33,9 @@ namespace MediaBrowser.Controller.Library /// <param name="files">The files.</param> /// <param name="directoryService">The directory service.</param> /// <param name="parent">The parent.</param> + /// <param name="collectionType">Type of the collection.</param> /// <returns>List{``0}.</returns> - List<T> ResolvePaths<T>(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent) + List<T> ResolvePaths<T>(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent, string collectionType = null) where T : BaseItem; /// <summary> @@ -152,6 +137,13 @@ namespace MediaBrowser.Controller.Library BaseItem GetItemById(Guid id); /// <summary> + /// Gets the memory item by identifier. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>BaseItem.</returns> + BaseItem GetMemoryItemById(Guid id); + + /// <summary> /// Gets the intros. /// </summary> /// <param name="item">The item.</param> 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 @@ -230,29 +230,18 @@ namespace MediaBrowser.Controller.Library } /// <summary> - /// Gets the name of the meta file by. + /// Determines whether [contains meta file by name] [the specified name]. /// </summary> /// <param name="name">The name.</param> - /// <returns>FileSystemInfo.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public FileSystemInfo GetMetaFileByName(string name) + /// <returns><c>true</c> if [contains meta file by name] [the specified name]; otherwise, <c>false</c>.</returns> + public bool ContainsMetaFileByName(string name) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(); } - return GetFileSystemEntryByName(name); - } - - /// <summary> - /// Determines whether [contains meta file by name] [the specified name]. - /// </summary> - /// <param name="name">The name.</param> - /// <returns><c>true</c> if [contains meta file by name] [the specified name]; otherwise, <c>false</c>.</returns> - public bool ContainsMetaFileByName(string name) - { - return GetMetaFileByName(name) != null; + return GetFileSystemEntryByName(name) != null; } /// <summary> @@ -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 /// <summary> 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 /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> Task DeleteItem(Guid id, CancellationToken cancellationToken); - + /// <summary> /// Gets the critic reviews. /// </summary> @@ -42,6 +42,13 @@ namespace MediaBrowser.Controller.Persistence IEnumerable<ItemReview> GetCriticReviews(Guid itemId); /// <summary> + /// Gets the children items. + /// </summary> + /// <param name="parentId">The parent identifier.</param> + /// <returns>IEnumerable<BaseItem>.</returns> + IEnumerable<BaseItem> GetChildrenItems(Guid parentId); + + /// <summary> /// Saves the critic reviews. /// </summary> /// <param name="itemId">The item id.</param> @@ -101,7 +108,7 @@ namespace MediaBrowser.Controller.Persistence /// <param name="type">The type.</param> /// <returns>IEnumerable{Guid}.</returns> IEnumerable<BaseItem> GetItemsOfType(Type type); - + /// <summary> /// Saves the children. /// </summary> 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 @@ -81,6 +81,12 @@ namespace MediaBrowser.Controller.Session public DateTime LastActivityDate { get; set; } /// <summary> + /// Gets or sets the last playback check in. + /// </summary> + /// <value>The last playback check in.</value> + public DateTime LastPlaybackCheckIn { get; set; } + + /// <summary> /// Gets or sets the name of the device. /// </summary> /// <value>The name of the device.</value> 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<BaseItem> 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 @@ <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="false" /> <ProfileCondition condition="LessThanEqual" property="VideoBitDepth" value="8" isRequired="false" /> <ProfileCondition condition="NotEquals" property="IsAnamorphic" value="true" isRequired="false" /> + <ProfileCondition condition="Equals" property="IsCabac" value="true" isRequired="false" /> </Conditions> </CodecProfile> <CodecProfile type="Video"> 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 @@ <XDlnaDoc>DMS-1.50</XDlnaDoc> <ProtocolInfo>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</ProtocolInfo> <TimelineOffsetSeconds>40</TimelineOffsetSeconds> - <RequiresPlainVideoItems>true</RequiresPlainVideoItems> - <RequiresPlainFolders>true</RequiresPlainFolders> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> <SupportsDirectRemoteContent>false</SupportsDirectRemoteContent> <SupportsCustomHttpHeaders>false</SupportsCustomHttpHeaders> <XmlRootAttributes /> 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 @@ <Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs"> <Link>Users\AuthenticationResult.cs</Link> </Compile> - <Compile Include="..\MediaBrowser.Model\Weather\WeatherUnits.cs"> - <Link>Weather\WeatherUnits.cs</Link> - </Compile> <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> 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 @@ <Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs"> <Link>Users\AuthenticationResult.cs</Link> </Compile> - <Compile Include="..\MediaBrowser.Model\Weather\WeatherUnits.cs"> - <Link>Weather\WeatherUnits.cs</Link> - </Compile> <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> 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<string> orgPnValues = new List<string>(); 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 /// </summary> /// <value><c>true</c> if this instance is anamorphic; otherwise, <c>false</c>.</value> public bool? IsAnamorphic { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is cabac. + /// </summary> + /// <value><c>null</c> if [is cabac] contains no value, <c>true</c> if [is cabac]; otherwise, <c>false</c>.</value> + 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 @@ <Compile Include="Updates\PackageInfo.cs" /> <Compile Include="Updates\PackageVersionInfo.cs" /> <Compile Include="Users\AuthenticationResult.cs" /> - <Compile Include="Weather\WeatherUnits.cs" /> <None Include="Fody.targets" /> <None Include="FodyWeavers.xml" /> <None Include="MediaBrowser.Model.snk" /> 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 /// <summary> /// Represents the result of a query for items /// </summary> - public class ItemsResult + public class ItemsResult : QueryResult<BaseItemDto> { - /// <summary> - /// The set of items returned based on sorting, paging, etc - /// </summary> - /// <value>The items.</value> - public BaseItemDto[] Items { get; set; } - - /// <summary> - /// The total number of records available - /// </summary> - /// <value>The total record count.</value> - public int TotalRecordCount { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="ItemsResult"/> class. - /// </summary> - 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 -{ - /// <summary> - /// Enum WeatherUnits - /// </summary> - public enum WeatherUnits - { - /// <summary> - /// The fahrenheit - /// </summary> - Fahrenheit, - /// <summary> - /// The celsius - /// </summary> - 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}"; /// <summary> /// The _HTTP client @@ -118,11 +118,26 @@ namespace MediaBrowser.Providers.Movies return new List<string>(); } - var updates = _jsonSerializer.DeserializeFromString<List<FanartUpdatesPostScanTask.FanArtUpdate>>(json); + var updates = _jsonSerializer.DeserializeFromString<List<RootObject>>(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<string>(); + + 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<RemoteImageInfo> list, string xmlPath, CancellationToken cancellationToken) + private void AddImages(List<RemoteImageInfo> 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(); - - // Loop through each element - while (reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); + var root = _json.DeserializeFromFile<RootObject>(path); - 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<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken) + private void AddImages(List<RemoteImageInfo> 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<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height) + private void PopulateImages(List<RemoteImageInfo> list, List<Image> images, ImageType type, int width, int height) { - reader.MoveToContent(); + if (images == null) + { + return; + } - while (reader.Read()) + list.AddRange(images.Select(i => { - cancellationToken.ThrowIfCancellationRequested(); + var url = i.url; - if (reader.NodeType == XmlNodeType.Element) + if (!string.IsNullOrEmpty(url)) { - switch (reader.Name) + 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)) { - 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; + 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 /// <summary> /// Gets the movie data path. /// </summary> - /// <param name="appPaths">The app paths.</param> - /// <param name="tmdbId">The TMDB id.</param> + /// <param name="appPaths">The application paths.</param> + /// <param name="id">The identifier.</param> /// <returns>System.String.</returns> - 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"); } /// <summary> - /// Downloads the movie XML. + /// Downloads the movie json. /// </summary> - /// <param name="tmdbId">The TMDB id.</param> + /// <param name="id">The identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - 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<Image> hdmovielogo { get; set; } + public List<Image> moviedisc { get; set; } + public List<Image> movielogo { get; set; } + public List<Image> movieposter { get; set; } + public List<Image> hdmovieclearart { get; set; } + public List<Image> movieart { get; set; } + public List<Image> moviebackground { get; set; } + public List<Image> moviebanner { get; set; } + public List<Image> 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<RemoteImageInfo> list, int seasonNumber, string xmlPath, CancellationToken cancellationToken) + private void AddImages(List<RemoteImageInfo> 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<FanartSeriesProvider.RootObject>(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<RemoteImageInfo> list, XmlReader reader, int seasonNumber, CancellationToken cancellationToken) + private void AddImages(List<RemoteImageInfo> 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<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, int seasonNumber) + private void PopulateImages(List<RemoteImageInfo> list, + List<FanartSeriesProvider.Image> images, + ImageType type, + int width, + int height, + int seasonNumber) { - reader.MoveToContent(); + if (images == null) + { + return; + } - while (reader.Read()) + list.AddRange(images.Select(i => { - cancellationToken.ThrowIfCancellationRequested(); + var url = i.url; + var season = i.season; - if (reader.NodeType == XmlNodeType.Element) + int imageSeasonNumber; + + if (!string.IsNullOrEmpty(url) && + !string.IsNullOrEmpty(season) && + int.TryParse(season, NumberStyles.Any, _usCulture, out imageSeasonNumber) && + seasonNumber == imageSeasonNumber) { - switch (reader.Name) + 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)) { - 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; + 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}"; /// <summary> /// 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<RemoteImageInfo> list, string xmlPath, CancellationToken cancellationToken) + private void AddImages(List<RemoteImageInfo> 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(); - - // Loop through each element - while (reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); + var root = _json.DeserializeFromFile<RootObject>(path); - 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<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken) + private void AddImages(List<RemoteImageInfo> 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<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, bool allowSeasonAll = false) + private void PopulateImages(List<RemoteImageInfo> list, + List<Image> images, + ImageType type, + int width, + int height, + bool allowSeasonAll = false) { - reader.MoveToContent(); + if (images == null) + { + return; + } - while (reader.Read()) + list.AddRange(images.Select(i => { - cancellationToken.ThrowIfCancellationRequested(); + var url = i.url; + var season = i.season; + + var isSeasonValid = string.IsNullOrEmpty(season) || + (allowSeasonAll && string.Equals(season, "all", StringComparison.OrdinalIgnoreCase)); - if (reader.NodeType == XmlNodeType.Element) + if (!string.IsNullOrEmpty(url) && isSeasonValid) { - switch (reader.Name) + 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)) { - 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; + 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 } /// <summary> - /// Downloads the series XML. + /// Downloads the series json. /// </summary> - /// <param name="tvdbId">The TVDB id.</param> + /// <param name="tvdbId">The TVDB identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - 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<Image> clearlogo { get; set; } + public List<Image> hdtvlogo { get; set; } + public List<Image> clearart { get; set; } + public List<Image> showbackground { get; set; } + public List<Image> tvthumb { get; set; } + public List<Image> seasonposter { get; set; } + public List<Image> seasonthumb { get; set; } + public List<Image> hdclearart { get; set; } + public List<Image> tvbanner { get; set; } + public List<Image> characterart { get; set; } + public List<Image> tvposter { get; set; } + public List<Image> 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<ServerRegistrationResponse>(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<string, string> + { + {"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<string, string> - { - {"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 + string connectUserId = null; + var result = new UserLinkResult(); + + try { - Name = connectUsername + var connectUser = await GetConnectUser(new ConnectUserQuery + { + Name = connectUsername - }, CancellationToken.None).ConfigureAwait(false); + }, CancellationToken.None).ConfigureAwait(false); - if (!connectUser.IsActive) + if (!connectUser.IsActive) + { + throw new ArgumentException("The Media Browser account has been disabled."); + } + + connectUserId = connectUser.Id; + result.GuestDisplayName = connectUser.Name; + } + catch (HttpException ex) { - throw new ArgumentException("The Media Browser account has been disabled."); + 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<string, string> { {"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<UserLinkResult> SendNewUserInvitation(string fromName, string email) + { + var url = GetConnectUrl("users/invite"); + + var options = new HttpRequestOptions + { + Url = url, + CancellationToken = CancellationToken.None + }; + + var postData = new Dictionary<string, string> + { + {"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(); + + /// <summary> + /// Taken from http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx + /// </summary> + /// <returns></returns> + private static Regex CreateValidEmailRegex() + { + string validEmailPattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|" + + @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)" + + @"@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$"; + + return new Regex(validEmailPattern, RegexOptions.IgnoreCase); + } + + internal static bool EmailIsValid(string emailAddress) + { + bool isValid = ValidEmailRegex.IsMatch(emailAddress); + + return isValid; + } + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 0e297816d9..98f895616b 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -205,8 +205,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First()); _listener = _supportsNativeWebSocket && NativeWebSocket.IsSupported - //? _listener = new HttpListenerServer(_logger, OnRequestReceived) - ? _listener = new WebSocketSharpListener(_logger, OnRequestReceived) + ? _listener = new HttpListenerServer(_logger, OnRequestReceived) + //? _listener = new WebSocketSharpListener(_logger, OnRequestReceived) : _listener = new WebSocketSharpListener(_logger, OnRequestReceived); _listener.WebSocketHandler = WebSocketHandler; diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index e902b939b2..d3d71e0f93 100644 --- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -3,7 +3,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; using System; -using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 71e1b1087e..13ea7fb447 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -530,20 +530,12 @@ namespace MediaBrowser.Server.Implementations.Library return item; } - public BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null) + public BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null, string collectionType = null) { - return ResolvePath(fileInfo, new DirectoryService(_logger), parent); + return ResolvePath(fileInfo, new DirectoryService(_logger), parent, collectionType); } - /// <summary> - /// Resolves a path into a BaseItem - /// </summary> - /// <param name="fileInfo">The file info.</param> - /// <param name="directoryService">The directory service.</param> - /// <param name="parent">The parent.</param> - /// <returns>BaseItem.</returns> - /// <exception cref="System.ArgumentNullException">fileInfo</exception> - 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"); } - /// <summary> - /// Resolves a set of files into a list of BaseItem - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="files">The files.</param> - /// <param name="directoryService">The directory service.</param> - /// <param name="parent">The parent.</param> - /// <returns>List{``0}.</returns> - public List<T> ResolvePaths<T>(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent) + public List<T> ResolvePaths<T>(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent, string collectionType = null) where T : BaseItem { var list = new List<T>(); @@ -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; + } + /// <summary> /// Gets the intros. /// </summary> @@ -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<ICollectionFolder>() - .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<Trailer>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false); + return FindMovie<Trailer>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false, collectionType); } if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false); + return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false, collectionType); } if (string.Equals(collectionType, CollectionType.AdultVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, false); + return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, false, collectionType); } if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, false); + return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, false, collectionType); } if (string.IsNullOrEmpty(collectionType) || string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, true); + return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, true, collectionType); } return null; @@ -190,7 +190,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies /// <param name="directoryService">The directory service.</param> /// <param name="supportMultiFileItems">if set to <c>true</c> [support multi file items].</param> /// <returns>Movie.</returns> - private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, bool supportMultiFileItems, bool supportsMultipleSources) + private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, bool supportMultiFileItems, bool supportsMultipleSources, string collectionType) where T : Video, new() { var movies = new List<T>(); @@ -239,7 +239,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { FileInfo = child, Path = child.FullName, - Parent = parent + Parent = parent, + CollectionType = collectionType }; var item = ResolveVideo<T>(childArgs); diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 929c3143d3..21c8ba8898 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -75,7 +75,7 @@ "ButtonClose": "Close", "LabelAllPlaysSentToPlayer": "All plays will be sent to the selected player.", "MessageInvalidUser": "Invalid username or password. Please try again.", - "HeaderLoginFailure": "Login Failure", + "HeaderLoginFailure": "Login Failure", "HeaderAllRecordings": "All Recordings", "RecommendationBecauseYouLike": "Because you like {0}", "RecommendationBecauseYouWatched": "Because you watched {0}", @@ -613,5 +613,8 @@ "LabelEnableCameraUploadForHelp": "Uploads will occur automatically in the background when signed into Media Browser.", "ErrorMessageStartHourGreaterThanEnd": "End time must be greater than the start time.", "ButtonLibraryAccess": "Library access", - "ButtonParentalControl": "Parental control" + "ButtonParentalControl": "Parental control", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Media Browser." } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 2397924445..3231593d43 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1166,6 +1166,7 @@ "OptionSaveMetadataAsHidden": "Save metadata and images as hidden files", "LabelExtractChaptersDuringLibraryScan": "Extract chapter images during the library scan", "LabelExtractChaptersDuringLibraryScanHelp": "If enabled, chapter images will be extracted when videos are imported during the library scan. If disabled they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.", + "LabelConnectGuestUserName": "Their Media Browser username or email address:", "LabelConnectUserName": "Media Browser username/email:", "LabelConnectUserNameHelp": "Connect this user to a Media Browser account to enable easy sign-in access from Media Browser any app without having to know the server ip address.", "ButtonLearnMoreAboutMediaBrowserConnect": "Learn more about Media Browser Connect", @@ -1229,7 +1230,7 @@ "LabelCustomDeviceDisplayName": "Display name:", "LabelCustomDeviceDisplayNameHelp": "Supply a custom display name or leave empty to use the name reported by the device.", "HeaderInviteUser": "Invite User", - "LabelConnectInviteUserHelp": "This is the username or email that your friend uses to sign in to the Media Browser website.", + "LabelConnectGuestUserNameHelp": "This is the username that your friend uses to sign in to the Media Browser website, or their email address.", "HeaderInviteUserHelp": "Sharing your media with friends is easier than ever before with Media Browser Connect.", "ButtonSendInvitation": "Send Invitation", "HeaderGuests": "Guests", diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 474ae5beb6..38d5eb072f 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -119,6 +119,7 @@ <Compile Include="Connect\ConnectData.cs" /> <Compile Include="Connect\ConnectManager.cs" /> <Compile Include="Connect\Responses.cs" /> + <Compile Include="Connect\Validator.cs" /> <Compile Include="Devices\DeviceManager.cs" /> <Compile Include="Devices\DeviceRepository.cs" /> <Compile Include="Devices\CameraUploadsFolder.cs" /> diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 70362654e6..cd79282909 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -257,7 +257,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _writeLock.Release(); } } - + /// <summary> /// Internal retrieve from items or users table /// </summary> @@ -473,6 +473,34 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + public IEnumerable<BaseItem> GetChildrenItems(Guid parentId) + { + if (parentId == Guid.Empty) + { + throw new ArgumentNullException("parentId"); + } + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "select type,data from TypedBaseItems where guid in (select ItemId from ChildrenIds where ParentId = @ParentId)"; + + cmd.Parameters.Add(cmd, "@ParentId", DbType.Guid).Value = parentId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + var item = GetItem(reader); + + if (item != null) + { + yield return item; + } + } + } + } + } + public IEnumerable<BaseItem> GetItemsOfType(Type type) { if (type == null) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs index 4bcd4a46dd..e9d7f44ecc 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs @@ -40,7 +40,7 @@ namespace MediaBrowser.Server.Implementations.Persistence // Add PixelFormat column - createTableCommand += "(ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, PRIMARY KEY (ItemId, StreamIndex))"; + createTableCommand += "(ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, PRIMARY KEY (ItemId, StreamIndex))"; string[] queries = { @@ -59,6 +59,7 @@ namespace MediaBrowser.Server.Implementations.Persistence AddPixelFormatColumnCommand(); AddBitDepthCommand(); AddIsAnamorphicColumn(); + AddIsCabacColumn(); AddRefFramesCommand(); PrepareStatements(); @@ -159,6 +160,37 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.RunQueries(new[] { builder.ToString() }, _logger); } + private void AddIsCabacColumn() + { + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "PRAGMA table_info(mediastreams)"; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var name = reader.GetString(1); + + if (string.Equals(name, "IsCabac", StringComparison.OrdinalIgnoreCase)) + { + return; + } + } + } + } + } + + var builder = new StringBuilder(); + + builder.AppendLine("alter table mediastreams"); + builder.AppendLine("add column IsCabac BIT NULL"); + + _connection.RunQueries(new[] { builder.ToString() }, _logger); + } + private void AddIsAnamorphicColumn() { using (var cmd = _connection.CreateCommand()) @@ -216,7 +248,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "PixelFormat", "BitDepth", "IsAnamorphic", - "RefFrames" + "RefFrames", + "IsCabac" }; /// <summary> @@ -395,6 +428,11 @@ namespace MediaBrowser.Server.Implementations.Persistence item.RefFrames = reader.GetInt32(24); } + if (!reader.IsDBNull(25)) + { + item.IsCabac = reader.GetBoolean(25); + } + return item; } @@ -460,6 +498,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveStreamCommand.GetParameter(22).Value = stream.BitDepth; _saveStreamCommand.GetParameter(23).Value = stream.IsAnamorphic; _saveStreamCommand.GetParameter(24).Value = stream.RefFrames; + _saveStreamCommand.GetParameter(25).Value = stream.IsCabac; _saveStreamCommand.Transaction = transaction; _saveStreamCommand.ExecuteNonQuery(); diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index a0cd600672..ac80687441 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -359,6 +359,7 @@ namespace MediaBrowser.Server.Implementations.Session session.NowPlayingItem = info.Item; session.LastActivityDate = DateTime.UtcNow; + session.LastPlaybackCheckIn = DateTime.UtcNow; session.PlayState.IsPaused = info.IsPaused; session.PlayState.PositionTicks = info.PositionTicks; @@ -498,6 +499,65 @@ namespace MediaBrowser.Server.Implementations.Session return users; } + private Timer _idleTimer; + + private void StartIdleCheckTimer() + { + if (_idleTimer == null) + { + _idleTimer = new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)); + } + } + private void StopIdleCheckTimer() + { + if (_idleTimer != null) + { + _idleTimer.Dispose(); + _idleTimer = null; + } + } + + private async void CheckForIdlePlayback(object state) + { + var playingSessions = Sessions.Where(i => i.NowPlayingItem != null) + .ToList(); + + if (playingSessions.Count > 0) + { + var idle = playingSessions + .Where(i => (DateTime.UtcNow - i.LastPlaybackCheckIn).TotalMinutes > 5) + .ToList(); + + foreach (var session in idle) + { + _logger.Debug("Session {0} has gone idle while playing", session.Id); + + try + { + await OnPlaybackStopped(new PlaybackStopInfo + { + Item = session.NowPlayingItem, + ItemId = (session.NowPlayingItem == null ? null : session.NowPlayingItem.Id), + SessionId = session.Id, + MediaSourceId = (session.PlayState == null ? null : session.PlayState.MediaSourceId) + }); + } + catch (Exception ex) + { + _logger.Debug("Error calling OnPlaybackStopped", ex); + } + } + + playingSessions = Sessions.Where(i => i.NowPlayingItem != null) + .ToList(); + } + + if (playingSessions.Count == 0) + { + StopIdleCheckTimer(); + } + } + /// <summary> /// Used to report that playback has started for an item /// </summary> @@ -553,6 +613,8 @@ namespace MediaBrowser.Server.Implementations.Session }, _logger); await SendPlaybackStartNotification(session, CancellationToken.None).ConfigureAwait(false); + + StartIdleCheckTimer(); } /// <summary> @@ -623,6 +685,8 @@ namespace MediaBrowser.Server.Implementations.Session DeviceId = session.DeviceId }, _logger); + + StartIdleCheckTimer(); } private async Task OnPlaybackProgress(Guid userId, string userDataKey, BaseItem item, long? positionTicks) diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index f4ae854257..be1146c996 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -452,7 +452,6 @@ namespace MediaBrowser.WebDashboard.Api "tvstudios.js", "tvupcoming.js", "useredit.js", - "userpassword.js", "myprofile.js", "userprofilespage.js", "userparentalcontrol.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index a50d3aae29..87a8900e08 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -1907,11 +1907,6 @@ </Content>
</ItemGroup>
<ItemGroup>
- <Content Include="dashboard-ui\userpassword.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- </ItemGroup>
- <ItemGroup>
<Content Include="dashboard-ui\myprofile.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1957,11 +1952,6 @@ </Content>
</ItemGroup>
<ItemGroup>
- <Content Include="dashboard-ui\scripts\userpassword.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- </ItemGroup>
- <ItemGroup>
<Content Include="dashboard-ui\scripts\advancedconfigurationpage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.sln b/MediaBrowser.sln index d4fdc623ba..5fd743fee1 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -777,4 +777,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal |
