diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-02-19 00:21:03 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-02-19 00:21:03 -0500 |
| commit | 4e38c3537398b01776f6e1c5e1c08bce73eec82e (patch) | |
| tree | 3fc399f51419d6aae3ae8d96769995cc28191d1f | |
| parent | cf4ae16f18376c38fed7a8fcaefdc883893473a2 (diff) | |
fixed remote control flyout
32 files changed, 594 insertions, 509 deletions
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 84f495efa..1eaf4acb1 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -5,7 +5,6 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; using ServiceStack; using System; using System.Linq; @@ -94,8 +93,8 @@ namespace MediaBrowser.Api { var item = _dtoService.GetItemByDtoId(request.ItemId); - var newEnableInternetProviders = request.EnableInternetProviders ?? true; - var dontFetchMetaChanged = item.DontFetchMeta != !newEnableInternetProviders; + var newLockData = request.LockData ?? false; + var dontFetchMetaChanged = item.DontFetchMeta != newLockData; UpdateItem(request, item); @@ -107,7 +106,7 @@ namespace MediaBrowser.Api foreach (var child in folder.RecursiveChildren.ToList()) { - child.DontFetchMeta = !newEnableInternetProviders; + child.DontFetchMeta = newLockData; await _libraryManager.UpdateItem(child, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); } } @@ -307,16 +306,13 @@ namespace MediaBrowser.Api { hasAspectRatio.AspectRatio = request.AspectRatio; } - - item.DontFetchMeta = !(request.EnableInternetProviders ?? true); - if (request.EnableInternetProviders ?? true) + + item.DontFetchMeta = (request.LockData ?? false); + + if (request.LockedFields != null) { item.LockedFields = request.LockedFields; } - else - { - item.LockedFields.Clear(); - } // Only allow this for series. Runtimes for media comes from ffprobe. if (item is Series) diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 65e6c04b7..09b87bce9 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -240,6 +240,13 @@ namespace MediaBrowser.Api.Playback.Progressive responseHeaders["Accept-Ranges"] = "none"; + var length = response.Headers["Content-Length"]; + + if (!string.IsNullOrEmpty(length)) + { + responseHeaders["Content-Length"] = length; + } + if (isHeadRequest) { using (response.Content) @@ -273,13 +280,13 @@ namespace MediaBrowser.Api.Playback.Progressive // Use the command line args with a dummy playlist path var outputPath = GetOutputFilePath(state); + responseHeaders["Accept-Ranges"] = "none"; + var contentType = MimeTypes.GetMimeType(outputPath); // Headers only if (isHeadRequest) { - responseHeaders["Accept-Ranges"] = "none"; - return ResultFactory.GetResult(new byte[] { }, contentType, responseHeaders); } @@ -294,7 +301,6 @@ namespace MediaBrowser.Api.Playback.Progressive var result = new ProgressiveStreamWriter(outputPath, Logger, FileSystem); - result.Options["Accept-Ranges"] = "none"; result.Options["Content-Type"] = contentType; // Add the response headers to the result object diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 2583450a3..27e164307 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -179,7 +179,7 @@ namespace MediaBrowser.Controller.Entities.Audio // Refresh all non-songs foreach (var item in others) { - if (tasks.Count > 3) + if (tasks.Count >= 3) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 62ea0cf5d..224907a72 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -216,8 +216,18 @@ namespace MediaBrowser.Controller.Entities /// Returns true if this item should not attempt to fetch metadata /// </summary> /// <value><c>true</c> if [dont fetch meta]; otherwise, <c>false</c>.</value> + [Obsolete("Please use IsLocked instead of DontFetchMeta")] public bool DontFetchMeta { get; set; } + [IgnoreDataMember] + public bool IsLocked + { + get + { + return DontFetchMeta; + } + } + /// <summary> /// Gets or sets the locked fields. /// </summary> diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index c928a130e..c08a2ddf2 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -521,7 +521,7 @@ namespace MediaBrowser.Controller.Entities foreach (var child in children) { - if (tasks.Count >= 4) + if (tasks.Count >= 3) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index e07db88c4..8e66605dd 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -148,6 +148,12 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value> bool IsInMixedFolder { get; } + + /// <summary> + /// Gets a value indicating whether this instance is locked. + /// </summary> + /// <value><c>true</c> if this instance is locked; otherwise, <c>false</c>.</value> + bool IsLocked { get; } } public static class HasImagesExtensions diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 3fd2af091..6cd078677 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -99,7 +99,7 @@ namespace MediaBrowser.Controller.Entities.Movies // Refresh songs foreach (var item in items) { - if (tasks.Count >= 4) + if (tasks.Count >= 3) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index b62492bfe..32f2d151d 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -147,9 +147,11 @@ <Compile Include="Persistence\MediaStreamQuery.cs" /> <Compile Include="Providers\DirectoryService.cs" /> <Compile Include="Providers\ICustomMetadataProvider.cs" /> + <Compile Include="Providers\IForcedProvider.cs" /> <Compile Include="Providers\IHasChangeMonitor.cs" /> <Compile Include="Entities\IHasMetadata.cs" /> <Compile Include="Providers\IImageProvider.cs" /> + <Compile Include="Providers\IImageSaver.cs" /> <Compile Include="Providers\ILocalMetadataProvider.cs" /> <Compile Include="Providers\IProviderRepository.cs" /> <Compile Include="Providers\IRemoteImageProvider.cs" /> @@ -216,7 +218,7 @@ <Compile Include="Plugins\IPluginConfigurationPage.cs" /> <Compile Include="Plugins\IServerEntryPoint.cs" /> <Compile Include="Providers\IImageEnhancer.cs" /> - <Compile Include="Providers\BaseProviderInfo.cs" /> + <Compile Include="Providers\ProviderRefreshStatus.cs" /> <Compile Include="Resolvers\IResolverIgnoreRule.cs" /> <Compile Include="Resolvers\EntityResolutionHelper.cs" /> <Compile Include="Resolvers\ResolverPriority.cs" /> @@ -224,7 +226,6 @@ <Compile Include="Library\ItemResolveArgs.cs" /> <Compile Include="IO\FileData.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Providers\BaseMetadataProvider.cs" /> <Compile Include="Session\ISessionController.cs" /> <Compile Include="Session\ISessionControllerFactory.cs" /> <Compile Include="Session\PlaybackInfo.cs" /> diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 59b7cd8db..ada0aa6e2 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -719,7 +719,7 @@ namespace MediaBrowser.Controller.Providers } break; } - case "TvRageId": + case "TVRageId": { var id = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(id)) diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs deleted file mode 100644 index f8580244a..000000000 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ /dev/null @@ -1,268 +0,0 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Providers -{ - /// <summary> - /// Class BaseMetadataProvider - /// </summary> - public abstract class BaseMetadataProvider - { - /// <summary> - /// Gets the logger. - /// </summary> - /// <value>The logger.</value> - protected ILogger Logger { get; set; } - - protected ILogManager LogManager { get; set; } - - /// <summary> - /// Gets the configuration manager. - /// </summary> - /// <value>The configuration manager.</value> - protected IServerConfigurationManager ConfigurationManager { get; private set; } - - /// <summary> - /// The _id - /// </summary> - public readonly Guid Id; - - /// <summary> - /// The true task result - /// </summary> - protected static readonly Task<bool> TrueTaskResult = Task.FromResult(true); - - protected static readonly Task<bool> FalseTaskResult = Task.FromResult(false); - - /// <summary> - /// Supportses the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - public abstract bool Supports(BaseItem item); - - /// <summary> - /// Gets a value indicating whether [requires internet]. - /// </summary> - /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value> - public virtual bool RequiresInternet - { - get - { - return false; - } - } - - /// <summary> - /// Gets the provider version. - /// </summary> - /// <value>The provider version.</value> - protected virtual string ProviderVersion - { - get - { - return null; - } - } - - public virtual ItemUpdateType ItemUpdateType - { - get { return RequiresInternet ? ItemUpdateType.MetadataDownload : ItemUpdateType.MetadataImport; } - } - - /// <summary> - /// Gets a value indicating whether [refresh on version change]. - /// </summary> - /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value> - protected virtual bool RefreshOnVersionChange - { - get - { - return false; - } - } - - /// <summary> - /// Determines if this provider is relatively slow and, therefore, should be skipped - /// in certain instances. Default is whether or not it requires internet. Can be overridden - /// for explicit designation. - /// </summary> - /// <value><c>true</c> if this instance is slow; otherwise, <c>false</c>.</value> - public virtual bool IsSlow - { - get { return RequiresInternet; } - } - - /// <summary> - /// Initializes a new instance of the <see cref="BaseMetadataProvider" /> class. - /// </summary> - protected BaseMetadataProvider(ILogManager logManager, IServerConfigurationManager configurationManager) - { - Logger = logManager.GetLogger(GetType().Name); - LogManager = logManager; - ConfigurationManager = configurationManager; - Id = GetType().FullName.GetMD5(); - - Initialize(); - } - - /// <summary> - /// Initializes this instance. - /// </summary> - protected virtual void Initialize() - { - } - - /// <summary> - /// Sets the persisted last refresh date on the item for this provider. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="value">The value.</param> - /// <param name="providerVersion">The provider version.</param> - /// <param name="providerInfo">The provider information.</param> - /// <param name="status">The status.</param> - /// <exception cref="System.ArgumentNullException">item</exception> - public virtual void SetLastRefreshed(BaseItem item, DateTime value, string providerVersion, - BaseProviderInfo providerInfo, ProviderRefreshStatus status = ProviderRefreshStatus.Success) - { - if (item == null) - { - throw new ArgumentNullException("item"); - } - - providerInfo.LastRefreshed = value; - providerInfo.LastRefreshStatus = status; - providerInfo.ProviderVersion = providerVersion; - } - - /// <summary> - /// Sets the last refreshed. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="value">The value.</param> - /// <param name="providerInfo">The provider information.</param> - /// <param name="status">The status.</param> - public void SetLastRefreshed(BaseItem item, DateTime value, - BaseProviderInfo providerInfo, ProviderRefreshStatus status = ProviderRefreshStatus.Success) - { - SetLastRefreshed(item, value, ProviderVersion, providerInfo, status); - } - - /// <summary> - /// Returns whether or not this provider should be re-fetched. Default functionality can - /// compare a provided date with a last refresh time. This can be overridden for more complex - /// determinations. - /// </summary> - /// <param name="item">The item.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public bool NeedsRefresh(BaseItem item, BaseProviderInfo data) - { - if (item == null) - { - throw new ArgumentNullException(); - } - - return NeedsRefreshInternal(item, data); - } - - /// <summary> - /// Gets a value indicating whether [enforce dont fetch metadata]. - /// </summary> - /// <value><c>true</c> if [enforce dont fetch metadata]; otherwise, <c>false</c>.</value> - public virtual bool EnforceDontFetchMetadata - { - get - { - return true; - } - } - - /// <summary> - /// Needses the refresh internal. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="providerInfo">The provider info.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - /// <exception cref="System.ArgumentNullException"></exception> - protected virtual bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) - { - if (item == null) - { - throw new ArgumentNullException("item"); - } - - if (providerInfo == null) - { - throw new ArgumentNullException("providerInfo"); - } - - if (providerInfo.LastRefreshed == default(DateTime)) - { - return true; - } - - if (NeedsRefreshBasedOnCompareDate(item, providerInfo)) - { - return true; - } - - if (RefreshOnVersionChange && !String.Equals(ProviderVersion, providerInfo.ProviderVersion)) - { - return true; - } - - if (providerInfo.LastRefreshStatus != ProviderRefreshStatus.Success) - { - return true; - } - - return false; - } - - /// <summary> - /// Needses the refresh based on compare date. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="providerInfo">The provider info.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - protected virtual bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) - { - return CompareDate(item) > providerInfo.LastRefreshed; - } - - /// <summary> - /// Override this to return the date that should be compared to the last refresh date - /// to determine if this provider should be re-fetched. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>DateTime.</returns> - protected virtual DateTime CompareDate(BaseItem item) - { - return DateTime.MinValue.AddMinutes(1); // want this to be greater than mindate so new items will refresh - } - - /// <summary> - /// Fetches metadata and returns true or false indicating if any work that requires persistence was done - /// </summary> - /// <param name="item">The item.</param> - /// <param name="force">if set to <c>true</c> [force].</param> - /// <param name="providerInfo">The provider information.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{System.Boolean}.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public abstract Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken); - - /// <summary> - /// Gets the priority. - /// </summary> - /// <value>The priority.</value> - public abstract MetadataProviderPriority Priority { get; } - } -} diff --git a/MediaBrowser.Controller/Providers/BaseProviderInfo.cs b/MediaBrowser.Controller/Providers/BaseProviderInfo.cs deleted file mode 100644 index 3a33924f0..000000000 --- a/MediaBrowser.Controller/Providers/BaseProviderInfo.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; - -namespace MediaBrowser.Controller.Providers -{ - /// <summary> - /// Class BaseProviderInfo - /// </summary> - public class BaseProviderInfo - { - public Guid ProviderId { get; set; } - /// <summary> - /// Gets or sets the last refreshed. - /// </summary> - /// <value>The last refreshed.</value> - public DateTime LastRefreshed { get; set; } - /// <summary> - /// Gets or sets the file system stamp. - /// </summary> - /// <value>The file system stamp.</value> - public Guid FileStamp { get; set; } - /// <summary> - /// Gets or sets the last refresh status. - /// </summary> - /// <value>The last refresh status.</value> - public ProviderRefreshStatus LastRefreshStatus { get; set; } - /// <summary> - /// Gets or sets the provider version. - /// </summary> - /// <value>The provider version.</value> - public string ProviderVersion { get; set; } - } - - /// <summary> - /// Enum ProviderRefreshStatus - /// </summary> - public enum ProviderRefreshStatus - { - /// <summary> - /// The success - /// </summary> - Success = 0, - /// <summary> - /// The completed with errors - /// </summary> - CompletedWithErrors = 1, - /// <summary> - /// The failure - /// </summary> - Failure = 2 - } -} diff --git a/MediaBrowser.Controller/Providers/IForcedProvider.cs b/MediaBrowser.Controller/Providers/IForcedProvider.cs new file mode 100644 index 000000000..9e35b00ad --- /dev/null +++ b/MediaBrowser.Controller/Providers/IForcedProvider.cs @@ -0,0 +1,10 @@ + +namespace MediaBrowser.Controller.Providers +{ + /// <summary> + /// This is a marker interface that will cause a provider to run even if IsLocked=true + /// </summary> + public interface IForcedProvider + { + } +} diff --git a/MediaBrowser.Controller/Providers/IImageSaver.cs b/MediaBrowser.Controller/Providers/IImageSaver.cs new file mode 100644 index 000000000..5516c08f6 --- /dev/null +++ b/MediaBrowser.Controller/Providers/IImageSaver.cs @@ -0,0 +1,29 @@ +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Entities; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Providers +{ + public interface IImageSaver + { + /// <summary> + /// Gets the name. + /// </summary> + /// <value>The name.</value> + string Name { get; } + } + + public interface IImageFileSaver : IImageSaver + { + /// <summary> + /// Gets the save paths. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="type">The type.</param> + /// <param name="format">The format.</param> + /// <param name="index">The index.</param> + /// <returns>IEnumerable{System.String}.</returns> + IEnumerable<string> GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index); + } +} diff --git a/MediaBrowser.Controller/Providers/IMetadataProvider.cs b/MediaBrowser.Controller/Providers/IMetadataProvider.cs index 70bc06059..d33b2c9eb 100644 --- a/MediaBrowser.Controller/Providers/IMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/IMetadataProvider.cs @@ -1,5 +1,4 @@ -using System; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Providers { @@ -26,10 +25,8 @@ namespace MediaBrowser.Controller.Providers } public class MetadataResult<T> - where T : IHasMetadata { public bool HasMetadata { get; set; } public T Item { get; set; } } - } diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 4aeb86a6a..eb4d3d9a6 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -55,8 +55,10 @@ namespace MediaBrowser.Controller.Providers /// <param name="metadataServices">The metadata services.</param> /// <param name="metadataProviders">The metadata providers.</param> /// <param name="savers">The savers.</param> + /// <param name="imageSavers">The image savers.</param> void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, IEnumerable<IMetadataProvider> metadataProviders, - IEnumerable<IMetadataSaver> savers); + IEnumerable<IMetadataSaver> savers, + IEnumerable<IImageSaver> imageSavers); /// <summary> /// Gets the available remote images. diff --git a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs index cbbd62557..065017cce 100644 --- a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs @@ -1,6 +1,7 @@ -using System.Threading; +using MediaBrowser.Controller.Entities; +using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Providers { @@ -8,10 +9,24 @@ namespace MediaBrowser.Controller.Providers { } - public interface IRemoteMetadataProvider<TItemType, in TLookupInfoType> : IMetadataProvider<TItemType>, IRemoteMetadataProvider + public interface IRemoteMetadataProvider<TItemType, TLookupInfoType> : IMetadataProvider<TItemType>, IRemoteMetadataProvider where TItemType : IHasMetadata, IHasLookupInfo<TLookupInfoType> where TLookupInfoType : ItemLookupInfo, new() { Task<MetadataResult<TItemType>> GetMetadata(TLookupInfoType info, CancellationToken cancellationToken); } + + public interface IRemoteSearchProvider<TLookupInfoType> + where TLookupInfoType : ItemLookupInfo + { + Task<IEnumerable<SearchResult<TLookupInfoType>>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken); + } + + public class SearchResult<T> + where T : ItemLookupInfo + { + public T Item { get; set; } + + public string ImageUrl { get; set; } + } } diff --git a/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs b/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs new file mode 100644 index 000000000..6523dc417 --- /dev/null +++ b/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs @@ -0,0 +1,22 @@ + +namespace MediaBrowser.Controller.Providers +{ + /// <summary> + /// Enum ProviderRefreshStatus + /// </summary> + public enum ProviderRefreshStatus + { + /// <summary> + /// The success + /// </summary> + Success = 0, + /// <summary> + /// The completed with errors + /// </summary> + CompletedWithErrors = 1, + /// <summary> + /// The failure + /// </summary> + Failure = 2 + } +} diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 566c136b7..8f4330446 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -657,7 +657,7 @@ namespace MediaBrowser.Model.Dto /// Gets or sets a value indicating whether [enable internet providers]. /// </summary> /// <value><c>true</c> if [enable internet providers]; otherwise, <c>false</c>.</value> - public bool? EnableInternetProviders { get; set; } + public bool? LockData { get; set; } /// <summary> /// Gets a value indicating whether this instance can resume. diff --git a/MediaBrowser.Model/Entities/LocationType.cs b/MediaBrowser.Model/Entities/LocationType.cs index 09c0b20ca..84de803aa 100644 --- a/MediaBrowser.Model/Entities/LocationType.cs +++ b/MediaBrowser.Model/Entities/LocationType.cs @@ -9,18 +9,18 @@ namespace MediaBrowser.Model.Entities /// <summary> /// The file system /// </summary> - FileSystem = 1, + FileSystem = 0, /// <summary> /// The remote /// </summary> - Remote = 2, + Remote = 1, /// <summary> /// The virtual /// </summary> - Virtual = 3, + Virtual = 2, /// <summary> /// The offline /// </summary> - Offline = 4 + Offline = 3 } } diff --git a/MediaBrowser.Model/Notifications/NotificationLevel.cs b/MediaBrowser.Model/Notifications/NotificationLevel.cs index c7e68b163..a49ee2fe6 100644 --- a/MediaBrowser.Model/Notifications/NotificationLevel.cs +++ b/MediaBrowser.Model/Notifications/NotificationLevel.cs @@ -3,8 +3,8 @@ namespace MediaBrowser.Model.Notifications { public enum NotificationLevel { - Normal = 1, - Warning = 2, - Error = 3 + Normal = 0, + Warning = 1, + Error = 2 } } diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs index b19241095..f408d026b 100644 --- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs +++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs @@ -1,25 +1,19 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers.Genres { public class GenreMetadataService : MetadataService<Genre, ItemLookupInfo> { - private readonly ILibraryManager _libraryManager; - - public GenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, ILibraryManager libraryManager) + public GenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem) { - _libraryManager = libraryManager; } /// <summary> diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index ced9e4868..19d1e3ba2 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -52,11 +52,10 @@ namespace MediaBrowser.Providers.Manager private readonly IFileSystem _fileSystem; - private readonly IProviderRepository _providerRepo; - private IMetadataService[] _metadataServices = { }; private IMetadataProvider[] _metadataProviders = { }; private IEnumerable<IMetadataSaver> _savers; + private IImageSaver[] _imageSavers; /// <summary> /// Initializes a new instance of the <see cref="ProviderManager" /> class. @@ -66,15 +65,13 @@ namespace MediaBrowser.Providers.Manager /// <param name="libraryMonitor">The directory watchers.</param> /// <param name="logManager">The log manager.</param> /// <param name="fileSystem">The file system.</param> - /// <param name="providerRepo">The provider repo.</param> - public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IProviderRepository providerRepo) + public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem) { _logger = logManager.GetLogger("ProviderManager"); _httpClient = httpClient; ConfigurationManager = configurationManager; _libraryMonitor = libraryMonitor; _fileSystem = fileSystem; - _providerRepo = providerRepo; } /// <summary> @@ -84,13 +81,16 @@ namespace MediaBrowser.Providers.Manager /// <param name="metadataServices">The metadata services.</param> /// <param name="metadataProviders">The metadata providers.</param> /// <param name="metadataSavers">The metadata savers.</param> - public void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, IEnumerable<IMetadataProvider> metadataProviders, IEnumerable<IMetadataSaver> metadataSavers) + /// <param name="imageSavers">The image savers.</param> + public void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, IEnumerable<IMetadataProvider> metadataProviders, IEnumerable<IMetadataSaver> metadataSavers, + IEnumerable<IImageSaver> imageSavers) { ImageProviders = imageProviders.ToArray(); _metadataServices = metadataServices.OrderBy(i => i.Order).ToArray(); _metadataProviders = metadataProviders.ToArray(); _savers = metadataSavers.ToArray(); + _imageSavers = imageSavers.ToArray(); } public Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken) @@ -107,62 +107,6 @@ namespace MediaBrowser.Providers.Manager } /// <summary> - /// Saves to library filesystem. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="path">The path.</param> - /// <param name="dataToSave">The data to save.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public async Task SaveToLibraryFilesystem(BaseItem item, string path, Stream dataToSave, CancellationToken cancellationToken) - { - if (item == null) - { - throw new ArgumentNullException(); - } - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(); - } - if (dataToSave == null) - { - throw new ArgumentNullException(); - } - - if (cancellationToken.IsCancellationRequested) - { - dataToSave.Dispose(); - cancellationToken.ThrowIfCancellationRequested(); - } - - //Tell the watchers to ignore - _libraryMonitor.ReportFileSystemChangeBeginning(path); - - if (dataToSave.CanSeek) - { - dataToSave.Position = 0; - } - - try - { - using (dataToSave) - { - using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) - { - await dataToSave.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false); - } - } - } - finally - { - //Remove the ignore - _libraryMonitor.ReportFileSystemChangeComplete(path, false); - } - } - - - /// <summary> /// Saves the image. /// </summary> /// <param name="item">The item.</param> @@ -252,8 +196,13 @@ namespace MediaBrowser.Providers.Manager result = result.Where(i => i.Type == type.Value); } - return string.IsNullOrEmpty(preferredLanguage) ? result : - FilterImages(result, preferredLanguage); + if (string.Equals(preferredLanguage, "en", StringComparison.OrdinalIgnoreCase)) + { + result = result.Where(i => string.IsNullOrEmpty(i.Language) || + string.Equals(i.Language, "en", StringComparison.OrdinalIgnoreCase)); + } + + return result; } catch (Exception ex) { @@ -262,17 +211,6 @@ namespace MediaBrowser.Providers.Manager } } - private IEnumerable<RemoteImageInfo> FilterImages(IEnumerable<RemoteImageInfo> images, string preferredLanguage) - { - if (string.Equals(preferredLanguage, "en", StringComparison.OrdinalIgnoreCase)) - { - images = images.Where(i => string.IsNullOrEmpty(i.Language) || - string.Equals(i.Language, "en", StringComparison.OrdinalIgnoreCase)); - } - - return images; - } - /// <summary> /// Gets the supported image providers. /// </summary> @@ -294,13 +232,16 @@ namespace MediaBrowser.Providers.Manager private IEnumerable<IImageProvider> GetImageProviders(IHasImages item, MetadataOptions options, bool includeDisabled) { + // Avoid implicitly captured closure + var currentOptions = options; + return ImageProviders.Where(i => CanRefresh(i, item, options, includeDisabled)) .OrderBy(i => { // See if there's a user-defined order if (!(i is ILocalImageProvider)) { - var index = Array.IndexOf(options.ImageFetcherOrder, i.Name); + var index = Array.IndexOf(currentOptions.ImageFetcherOrder, i.Name); if (index != -1) { @@ -325,36 +266,13 @@ namespace MediaBrowser.Providers.Manager private IEnumerable<IMetadataProvider<T>> GetMetadataProvidersInternal<T>(IHasMetadata item, MetadataOptions options, bool includeDisabled) where T : IHasMetadata { - return _metadataProviders.OfType<IMetadataProvider<T>>() - .Where(i => CanRefresh(i, item, options, includeDisabled)) - .OrderBy(i => - { - // See if there's a user-defined order - if (i is ILocalMetadataProvider) - { - var index = Array.IndexOf(options.LocalMetadataReaderOrder, i.Name); - - if (index != -1) - { - return index; - } - } - - // See if there's a user-defined order - if (i is IRemoteMetadataProvider) - { - var index = Array.IndexOf(options.MetadataFetcherOrder, i.Name); - - if (index != -1) - { - return index; - } - } + // Avoid implicitly captured closure + var currentOptions = options; - // Not configured. Just return some high number to put it at the end. - return 100; - }) - .ThenBy(GetOrder); + return _metadataProviders.OfType<IMetadataProvider<T>>() + .Where(i => CanRefresh(i, item, currentOptions, includeDisabled)) + .OrderBy(i => GetConfiguredOrder(i, options)) + .ThenBy(GetDefaultOrder); } private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasImages item, bool includeDisabled) @@ -368,6 +286,12 @@ namespace MediaBrowser.Providers.Manager { if (!includeDisabled) { + // If locked only allow local providers + if (item.IsLocked && !(provider is ILocalMetadataProvider) && !(provider is IForcedProvider)) + { + return false; + } + if (provider is IRemoteMetadataProvider) { if (Array.IndexOf(options.DisabledMetadataFetchers, provider.Name) != -1) @@ -398,6 +322,12 @@ namespace MediaBrowser.Providers.Manager { if (!includeDisabled) { + // If locked only allow local providers + if (item.IsLocked && !(provider is ILocalImageProvider)) + { + return false; + } + if (provider is IRemoteImageProvider) { if (Array.IndexOf(options.DisabledImageFetchers, provider.Name) != -1) @@ -440,12 +370,35 @@ namespace MediaBrowser.Providers.Manager return hasOrder.Order; } - /// <summary> - /// Gets the order. - /// </summary> - /// <param name="provider">The provider.</param> - /// <returns>System.Int32.</returns> - private int GetOrder(IMetadataProvider provider) + private int GetConfiguredOrder(IMetadataProvider provider, MetadataOptions options) + { + // See if there's a user-defined order + if (provider is ILocalMetadataProvider) + { + var index = Array.IndexOf(options.LocalMetadataReaderOrder, provider.Name); + + if (index != -1) + { + return index; + } + } + + // See if there's a user-defined order + if (provider is IRemoteMetadataProvider) + { + var index = Array.IndexOf(options.MetadataFetcherOrder, provider.Name); + + if (index != -1) + { + return index; + } + } + + // Not configured. Just return some high number to put it at the end. + return 100; + } + + private int GetDefaultOrder(IMetadataProvider provider) { var hasOrder = provider as IHasOrder; @@ -578,6 +531,7 @@ namespace MediaBrowser.Providers.Manager } private readonly ConcurrentDictionary<string, SemaphoreSlim> _fileLocks = new ConcurrentDictionary<string, SemaphoreSlim>(); + /// <summary> /// Saves the metadata. /// </summary> @@ -658,5 +612,14 @@ namespace MediaBrowser.Providers.Manager return false; } } + + //private IEnumerable<TLookupType> GetRemoteSearchResults<TLookupType>(TLookupType searchInfo, + // CancellationToken cancellationToken) + // where TLookupType : ItemLookupInfo + //{ + // var providers = _metadataProviders.OfType<IRemoteSearchProvider<TLookupType>>(); + + + //} } }
\ No newline at end of file diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 3a7fcd918..724a60b97 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -198,6 +198,7 @@ <Compile Include="TV\TvdbPrescanTask.cs" /> <Compile Include="Users\UserMetadataService.cs" /> <Compile Include="Videos\VideoMetadataService.cs" /> + <Compile Include="Xbmc\XbmcImageSaver.cs" /> <Compile Include="Years\YearMetadataService.cs" /> </ItemGroup> <ItemGroup> diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index 7ac48655a..161532fd3 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -31,7 +31,8 @@ namespace MediaBrowser.Providers.MediaInfo ICustomMetadataProvider<Video>, ICustomMetadataProvider<Audio>, IHasChangeMonitor, - IHasOrder + IHasOrder, + IForcedProvider { private readonly ILogger _logger; private readonly IIsoManager _isoManager; diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index f439f4bc5..5691190dc 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -21,9 +22,9 @@ namespace MediaBrowser.Providers.People public class MovieDbPersonProvider : IRemoteMetadataProvider<Person, PersonLookupInfo> { const string DataFileName = "info.json"; - + internal static MovieDbPersonProvider Current { get; private set; } - + private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; @@ -41,6 +42,73 @@ namespace MediaBrowser.Providers.People get { return "TheMovieDb"; } } + public async Task<IEnumerable<SearchResult<PersonLookupInfo>>> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken) + { + var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb); + + var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); + + var tmdbImageUrl = tmdbSettings.images.base_url + "original"; + + if (!string.IsNullOrEmpty(tmdbId)) + { + await EnsurePersonInfo(tmdbId, cancellationToken).ConfigureAwait(false); + + var dataFilePath = GetPersonDataFilePath(_configurationManager.ApplicationPaths, tmdbId); + var info = _jsonSerializer.DeserializeFromFile<PersonResult>(dataFilePath); + + var images = (info.images ?? new Images()).profiles ?? new List<Profile>(); + + var result = new SearchResult<PersonLookupInfo> + { + Item = new PersonLookupInfo + { + Name = info.name + }, + + ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].file_path) + }; + + result.Item.SetProviderId(MetadataProviders.Tmdb, info.id.ToString(_usCulture)); + result.Item.SetProviderId(MetadataProviders.Imdb, info.imdb_id.ToString(_usCulture)); + + return new[] { result }; + } + + var url = string.Format(@"http://api.themoviedb.org/3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(searchInfo.Name), MovieDbProvider.ApiKey); + + using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions + { + Url = url, + CancellationToken = cancellationToken, + AcceptHeader = MovieDbProvider.AcceptHeader + + }).ConfigureAwait(false)) + { + var result = _jsonSerializer.DeserializeFromStream<PersonSearchResults>(json) ?? + new PersonSearchResults(); + + return result.Results.Select(i => GetSearchResult(i, tmdbImageUrl)); + } + } + + private SearchResult<PersonLookupInfo> GetSearchResult(PersonSearchResult i, string baseImageUrl) + { + var result = new SearchResult<PersonLookupInfo> + { + Item = new PersonLookupInfo + { + Name = i.Name + }, + + ImageUrl = string.IsNullOrEmpty(i.Profile_Path) ? null : (baseImageUrl + i.Profile_Path) + }; + + result.Item.SetProviderId(MetadataProviders.Tmdb, i.Id.ToString(_usCulture)); + + return result; + } + public async Task<MetadataResult<Person>> GetMetadata(PersonLookupInfo id, CancellationToken cancellationToken) { var tmdbId = id.GetProviderId(MetadataProviders.Tmdb); @@ -48,7 +116,7 @@ namespace MediaBrowser.Providers.People // We don't already have an Id, need to fetch it if (string.IsNullOrEmpty(tmdbId)) { - tmdbId = await GetTmdbId(id.Name, cancellationToken).ConfigureAwait(false); + tmdbId = await GetTmdbId(id, cancellationToken).ConfigureAwait(false); } var result = new MetadataResult<Person>(); @@ -100,26 +168,14 @@ namespace MediaBrowser.Providers.People /// <summary> /// Gets the TMDB id. /// </summary> - /// <param name="name">The name.</param> + /// <param name="info">The information.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{System.String}.</returns> - private async Task<string> GetTmdbId(string name, CancellationToken cancellationToken) + private async Task<string> GetTmdbId(PersonLookupInfo info, CancellationToken cancellationToken) { - string url = string.Format(@"http://api.themoviedb.org/3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(name), MovieDbProvider.ApiKey); - PersonSearchResults searchResult = null; - - using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = MovieDbProvider.AcceptHeader - - }).ConfigureAwait(false)) - { - searchResult = _jsonSerializer.DeserializeFromStream<PersonSearchResults>(json); - } + var results = await GetSearchResults(info, cancellationToken).ConfigureAwait(false); - return searchResult != null && searchResult.Total_Results > 0 ? searchResult.Results[0].Id.ToString(_usCulture) : null; + return results.Select(i => i.Item.GetProviderId(MetadataProviders.Tmdb)).FirstOrDefault(); } internal async Task EnsurePersonInfo(string id, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index 6a3d7d837..eed91dfaa 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -22,6 +22,8 @@ namespace MediaBrowser.Providers.Savers "Added", "AspectRatio", + "AudioDbAlbumId", + "AudioDbArtistId", "AwardSummary", "BirthDate", "Budget", @@ -73,6 +75,7 @@ namespace MediaBrowser.Providers.Savers "TVcomId", "TvDbId", "Type", + "TVRageId", "VoteCount", "Website", "Zap2ItId" @@ -477,7 +480,7 @@ namespace MediaBrowser.Providers.Savers if (!string.IsNullOrEmpty(externalId)) { - builder.Append("<TvRageId>" + SecurityElement.Escape(externalId) + "</TvRageId>"); + builder.Append("<TVRageId>" + SecurityElement.Escape(externalId) + "</TVRageId>"); } var hasTagline = item as IHasTaglines; diff --git a/MediaBrowser.Providers/Xbmc/XbmcImageSaver.cs b/MediaBrowser.Providers/Xbmc/XbmcImageSaver.cs new file mode 100644 index 000000000..5a4408f1b --- /dev/null +++ b/MediaBrowser.Providers/Xbmc/XbmcImageSaver.cs @@ -0,0 +1,272 @@ +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Providers.Xbmc +{ + public class XbmcImageSaver : IImageFileSaver + { + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + public IEnumerable<string> GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index) + { + var season = item as Season; + + if (!SupportsItem(item, type, season)) + { + return new string[] { }; + } + + var extension = "." + format.ToString().ToLower(); + + // Backdrop paths + if (type == ImageType.Backdrop) + { + if (index == 0) + { + if (item.IsInMixedFolder) + { + return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart", extension) }; + } + + if (season != null && season.IndexNumber.HasValue) + { + var seriesFolder = season.SeriesPath; + + var seasonMarker = season.IndexNumber.Value == 0 + ? "-specials" + : season.IndexNumber.Value.ToString("00", _usCulture); + + var imageFilename = "season" + seasonMarker + "-fanart" + extension; + + return new[] { Path.Combine(seriesFolder, imageFilename) }; + } + + return new[] + { + Path.Combine(item.ContainingFolderPath, "fanart" + extension) + }; + } + + if (item.IsInMixedFolder) + { + return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + index.ToString(_usCulture), extension) }; + } + + var extraFanartFilename = GetBackdropSaveFilename(item.GetImages(ImageType.Backdrop), "fanart", "fanart", index); + + return new[] + { + Path.Combine(item.ContainingFolderPath, "extrafanart", extraFanartFilename + extension), + Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + index.ToString(_usCulture) + extension) + }; + } + + if (type == ImageType.Primary) + { + if (season != null && season.IndexNumber.HasValue) + { + var seriesFolder = season.SeriesPath; + + var seasonMarker = season.IndexNumber.Value == 0 + ? "-specials" + : season.IndexNumber.Value.ToString("00", _usCulture); + + var imageFilename = "season" + seasonMarker + "-poster" + extension; + + return new[] { Path.Combine(seriesFolder, imageFilename) }; + } + + if (item is Episode) + { + var seasonFolder = Path.GetDirectoryName(item.Path); + + var imageFilename = Path.GetFileNameWithoutExtension(item.Path) + "-thumb" + extension; + + return new[] { Path.Combine(seasonFolder, imageFilename) }; + } + + if (item.IsInMixedFolder || item is MusicVideo) + { + return new[] { GetSavePathForItemInMixedFolder(item, type, string.Empty, extension) }; + } + + if (item is MusicAlbum || item is MusicArtist) + { + return new[] { Path.Combine(item.ContainingFolderPath, "folder" + extension) }; + } + + return new[] { Path.Combine(item.ContainingFolderPath, "poster" + extension) }; + } + + if (type == ImageType.Banner) + { + if (season != null && season.IndexNumber.HasValue) + { + var seriesFolder = season.SeriesPath; + + var seasonMarker = season.IndexNumber.Value == 0 + ? "-specials" + : season.IndexNumber.Value.ToString("00", _usCulture); + + var imageFilename = "season" + seasonMarker + "-banner" + extension; + + return new[] { Path.Combine(seriesFolder, imageFilename) }; + } + } + + if (type == ImageType.Thumb) + { + if (season != null && season.IndexNumber.HasValue) + { + var seriesFolder = season.SeriesPath; + + var seasonMarker = season.IndexNumber.Value == 0 + ? "-specials" + : season.IndexNumber.Value.ToString("00", _usCulture); + + var imageFilename = "season" + seasonMarker + "-landscape" + extension; + + return new[] { Path.Combine(seriesFolder, imageFilename) }; + } + + if (item.IsInMixedFolder) + { + return new[] { GetSavePathForItemInMixedFolder(item, type, "landscape", extension) }; + } + + return new[] { Path.Combine(item.ContainingFolderPath, "landscape" + extension) }; + } + + return GetStandardSavePaths(item, type, index, extension); + } + + private IEnumerable<string> GetStandardSavePaths(IHasImages item, ImageType type, int imageIndex, string extension) + { + string filename; + + switch (type) + { + case ImageType.Art: + filename = "clearart"; + break; + case ImageType.BoxRear: + filename = "back"; + break; + case ImageType.Disc: + filename = item is MusicAlbum ? "cdart" : "disc"; + break; + case ImageType.Screenshot: + filename = GetBackdropSaveFilename(item.GetImages(type), "screenshot", "screenshot", imageIndex); + break; + default: + filename = type.ToString().ToLower(); + break; + } + + string path = null; + + if (item.IsInMixedFolder) + { + path = GetSavePathForItemInMixedFolder(item, type, filename, extension); + } + + if (string.IsNullOrEmpty(path)) + { + path = Path.Combine(item.ContainingFolderPath, filename + extension); + } + + if (string.IsNullOrEmpty(path)) + { + return new string[] { }; + } + + return new[] { path }; + } + + + private string GetSavePathForItemInMixedFolder(IHasImages item, ImageType type, string imageFilename, string extension) + { + if (type == ImageType.Primary) + { + imageFilename = "poster"; + } + var folder = Path.GetDirectoryName(item.Path); + + return Path.Combine(folder, Path.GetFileNameWithoutExtension(item.Path) + "-" + imageFilename + extension); + } + + private bool SupportsItem(IHasImages item, ImageType type, Season season) + { + if (item.IsOwnedItem || item is Audio || item is User) + { + return false; + } + + if (type != ImageType.Primary && item is Episode) + { + return false; + } + + if (!item.SupportsLocalMetadata) + { + return false; + } + + var locationType = item.LocationType; + if (locationType == LocationType.Remote || locationType == LocationType.Virtual) + { + var allowSaving = false; + + // If season is virtual under a physical series, save locally if using compatible convention + if (season != null) + { + var series = season.Series; + + if (series != null && series.SupportsLocalMetadata) + { + allowSaving = true; + } + } + + if (!allowSaving) + { + return false; + } + } + + return true; + } + + private string GetBackdropSaveFilename(IEnumerable<ItemImageInfo> images, string zeroIndexFilename, string numberedIndexPrefix, int? index) + { + if (index.HasValue && index.Value == 0) + { + return zeroIndexFilename; + } + + var filenames = images.Select(i => Path.GetFileNameWithoutExtension(i.Path)).ToList(); + + var current = 1; + while (filenames.Contains(numberedIndexPrefix + current.ToString(_usCulture), StringComparer.OrdinalIgnoreCase)) + { + current++; + } + + return numberedIndexPrefix + current.ToString(_usCulture); + } + + public string Name + { + get { return "MB3/Plex/Xbmc Images"; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index aba8c3353..65a496533 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -664,7 +664,7 @@ namespace MediaBrowser.Server.Implementations.Dto if (fields.Contains(ItemFields.Settings)) { dto.LockedFields = item.LockedFields; - dto.EnableInternetProviders = !item.DontFetchMeta; + dto.LockData = item.DontFetchMeta; } var hasBudget = item as IHasBudget; diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index 3712a58f5..4c21d2eb7 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -435,10 +435,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (!compress || string.IsNullOrEmpty(requestedCompressionType)) { - var stream = await factoryFn().ConfigureAwait(false); - var rangeHeader = requestContext.GetHeader("Range"); + var stream = await factoryFn().ConfigureAwait(false); + if (!string.IsNullOrEmpty(rangeHeader)) { return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest); @@ -448,34 +448,54 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (isHeadRequest) { + stream.Dispose(); + return GetHttpResult(new byte[] { }, contentType); } return new StreamWriter(stream, contentType, _logger); } - if (isHeadRequest) - { - return GetHttpResult(new byte[] { }, contentType); - } - string content; + long originalContentLength = 0; using (var stream = await factoryFn().ConfigureAwait(false)) { - using (var reader = new StreamReader(stream)) + using (var memoryStream = new MemoryStream()) { - content = await reader.ReadToEndAsync().ConfigureAwait(false); + await stream.CopyToAsync(memoryStream).ConfigureAwait(false); + memoryStream.Position = 0; + + originalContentLength = memoryStream.Length; + + using (var reader = new StreamReader(memoryStream)) + { + content = await reader.ReadToEndAsync().ConfigureAwait(false); + } } } if (!SupportsCompression) { + responseHeaders["Content-Length"] = originalContentLength.ToString(UsCulture); + + if (isHeadRequest) + { + return GetHttpResult(new byte[] { }, contentType); + } + return new HttpResult(content, contentType); } var contents = content.Compress(requestedCompressionType); + responseHeaders["Content-Length"] = contents.Length.ToString(UsCulture); + + if (isHeadRequest) + { + return GetHttpResult(new byte[] { }, contentType); + } + return new CompressedResult(contents, requestedCompressionType, contentType); } diff --git a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs index 520f03561..ac1621709 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs @@ -69,7 +69,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer var response = (HttpListenerResponse)res.OriginalResponse; response.ContentLength64 = length; - + // Disable chunked encoding. Technically this is only needed when using Content-Range, but // anytime we know the content length there's no need for it response.SendChunked = false; diff --git a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs index 4e8469326..fecd72a39 100644 --- a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs +++ b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs @@ -8,7 +8,6 @@ using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.Linq; -using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -171,7 +170,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager throw; } - catch (HttpListenerException ex) + catch (Exception ex) { _logger.ErrorException("Error starting Http Server", ex); diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index fe734bcf8..10dec2da6 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -336,7 +336,7 @@ namespace MediaBrowser.ServerApplication LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager); RegisterSingleInstance(LibraryMonitor); - ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ProviderRepository); + ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager); RegisterSingleInstance(ProviderManager); RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager)); @@ -548,7 +548,8 @@ namespace MediaBrowser.ServerApplication GetExports<ILibraryPostScanTask>()); ProviderManager.AddParts(GetExports<IImageProvider>(), GetExports<IMetadataService>(), GetExports<IMetadataProvider>(), - GetExports<IMetadataSaver>()); + GetExports<IMetadataSaver>(), + GetExports<IImageSaver>()); ImageProcessor.AddParts(GetExports<IImageEnhancer>()); |
