mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
add new chapter provider feature
This commit is contained in:
parent
ba33637251
commit
945e843270
28
MediaBrowser.Api/Library/ChapterService.cs
Normal file
28
MediaBrowser.Api/Library/ChapterService.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using MediaBrowser.Controller.Chapters;
|
||||||
|
using ServiceStack;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Library
|
||||||
|
{
|
||||||
|
[Route("/Providers/Chapters", "GET")]
|
||||||
|
public class GetChapterProviders : IReturnVoid
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ChapterService : BaseApiService
|
||||||
|
{
|
||||||
|
private readonly IChapterManager _chapterManager;
|
||||||
|
|
||||||
|
public ChapterService(IChapterManager chapterManager)
|
||||||
|
{
|
||||||
|
_chapterManager = chapterManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Get(GetChapterProviders request)
|
||||||
|
{
|
||||||
|
var result = _chapterManager.GetProviders().ToList();
|
||||||
|
|
||||||
|
return ToOptimizedResult(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -68,6 +68,7 @@
|
|||||||
<Compile Include="ChannelService.cs" />
|
<Compile Include="ChannelService.cs" />
|
||||||
<Compile Include="Dlna\DlnaServerService.cs" />
|
<Compile Include="Dlna\DlnaServerService.cs" />
|
||||||
<Compile Include="Dlna\DlnaService.cs" />
|
<Compile Include="Dlna\DlnaService.cs" />
|
||||||
|
<Compile Include="Library\ChapterService.cs" />
|
||||||
<Compile Include="Library\SubtitleService.cs" />
|
<Compile Include="Library\SubtitleService.cs" />
|
||||||
<Compile Include="Movies\CollectionService.cs" />
|
<Compile Include="Movies\CollectionService.cs" />
|
||||||
<Compile Include="Music\AlbumsService.cs" />
|
<Compile Include="Music\AlbumsService.cs" />
|
||||||
|
@ -363,11 +363,11 @@ namespace MediaBrowser.Api.Playback
|
|||||||
switch (qualitySetting)
|
switch (qualitySetting)
|
||||||
{
|
{
|
||||||
case EncodingQuality.HighSpeed:
|
case EncodingQuality.HighSpeed:
|
||||||
crf = "16";
|
crf = "12";
|
||||||
profileScore = 2;
|
profileScore = 2;
|
||||||
break;
|
break;
|
||||||
case EncodingQuality.HighQuality:
|
case EncodingQuality.HighQuality:
|
||||||
crf = "10";
|
crf = "8";
|
||||||
profileScore = 1;
|
profileScore = 1;
|
||||||
break;
|
break;
|
||||||
case EncodingQuality.MaxQuality:
|
case EncodingQuality.MaxQuality:
|
||||||
|
@ -561,7 +561,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
return dtos.ToList();
|
return dtos.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException("The item does not support special features");
|
return new List<BaseItemDto>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -25,13 +26,16 @@ namespace MediaBrowser.Common.Implementations.Security
|
|||||||
|
|
||||||
var mac = _networkManager.GetMacAddress();
|
var mac = _networkManager.GetMacAddress();
|
||||||
|
|
||||||
|
var plugins = string.Join("|", _applicationHost.Plugins.Select(i => i.Name).ToArray());
|
||||||
|
|
||||||
var data = new Dictionary<string, string>
|
var data = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "feature", _applicationHost.Name },
|
{ "feature", _applicationHost.Name },
|
||||||
{ "mac", mac },
|
{ "mac", mac },
|
||||||
{ "ver", _applicationHost.ApplicationVersion.ToString() },
|
{ "ver", _applicationHost.ApplicationVersion.ToString() },
|
||||||
{ "platform", Environment.OSVersion.VersionString },
|
{ "platform", Environment.OSVersion.VersionString },
|
||||||
{ "isservice", _applicationHost.IsRunningAsService.ToString().ToLower()}
|
{ "isservice", _applicationHost.IsRunningAsService.ToString().ToLower()},
|
||||||
|
{ "plugins", plugins}
|
||||||
};
|
};
|
||||||
|
|
||||||
return _httpClient.Post(Constants.Constants.MbAdminUrl + "service/registration/ping", data, cancellationToken);
|
return _httpClient.Post(Constants.Constants.MbAdminUrl + "service/registration/ping", data, cancellationToken);
|
||||||
|
@ -21,6 +21,8 @@ namespace MediaBrowser.Controller.Chapters
|
|||||||
public long? RuntimeTicks { get; set; }
|
public long? RuntimeTicks { get; set; }
|
||||||
public Dictionary<string, string> ProviderIds { get; set; }
|
public Dictionary<string, string> ProviderIds { get; set; }
|
||||||
|
|
||||||
|
public bool SearchAllProviders { get; set; }
|
||||||
|
|
||||||
public ChapterSearchRequest()
|
public ChapterSearchRequest()
|
||||||
{
|
{
|
||||||
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
57
MediaBrowser.Controller/Chapters/IChapterManager.cs
Normal file
57
MediaBrowser.Controller/Chapters/IChapterManager.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Chapters;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Chapters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IChapterManager
|
||||||
|
/// </summary>
|
||||||
|
public interface IChapterManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the parts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chapterProviders">The chapter providers.</param>
|
||||||
|
void AddParts(IEnumerable<IChapterProvider> chapterProviders);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the specified video.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="video">The video.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{RemoteChapterResult}}.</returns>
|
||||||
|
Task<IEnumerable<RemoteChapterResult>> Search(Video video, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the specified request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{RemoteChapterResult}}.</returns>
|
||||||
|
Task<IEnumerable<RemoteChapterResult>> Search(ChapterSearchRequest request, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the chapters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{ChapterResponse}.</returns>
|
||||||
|
Task<ChapterResponse> GetChapters(string id, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the providers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="itemId">The item identifier.</param>
|
||||||
|
/// <returns>IEnumerable{ChapterProviderInfo}.</returns>
|
||||||
|
IEnumerable<ChapterProviderInfo> GetProviders(string itemId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the providers.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>IEnumerable{ChapterProviderInfo}.</returns>
|
||||||
|
IEnumerable<ChapterProviderInfo> GetProviders();
|
||||||
|
}
|
||||||
|
}
|
@ -91,6 +91,7 @@
|
|||||||
<Compile Include="Channels\IRequiresMediaInfoCallback.cs" />
|
<Compile Include="Channels\IRequiresMediaInfoCallback.cs" />
|
||||||
<Compile Include="Channels\ISearchableChannel.cs" />
|
<Compile Include="Channels\ISearchableChannel.cs" />
|
||||||
<Compile Include="Chapters\ChapterSearchRequest.cs" />
|
<Compile Include="Chapters\ChapterSearchRequest.cs" />
|
||||||
|
<Compile Include="Chapters\IChapterManager.cs" />
|
||||||
<Compile Include="Chapters\IChapterProvider.cs" />
|
<Compile Include="Chapters\IChapterProvider.cs" />
|
||||||
<Compile Include="Chapters\ChapterResponse.cs" />
|
<Compile Include="Chapters\ChapterResponse.cs" />
|
||||||
<Compile Include="Collections\CollectionCreationOptions.cs" />
|
<Compile Include="Collections\CollectionCreationOptions.cs" />
|
||||||
|
@ -12,7 +12,14 @@ namespace MediaBrowser.Controller.Providers
|
|||||||
public interface ICustomMetadataProvider<TItemType> : IMetadataProvider<TItemType>, ICustomMetadataProvider
|
public interface ICustomMetadataProvider<TItemType> : IMetadataProvider<TItemType>, ICustomMetadataProvider
|
||||||
where TItemType : IHasMetadata
|
where TItemType : IHasMetadata
|
||||||
{
|
{
|
||||||
Task<ItemUpdateType> FetchAsync(TItemType item, IDirectoryService directoryService, CancellationToken cancellationToken);
|
/// <summary>
|
||||||
|
/// Fetches the asynchronous.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{ItemUpdateType}.</returns>
|
||||||
|
Task<ItemUpdateType> FetchAsync(TItemType item, MetadataRefreshOptions options, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IPreRefreshProvider : ICustomMetadataProvider
|
public interface IPreRefreshProvider : ICustomMetadataProvider
|
||||||
|
@ -15,4 +15,10 @@ namespace MediaBrowser.Model.Chapters
|
|||||||
/// <value>The name.</value>
|
/// <value>The name.</value>
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ChapterProviderInfo
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,12 @@ namespace MediaBrowser.Model.Chapters
|
|||||||
/// <value>The name.</value>
|
/// <value>The name.</value>
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name of the provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name of the provider.</value>
|
||||||
|
public string ProviderName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the community rating.
|
/// Gets or sets the community rating.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -193,10 +193,6 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
|
|
||||||
public bool AllowVideoUpscaling { get; set; }
|
public bool AllowVideoUpscaling { get; set; }
|
||||||
|
|
||||||
public bool EnableMovieChapterImageExtraction { get; set; }
|
|
||||||
public bool EnableEpisodeChapterImageExtraction { get; set; }
|
|
||||||
public bool EnableOtherVideoChapterImageExtraction { get; set; }
|
|
||||||
|
|
||||||
public MetadataOptions[] MetadataOptions { get; set; }
|
public MetadataOptions[] MetadataOptions { get; set; }
|
||||||
|
|
||||||
public bool EnableDebugEncodingLogging { get; set; }
|
public bool EnableDebugEncodingLogging { get; set; }
|
||||||
@ -227,6 +223,7 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
public string[] ManualLoginClients { get; set; }
|
public string[] ManualLoginClients { get; set; }
|
||||||
|
|
||||||
public ChannelOptions ChannelOptions { get; set; }
|
public ChannelOptions ChannelOptions { get; set; }
|
||||||
|
public ChapterOptions ChapterOptions { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
||||||
@ -241,9 +238,6 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
EnableHttpLevelLogging = true;
|
EnableHttpLevelLogging = true;
|
||||||
EnableDashboardResponseCaching = true;
|
EnableDashboardResponseCaching = true;
|
||||||
|
|
||||||
EnableMovieChapterImageExtraction = true;
|
|
||||||
EnableEpisodeChapterImageExtraction = false;
|
|
||||||
EnableOtherVideoChapterImageExtraction = false;
|
|
||||||
EnableAutomaticRestart = true;
|
EnableAutomaticRestart = true;
|
||||||
EnablePeoplePrefixSubFolders = true;
|
EnablePeoplePrefixSubFolders = true;
|
||||||
|
|
||||||
@ -297,6 +291,7 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
SubtitleOptions = new SubtitleOptions();
|
SubtitleOptions = new SubtitleOptions();
|
||||||
|
|
||||||
ChannelOptions = new ChannelOptions();
|
ChannelOptions = new ChannelOptions();
|
||||||
|
ChapterOptions = new ChapterOptions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,4 +310,29 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
MaxDownloadAge = 30;
|
MaxDownloadAge = 30;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ChapterOptions
|
||||||
|
{
|
||||||
|
public bool EnableMovieChapterImageExtraction { get; set; }
|
||||||
|
public bool EnableEpisodeChapterImageExtraction { get; set; }
|
||||||
|
public bool EnableOtherVideoChapterImageExtraction { get; set; }
|
||||||
|
|
||||||
|
public bool DownloadMovieChapters { get; set; }
|
||||||
|
public bool DownloadEpisodeChapters { get; set; }
|
||||||
|
|
||||||
|
public string[] FetcherOrder { get; set; }
|
||||||
|
public string[] DisabledFetchers { get; set; }
|
||||||
|
|
||||||
|
public ChapterOptions()
|
||||||
|
{
|
||||||
|
EnableMovieChapterImageExtraction = true;
|
||||||
|
EnableEpisodeChapterImageExtraction = false;
|
||||||
|
EnableOtherVideoChapterImageExtraction = false;
|
||||||
|
|
||||||
|
DownloadMovieChapters = true;
|
||||||
|
|
||||||
|
DisabledFetchers = new string[] { };
|
||||||
|
FetcherOrder = new string[] { };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ namespace MediaBrowser.Model.LiveTv
|
|||||||
/// <value>The external identifier.</value>
|
/// <value>The external identifier.</value>
|
||||||
public string ExternalId { get; set; }
|
public string ExternalId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the media sources.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The media sources.</value>
|
||||||
public List<MediaSourceInfo> MediaSources { get; set; }
|
public List<MediaSourceInfo> MediaSources { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
240
MediaBrowser.Providers/Chapters/ChapterManager.cs
Normal file
240
MediaBrowser.Providers/Chapters/ChapterManager.cs
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Chapters;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Chapters;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Providers.Chapters
|
||||||
|
{
|
||||||
|
public class ChapterManager : IChapterManager
|
||||||
|
{
|
||||||
|
private IChapterProvider[] _providers;
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly IServerConfigurationManager _config;
|
||||||
|
|
||||||
|
public ChapterManager(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
_logger = logger;
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddParts(IEnumerable<IChapterProvider> chapterProviders)
|
||||||
|
{
|
||||||
|
_providers = chapterProviders.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<RemoteChapterResult>> Search(Video video, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
VideoContentType mediaType;
|
||||||
|
|
||||||
|
if (video is Episode)
|
||||||
|
{
|
||||||
|
mediaType = VideoContentType.Episode;
|
||||||
|
}
|
||||||
|
else if (video is Movie)
|
||||||
|
{
|
||||||
|
mediaType = VideoContentType.Movie;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// These are the only supported types
|
||||||
|
return Task.FromResult<IEnumerable<RemoteChapterResult>>(new List<RemoteChapterResult>());
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = new ChapterSearchRequest
|
||||||
|
{
|
||||||
|
ContentType = mediaType,
|
||||||
|
IndexNumber = video.IndexNumber,
|
||||||
|
//Language = language,
|
||||||
|
MediaPath = video.Path,
|
||||||
|
Name = video.Name,
|
||||||
|
ParentIndexNumber = video.ParentIndexNumber,
|
||||||
|
ProductionYear = video.ProductionYear,
|
||||||
|
ProviderIds = video.ProviderIds,
|
||||||
|
RuntimeTicks = video.RunTimeTicks
|
||||||
|
};
|
||||||
|
|
||||||
|
var episode = video as Episode;
|
||||||
|
|
||||||
|
if (episode != null)
|
||||||
|
{
|
||||||
|
request.IndexNumberEnd = episode.IndexNumberEnd;
|
||||||
|
request.SeriesName = episode.SeriesName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Search(request, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<RemoteChapterResult>> Search(ChapterSearchRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var contentType = request.ContentType;
|
||||||
|
var providers = GetInternalProviders(false)
|
||||||
|
.Where(i => i.SupportedMediaTypes.Contains(contentType))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// If not searching all, search one at a time until something is found
|
||||||
|
if (!request.SearchAllProviders)
|
||||||
|
{
|
||||||
|
foreach (var provider in providers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await Search(request, provider, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error downloading subtitles from {0}", ex, provider.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new List<RemoteChapterResult>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var tasks = providers.Select(async i =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await Search(request, i, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error downloading subtitles from {0}", ex, i.Name);
|
||||||
|
return new List<RemoteChapterResult>();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return results.SelectMany(i => i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<RemoteChapterResult>> Search(ChapterSearchRequest request,
|
||||||
|
IChapterProvider provider,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var searchResults = await provider.Search(request, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
foreach (var result in searchResults)
|
||||||
|
{
|
||||||
|
result.Id = GetProviderId(provider.Name) + "_" + result.Id;
|
||||||
|
result.ProviderName = provider.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ChapterResponse> GetChapters(string id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var parts = id.Split(new[] { '_' }, 2);
|
||||||
|
|
||||||
|
var provider = GetProvider(parts.First());
|
||||||
|
id = parts.Last();
|
||||||
|
|
||||||
|
return provider.GetChapters(id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ChapterProviderInfo> GetProviders(string itemId)
|
||||||
|
{
|
||||||
|
var video = _libraryManager.GetItemById(itemId) as Video;
|
||||||
|
VideoContentType mediaType;
|
||||||
|
|
||||||
|
if (video is Episode)
|
||||||
|
{
|
||||||
|
mediaType = VideoContentType.Episode;
|
||||||
|
}
|
||||||
|
else if (video is Movie)
|
||||||
|
{
|
||||||
|
mediaType = VideoContentType.Movie;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// These are the only supported types
|
||||||
|
return new List<ChapterProviderInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var providers = GetInternalProviders(false)
|
||||||
|
.Where(i => i.SupportedMediaTypes.Contains(mediaType));
|
||||||
|
|
||||||
|
return GetInfos(providers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ChapterProviderInfo> GetProviders()
|
||||||
|
{
|
||||||
|
return GetInfos(GetInternalProviders(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<IChapterProvider> GetInternalProviders(bool includeDisabledProviders)
|
||||||
|
{
|
||||||
|
var providers = _providers;
|
||||||
|
|
||||||
|
if (!includeDisabledProviders)
|
||||||
|
{
|
||||||
|
providers = providers
|
||||||
|
.Where(i => _config.Configuration.ChapterOptions.DisabledFetchers.Contains(i.Name))
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return providers
|
||||||
|
.OrderBy(GetConfiguredOrder)
|
||||||
|
.ThenBy(GetDefaultOrder)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<ChapterProviderInfo> GetInfos(IEnumerable<IChapterProvider> providers)
|
||||||
|
{
|
||||||
|
return providers.Select(i => new ChapterProviderInfo
|
||||||
|
{
|
||||||
|
Name = i.Name,
|
||||||
|
Id = GetProviderId(i.Name)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetProviderId(string name)
|
||||||
|
{
|
||||||
|
return name.ToLower().GetMD5().ToString("N");
|
||||||
|
}
|
||||||
|
|
||||||
|
private IChapterProvider GetProvider(string id)
|
||||||
|
{
|
||||||
|
return _providers.First(i => string.Equals(id, GetProviderId(i.Name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetConfiguredOrder(IChapterProvider provider)
|
||||||
|
{
|
||||||
|
// See if there's a user-defined order
|
||||||
|
var index = Array.IndexOf(_config.Configuration.ChapterOptions.FetcherOrder, 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(IChapterProvider provider)
|
||||||
|
{
|
||||||
|
var hasOrder = provider as IHasOrder;
|
||||||
|
|
||||||
|
if (hasOrder != null)
|
||||||
|
{
|
||||||
|
return hasOrder.Order;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -271,7 +271,7 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
|
|
||||||
foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider))
|
foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider))
|
||||||
{
|
{
|
||||||
await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false);
|
await RunCustomProvider(provider, item, options, refreshResult, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var temp = CreateNew();
|
var temp = CreateNew();
|
||||||
@ -343,19 +343,19 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
|
|
||||||
foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider)))
|
foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider)))
|
||||||
{
|
{
|
||||||
await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false);
|
await RunCustomProvider(provider, item, options, refreshResult, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return refreshResult;
|
return refreshResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunCustomProvider(ICustomMetadataProvider<TItemType> provider, TItemType item, IDirectoryService directoryService, RefreshResult refreshResult, CancellationToken cancellationToken)
|
private async Task RunCustomProvider(ICustomMetadataProvider<TItemType> provider, TItemType item, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name);
|
Logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, directoryService, cancellationToken).ConfigureAwait(false);
|
refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, options, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +79,7 @@
|
|||||||
<Compile Include="BoxSets\MovieDbBoxSetImageProvider.cs" />
|
<Compile Include="BoxSets\MovieDbBoxSetImageProvider.cs" />
|
||||||
<Compile Include="BoxSets\MovieDbBoxSetProvider.cs" />
|
<Compile Include="BoxSets\MovieDbBoxSetProvider.cs" />
|
||||||
<Compile Include="Channels\ChannelMetadataService.cs" />
|
<Compile Include="Channels\ChannelMetadataService.cs" />
|
||||||
|
<Compile Include="Chapters\ChapterManager.cs" />
|
||||||
<Compile Include="Folders\CollectionFolderImageProvider.cs" />
|
<Compile Include="Folders\CollectionFolderImageProvider.cs" />
|
||||||
<Compile Include="Folders\FolderMetadataService.cs" />
|
<Compile Include="Folders\FolderMetadataService.cs" />
|
||||||
<Compile Include="Folders\ImagesByNameImageProvider.cs" />
|
<Compile Include="Folders\ImagesByNameImageProvider.cs" />
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using MediaBrowser.Controller.Chapters;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
@ -49,58 +50,59 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly ISubtitleManager _subtitleManager;
|
private readonly ISubtitleManager _subtitleManager;
|
||||||
|
private readonly IChapterManager _chapterManager;
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return "ffprobe"; }
|
get { return "ffprobe"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(Episode item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(Episode item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchVideoInfo(item, directoryService, cancellationToken);
|
return FetchVideoInfo(item, options, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(MusicVideo item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(MusicVideo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchVideoInfo(item, directoryService, cancellationToken);
|
return FetchVideoInfo(item, options, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(Movie item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(Movie item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchVideoInfo(item, directoryService, cancellationToken);
|
return FetchVideoInfo(item, options, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(AdultVideo item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(AdultVideo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchVideoInfo(item, directoryService, cancellationToken);
|
return FetchVideoInfo(item, options, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(LiveTvVideoRecording item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(LiveTvVideoRecording item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchVideoInfo(item, directoryService, cancellationToken);
|
return FetchVideoInfo(item, options, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(Trailer item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(Trailer item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchVideoInfo(item, directoryService, cancellationToken);
|
return FetchVideoInfo(item, options, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(Video item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(Video item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchVideoInfo(item, directoryService, cancellationToken);
|
return FetchVideoInfo(item, options, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(Audio item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(Audio item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchAudioInfo(item, cancellationToken);
|
return FetchAudioInfo(item, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(LiveTvAudioRecording item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(LiveTvAudioRecording item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return FetchAudioInfo(item, cancellationToken);
|
return FetchAudioInfo(item, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FFProbeProvider(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem, IServerConfigurationManager config, ISubtitleManager subtitleManager)
|
public FFProbeProvider(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem, IServerConfigurationManager config, ISubtitleManager subtitleManager, IChapterManager chapterManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_isoManager = isoManager;
|
_isoManager = isoManager;
|
||||||
@ -114,10 +116,11 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_config = config;
|
_config = config;
|
||||||
_subtitleManager = subtitleManager;
|
_subtitleManager = subtitleManager;
|
||||||
|
_chapterManager = chapterManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.None);
|
private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.None);
|
||||||
public Task<ItemUpdateType> FetchVideoInfo<T>(T item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchVideoInfo<T>(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
where T : Video
|
where T : Video
|
||||||
{
|
{
|
||||||
if (item.LocationType != LocationType.FileSystem)
|
if (item.LocationType != LocationType.FileSystem)
|
||||||
@ -140,9 +143,9 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
return _cachedTask;
|
return _cachedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager, _fileSystem, _config, _subtitleManager);
|
var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager, _fileSystem, _config, _subtitleManager, _chapterManager);
|
||||||
|
|
||||||
return prober.ProbeVideo(item, directoryService, true, cancellationToken);
|
return prober.ProbeVideo(item, options, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAudioInfo<T>(T item, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAudioInfo<T>(T item, CancellationToken cancellationToken)
|
||||||
@ -171,9 +174,10 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
if (video != null && !video.IsPlaceHolder)
|
if (video != null && !video.IsPlaceHolder)
|
||||||
{
|
{
|
||||||
var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager, _fileSystem, _config, _subtitleManager);
|
return !video.SubtitleFiles
|
||||||
|
.SequenceEqual(SubtitleResolver.GetSubtitleFiles(video, directoryService, false)
|
||||||
return !video.SubtitleFiles.SequenceEqual(SubtitleResolver.GetSubtitleFiles(video, directoryService, false).Select(i => i.FullName).OrderBy(i => i), StringComparer.OrdinalIgnoreCase);
|
.Select(i => i.FullName)
|
||||||
|
.OrderBy(i => i), StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using MediaBrowser.Controller.Chapters;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
@ -41,10 +42,11 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly ISubtitleManager _subtitleManager;
|
private readonly ISubtitleManager _subtitleManager;
|
||||||
|
private readonly IChapterManager _chapterManager;
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem, IServerConfigurationManager config, ISubtitleManager subtitleManager)
|
public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem, IServerConfigurationManager config, ISubtitleManager subtitleManager, IChapterManager chapterManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_isoManager = isoManager;
|
_isoManager = isoManager;
|
||||||
@ -58,9 +60,12 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_config = config;
|
_config = config;
|
||||||
_subtitleManager = subtitleManager;
|
_subtitleManager = subtitleManager;
|
||||||
|
_chapterManager = chapterManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ItemUpdateType> ProbeVideo<T>(T item, IDirectoryService directoryService, bool enableSubtitleDownloading, CancellationToken cancellationToken)
|
public async Task<ItemUpdateType> ProbeVideo<T>(T item,
|
||||||
|
MetadataRefreshOptions options,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
where T : Video
|
where T : Video
|
||||||
{
|
{
|
||||||
var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
|
var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
|
||||||
@ -105,7 +110,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await Fetch(item, cancellationToken, result, isoMount, blurayDiscInfo, directoryService, enableSubtitleDownloading).ConfigureAwait(false);
|
await Fetch(item, cancellationToken, result, isoMount, blurayDiscInfo, options).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -121,7 +126,9 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
private const string SchemaVersion = "1";
|
private const string SchemaVersion = "1";
|
||||||
|
|
||||||
private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item, IIsoMount isoMount, CancellationToken cancellationToken)
|
private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item,
|
||||||
|
IIsoMount isoMount,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
@ -160,7 +167,12 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task Fetch(Video video, CancellationToken cancellationToken, InternalMediaInfoResult data, IIsoMount isoMount, BlurayDiscInfo blurayInfo, IDirectoryService directoryService, bool enableSubtitleDownloading)
|
protected async Task Fetch(Video video,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
InternalMediaInfoResult data,
|
||||||
|
IIsoMount isoMount,
|
||||||
|
BlurayDiscInfo blurayInfo,
|
||||||
|
MetadataRefreshOptions options)
|
||||||
{
|
{
|
||||||
var mediaInfo = MediaEncoderHelpers.GetMediaInfo(data);
|
var mediaInfo = MediaEncoderHelpers.GetMediaInfo(data);
|
||||||
var mediaStreams = mediaInfo.MediaStreams;
|
var mediaStreams = mediaInfo.MediaStreams;
|
||||||
@ -208,17 +220,12 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
FetchBdInfo(video, chapters, mediaStreams, blurayInfo);
|
FetchBdInfo(video, chapters, mediaStreams, blurayInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
await AddExternalSubtitles(video, mediaStreams, directoryService, enableSubtitleDownloading, cancellationToken).ConfigureAwait(false);
|
await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
FetchWtvInfo(video, data);
|
FetchWtvInfo(video, data);
|
||||||
|
|
||||||
video.IsHD = mediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1270);
|
video.IsHD = mediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1270);
|
||||||
|
|
||||||
if (chapters.Count == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video))
|
|
||||||
{
|
|
||||||
AddDummyChapters(video, chapters);
|
|
||||||
}
|
|
||||||
|
|
||||||
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
|
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
|
||||||
|
|
||||||
video.VideoBitRate = videoStream == null ? null : videoStream.BitRate;
|
video.VideoBitRate = videoStream == null ? null : videoStream.BitRate;
|
||||||
@ -228,18 +235,34 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
ExtractTimestamp(video);
|
ExtractTimestamp(video);
|
||||||
|
|
||||||
await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
|
|
||||||
{
|
|
||||||
Chapters = chapters,
|
|
||||||
Video = video,
|
|
||||||
ExtractImages = false,
|
|
||||||
SaveChapters = false
|
|
||||||
|
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken).ConfigureAwait(false);
|
await _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
|
if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh ||
|
||||||
|
options.MetadataRefreshMode == MetadataRefreshMode.EnsureMetadata)
|
||||||
|
{
|
||||||
|
var remoteChapters = await DownloadChapters(video, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (remoteChapters.Count > 0)
|
||||||
|
{
|
||||||
|
chapters = remoteChapters;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chapters.Count == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video))
|
||||||
|
{
|
||||||
|
AddDummyChapters(video, chapters);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
|
||||||
|
{
|
||||||
|
Chapters = chapters,
|
||||||
|
Video = video,
|
||||||
|
ExtractImages = false,
|
||||||
|
SaveChapters = false
|
||||||
|
|
||||||
|
}, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChapterInfo GetChapterInfo(MediaChapter chapter)
|
private ChapterInfo GetChapterInfo(MediaChapter chapter)
|
||||||
@ -416,15 +439,20 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="video">The video.</param>
|
/// <param name="video">The video.</param>
|
||||||
/// <param name="currentStreams">The current streams.</param>
|
/// <param name="currentStreams">The current streams.</param>
|
||||||
/// <param name="directoryService">The directory service.</param>
|
/// <param name="options">The options.</param>
|
||||||
/// <param name="enableSubtitleDownloading">if set to <c>true</c> [enable subtitle downloading].</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
private async Task AddExternalSubtitles(Video video, List<MediaStream> currentStreams, IDirectoryService directoryService, bool enableSubtitleDownloading, CancellationToken cancellationToken)
|
private async Task AddExternalSubtitles(Video video,
|
||||||
|
List<MediaStream> currentStreams,
|
||||||
|
MetadataRefreshOptions options,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var subtitleResolver = new SubtitleResolver(_localization);
|
var subtitleResolver = new SubtitleResolver(_localization);
|
||||||
|
|
||||||
var externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, currentStreams.Count, directoryService, false).ToList();
|
var externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, currentStreams.Count, options.DirectoryService, false).ToList();
|
||||||
|
|
||||||
|
var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.EnsureMetadata ||
|
||||||
|
options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh;
|
||||||
|
|
||||||
if (enableSubtitleDownloading && (_config.Configuration.SubtitleOptions.DownloadEpisodeSubtitles &&
|
if (enableSubtitleDownloading && (_config.Configuration.SubtitleOptions.DownloadEpisodeSubtitles &&
|
||||||
video is Episode) ||
|
video is Episode) ||
|
||||||
@ -444,7 +472,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
// Rescan
|
// Rescan
|
||||||
if (downloadedLanguages.Count > 0)
|
if (downloadedLanguages.Count > 0)
|
||||||
{
|
{
|
||||||
externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, currentStreams.Count, directoryService, true).ToList();
|
externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, currentStreams.Count, options.DirectoryService, true).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,6 +481,33 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
currentStreams.AddRange(externalSubtitleStreams);
|
currentStreams.AddRange(externalSubtitleStreams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<List<ChapterInfo>> DownloadChapters(Video video, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if ((_config.Configuration.ChapterOptions.DownloadEpisodeChapters &&
|
||||||
|
video is Episode) ||
|
||||||
|
(_config.Configuration.ChapterOptions.DownloadMovieChapters &&
|
||||||
|
video is Movie))
|
||||||
|
{
|
||||||
|
var results = await _chapterManager.Search(video, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var result = results.FirstOrDefault();
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
var chapters = await _chapterManager.GetChapters(result.Id, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return chapters.Chapters.Select(i => new ChapterInfo
|
||||||
|
{
|
||||||
|
Name = i.Name,
|
||||||
|
StartPositionTicks = i.StartPositionTicks
|
||||||
|
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<ChapterInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The dummy chapter duration
|
/// The dummy chapter duration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -499,6 +554,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <param name="mount">The mount.</param>
|
/// <param name="mount">The mount.</param>
|
||||||
|
/// <param name="blurayDiscInfo">The bluray disc information.</param>
|
||||||
private void OnPreFetch(Video item, IIsoMount mount, BlurayDiscInfo blurayDiscInfo)
|
private void OnPreFetch(Video item, IIsoMount mount, BlurayDiscInfo blurayDiscInfo)
|
||||||
{
|
{
|
||||||
if (item.VideoType == VideoType.Iso)
|
if (item.VideoType == VideoType.Iso)
|
||||||
|
@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Photos
|
|||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ItemUpdateType> FetchAsync(Photo item, IDirectoryService directoryService, CancellationToken cancellationToken)
|
public Task<ItemUpdateType> FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
item.SetImagePath(ImageType.Primary, item.Path);
|
item.SetImagePath(ImageType.Primary, item.Path);
|
||||||
item.SetImagePath(ImageType.Backdrop, item.Path);
|
item.SetImagePath(ImageType.Backdrop, item.Path);
|
||||||
|
@ -410,6 +410,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||||||
{
|
{
|
||||||
stream.PacketLength = null;
|
stream.PacketLength = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't trust the provider values
|
||||||
|
stream.Index = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,5 +143,7 @@
|
|||||||
"HeaderSelectChannelDownloadPathHelp": "Browse or enter the path to use for storing channel cache files. The folder must be writeable.",
|
"HeaderSelectChannelDownloadPathHelp": "Browse or enter the path to use for storing channel cache files. The folder must be writeable.",
|
||||||
"OptionNewCollection": "New...",
|
"OptionNewCollection": "New...",
|
||||||
"ButtonAdd": "Add",
|
"ButtonAdd": "Add",
|
||||||
"ButtonRemove": "Remove"
|
"ButtonRemove": "Remove",
|
||||||
|
"LabelChapterDownloaders": "Chapter downloaders:",
|
||||||
|
"LabelChapterDownloadersHelp": "Enable and rank your preferred chapter downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information."
|
||||||
}
|
}
|
@ -733,11 +733,15 @@
|
|||||||
"OptionReportByteRangeSeekingWhenTranscodingHelp": "This is required for some devices that don't time seek very well.",
|
"OptionReportByteRangeSeekingWhenTranscodingHelp": "This is required for some devices that don't time seek very well.",
|
||||||
"HeaderSubtitleDownloadingHelp": "When Media Browser scans your video files it can search for missing subtitles, and download them using a subtitle provider such as OpenSubtitles.org.",
|
"HeaderSubtitleDownloadingHelp": "When Media Browser scans your video files it can search for missing subtitles, and download them using a subtitle provider such as OpenSubtitles.org.",
|
||||||
"HeaderDownloadSubtitlesFor": "Download subtitles for:",
|
"HeaderDownloadSubtitlesFor": "Download subtitles for:",
|
||||||
|
"MessageNoChapterProviders": "Install a chapter provider plugin such as ChapterDb or tagChimp to enable additional chapter metadata options.",
|
||||||
"LabelSkipIfGraphicalSubsPresent": "Skip if the video already contains graphical subtitles",
|
"LabelSkipIfGraphicalSubsPresent": "Skip if the video already contains graphical subtitles",
|
||||||
"LabelSkipIfGraphicalSubsPresentHelp": "Keeping text versions of subtitles will result in more efficient delivery to mobile clients.",
|
"LabelSkipIfGraphicalSubsPresentHelp": "Keeping text versions of subtitles will result in more efficient delivery to mobile clients.",
|
||||||
"TabSubtitles": "Subtitles",
|
"TabSubtitles": "Subtitles",
|
||||||
|
"TabChapters": "Chapters",
|
||||||
|
"HeaderDownloadChaptersFor": "Download chapter names for:",
|
||||||
"LabelOpenSubtitlesUsername": "Open Subtitles username:",
|
"LabelOpenSubtitlesUsername": "Open Subtitles username:",
|
||||||
"LabelOpenSubtitlesPassword": "Open Subtitles password:",
|
"LabelOpenSubtitlesPassword": "Open Subtitles password:",
|
||||||
|
"HeaderChapterDownloadingHelp": "When Media Browser scans your video files it can download friendly chapter names from the internet using chapter plugins such as ChapterDb and tagChimp.",
|
||||||
"LabelPlayDefaultAudioTrack": "Play default audio track regardless of language",
|
"LabelPlayDefaultAudioTrack": "Play default audio track regardless of language",
|
||||||
"LabelSubtitlePlaybackMode": "Subtitle mode:",
|
"LabelSubtitlePlaybackMode": "Subtitle mode:",
|
||||||
"LabelDownloadLanguages": "Download languages:",
|
"LabelDownloadLanguages": "Download languages:",
|
||||||
|
@ -91,21 +91,21 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
|
|||||||
|
|
||||||
if (video is Movie)
|
if (video is Movie)
|
||||||
{
|
{
|
||||||
if (!_config.Configuration.EnableMovieChapterImageExtraction)
|
if (!_config.Configuration.ChapterOptions.EnableMovieChapterImageExtraction)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (video is Episode)
|
else if (video is Episode)
|
||||||
{
|
{
|
||||||
if (!_config.Configuration.EnableEpisodeChapterImageExtraction)
|
if (!_config.Configuration.ChapterOptions.EnableEpisodeChapterImageExtraction)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!_config.Configuration.EnableOtherVideoChapterImageExtraction)
|
if (!_config.Configuration.ChapterOptions.EnableOtherVideoChapterImageExtraction)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using MediaBrowser.Common.Net;
|
|||||||
using MediaBrowser.Common.Progress;
|
using MediaBrowser.Common.Progress;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
|
using MediaBrowser.Controller.Chapters;
|
||||||
using MediaBrowser.Controller.Collections;
|
using MediaBrowser.Controller.Collections;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
@ -43,6 +44,7 @@ using MediaBrowser.Model.Logging;
|
|||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.System;
|
using MediaBrowser.Model.System;
|
||||||
using MediaBrowser.Model.Updates;
|
using MediaBrowser.Model.Updates;
|
||||||
|
using MediaBrowser.Providers.Chapters;
|
||||||
using MediaBrowser.Providers.Manager;
|
using MediaBrowser.Providers.Manager;
|
||||||
using MediaBrowser.Providers.Subtitles;
|
using MediaBrowser.Providers.Subtitles;
|
||||||
using MediaBrowser.Server.Implementations;
|
using MediaBrowser.Server.Implementations;
|
||||||
@ -196,6 +198,7 @@ namespace MediaBrowser.ServerApplication
|
|||||||
|
|
||||||
private INotificationManager NotificationManager { get; set; }
|
private INotificationManager NotificationManager { get; set; }
|
||||||
private ISubtitleManager SubtitleManager { get; set; }
|
private ISubtitleManager SubtitleManager { get; set; }
|
||||||
|
private IChapterManager ChapterManager { get; set; }
|
||||||
|
|
||||||
private IUserViewManager UserViewManager { get; set; }
|
private IUserViewManager UserViewManager { get; set; }
|
||||||
|
|
||||||
@ -544,6 +547,9 @@ namespace MediaBrowser.ServerApplication
|
|||||||
SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, ItemRepository);
|
SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, ItemRepository);
|
||||||
RegisterSingleInstance(SubtitleManager);
|
RegisterSingleInstance(SubtitleManager);
|
||||||
|
|
||||||
|
ChapterManager = new ChapterManager(LibraryManager, LogManager.GetLogger("ChapterManager"), ServerConfigurationManager);
|
||||||
|
RegisterSingleInstance(ChapterManager);
|
||||||
|
|
||||||
var displayPreferencesTask = Task.Run(async () => await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false));
|
var displayPreferencesTask = Task.Run(async () => await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false));
|
||||||
var itemsTask = Task.Run(async () => await ConfigureItemRepositories().ConfigureAwait(false));
|
var itemsTask = Task.Run(async () => await ConfigureItemRepositories().ConfigureAwait(false));
|
||||||
var userdataTask = Task.Run(async () => await ConfigureUserDataRepositories().ConfigureAwait(false));
|
var userdataTask = Task.Run(async () => await ConfigureUserDataRepositories().ConfigureAwait(false));
|
||||||
@ -725,7 +731,8 @@ namespace MediaBrowser.ServerApplication
|
|||||||
LiveTvManager.AddParts(GetExports<ILiveTvService>());
|
LiveTvManager.AddParts(GetExports<ILiveTvService>());
|
||||||
|
|
||||||
SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
|
SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
|
||||||
|
ChapterManager.AddParts(GetExports<IChapterProvider>());
|
||||||
|
|
||||||
SessionManager.AddParts(GetExports<ISessionControllerFactory>());
|
SessionManager.AddParts(GetExports<ISessionControllerFactory>());
|
||||||
|
|
||||||
ChannelManager.AddParts(GetExports<IChannel>(), GetExports<IChannelFactory>());
|
ChannelManager.AddParts(GetExports<IChannel>(), GetExports<IChannelFactory>());
|
||||||
|
@ -591,6 +591,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||||||
"metadataconfigurationpage.js",
|
"metadataconfigurationpage.js",
|
||||||
"metadataimagespage.js",
|
"metadataimagespage.js",
|
||||||
"metadatasubtitles.js",
|
"metadatasubtitles.js",
|
||||||
|
"metadatachapters.js",
|
||||||
"moviegenres.js",
|
"moviegenres.js",
|
||||||
"moviecollections.js",
|
"moviecollections.js",
|
||||||
"movies.js",
|
"movies.js",
|
||||||
|
@ -331,6 +331,9 @@
|
|||||||
<Content Include="dashboard-ui\librarypathmapping.html">
|
<Content Include="dashboard-ui\librarypathmapping.html">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\metadatachapters.html">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\mypreferencesdisplay.html">
|
<Content Include="dashboard-ui\mypreferencesdisplay.html">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@ -670,6 +673,9 @@
|
|||||||
<Content Include="dashboard-ui\scripts\localsettings.js">
|
<Content Include="dashboard-ui\scripts\localsettings.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\scripts\metadatachapters.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\scripts\mypreferencesdisplay.js">
|
<Content Include="dashboard-ui\scripts\mypreferencesdisplay.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.399</version>
|
<version>3.0.400</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
|
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.399" />
|
<dependency id="MediaBrowser.Common" version="3.0.400" />
|
||||||
<dependency id="NLog" version="2.1.0" />
|
<dependency id="NLog" version="2.1.0" />
|
||||||
<dependency id="SimpleInjector" version="2.5.0" />
|
<dependency id="SimpleInjector" version="2.5.0" />
|
||||||
<dependency id="sharpcompress" version="0.10.2" />
|
<dependency id="sharpcompress" version="0.10.2" />
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.399</version>
|
<version>3.0.400</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.399</version>
|
<version>3.0.400</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.399" />
|
<dependency id="MediaBrowser.Common" version="3.0.400" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user