commit
080a6511dc
|
@ -70,12 +70,13 @@ namespace MediaBrowser.Api
|
|||
Cultures = _localizationManager.GetCultures().ToList()
|
||||
};
|
||||
|
||||
if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName))
|
||||
if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName) &&
|
||||
item.SourceType == SourceType.Library)
|
||||
{
|
||||
var inheritedContentType = _libraryManager.GetInheritedContentType(item);
|
||||
var configuredContentType = _libraryManager.GetConfiguredContentType(item);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || !string.IsNullOrWhiteSpace(configuredContentType))
|
||||
if (string.IsNullOrWhiteSpace(inheritedContentType) || !string.IsNullOrWhiteSpace(configuredContentType))
|
||||
{
|
||||
info.ContentTypeOptions = GetContentTypeOptions(true);
|
||||
info.ContentType = configuredContentType;
|
||||
|
|
|
@ -25,6 +25,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
||||
namespace MediaBrowser.Api.Library
|
||||
{
|
||||
|
@ -288,12 +289,13 @@ namespace MediaBrowser.Api.Library
|
|||
private readonly ITVSeriesManager _tvManager;
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LibraryService" /> class.
|
||||
/// </summary>
|
||||
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
|
||||
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
|
||||
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, IServerConfigurationManager config)
|
||||
{
|
||||
_itemRepo = itemRepo;
|
||||
_libraryManager = libraryManager;
|
||||
|
@ -307,6 +309,7 @@ namespace MediaBrowser.Api.Library
|
|||
_tvManager = tvManager;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_fileSystem = fileSystem;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public object Get(GetSimilarItems request)
|
||||
|
@ -377,7 +380,7 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
if (item is Movie || (program != null && program.IsMovie) || item is Trailer)
|
||||
{
|
||||
return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService)
|
||||
return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _config)
|
||||
{
|
||||
AuthorizationContext = AuthorizationContext,
|
||||
Logger = Logger,
|
||||
|
|
|
@ -155,12 +155,72 @@ namespace MediaBrowser.Api.LiveTv
|
|||
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableUserData { get; set; }
|
||||
|
||||
public bool? IsMovie { get; set; }
|
||||
public bool? IsSeries { get; set; }
|
||||
public bool? IsKids { get; set; }
|
||||
public bool? IsSports { get; set; }
|
||||
|
||||
public GetRecordings()
|
||||
{
|
||||
EnableTotalRecordCount = true;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Recordings/Series", "GET", Summary = "Gets live tv recordings")]
|
||||
[Authenticated]
|
||||
public class GetRecordingSeries : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
|
||||
{
|
||||
[ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
[ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
[ApiMember(Name = "GroupId", Description = "Optional filter by recording group.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string GroupId { get; set; }
|
||||
|
||||
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? StartIndex { get; set; }
|
||||
|
||||
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? Limit { get; set; }
|
||||
|
||||
[ApiMember(Name = "Status", Description = "Optional filter by recording status.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public RecordingStatus? Status { get; set; }
|
||||
|
||||
[ApiMember(Name = "Status", Description = "Optional filter by recordings that are in progress, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsInProgress { get; set; }
|
||||
|
||||
[ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string SeriesTimerId { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
public bool EnableTotalRecordCount { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableUserData { get; set; }
|
||||
|
||||
public GetRecordingSeries()
|
||||
{
|
||||
EnableTotalRecordCount = true;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
|
||||
[Authenticated]
|
||||
public class GetRecordingGroups : IReturn<QueryResult<BaseItemDto>>
|
||||
|
@ -535,12 +595,6 @@ namespace MediaBrowser.Api.LiveTv
|
|||
[Authenticated]
|
||||
public class GetLiveTvRegistrationInfo : IReturn<MBRegistrationRecord>
|
||||
{
|
||||
[ApiMember(Name = "ChannelId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
[ApiMember(Name = "ProgramId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ProgramId { get; set; }
|
||||
|
||||
[ApiMember(Name = "Feature", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Feature { get; set; }
|
||||
}
|
||||
|
@ -592,7 +646,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
public async Task<object> Get(GetLiveTvRegistrationInfo request)
|
||||
{
|
||||
var result = await _liveTvManager.GetRegistrationInfo(request.ChannelId, request.ProgramId, request.Feature).ConfigureAwait(false);
|
||||
var result = await _liveTvManager.GetRegistrationInfo(request.Feature).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
@ -854,6 +908,32 @@ namespace MediaBrowser.Api.LiveTv
|
|||
options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
|
||||
|
||||
var result = await _liveTvManager.GetRecordings(new RecordingQuery
|
||||
{
|
||||
ChannelId = request.ChannelId,
|
||||
UserId = request.UserId,
|
||||
GroupId = request.GroupId,
|
||||
StartIndex = request.StartIndex,
|
||||
Limit = request.Limit,
|
||||
Status = request.Status,
|
||||
SeriesTimerId = request.SeriesTimerId,
|
||||
IsInProgress = request.IsInProgress,
|
||||
EnableTotalRecordCount = request.EnableTotalRecordCount,
|
||||
IsMovie = request.IsMovie,
|
||||
IsSeries = request.IsSeries,
|
||||
IsKids = request.IsKids,
|
||||
IsSports = request.IsSports
|
||||
|
||||
}, options, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetRecordingSeries request)
|
||||
{
|
||||
var options = GetDtoOptions(request);
|
||||
options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
|
||||
|
||||
var result = await _liveTvManager.GetRecordingSeries(new RecordingQuery
|
||||
{
|
||||
ChannelId = request.ChannelId,
|
||||
UserId = request.UserId,
|
||||
|
|
|
@ -14,6 +14,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
|
||||
namespace MediaBrowser.Api.Movies
|
||||
|
@ -88,6 +89,7 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
private readonly IItemRepository _itemRepo;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MoviesService" /> class.
|
||||
|
@ -97,13 +99,14 @@ namespace MediaBrowser.Api.Movies
|
|||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="itemRepo">The item repo.</param>
|
||||
/// <param name="dtoService">The dto service.</param>
|
||||
public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
|
||||
public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IServerConfigurationManager config)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_libraryManager = libraryManager;
|
||||
_itemRepo = itemRepo;
|
||||
_dtoService = dtoService;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -146,15 +149,17 @@ namespace MediaBrowser.Api.Movies
|
|||
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
|
||||
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var itemTypes = new List<string> { typeof(Movie).Name };
|
||||
if (_config.Configuration.EnableExternalContentInSuggestions)
|
||||
{
|
||||
itemTypes.Add(typeof(Trailer).Name);
|
||||
itemTypes.Add(typeof(LiveTvProgram).Name);
|
||||
}
|
||||
|
||||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Limit = request.Limit,
|
||||
IncludeItemTypes = new[]
|
||||
{
|
||||
typeof(Movie).Name,
|
||||
typeof(Trailer).Name,
|
||||
typeof(LiveTvProgram).Name
|
||||
},
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
SimilarTo = item,
|
||||
EnableGroupByMetadataKey = true
|
||||
|
@ -198,14 +203,16 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList();
|
||||
|
||||
var itemTypes = new List<string> { typeof(Movie).Name };
|
||||
if (_config.Configuration.EnableExternalContentInSuggestions)
|
||||
{
|
||||
itemTypes.Add(typeof(Trailer).Name);
|
||||
itemTypes.Add(typeof(LiveTvProgram).Name);
|
||||
}
|
||||
|
||||
var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[]
|
||||
{
|
||||
typeof(Movie).Name,
|
||||
typeof(Trailer).Name,
|
||||
typeof(LiveTvProgram).Name
|
||||
},
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
SortBy = new[] { ItemSortBy.Random },
|
||||
SortOrder = SortOrder.Descending,
|
||||
|
@ -278,6 +285,13 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
private IEnumerable<RecommendationDto> GetWithDirector(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
|
||||
{
|
||||
var itemTypes = new List<string> { typeof(Movie).Name };
|
||||
if (_config.Configuration.EnableExternalContentInSuggestions)
|
||||
{
|
||||
itemTypes.Add(typeof(Trailer).Name);
|
||||
itemTypes.Add(typeof(LiveTvProgram).Name);
|
||||
}
|
||||
|
||||
foreach (var name in names)
|
||||
{
|
||||
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
|
@ -286,12 +300,7 @@ namespace MediaBrowser.Api.Movies
|
|||
// Account for duplicates by imdb id, since the database doesn't support this yet
|
||||
Limit = itemLimit + 2,
|
||||
PersonTypes = new[] { PersonType.Director },
|
||||
IncludeItemTypes = new[]
|
||||
{
|
||||
typeof(Movie).Name,
|
||||
typeof(Trailer).Name,
|
||||
typeof(LiveTvProgram).Name
|
||||
},
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
EnableGroupByMetadataKey = true
|
||||
|
||||
|
@ -314,6 +323,13 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
private IEnumerable<RecommendationDto> GetWithActor(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
|
||||
{
|
||||
var itemTypes = new List<string> { typeof(Movie).Name };
|
||||
if (_config.Configuration.EnableExternalContentInSuggestions)
|
||||
{
|
||||
itemTypes.Add(typeof(Trailer).Name);
|
||||
itemTypes.Add(typeof(LiveTvProgram).Name);
|
||||
}
|
||||
|
||||
foreach (var name in names)
|
||||
{
|
||||
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
|
@ -321,12 +337,7 @@ namespace MediaBrowser.Api.Movies
|
|||
Person = name,
|
||||
// Account for duplicates by imdb id, since the database doesn't support this yet
|
||||
Limit = itemLimit + 2,
|
||||
IncludeItemTypes = new[]
|
||||
{
|
||||
typeof(Movie).Name,
|
||||
typeof(Trailer).Name,
|
||||
typeof(LiveTvProgram).Name
|
||||
},
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
EnableGroupByMetadataKey = true
|
||||
|
||||
|
@ -349,17 +360,19 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
|
||||
{
|
||||
var itemTypes = new List<string> { typeof(Movie).Name };
|
||||
if (_config.Configuration.EnableExternalContentInSuggestions)
|
||||
{
|
||||
itemTypes.Add(typeof(Trailer).Name);
|
||||
itemTypes.Add(typeof(LiveTvProgram).Name);
|
||||
}
|
||||
|
||||
foreach (var item in baselineItems)
|
||||
{
|
||||
var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Limit = itemLimit,
|
||||
IncludeItemTypes = new[]
|
||||
{
|
||||
typeof(Movie).Name,
|
||||
typeof(Trailer).Name,
|
||||
typeof(LiveTvProgram).Name
|
||||
},
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
SimilarTo = item,
|
||||
EnableGroupByMetadataKey = true
|
||||
|
|
|
@ -337,44 +337,60 @@ namespace MediaBrowser.Api.Playback
|
|||
/// Gets the video bitrate to specify on the command line
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <param name="videoCodec">The video codec.</param>
|
||||
/// <param name="videoEncoder">The video codec.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetVideoQualityParam(StreamState state, string videoCodec)
|
||||
protected string GetVideoQualityParam(StreamState state, string videoEncoder)
|
||||
{
|
||||
var param = string.Empty;
|
||||
|
||||
var isVc1 = state.VideoStream != null &&
|
||||
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset superfast";
|
||||
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
|
||||
|
||||
param += " -crf 23";
|
||||
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(encodingOptions.H264Preset))
|
||||
{
|
||||
param += "-preset " + encodingOptions.H264Preset;
|
||||
}
|
||||
else
|
||||
{
|
||||
param += "-preset superfast";
|
||||
}
|
||||
|
||||
if (encodingOptions.H264Crf >= 0 && encodingOptions.H264Crf <= 51)
|
||||
{
|
||||
param += " -crf " + encodingOptions.H264Crf.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
param += " -crf 23";
|
||||
}
|
||||
}
|
||||
|
||||
else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset fast";
|
||||
param += "-preset fast";
|
||||
|
||||
param += " -crf 28";
|
||||
}
|
||||
|
||||
// h264 (h264_qsv)
|
||||
else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset 7 -look_ahead 0";
|
||||
param += "-preset 7 -look_ahead 0";
|
||||
|
||||
}
|
||||
|
||||
// h264 (h264_nvenc)
|
||||
else if (string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset default";
|
||||
param += "-preset default";
|
||||
}
|
||||
|
||||
// webm
|
||||
else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Values 0-3, 0 being highest quality but slower
|
||||
var profileScore = 0;
|
||||
|
@ -394,30 +410,30 @@ namespace MediaBrowser.Api.Playback
|
|||
profileScore = Math.Min(profileScore, 2);
|
||||
|
||||
// http://www.webmproject.org/docs/encoder-parameters/
|
||||
param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}",
|
||||
param += string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}",
|
||||
profileScore.ToString(UsCulture),
|
||||
crf,
|
||||
qmin,
|
||||
qmax);
|
||||
}
|
||||
|
||||
else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
|
||||
param += "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
|
||||
}
|
||||
|
||||
// asf/wmv
|
||||
else if (string.Equals(videoCodec, "wmv2", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-qmin 2";
|
||||
param += "-qmin 2";
|
||||
}
|
||||
|
||||
else if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-mbd 2";
|
||||
param += "-mbd 2";
|
||||
}
|
||||
|
||||
param += GetVideoBitrateParam(state, videoCodec);
|
||||
param += GetVideoBitrateParam(state, videoEncoder);
|
||||
|
||||
var framerate = GetFramerateParam(state);
|
||||
if (framerate.HasValue)
|
||||
|
@ -432,8 +448,8 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
if (!string.IsNullOrEmpty(state.VideoRequest.Profile))
|
||||
{
|
||||
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// not supported by h264_omx
|
||||
param += " -profile:v " + state.VideoRequest.Profile;
|
||||
|
@ -442,11 +458,13 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
if (!string.IsNullOrEmpty(state.VideoRequest.Level))
|
||||
{
|
||||
var level = NormalizeTranscodingLevel(state.OutputVideoCodec, state.VideoRequest.Level);
|
||||
|
||||
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
|
||||
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
switch (state.VideoRequest.Level)
|
||||
switch (level)
|
||||
{
|
||||
case "30":
|
||||
param += " -level 3";
|
||||
|
@ -476,20 +494,20 @@ namespace MediaBrowser.Api.Playback
|
|||
param += " -level 5.2";
|
||||
break;
|
||||
default:
|
||||
param += " -level " + state.VideoRequest.Level;
|
||||
param += " -level " + level;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
|
||||
else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param += " -level " + state.VideoRequest.Level;
|
||||
param += " -level " + level;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-pix_fmt yuv420p " + param;
|
||||
}
|
||||
|
@ -497,6 +515,25 @@ namespace MediaBrowser.Api.Playback
|
|||
return param;
|
||||
}
|
||||
|
||||
private string NormalizeTranscodingLevel(string videoCodec, string level)
|
||||
{
|
||||
double requestLevel;
|
||||
|
||||
// Clients may direct play higher than level 41, but there's no reason to transcode higher
|
||||
if (double.TryParse(level, NumberStyles.Any, UsCulture, out requestLevel))
|
||||
{
|
||||
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (requestLevel > 41)
|
||||
{
|
||||
return "41";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
protected string GetAudioFilterParam(StreamState state, bool isHls)
|
||||
{
|
||||
var volParam = string.Empty;
|
||||
|
@ -1160,17 +1197,21 @@ namespace MediaBrowser.Api.Playback
|
|||
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive)
|
||||
if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited)
|
||||
{
|
||||
await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
|
||||
if (state.ReadInputAtNativeFramerate)
|
||||
if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited)
|
||||
{
|
||||
await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
StartThrottler(state, transcodingJob);
|
||||
if (!transcodingJob.HasExited)
|
||||
{
|
||||
StartThrottler(state, transcodingJob);
|
||||
}
|
||||
|
||||
ReportUsage(state);
|
||||
|
||||
return transcodingJob;
|
||||
|
@ -1770,6 +1811,15 @@ namespace MediaBrowser.Api.Playback
|
|||
// state.SegmentLength = 6;
|
||||
//}
|
||||
|
||||
if (state.VideoRequest != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(state.VideoRequest.VideoCodec))
|
||||
{
|
||||
state.SupportedVideoCodecs = state.VideoRequest.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
|
||||
state.VideoRequest.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.AudioCodec))
|
||||
{
|
||||
state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
|
||||
|
@ -2012,7 +2062,7 @@ namespace MediaBrowser.Api.Playback
|
|||
}
|
||||
|
||||
// Source and target codecs must match
|
||||
if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase))
|
||||
if (string.IsNullOrEmpty(videoStream.Codec) || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
|
@ -70,8 +71,9 @@ namespace MediaBrowser.Api.Playback
|
|||
private readonly INetworkManager _networkManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IJsonSerializer _json;
|
||||
|
||||
public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager, IMediaEncoder mediaEncoder, IUserManager userManager)
|
||||
public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager, IMediaEncoder mediaEncoder, IUserManager userManager, IJsonSerializer json)
|
||||
{
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_deviceManager = deviceManager;
|
||||
|
@ -80,6 +82,7 @@ namespace MediaBrowser.Api.Playback
|
|||
_networkManager = networkManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_userManager = userManager;
|
||||
_json = json;
|
||||
}
|
||||
|
||||
public object Get(GetBitrateTestBytes request)
|
||||
|
@ -147,6 +150,8 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
var profile = request.DeviceProfile;
|
||||
|
||||
//Logger.Info("GetPostedPlaybackInfo profile: {0}", _json.SerializeToString(profile));
|
||||
|
||||
if (profile == null)
|
||||
{
|
||||
var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
|
||||
|
|
|
@ -112,6 +112,7 @@ namespace MediaBrowser.Api.Playback
|
|||
public string OutputVideoSync = "-1";
|
||||
|
||||
public List<string> SupportedAudioCodecs { get; set; }
|
||||
public List<string> SupportedVideoCodecs { get; set; }
|
||||
public string UserAgent { get; set; }
|
||||
|
||||
public StreamState(IMediaSourceManager mediaSourceManager, ILogger logger)
|
||||
|
@ -119,6 +120,7 @@ namespace MediaBrowser.Api.Playback
|
|||
_mediaSourceManager = mediaSourceManager;
|
||||
_logger = logger;
|
||||
SupportedAudioCodecs = new List<string>();
|
||||
SupportedVideoCodecs = new List<string>();
|
||||
PlayableStreamFileNames = new List<string>();
|
||||
RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
|
|
@ -478,7 +478,7 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
else
|
||||
{
|
||||
episodes = series.GetSeasonEpisodes(user, season);
|
||||
episodes = series.GetSeasonEpisodes(season, user);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -142,9 +142,15 @@ namespace MediaBrowser.Common.Implementations.Security
|
|||
}
|
||||
set
|
||||
{
|
||||
if (value != LicenseFile.RegKey)
|
||||
var newValue = value;
|
||||
if (newValue != null)
|
||||
{
|
||||
LicenseFile.RegKey = value;
|
||||
newValue = newValue.Trim();
|
||||
}
|
||||
|
||||
if (newValue != LicenseFile.RegKey)
|
||||
{
|
||||
LicenseFile.RegKey = newValue;
|
||||
LicenseFile.Save();
|
||||
|
||||
// re-load registration info
|
||||
|
|
|
@ -14,16 +14,14 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private TimeSpan _cacheLength;
|
||||
|
||||
public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer, TimeSpan cacheLength)
|
||||
public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_cacheLength = cacheLength;
|
||||
}
|
||||
|
||||
public async Task<CheckForUpdateResult> CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, CancellationToken cancellationToken)
|
||||
public async Task<CheckForUpdateResult> CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, TimeSpan cacheLength, CancellationToken cancellationToken)
|
||||
{
|
||||
var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
|
||||
|
||||
|
@ -35,10 +33,10 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
UserAgent = "Emby/3.0"
|
||||
};
|
||||
|
||||
if (_cacheLength.Ticks > 0)
|
||||
if (cacheLength.Ticks > 0)
|
||||
{
|
||||
options.CacheMode = CacheMode.Unconditional;
|
||||
options.CacheLength = _cacheLength;
|
||||
options.CacheLength = cacheLength;
|
||||
}
|
||||
|
||||
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
|
||||
|
@ -110,12 +108,6 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
UserAgent = "Emby/3.0"
|
||||
};
|
||||
|
||||
if (_cacheLength.Ticks > 0)
|
||||
{
|
||||
options.CacheMode = CacheMode.Unconditional;
|
||||
options.CacheLength = _cacheLength;
|
||||
}
|
||||
|
||||
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
|
||||
{
|
||||
var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);
|
||||
|
|
|
@ -31,6 +31,8 @@ namespace MediaBrowser.Controller.Channels
|
|||
/// <returns>ChannelFeatures.</returns>
|
||||
ChannelFeatures GetChannelFeatures(string id);
|
||||
|
||||
bool SupportsSync(string channelId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all channel features.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Collections
|
||||
namespace MediaBrowser.Controller.Collections
|
||||
{
|
||||
public class ManualCollectionsFolder : BasePluginFolder, IHiddenFromDisplay
|
||||
{
|
|
@ -106,7 +106,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
LibraryOptions[path] = options;
|
||||
|
||||
options.SchemaVersion = 1;
|
||||
options.SchemaVersion = 2;
|
||||
XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1057,10 +1057,20 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <returns>IList{BaseItem}.</returns>
|
||||
public IList<BaseItem> GetRecursiveChildren()
|
||||
{
|
||||
return GetRecursiveChildren(i => true);
|
||||
return GetRecursiveChildren(true);
|
||||
}
|
||||
|
||||
public IList<BaseItem> GetRecursiveChildren(bool includeLinkedChildren)
|
||||
{
|
||||
return GetRecursiveChildren(i => true, includeLinkedChildren);
|
||||
}
|
||||
|
||||
public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter)
|
||||
{
|
||||
return GetRecursiveChildren(filter, true);
|
||||
}
|
||||
|
||||
public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter, bool includeLinkedChildren)
|
||||
{
|
||||
var result = new Dictionary<Guid, BaseItem>();
|
||||
|
||||
|
|
|
@ -85,9 +85,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
|
||||
public override int GetChildCount(User user)
|
||||
{
|
||||
Logger.Debug("Season {0} getting child cound", (Path ?? Name));
|
||||
var result = GetChildren(user, true).Count();
|
||||
Logger.Debug("Season {0} child cound: ", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -158,13 +156,10 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
|
||||
var id = Guid.NewGuid().ToString("N");
|
||||
|
||||
Logger.Debug("Season.GetItemsInternal entering GetEpisodes. Request id: " + id);
|
||||
var items = GetEpisodes(user).Where(filter);
|
||||
|
||||
Logger.Debug("Season.GetItemsInternal entering PostFilterAndSort. Request id: " + id);
|
||||
var result = PostFilterAndSort(items, query, false, false);
|
||||
|
||||
Logger.Debug("Season.GetItemsInternal complete. Request id: " + id);
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
|
@ -185,34 +180,12 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
|
||||
public IEnumerable<Episode> GetEpisodes(Series series, User user, IEnumerable<Episode> allSeriesEpisodes)
|
||||
{
|
||||
return series.GetSeasonEpisodes(user, this, allSeriesEpisodes);
|
||||
return series.GetSeasonEpisodes(this, user, allSeriesEpisodes);
|
||||
}
|
||||
|
||||
public IEnumerable<Episode> GetEpisodes()
|
||||
{
|
||||
var episodes = GetRecursiveChildren().OfType<Episode>();
|
||||
var series = Series;
|
||||
|
||||
if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
|
||||
{
|
||||
var seasonNumber = IndexNumber;
|
||||
var list = episodes.ToList();
|
||||
|
||||
if (seasonNumber.HasValue)
|
||||
{
|
||||
list.AddRange(series.GetRecursiveChildren().OfType<Episode>()
|
||||
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.AddRange(series.GetRecursiveChildren().OfType<Episode>()
|
||||
.Where(i => !i.ParentIndexNumber.HasValue));
|
||||
}
|
||||
|
||||
episodes = list.DistinctBy(i => i.Id);
|
||||
}
|
||||
|
||||
return episodes;
|
||||
return Series.GetSeasonEpisodes(this, null, null);
|
||||
}
|
||||
|
||||
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
|
||||
|
|
|
@ -209,7 +209,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
|
||||
var seriesKey = GetUniqueSeriesKey(this);
|
||||
|
||||
Logger.Debug("GetSeasons SeriesKey: {0}", seriesKey);
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
AncestorWithPresentationUniqueKey = seriesKey,
|
||||
|
@ -267,7 +266,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
public IEnumerable<Episode> GetEpisodes(User user)
|
||||
{
|
||||
var seriesKey = GetUniqueSeriesKey(this);
|
||||
Logger.Debug("GetEpisodes seriesKey: {0}", seriesKey);
|
||||
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
|
@ -291,8 +289,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
|
||||
var allItems = LibraryManager.GetItemList(query).ToList();
|
||||
|
||||
Logger.Debug("GetEpisodes return {0} items from database", allItems.Count);
|
||||
|
||||
var allSeriesEpisodes = allItems.OfType<Episode>().ToList();
|
||||
|
||||
var allEpisodes = allItems.OfType<Season>()
|
||||
|
@ -373,27 +369,9 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
progress.Report(100);
|
||||
}
|
||||
|
||||
private IEnumerable<Episode> GetAllEpisodes(User user)
|
||||
{
|
||||
Logger.Debug("Series.GetAllEpisodes entering GetItemList");
|
||||
|
||||
var result = LibraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this),
|
||||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
SortBy = new[] { ItemSortBy.SortName }
|
||||
|
||||
}).Cast<Episode>().ToList();
|
||||
|
||||
Logger.Debug("Series.GetAllEpisodes returning {0} episodes", result.Count);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerable<Episode> GetSeasonEpisodes(User user, Season parentSeason)
|
||||
public IEnumerable<Episode> GetSeasonEpisodes(Season parentSeason, User user)
|
||||
{
|
||||
var seriesKey = GetUniqueSeriesKey(this);
|
||||
Logger.Debug("GetSeasonEpisodes seriesKey: {0}", seriesKey);
|
||||
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
|
@ -401,34 +379,35 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
SortBy = new[] { ItemSortBy.SortName }
|
||||
};
|
||||
var config = user.Configuration;
|
||||
if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
|
||||
if (user != null)
|
||||
{
|
||||
query.IsVirtualItem = false;
|
||||
}
|
||||
else if (!config.DisplayMissingEpisodes)
|
||||
{
|
||||
query.IsMissing = false;
|
||||
}
|
||||
else if (!config.DisplayUnairedEpisodes)
|
||||
{
|
||||
query.IsVirtualUnaired = false;
|
||||
var config = user.Configuration;
|
||||
if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
|
||||
{
|
||||
query.IsVirtualItem = false;
|
||||
}
|
||||
else if (!config.DisplayMissingEpisodes)
|
||||
{
|
||||
query.IsMissing = false;
|
||||
}
|
||||
else if (!config.DisplayUnairedEpisodes)
|
||||
{
|
||||
query.IsVirtualUnaired = false;
|
||||
}
|
||||
}
|
||||
|
||||
var allItems = LibraryManager.GetItemList(query).OfType<Episode>();
|
||||
|
||||
return GetSeasonEpisodes(user, parentSeason, allItems);
|
||||
return GetSeasonEpisodes(parentSeason, user, allItems);
|
||||
}
|
||||
|
||||
public IEnumerable<Episode> GetSeasonEpisodes(User user, Season parentSeason, IEnumerable<Episode> allSeriesEpisodes)
|
||||
public IEnumerable<Episode> GetSeasonEpisodes(Season parentSeason, User user, IEnumerable<Episode> allSeriesEpisodes)
|
||||
{
|
||||
if (allSeriesEpisodes == null)
|
||||
{
|
||||
Logger.Debug("GetSeasonEpisodes allSeriesEpisodes is null");
|
||||
return GetSeasonEpisodes(user, parentSeason);
|
||||
return GetSeasonEpisodes(parentSeason, user);
|
||||
}
|
||||
|
||||
Logger.Debug("GetSeasonEpisodes FilterEpisodesBySeason");
|
||||
var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons);
|
||||
|
||||
var sortBy = (parentSeason.IndexNumber ?? -1) == 0 ? ItemSortBy.SortName : ItemSortBy.AiredEpisodeOrder;
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
|
||||
|
||||
if (!IsInMixedFolder)
|
||||
if (!IsInMixedFolder && LocationType == LocationType.FileSystem)
|
||||
{
|
||||
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
|
||||
}
|
||||
|
|
|
@ -89,5 +89,7 @@ namespace MediaBrowser.Controller
|
|||
string GetLocalApiUrl(IPAddress ipAddress);
|
||||
|
||||
void LaunchUrl(string url);
|
||||
|
||||
void EnableLoopback(string appName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -566,5 +566,8 @@ namespace MediaBrowser.Controller.Library
|
|||
QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
|
||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
|
||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
|
||||
|
||||
void RegisterIgnoredPath(string path);
|
||||
void UnRegisterIgnoredPath(string path);
|
||||
}
|
||||
}
|
|
@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Library
|
|||
}
|
||||
}
|
||||
|
||||
class TextComparer : IComparer<string>, IEqualityComparer<string>
|
||||
public class DistinctNameComparer : IComparer<string>, IEqualityComparer<string>
|
||||
{
|
||||
public int Compare(string x, string y)
|
||||
{
|
||||
|
@ -63,7 +63,7 @@ namespace MediaBrowser.Controller.Library
|
|||
return 0;
|
||||
}
|
||||
|
||||
return string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace);
|
||||
return string.Compare(x.RemoveDiacritics(), y.RemoveDiacritics(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public bool Equals(string x, string y)
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public interface IHasRegistrationInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the registration information.
|
||||
/// </summary>
|
||||
/// <param name="feature">The feature.</param>
|
||||
/// <returns>Task<MBRegistrationRecord>.</returns>
|
||||
Task<MBRegistrationRecord> GetRegistrationInfo(string feature);
|
||||
}
|
||||
}
|
|
@ -108,6 +108,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>QueryResult{RecordingInfoDto}.</returns>
|
||||
Task<QueryResult<BaseItemDto>> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
Task<QueryResult<BaseItemDto>> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timers.
|
||||
|
@ -364,11 +365,9 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <summary>
|
||||
/// Gets the registration information.
|
||||
/// </summary>
|
||||
/// <param name="channelId">The channel identifier.</param>
|
||||
/// <param name="programId">The program identifier.</param>
|
||||
/// <param name="feature">The feature.</param>
|
||||
/// <returns>Task<MBRegistrationRecord>.</returns>
|
||||
Task<MBRegistrationRecord> GetRegistrationInfo(string channelId, string programId, string feature);
|
||||
Task<MBRegistrationRecord> GetRegistrationInfo(string feature);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the channel information.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
|
@ -66,6 +67,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
|
||||
public bool? IsHD { get; set; }
|
||||
|
||||
public bool? Is3D { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the audio.
|
||||
/// </summary>
|
||||
|
@ -84,6 +87,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
|
||||
public bool IsRepeat { get; set; }
|
||||
|
||||
public bool IsSubjectToBlackout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the episode title.
|
||||
/// </summary>
|
||||
|
@ -144,6 +149,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
|
||||
public bool IsKids { get; set; }
|
||||
|
||||
public bool IsEducational { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is premiere.
|
||||
/// </summary>
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
<Compile Include="Collections\CollectionCreationOptions.cs" />
|
||||
<Compile Include="Collections\CollectionEvents.cs" />
|
||||
<Compile Include="Collections\ICollectionManager.cs" />
|
||||
<Compile Include="Collections\ManualCollectionsFolder.cs" />
|
||||
<Compile Include="Connect\ConnectSupporterSummary.cs" />
|
||||
<Compile Include="Connect\IConnectManager.cs" />
|
||||
<Compile Include="Connect\UserLinkResult.cs" />
|
||||
|
@ -198,7 +199,6 @@
|
|||
<Compile Include="Library\NameExtensions.cs" />
|
||||
<Compile Include="Library\PlaybackStopEventArgs.cs" />
|
||||
<Compile Include="Library\UserDataSaveEventArgs.cs" />
|
||||
<Compile Include="LiveTv\IHasRegistrationInfo.cs" />
|
||||
<Compile Include="LiveTv\IListingsProvider.cs" />
|
||||
<Compile Include="LiveTv\ITunerHost.cs" />
|
||||
<Compile Include="LiveTv\RecordingGroup.cs" />
|
||||
|
|
|
@ -23,14 +23,18 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// The logger
|
||||
/// </summary>
|
||||
protected ILogger Logger { get; private set; }
|
||||
protected IProviderManager ProviderManager { get; private set; }
|
||||
|
||||
private Dictionary<string, string> _validProviderIds;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public BaseItemXmlParser(ILogger logger)
|
||||
public BaseItemXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
{
|
||||
Logger = logger;
|
||||
ProviderManager = providerManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -60,6 +64,22 @@ namespace MediaBrowser.Controller.Providers
|
|||
ValidationType = ValidationType.None
|
||||
};
|
||||
|
||||
_validProviderIds = _validProviderIds = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
var idInfos = ProviderManager.GetExternalIdInfos(item.Item);
|
||||
|
||||
foreach (var info in idInfos)
|
||||
{
|
||||
var id = info.Key + "Id";
|
||||
if (!_validProviderIds.ContainsKey(id))
|
||||
{
|
||||
_validProviderIds.Add(id, info.Key);
|
||||
}
|
||||
}
|
||||
|
||||
//Additional Mappings
|
||||
_validProviderIds.Add("IMDB", "Imdb");
|
||||
|
||||
//Fetch(item, metadataFile, settings, Encoding.GetEncoding("ISO-8859-1"), cancellationToken);
|
||||
Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken);
|
||||
}
|
||||
|
@ -657,14 +677,6 @@ namespace MediaBrowser.Controller.Providers
|
|||
break;
|
||||
}
|
||||
|
||||
case "TvDbId":
|
||||
var tvdbId = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(tvdbId))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.Tvdb, tvdbId);
|
||||
}
|
||||
break;
|
||||
|
||||
case "VoteCount":
|
||||
{
|
||||
var val = reader.ReadElementContentAsString();
|
||||
|
@ -679,95 +691,7 @@ namespace MediaBrowser.Controller.Providers
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "MusicBrainzAlbumId":
|
||||
{
|
||||
var mbz = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(mbz))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MusicBrainzAlbumArtistId":
|
||||
{
|
||||
var mbz = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(mbz))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, mbz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MusicBrainzArtistId":
|
||||
{
|
||||
var mbz = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(mbz))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.MusicBrainzArtist, mbz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MusicBrainzReleaseGroupId":
|
||||
{
|
||||
var mbz = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(mbz))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, mbz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "TVRageId":
|
||||
{
|
||||
var id = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.TvRage, id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "TvMazeId":
|
||||
{
|
||||
var id = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.TvMaze, id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "AudioDbArtistId":
|
||||
{
|
||||
var id = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.AudioDbArtist, id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "AudioDbAlbumId":
|
||||
{
|
||||
var id = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.AudioDbAlbum, id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "RottenTomatoesId":
|
||||
var rtId = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(rtId))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.RottenTomatoes, rtId);
|
||||
}
|
||||
break;
|
||||
|
||||
case "TMDbId":
|
||||
var tmdb = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(tmdb))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.Tmdb, tmdb);
|
||||
}
|
||||
break;
|
||||
|
||||
case "TMDbCollectionId":
|
||||
case "CollectionNumber":
|
||||
var tmdbCollection = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(tmdbCollection))
|
||||
{
|
||||
|
@ -775,30 +699,6 @@ namespace MediaBrowser.Controller.Providers
|
|||
}
|
||||
break;
|
||||
|
||||
case "TVcomId":
|
||||
var TVcomId = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(TVcomId))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.Tvcom, TVcomId);
|
||||
}
|
||||
break;
|
||||
|
||||
case "Zap2ItId":
|
||||
var zap2ItId = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(zap2ItId))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.Zap2It, zap2ItId);
|
||||
}
|
||||
break;
|
||||
|
||||
case "IMDB":
|
||||
var imDbId = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(imDbId))
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.Imdb, imDbId);
|
||||
}
|
||||
break;
|
||||
|
||||
case "Genres":
|
||||
{
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
|
@ -890,8 +790,25 @@ namespace MediaBrowser.Controller.Providers
|
|||
}
|
||||
|
||||
default:
|
||||
reader.Skip();
|
||||
break;
|
||||
{
|
||||
string readerName = reader.Name;
|
||||
string providerIdValue;
|
||||
if (_validProviderIds.TryGetValue(readerName, out providerIdValue))
|
||||
{
|
||||
var id = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
item.SetProviderId(providerIdValue, id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Skip();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -483,7 +483,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
{
|
||||
if (OnDeviceUnavailable != null)
|
||||
{
|
||||
_logger.Debug("Disposing device due to loss of connection");
|
||||
OnDeviceUnavailable();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (_successiveStopCount >= maxSuccessiveStopReturns)
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
{
|
||||
Container = "mkv",
|
||||
VideoCodec = "h264,mpeg2video",
|
||||
AudioCodec = "aac,ac3,dca,mp3,mp2,pcm",
|
||||
AudioCodec = "aac,ac3,dca,mp3,mp2,pcm,dts",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
|
||||
|
|
|
@ -65,14 +65,14 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
{
|
||||
Container = "avi",
|
||||
VideoCodec = "h264,mpeg4,mjpeg",
|
||||
AudioCodec = "mp3,ac3,dca",
|
||||
AudioCodec = "mp3,ac3,dca,dts",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "mkv",
|
||||
VideoCodec = "h264,mpeg4,mjpeg4",
|
||||
AudioCodec = "mp3,ac3,dca,aac",
|
||||
AudioCodec = "mp3,ac3,dca,aac,dts",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
|
@ -300,7 +300,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
new CodecProfile
|
||||
{
|
||||
Type = CodecType.VideoAudio,
|
||||
Codec = "ac3,wmav2,dca,aac,mp3",
|
||||
Codec = "ac3,wmav2,dca,aac,mp3,dts",
|
||||
|
||||
Conditions = new[]
|
||||
{
|
||||
|
|
|
@ -115,7 +115,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
{
|
||||
Container = "mkv",
|
||||
VideoCodec = "mpeg4,h264",
|
||||
AudioCodec = "ac3,dca,aac,mp3,pcm",
|
||||
AudioCodec = "ac3,dca,aac,mp3,pcm,dts",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
|
|
|
@ -115,7 +115,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
{
|
||||
Container = "mkv",
|
||||
VideoCodec = "mpeg4,h264",
|
||||
AudioCodec = "ac3,dca,aac,mp3,pcm",
|
||||
AudioCodec = "ac3,dca,aac,mp3,pcm,dts",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
{
|
||||
Container = "mkv",
|
||||
VideoCodec = "mpeg4,h264",
|
||||
AudioCodec = "ac3,dca,aac,mp3,pcm",
|
||||
AudioCodec = "ac3,dca,aac,mp3,pcm,dts",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
{
|
||||
Container = "mkv",
|
||||
VideoCodec = "mpeg4,h264",
|
||||
AudioCodec = "ac3,dca,aac,mp3,pcm",
|
||||
AudioCodec = "ac3,dca,aac,mp3,pcm,dts",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Container = "avi",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
|
||||
AudioCodec = "ac3,dca,mp2,mp3,pcm,dca"
|
||||
AudioCodec = "ac3,dca,mp2,mp3,pcm,dts"
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
|
@ -66,7 +66,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Container = "mpeg",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "mpeg1video,mpeg2video",
|
||||
AudioCodec = "ac3,dca,mp2,mp3,pcm,dca"
|
||||
AudioCodec = "ac3,dca,mp2,mp3,pcm,dts"
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
|
@ -74,7 +74,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Container = "mkv",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
|
||||
AudioCodec = "ac3,dca,aac,mp2,mp3,pcm,dca"
|
||||
AudioCodec = "ac3,dca,aac,mp2,mp3,pcm,dts"
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
|
@ -82,7 +82,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Container = "ts,m2ts",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "mpeg1video,mpeg2video,h264,vc1",
|
||||
AudioCodec = "ac3,dca,mp2,mp3,aac,dca"
|
||||
AudioCodec = "ac3,dca,mp2,mp3,aac,dts"
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
|
@ -90,7 +90,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Container = "mp4,mov",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "h264,mpeg4",
|
||||
AudioCodec = "ac3,aac,mp2,mp3,dca"
|
||||
AudioCodec = "ac3,aac,mp2,mp3,dca,dts"
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,pcm_dvd" videoCodec="mpeg2video,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,dca,mp3,mp2,pcm" videoCodec="h264,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,dca,mp3,mp2,pcm,dts" videoCodec="h264,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="aac,mp3,mp2" videoCodec="h264,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="mov" audioCodec="aac,pcm" videoCodec="h264" type="Video" />
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="asf" audioCodec="mp3,ac3,wmav2,wmapro,wmavoice" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="mp3,ac3,dca" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="mp3,ac3,dca,aac" videoCodec="h264,mpeg4,mjpeg4" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="mp3,ac3,dca,dts" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="mp3,ac3,dca,aac,dts" videoCodec="h264,mpeg4,mjpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mp4" audioCodec="mp3,aac" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="3gp" audioCodec="aac,he-aac" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mpg,mpeg" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||
|
@ -100,7 +100,7 @@
|
|||
</Conditions>
|
||||
<ApplyConditions />
|
||||
</CodecProfile>
|
||||
<CodecProfile type="VideoAudio" codec="ac3,wmav2,dca,aac,mp3">
|
||||
<CodecProfile type="VideoAudio" codec="ac3,wmav2,dca,aac,mp3,dts">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
|
||||
</Conditions>
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,aac,pcm,mp3" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm,dts" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
|
||||
<DirectPlayProfile container="wmv,asf" type="Video" />
|
||||
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" />
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,aac,pcm,mp3" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm,dts" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
|
||||
<DirectPlayProfile container="wmv,asf" type="Video" />
|
||||
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" />
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,aac,pcm,mp3" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm,dts" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
|
||||
<DirectPlayProfile container="wmv,asf" type="Video" />
|
||||
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" />
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,aac,pcm,mp3" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm,dts" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
|
||||
<DirectPlayProfile container="wmv,asf" type="Video" />
|
||||
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" />
|
||||
|
|
|
@ -36,11 +36,11 @@
|
|||
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
|
||||
<XmlRootAttributes />
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="ts,m2ts" audioCodec="ac3,dca,mp2,mp3,aac,dca" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="mp4,mov" audioCodec="ac3,aac,mp2,mp3,dca" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="ts,m2ts" audioCodec="ac3,dca,mp2,mp3,aac,dts" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="mp4,mov" audioCodec="ac3,aac,mp2,mp3,dca,dts" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="vc1" type="Video" />
|
||||
<DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
<Compile Include="Parsers\MovieXmlParser.cs" />
|
||||
<Compile Include="Parsers\MusicVideoXmlParser.cs" />
|
||||
<Compile Include="Parsers\PlaylistXmlParser.cs" />
|
||||
<Compile Include="Parsers\SeasonXmlParser.cs" />
|
||||
<Compile Include="Parsers\SeriesXmlParser.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Providers\BoxSetXmlProvider.cs" />
|
||||
|
@ -75,7 +74,6 @@
|
|||
<Compile Include="Providers\MusicVideoXmlProvider.cs" />
|
||||
<Compile Include="Providers\PersonXmlProvider.cs" />
|
||||
<Compile Include="Providers\PlaylistXmlProvider.cs" />
|
||||
<Compile Include="Providers\SeasonXmlProvider.cs" />
|
||||
<Compile Include="Providers\SeriesXmlProvider.cs" />
|
||||
<Compile Include="Providers\VideoXmlProvider.cs" />
|
||||
<Compile Include="Savers\BoxSetXmlSaver.cs" />
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
{
|
||||
public class BoxSetXmlParser : BaseItemXmlParser<BoxSet>
|
||||
{
|
||||
public BoxSetXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
public BoxSetXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
private List<LocalImageInfo> _imagesFound;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public EpisodeXmlParser(ILogger logger, IFileSystem fileSystem)
|
||||
: base(logger)
|
||||
public EpisodeXmlParser(ILogger logger, IFileSystem fileSystem, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
{
|
||||
public class GameSystemXmlParser : BaseItemXmlParser<GameSystem>
|
||||
{
|
||||
public GameSystemXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
public GameSystemXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
||||
public GameXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
public GameXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
public class BaseVideoXmlParser<T> : BaseItemXmlParser<T>
|
||||
where T : Video
|
||||
{
|
||||
public BaseVideoXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
public BaseVideoXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -50,15 +50,15 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
|
||||
public class MovieXmlParser : BaseVideoXmlParser<Movie>
|
||||
{
|
||||
public MovieXmlParser(ILogger logger) : base(logger)
|
||||
public MovieXmlParser(ILogger logger, IProviderManager providerManager) : base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class VideoXmlParser : BaseVideoXmlParser<Video>
|
||||
{
|
||||
public VideoXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
public VideoXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
/// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public MusicVideoXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
public MusicVideoXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
{
|
||||
public class PlaylistXmlParser : BaseItemXmlParser<Playlist>
|
||||
{
|
||||
public PlaylistXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
public PlaylistXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
using System.Xml;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace MediaBrowser.LocalMetadata.Parsers
|
||||
{
|
||||
public class SeasonXmlParser : BaseItemXmlParser<Season>
|
||||
{
|
||||
public SeasonXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the data from XML node.
|
||||
/// </summary>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Season> result)
|
||||
{
|
||||
var item = result.Item;
|
||||
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "SeasonNumber":
|
||||
{
|
||||
var number = reader.ReadElementContentAsString();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(number))
|
||||
{
|
||||
int num;
|
||||
|
||||
if (int.TryParse(number, out num))
|
||||
{
|
||||
item.IndexNumber = num;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
base.FetchDataFromXmlNode(reader, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,8 +17,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
/// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public SeriesXmlParser(ILogger logger)
|
||||
: base(logger)
|
||||
public SeriesXmlParser(ILogger logger, IProviderManager providerManager)
|
||||
: base(logger, providerManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -14,16 +14,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
public class BoxSetXmlProvider : BaseXmlProvider<BoxSet>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<BoxSet> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new BoxSetXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
new BoxSetXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -13,11 +13,13 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
public class EpisodeXmlProvider : BaseXmlProvider<Episode>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public EpisodeXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public EpisodeXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Episode> result, string path, CancellationToken cancellationToken)
|
||||
|
@ -25,7 +27,7 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
var images = new List<LocalImageInfo>();
|
||||
var chapters = new List<ChapterInfo>();
|
||||
|
||||
new EpisodeXmlParser(_logger, FileSystem).Fetch(result, images, path, cancellationToken);
|
||||
new EpisodeXmlParser(_logger, FileSystem, _providerManager).Fetch(result, images, path, cancellationToken);
|
||||
|
||||
result.Images = images;
|
||||
}
|
||||
|
|
|
@ -13,16 +13,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
public class FolderXmlProvider : BaseXmlProvider<Folder>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public FolderXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public FolderXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Folder> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new BaseItemXmlParser<Folder>(_logger).Fetch(result, path, cancellationToken);
|
||||
new BaseItemXmlParser<Folder>(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -11,16 +11,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
public class GameSystemXmlProvider : BaseXmlProvider<GameSystem>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public GameSystemXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public GameSystemXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<GameSystem> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new GameSystemXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
new GameSystemXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -11,16 +11,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
public class GameXmlProvider : BaseXmlProvider<Game>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public GameXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public GameXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Game> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new GameXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
new GameXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -11,16 +11,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
public class MovieXmlProvider : BaseXmlProvider<Movie>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public MovieXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public MovieXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Movie> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new MovieXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
new MovieXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -10,16 +10,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
class MusicVideoXmlProvider : BaseXmlProvider<MusicVideo>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public MusicVideoXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public MusicVideoXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<MusicVideo> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new MusicVideoXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
new MusicVideoXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -10,16 +10,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
public class PersonXmlProvider : BaseXmlProvider<Person>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public PersonXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public PersonXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Person> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new BaseItemXmlParser<Person>(_logger).Fetch(result, path, cancellationToken);
|
||||
new BaseItemXmlParser<Person>(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -11,16 +11,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
class PlaylistXmlProvider : BaseXmlProvider<Playlist>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public PlaylistXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public PlaylistXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Playlist> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new PlaylistXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
new PlaylistXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
using System.IO;
|
||||
using System.Threading;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.LocalMetadata.Parsers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace MediaBrowser.LocalMetadata.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Class SeriesProviderFromXml
|
||||
/// </summary>
|
||||
public class SeasonXmlProvider : BaseXmlProvider<Season>, IHasOrder
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public SeasonXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Season> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new SeasonXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
{
|
||||
return directoryService.GetFile(Path.Combine(info.Path, "season.xml"));
|
||||
}
|
||||
|
||||
public int Order
|
||||
{
|
||||
get
|
||||
{
|
||||
// After Xbmc
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,16 +14,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
public class SeriesXmlProvider : BaseXmlProvider<Series>, IHasOrder
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public SeriesXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public SeriesXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Series> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new SeriesXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
new SeriesXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -10,16 +10,18 @@ namespace MediaBrowser.LocalMetadata.Providers
|
|||
class VideoXmlProvider : BaseXmlProvider<Video>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public VideoXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
public VideoXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
protected override void Fetch(MetadataResult<Video> result, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
new VideoXmlParser(_logger).Fetch(result, path, cancellationToken);
|
||||
new VideoXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
||||
|
|
|
@ -133,7 +133,7 @@ namespace MediaBrowser.LocalMetadata.Savers
|
|||
/// <param name="xmlTagsUsed">The XML tags used.</param>
|
||||
public static void Save(StringBuilder xml, string path, List<string> xmlTagsUsed, IServerConfigurationManager config, IFileSystem fileSystem)
|
||||
{
|
||||
if (fileSystem.FileExists(path))
|
||||
if (fileSystem.FileExists(path))
|
||||
{
|
||||
var position = xml.ToString().LastIndexOf("</", StringComparison.OrdinalIgnoreCase);
|
||||
xml.Insert(position, GetCustomTags(path, xmlTagsUsed));
|
||||
|
@ -145,7 +145,7 @@ namespace MediaBrowser.LocalMetadata.Savers
|
|||
//Add the new node to the document.
|
||||
xmlDocument.InsertBefore(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "yes"), xmlDocument.DocumentElement);
|
||||
|
||||
fileSystem.CreateDirectory(Path.GetDirectoryName(path));
|
||||
fileSystem.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
var wasHidden = false;
|
||||
|
||||
|
@ -445,121 +445,18 @@ namespace MediaBrowser.LocalMetadata.Savers
|
|||
builder.Append("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>");
|
||||
}
|
||||
|
||||
var imdb = item.GetProviderId(MetadataProviders.Imdb);
|
||||
|
||||
if (!string.IsNullOrEmpty(imdb))
|
||||
if (item.ProviderIds != null)
|
||||
{
|
||||
builder.Append("<IMDB>" + SecurityElement.Escape(imdb) + "</IMDB>");
|
||||
}
|
||||
|
||||
var tmdb = item.GetProviderId(MetadataProviders.Tmdb);
|
||||
|
||||
if (!string.IsNullOrEmpty(tmdb))
|
||||
{
|
||||
builder.Append("<TMDbId>" + SecurityElement.Escape(tmdb) + "</TMDbId>");
|
||||
}
|
||||
|
||||
if (!(item is Series))
|
||||
{
|
||||
var tvdb = item.GetProviderId(MetadataProviders.Tvdb);
|
||||
|
||||
if (!string.IsNullOrEmpty(tvdb))
|
||||
foreach (var providerKey in item.ProviderIds.Keys)
|
||||
{
|
||||
builder.Append("<TvDbId>" + SecurityElement.Escape(tvdb) + "</TvDbId>");
|
||||
var providerId = item.ProviderIds[providerKey];
|
||||
if (!string.IsNullOrEmpty(providerId))
|
||||
{
|
||||
builder.Append(string.Format("<{0}>{1}</{0}>", providerKey + "Id", SecurityElement.Escape(providerId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var externalId = item.GetProviderId(MetadataProviders.Tvcom);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<TVcomId>" + SecurityElement.Escape(externalId) + "</TVcomId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.RottenTomatoes);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<RottenTomatoesId>" + SecurityElement.Escape(externalId) + "</RottenTomatoesId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.Zap2It);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<Zap2ItId>" + SecurityElement.Escape(externalId) + "</Zap2ItId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbum);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<MusicBrainzAlbumId>" + SecurityElement.Escape(externalId) + "</MusicBrainzAlbumId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<MusicBrainzAlbumArtistId>" + SecurityElement.Escape(externalId) + "</MusicBrainzAlbumArtistId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<MusicBrainzArtistId>" + SecurityElement.Escape(externalId) + "</MusicBrainzArtistId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<MusicBrainzReleaseGroupId>" + SecurityElement.Escape(externalId) + "</MusicBrainzReleaseGroupId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.Gamesdb);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<GamesDbId>" + SecurityElement.Escape(externalId) + "</GamesDbId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.TmdbCollection);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<TMDbCollectionId>" + SecurityElement.Escape(externalId) + "</TMDbCollectionId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.AudioDbArtist);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<AudioDbArtistId>" + SecurityElement.Escape(externalId) + "</AudioDbArtistId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.AudioDbAlbum);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<AudioDbAlbumId>" + SecurityElement.Escape(externalId) + "</AudioDbAlbumId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.TvRage);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<TVRageId>" + SecurityElement.Escape(externalId) + "</TVRageId>");
|
||||
}
|
||||
|
||||
externalId = item.GetProviderId(MetadataProviders.TvMaze);
|
||||
|
||||
if (!string.IsNullOrEmpty(externalId))
|
||||
{
|
||||
builder.Append("<TvMazeId>" + SecurityElement.Escape(externalId) + "</TvMazeId>");
|
||||
}
|
||||
|
||||
var hasTagline = item as IHasTaglines;
|
||||
if (hasTagline != null)
|
||||
{
|
||||
|
|
|
@ -481,6 +481,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
}
|
||||
}
|
||||
|
||||
if (state.IsVideoRequest)
|
||||
{
|
||||
var encodingOptions = GetEncodingOptions();
|
||||
var videoEncoder = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, encodingOptions);
|
||||
if (videoEncoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
arg = "-hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device " + encodingOptions.VaapiDevice + " " + arg;
|
||||
}
|
||||
}
|
||||
|
||||
return arg.Trim();
|
||||
}
|
||||
|
||||
|
@ -585,23 +595,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
/// Gets the video bitrate to specify on the command line
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <param name="videoCodec">The video codec.</param>
|
||||
/// <param name="videoEncoder">The video codec.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetVideoQualityParam(EncodingJob state, string videoCodec)
|
||||
protected string GetVideoQualityParam(EncodingJob state, string videoEncoder)
|
||||
{
|
||||
var param = string.Empty;
|
||||
|
||||
var isVc1 = state.VideoStream != null &&
|
||||
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset superfast";
|
||||
|
||||
param += " -crf 23";
|
||||
}
|
||||
|
||||
else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset fast";
|
||||
|
||||
|
@ -609,20 +619,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
}
|
||||
|
||||
// h264 (h264_qsv)
|
||||
else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset 7 -look_ahead 0";
|
||||
|
||||
}
|
||||
|
||||
// h264 (h264_nvenc)
|
||||
else if (string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset llhq";
|
||||
}
|
||||
|
||||
// webm
|
||||
else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Values 0-3, 0 being highest quality but slower
|
||||
var profileScore = 0;
|
||||
|
@ -649,23 +659,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
qmax);
|
||||
}
|
||||
|
||||
else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
|
||||
}
|
||||
|
||||
// asf/wmv
|
||||
else if (string.Equals(videoCodec, "wmv2", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-qmin 2";
|
||||
}
|
||||
|
||||
else if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-mbd 2";
|
||||
}
|
||||
|
||||
param += GetVideoBitrateParam(state, videoCodec);
|
||||
param += GetVideoBitrateParam(state, videoEncoder);
|
||||
|
||||
var framerate = GetFramerateParam(state);
|
||||
if (framerate.HasValue)
|
||||
|
@ -680,8 +690,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
if (!string.IsNullOrEmpty(state.Options.Profile))
|
||||
{
|
||||
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// not supported by h264_omx
|
||||
param += " -profile:v " + state.Options.Profile;
|
||||
|
@ -692,9 +702,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
if (!string.IsNullOrEmpty(levelString))
|
||||
{
|
||||
levelString = NormalizeTranscodingLevel(state.OutputVideoCodec, levelString);
|
||||
|
||||
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
|
||||
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
switch (levelString)
|
||||
{
|
||||
|
@ -730,16 +742,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
|
||||
else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param += " -level " + levelString;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-pix_fmt yuv420p " + param;
|
||||
}
|
||||
|
@ -747,6 +759,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
return param;
|
||||
}
|
||||
|
||||
private string NormalizeTranscodingLevel(string videoCodec, string level)
|
||||
{
|
||||
double requestLevel;
|
||||
|
||||
// Clients may direct play higher than level 41, but there's no reason to transcode higher
|
||||
if (double.TryParse(level, NumberStyles.Any, UsCulture, out requestLevel))
|
||||
{
|
||||
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (requestLevel > 41)
|
||||
{
|
||||
return "41";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
protected string GetVideoBitrateParam(EncodingJob state, string videoCodec)
|
||||
{
|
||||
var bitrate = state.OutputVideoBitrate;
|
||||
|
|
|
@ -928,7 +928,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
{
|
||||
StartProcess(processWrapper);
|
||||
|
||||
ranToCompletion = process.WaitForExit(10000);
|
||||
var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
|
||||
if (timeoutMs <= 0)
|
||||
{
|
||||
timeoutMs = Environment.Is64BitOperatingSystem ? (Environment.ProcessorCount > 2 ? 14000 : 20000) : 40000;
|
||||
}
|
||||
|
||||
ranToCompletion = process.WaitForExit(timeoutMs);
|
||||
|
||||
if (!ranToCompletion)
|
||||
{
|
||||
|
|
|
@ -818,14 +818,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||
|
||||
public string GetSubtitleFileCharacterSetFromLanguage(string language)
|
||||
{
|
||||
// https://developer.xamarin.com/api/type/System.Text.Encoding/
|
||||
|
||||
switch (language.ToLower())
|
||||
{
|
||||
case "hun":
|
||||
return "windows-1252";
|
||||
case "pol":
|
||||
case "cze":
|
||||
case "ces":
|
||||
case "slo":
|
||||
case "slk":
|
||||
case "hun":
|
||||
case "slv":
|
||||
case "srp":
|
||||
case "hrv":
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace MediaBrowser.Model.Configuration
|
|||
public string HardwareAccelerationType { get; set; }
|
||||
public string EncoderAppPath { get; set; }
|
||||
public string VaapiDevice { get; set; }
|
||||
public int H264Crf { get; set; }
|
||||
public string H264Preset { get; set; }
|
||||
|
||||
public EncodingOptions()
|
||||
{
|
||||
|
@ -19,6 +21,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
ThrottleDelaySeconds = 180;
|
||||
EncodingThreadCount = -1;
|
||||
VaapiDevice = "/dev/dri/card0";
|
||||
H264Crf = 23;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
public bool EnablePhotos { get; set; }
|
||||
public bool EnableRealtimeMonitor { get; set; }
|
||||
public int SchemaVersion { get; set; }
|
||||
public bool EnableChapterImageExtraction { get; set; }
|
||||
public bool ExtractChapterImagesDuringLibraryScan { get; set; }
|
||||
|
||||
public LibraryOptions()
|
||||
{
|
||||
|
|
|
@ -204,7 +204,10 @@ namespace MediaBrowser.Model.Configuration
|
|||
public bool DisplayCollectionsView { get; set; }
|
||||
public string[] LocalNetworkAddresses { get; set; }
|
||||
public string[] CodecsUsed { get; set; }
|
||||
public bool EnableChannelView { get; set; }
|
||||
public bool EnableExternalContentInSuggestions { get; set; }
|
||||
|
||||
public int ImageExtractionTimeoutMs { get; set; }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
||||
/// </summary>
|
||||
|
@ -214,9 +217,11 @@ namespace MediaBrowser.Model.Configuration
|
|||
Migrations = new string[] { };
|
||||
CodecsUsed = new string[] { };
|
||||
SqliteCacheSize = 0;
|
||||
ImageExtractionTimeoutMs = 0;
|
||||
|
||||
EnableLocalizedGuids = true;
|
||||
DisplaySpecialsWithinSeasons = true;
|
||||
EnableExternalContentInSuggestions = true;
|
||||
|
||||
ImageSavingConvention = ImageSavingConvention.Compatible;
|
||||
PublicPort = 8096;
|
||||
|
@ -229,6 +234,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
EnableAnonymousUsageReporting = true;
|
||||
|
||||
EnableAutomaticRestart = true;
|
||||
EnableFolderView = true;
|
||||
|
||||
EnableUPnP = true;
|
||||
SharingExpirationDays = 30;
|
||||
|
|
|
@ -41,7 +41,6 @@ namespace MediaBrowser.Model.Configuration
|
|||
public string[] PlainFolderViews { get; set; }
|
||||
|
||||
public bool HidePlayedInLatest { get; set; }
|
||||
public bool EnableChannelView { get; set; }
|
||||
|
||||
public bool RememberAudioSelections { get; set; }
|
||||
public bool RememberSubtitleSelections { get; set; }
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace MediaBrowser.Model.LiveTv
|
|||
public string SeriesRecordingPath { get; set; }
|
||||
public bool EnableAutoOrganize { get; set; }
|
||||
public bool EnableRecordingEncoding { get; set; }
|
||||
public string RecordingEncodingFormat { get; set; }
|
||||
public bool EnableRecordingSubfolders { get; set; }
|
||||
public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
|
||||
|
||||
|
@ -31,6 +32,7 @@ namespace MediaBrowser.Model.LiveTv
|
|||
TunerHosts = new List<TunerHostInfo>();
|
||||
ListingProviders = new List<ListingsProviderInfo>();
|
||||
MediaLocationsCreated = new string[] { };
|
||||
RecordingEncodingFormat = "mp4";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
Stereo,
|
||||
Dolby,
|
||||
DolbyDigital,
|
||||
Thx
|
||||
Thx,
|
||||
Atmos
|
||||
}
|
||||
}
|
|
@ -68,6 +68,10 @@ namespace MediaBrowser.Model.LiveTv
|
|||
/// <value>The fields.</value>
|
||||
public ItemFields[] Fields { get; set; }
|
||||
public bool? EnableImages { get; set; }
|
||||
public bool? IsMovie { get; set; }
|
||||
public bool? IsSeries { get; set; }
|
||||
public bool? IsKids { get; set; }
|
||||
public bool? IsSports { get; set; }
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
public ImageType[] EnableImageTypes { get; set; }
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace MediaBrowser.Model.System
|
|||
/// </summary>
|
||||
public class SystemInfo : PublicSystemInfo
|
||||
{
|
||||
public PackageVersionClass SystemUpdateLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display name of the operating system.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -21,4 +22,17 @@ namespace MediaBrowser.Providers.Folders
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ManualCollectionsFolderMetadataService : MetadataService<ManualCollectionsFolder, ItemLookupInfo>
|
||||
{
|
||||
protected override void MergeData(MetadataResult<ManualCollectionsFolder> source, MetadataResult<ManualCollectionsFolder> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||
{
|
||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||
}
|
||||
|
||||
public ManualCollectionsFolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -261,11 +261,18 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||
|
||||
NormalizeChapterNames(chapters);
|
||||
|
||||
var libraryOptions = _libraryManager.GetLibraryOptions(video);
|
||||
var extractDuringScan = chapterOptions.ExtractDuringLibraryScan;
|
||||
if (libraryOptions != null && libraryOptions.SchemaVersion >= 2)
|
||||
{
|
||||
extractDuringScan = libraryOptions.ExtractChapterImagesDuringLibraryScan;
|
||||
}
|
||||
|
||||
await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
|
||||
{
|
||||
Chapters = chapters,
|
||||
Video = video,
|
||||
ExtractImages = chapterOptions.ExtractDuringLibraryScan,
|
||||
ExtractImages = extractDuringScan,
|
||||
SaveChapters = false
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
|
|
@ -6,6 +6,7 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Providers.Manager;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CommonIO;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
|
@ -21,7 +22,7 @@ namespace MediaBrowser.Providers.Music
|
|||
|
||||
if (replaceData || targetItem.Artists.Count == 0)
|
||||
{
|
||||
targetItem.Artists = sourceItem.Artists;
|
||||
targetItem.Artists = sourceItem.Artists.ToList();
|
||||
}
|
||||
|
||||
if (replaceData || string.IsNullOrEmpty(targetItem.Album))
|
||||
|
|
|
@ -138,8 +138,6 @@ namespace MediaBrowser.Providers.TV
|
|||
.Where(i => i.LocationType == LocationType.Virtual)
|
||||
.ToList();
|
||||
|
||||
var episodes = series.GetRecursiveChildren().OfType<Episode>().ToList();
|
||||
|
||||
var seasonsToRemove = virtualSeasons
|
||||
.Where(i =>
|
||||
{
|
||||
|
@ -152,19 +150,15 @@ namespace MediaBrowser.Providers.TV
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there are no episodes with this season number, delete it
|
||||
if (episodes.All(e => !e.ParentIndexNumber.HasValue || e.ParentIndexNumber.Value != seasonNumber))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Season does not have a number
|
||||
// Remove if there are no episodes directly in series without a season number
|
||||
return episodes.All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder);
|
||||
// If there are no episodes with this season number, delete it
|
||||
if (!i.GetEpisodes().Any())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
|
|
|
@ -530,6 +530,19 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
return GetChannelFeaturesDto(channel, channelProvider, channelProvider.GetChannelFeatures());
|
||||
}
|
||||
|
||||
public bool SupportsSync(string channelId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(channelId))
|
||||
{
|
||||
throw new ArgumentNullException("channelId");
|
||||
}
|
||||
|
||||
//var channel = GetChannel(channelId);
|
||||
var channelProvider = GetChannelProvider(channelId);
|
||||
|
||||
return channelProvider.GetChannelFeatures().SupportsContentDownloading;
|
||||
}
|
||||
|
||||
public ChannelFeatures GetChannelFeaturesDto(Channel channel,
|
||||
IChannel provider,
|
||||
InternalChannelFeatures features)
|
||||
|
@ -1450,6 +1463,24 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
return result;
|
||||
}
|
||||
|
||||
internal IChannel GetChannelProvider(string internalChannelId)
|
||||
{
|
||||
if (internalChannelId == null)
|
||||
{
|
||||
throw new ArgumentNullException("internalChannelId");
|
||||
}
|
||||
|
||||
var result = GetAllChannels()
|
||||
.FirstOrDefault(i => string.Equals(GetInternalChannelId(i.Name).ToString("N"), internalChannelId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("No channel provider found for channel id " + internalChannelId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IEnumerable<BaseItem> ApplyFilters(IEnumerable<BaseItem> items, IEnumerable<ItemFilter> filters, User user)
|
||||
{
|
||||
foreach (var filter in filters.OrderByDescending(f => (int)f))
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using System.IO;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Collections
|
||||
{
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Connect
|
|||
{
|
||||
LoadCachedAddress();
|
||||
|
||||
_timer = new PeriodicTimer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3));
|
||||
_timer = new PeriodicTimer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(1));
|
||||
((ConnectManager)_connectManager).Start();
|
||||
}
|
||||
|
||||
|
|
|
@ -1168,6 +1168,26 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
};
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// Include artists that are not in the database yet, e.g., just added via metadata editor
|
||||
var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
|
||||
dto.ArtistItems.AddRange(hasArtist.Artists
|
||||
.Except(foundArtists, new DistinctNameComparer())
|
||||
.Select(i =>
|
||||
{
|
||||
var artist = _libraryManager.GetArtist(i);
|
||||
if (artist != null)
|
||||
{
|
||||
return new NameIdPair
|
||||
{
|
||||
Name = artist.Name,
|
||||
Id = artist.Id.ToString("N")
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}).Where(i => i != null));
|
||||
}
|
||||
|
||||
var hasAlbumArtist = item as IHasAlbumArtist;
|
||||
|
|
|
@ -92,11 +92,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||
DeviceId = session.DeviceId
|
||||
};
|
||||
|
||||
// Report usage to remote server, except for web client, since we already have data on that
|
||||
if (!string.Equals(info.AppName, "Dashboard", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReportNewSession(info);
|
||||
}
|
||||
ReportNewSession(info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
|
|
@ -71,14 +71,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
|||
|
||||
HostConfig.Instance.MapExceptionToStatusCode = new Dictionary<Type, int>
|
||||
{
|
||||
{typeof (InvalidOperationException), 422},
|
||||
{typeof (InvalidOperationException), 500},
|
||||
{typeof (NotImplementedException), 500},
|
||||
{typeof (ResourceNotFoundException), 404},
|
||||
{typeof (FileNotFoundException), 404},
|
||||
{typeof (DirectoryNotFoundException), 404},
|
||||
{typeof (SecurityException), 401},
|
||||
{typeof (PaymentRequiredException), 402},
|
||||
{typeof (UnauthorizedAccessException), 500},
|
||||
{typeof (ApplicationException), 500}
|
||||
{typeof (ApplicationException), 500},
|
||||
{typeof (PlatformNotSupportedException), 500},
|
||||
{typeof (NotSupportedException), 500}
|
||||
};
|
||||
|
||||
HostConfig.Instance.GlobalResponseHeaders = new Dictionary<string, string>();
|
||||
|
@ -99,14 +102,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
|||
// new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()),
|
||||
//}));
|
||||
|
||||
PreRequestFilters.Add((httpReq, httpRes) =>
|
||||
{
|
||||
//Handles Request and closes Responses after emitting global HTTP Headers
|
||||
if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
httpRes.EndRequest(); //add a 'using ServiceStack;'
|
||||
}
|
||||
});
|
||||
//PreRequestFilters.Add((httpReq, httpRes) =>
|
||||
//{
|
||||
// //Handles Request and closes Responses after emitting global HTTP Headers
|
||||
// if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// httpRes.EndRequest(); //add a 'using ServiceStack;'
|
||||
// }
|
||||
//});
|
||||
|
||||
HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
|
||||
}
|
||||
|
@ -400,6 +403,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
|||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
httpRes.StatusCode = 200;
|
||||
httpRes.AddHeader("Access-Control-Allow-Origin", "*");
|
||||
httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
|
||||
httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
|
||||
httpRes.ContentType = "text/html";
|
||||
|
||||
httpRes.Close();
|
||||
}
|
||||
|
||||
var operationName = httpReq.OperationName;
|
||||
var localPath = url.LocalPath;
|
||||
|
||||
|
|
|
@ -46,6 +46,14 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
"TempSBE"
|
||||
};
|
||||
|
||||
private readonly IReadOnlyList<string> _alwaysIgnoreSubstrings = new List<string>
|
||||
{
|
||||
// Synology
|
||||
"@eaDir",
|
||||
".wd_tv",
|
||||
".actors"
|
||||
};
|
||||
|
||||
private readonly IReadOnlyList<string> _alwaysIgnoreExtensions = new List<string>
|
||||
{
|
||||
// thumbs.db
|
||||
|
@ -421,10 +429,11 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
}
|
||||
|
||||
var filename = Path.GetFileName(path);
|
||||
|
||||
|
||||
var monitorPath = !string.IsNullOrEmpty(filename) &&
|
||||
!_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) &&
|
||||
!_alwaysIgnoreExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
!_alwaysIgnoreExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase) &&
|
||||
_alwaysIgnoreSubstrings.All(i => path.IndexOf(i, StringComparison.OrdinalIgnoreCase) == -1);
|
||||
|
||||
// Ignore certain files
|
||||
var tempIgnorePaths = _tempIgnoredPaths.Keys.ToList();
|
||||
|
|
|
@ -401,7 +401,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
var locationType = item.LocationType;
|
||||
|
||||
var children = item.IsFolder
|
||||
? ((Folder)item).GetRecursiveChildren().ToList()
|
||||
? ((Folder)item).GetRecursiveChildren(false).ToList()
|
||||
: new List<BaseItem>();
|
||||
|
||||
foreach (var metadataPath in GetMetadataPaths(item, children))
|
||||
|
@ -621,9 +621,38 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return ResolveItem(args, resolvers);
|
||||
}
|
||||
|
||||
private readonly List<string> _ignoredPaths = new List<string>();
|
||||
|
||||
public void RegisterIgnoredPath(string path)
|
||||
{
|
||||
lock (_ignoredPaths)
|
||||
{
|
||||
_ignoredPaths.Add(path);
|
||||
}
|
||||
}
|
||||
public void UnRegisterIgnoredPath(string path)
|
||||
{
|
||||
lock (_ignoredPaths)
|
||||
{
|
||||
_ignoredPaths.Remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IgnoreFile(FileSystemMetadata file, BaseItem parent)
|
||||
{
|
||||
return EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent));
|
||||
if (EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//lock (_ignoredPaths)
|
||||
{
|
||||
if (_ignoredPaths.Contains(file.FullName, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)
|
||||
|
|
|
@ -54,14 +54,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
|
|||
{
|
||||
if (args.IsDirectory)
|
||||
{
|
||||
if (args.HasParent<Series>())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var collectionType = args.GetCollectionType();
|
||||
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (args.HasParent<Series>())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var configuredContentType = _libraryManager.GetConfiguredContentType(args.Path);
|
||||
if (!string.Equals(configuredContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -76,11 +76,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(collectionType))
|
||||
{
|
||||
if (args.HasParent<Series>())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (args.Parent.IsRoot)
|
||||
{
|
||||
return null;
|
||||
|
|
|
@ -120,8 +120,8 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var channels = channelResult.Items;
|
||||
|
||||
if (user.Configuration.EnableChannelView && channels.Length > 0)
|
||||
|
||||
if (_config.Configuration.EnableChannelView && channels.Length > 0)
|
||||
{
|
||||
list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ using Microsoft.Win32;
|
|||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||
{
|
||||
public class EmbyTV : ILiveTvService, ISupportsNewTimerIds, IHasRegistrationInfo, IDisposable
|
||||
public class EmbyTV : ILiveTvService, ISupportsNewTimerIds, IDisposable
|
||||
{
|
||||
private readonly IApplicationHost _appHpst;
|
||||
private readonly ILogger _logger;
|
||||
|
@ -46,7 +46,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
private readonly LiveTvManager _liveTvManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ISecurityManager _security;
|
||||
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
@ -62,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
|
||||
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement)
|
||||
public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement)
|
||||
{
|
||||
Current = this;
|
||||
|
||||
|
@ -71,7 +70,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
_httpClient = httpClient;
|
||||
_config = config;
|
||||
_fileSystem = fileSystem;
|
||||
_security = security;
|
||||
_libraryManager = libraryManager;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_providerManager = providerManager;
|
||||
|
@ -851,29 +849,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
var recordPath = RecordingPath;
|
||||
var config = GetConfiguration();
|
||||
|
||||
if (info.IsMovie)
|
||||
{
|
||||
var customRecordingPath = config.MovieRecordingPath;
|
||||
var allowSubfolder = true;
|
||||
if (!string.IsNullOrWhiteSpace(customRecordingPath))
|
||||
{
|
||||
allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase);
|
||||
recordPath = customRecordingPath;
|
||||
}
|
||||
|
||||
if (allowSubfolder && config.EnableRecordingSubfolders)
|
||||
{
|
||||
recordPath = Path.Combine(recordPath, "Movies");
|
||||
}
|
||||
|
||||
var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
|
||||
if (info.ProductionYear.HasValue)
|
||||
{
|
||||
folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
|
||||
}
|
||||
recordPath = Path.Combine(recordPath, folderName);
|
||||
}
|
||||
else if (info.IsSeries)
|
||||
if (info.IsSeries)
|
||||
{
|
||||
var customRecordingPath = config.SeriesRecordingPath;
|
||||
var allowSubfolder = true;
|
||||
|
@ -910,6 +886,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
recordPath = Path.Combine(recordPath, folderName);
|
||||
}
|
||||
}
|
||||
else if (info.IsMovie)
|
||||
{
|
||||
var customRecordingPath = config.MovieRecordingPath;
|
||||
var allowSubfolder = true;
|
||||
if (!string.IsNullOrWhiteSpace(customRecordingPath))
|
||||
{
|
||||
allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase);
|
||||
recordPath = customRecordingPath;
|
||||
}
|
||||
|
||||
if (allowSubfolder && config.EnableRecordingSubfolders)
|
||||
{
|
||||
recordPath = Path.Combine(recordPath, "Movies");
|
||||
}
|
||||
|
||||
var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
|
||||
if (info.ProductionYear.HasValue)
|
||||
{
|
||||
folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
|
||||
}
|
||||
recordPath = Path.Combine(recordPath, folderName);
|
||||
}
|
||||
else if (info.IsKids)
|
||||
{
|
||||
if (config.EnableRecordingSubfolders)
|
||||
|
@ -995,6 +993,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
|
||||
recordPath = EnsureFileUnique(recordPath, timer.Id);
|
||||
|
||||
_libraryManager.RegisterIgnoredPath(recordPath);
|
||||
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
|
||||
_fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
|
||||
activeRecordingInfo.Path = recordPath;
|
||||
|
@ -1046,6 +1045,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
semaphore.Release();
|
||||
}
|
||||
|
||||
_libraryManager.UnRegisterIgnoredPath(recordPath);
|
||||
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
|
||||
|
||||
ActiveRecordingInfo removed;
|
||||
|
@ -1114,7 +1114,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
if (config.EnableRecordingEncoding)
|
||||
{
|
||||
var regInfo = await _security.GetRegistrationStatus("embytvrecordingconversion").ConfigureAwait(false);
|
||||
var regInfo = await _liveTvManager.GetRegistrationInfo("embytvrecordingconversion").ConfigureAwait(false);
|
||||
|
||||
if (regInfo.IsValid)
|
||||
{
|
||||
|
@ -1171,8 +1171,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers)
|
||||
{
|
||||
var newTimers = GetTimersForSeries(seriesTimer, epgData, true).ToList();
|
||||
|
||||
var registration = await GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
|
||||
|
||||
var registration = await _liveTvManager.GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
|
||||
|
||||
if (registration.IsValid)
|
||||
{
|
||||
|
@ -1349,20 +1349,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
}
|
||||
}
|
||||
|
||||
public Task<MBRegistrationRecord> GetRegistrationInfo(string feature)
|
||||
{
|
||||
if (string.Equals(feature, "seriesrecordings", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _security.GetRegistrationStatus("embytvseriesrecordings");
|
||||
}
|
||||
|
||||
return Task.FromResult(new MBRegistrationRecord
|
||||
{
|
||||
IsValid = true,
|
||||
IsRegistered = true
|
||||
});
|
||||
}
|
||||
|
||||
public List<VirtualFolderInfo> GetRecordingFolders()
|
||||
{
|
||||
var list = new List<VirtualFolderInfo>();
|
||||
|
|
|
@ -46,18 +46,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
private string OutputFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
var format = _liveTvOptions.RecordingEncodingFormat;
|
||||
|
||||
if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "mkv";
|
||||
}
|
||||
|
||||
return "mp4";
|
||||
}
|
||||
}
|
||||
|
||||
public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile)
|
||||
{
|
||||
return Path.ChangeExtension(targetFile, ".mp4");
|
||||
return Path.ChangeExtension(targetFile, "." + OutputFormat);
|
||||
}
|
||||
|
||||
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
if (mediaSource.Path.IndexOf("m3u8", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
await RecordWithoutTempFile(mediaSource, targetFile, duration, onStarted, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var tempfile = Path.Combine(_appPaths.TranscodingTempPath, Guid.NewGuid().ToString("N") + ".ts");
|
||||
|
||||
try
|
||||
{
|
||||
await RecordInternal(mediaSource, tempfile, targetFile, duration, onStarted, cancellationToken)
|
||||
await RecordWithTempFile(mediaSource, tempfile, targetFile, duration, onStarted, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
|
@ -73,7 +96,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
}
|
||||
}
|
||||
|
||||
public async Task RecordInternal(MediaSourceInfo mediaSource, string tempFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
private async Task RecordWithoutTempFile(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
var durationToken = new CancellationTokenSource(duration);
|
||||
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
|
||||
|
||||
await RecordFromFile(mediaSource, mediaSource.Path, targetFile, duration, onStarted, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_logger.Info("Recording completed to file {0}", targetFile);
|
||||
}
|
||||
|
||||
private async Task RecordWithTempFile(MediaSourceInfo mediaSource, string tempFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
var httpRequestOptions = new HttpRequestOptions()
|
||||
{
|
||||
|
@ -215,15 +248,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
private string GetAudioArgs(MediaSourceInfo mediaSource)
|
||||
{
|
||||
// do not copy aac because many players have difficulty with aac_latm
|
||||
var copyAudio = new[] { "mp3" };
|
||||
var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
|
||||
var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty;
|
||||
|
||||
if (copyAudio.Contains(inputAudioCodec, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return "-codec:a:0 copy";
|
||||
}
|
||||
// do not copy aac because many players have difficulty with aac_latm
|
||||
if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings && !string.Equals(inputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "-codec:a:0 copy";
|
||||
|
|
|
@ -194,14 +194,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|||
return station;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(channelName))
|
||||
if (!string.IsNullOrWhiteSpace(channelName))
|
||||
{
|
||||
return null;
|
||||
channelName = NormalizeName(channelName);
|
||||
|
||||
var result = channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
channelName = NormalizeName(channelName);
|
||||
|
||||
return channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
|
||||
if (!string.IsNullOrWhiteSpace(channelNumber))
|
||||
{
|
||||
return channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.stationID ?? string.Empty), channelNumber, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -348,7 +356,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|||
|
||||
if (programInfo.audioProperties != null)
|
||||
{
|
||||
if (programInfo.audioProperties.Exists(item => string.Equals(item, "dd 5.1", StringComparison.OrdinalIgnoreCase)))
|
||||
if (programInfo.audioProperties.Exists(item => string.Equals(item, "atmos", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
audioType = ProgramAudio.Atmos;
|
||||
}
|
||||
else if (programInfo.audioProperties.Exists(item => string.Equals(item, "dd 5.1", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
audioType = ProgramAudio.DolbyDigital;
|
||||
}
|
||||
|
@ -405,6 +417,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|||
if (programInfo.videoProperties != null)
|
||||
{
|
||||
info.IsHD = programInfo.videoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase);
|
||||
info.Is3D = programInfo.videoProperties.Contains("3d", StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (details.contentRating != null && details.contentRating.Count > 0)
|
||||
|
@ -785,9 +798,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
|||
get { return "Schedules Direct"; }
|
||||
}
|
||||
|
||||
public static string TypeName = "SchedulesDirect";
|
||||
public string Type
|
||||
{
|
||||
get { return "SchedulesDirect"; }
|
||||
get { return TypeName; }
|
||||
}
|
||||
|
||||
private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken)
|
||||
|
|
|
@ -31,7 +31,11 @@ using CommonIO;
|
|||
using IniParser;
|
||||
using IniParser.Model;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Security;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Server.Implementations.LiveTv.Listings;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
{
|
||||
|
@ -49,6 +53,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
private readonly ITaskManager _taskManager;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IProviderManager _providerManager;
|
||||
private readonly ISecurityManager _security;
|
||||
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly ILocalizationManager _localization;
|
||||
|
@ -71,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
|
||||
public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
|
||||
|
||||
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem)
|
||||
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem, ISecurityManager security)
|
||||
{
|
||||
_config = config;
|
||||
_logger = logger;
|
||||
|
@ -83,6 +88,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
_jsonSerializer = jsonSerializer;
|
||||
_providerManager = providerManager;
|
||||
_fileSystem = fileSystem;
|
||||
_security = security;
|
||||
_dtoService = dtoService;
|
||||
_userDataManager = userDataManager;
|
||||
|
||||
|
@ -1423,6 +1429,49 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
return new QueryResult<BaseItem>();
|
||||
}
|
||||
|
||||
var includeItemTypes = new List<string>();
|
||||
var excludeItemTypes = new List<string>();
|
||||
var genres = new List<string>();
|
||||
|
||||
if (query.IsMovie.HasValue)
|
||||
{
|
||||
if (query.IsMovie.Value)
|
||||
{
|
||||
includeItemTypes.Add(typeof(Movie).Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
excludeItemTypes.Add(typeof(Movie).Name);
|
||||
}
|
||||
}
|
||||
if (query.IsSeries.HasValue)
|
||||
{
|
||||
if (query.IsSeries.Value)
|
||||
{
|
||||
includeItemTypes.Add(typeof(Episode).Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
excludeItemTypes.Add(typeof(Episode).Name);
|
||||
}
|
||||
}
|
||||
if (query.IsSports.HasValue)
|
||||
{
|
||||
if (query.IsSports.Value)
|
||||
{
|
||||
genres.Add("Sports");
|
||||
}
|
||||
}
|
||||
if (query.IsKids.HasValue)
|
||||
{
|
||||
if (query.IsKids.Value)
|
||||
{
|
||||
genres.Add("Kids");
|
||||
genres.Add("Children");
|
||||
genres.Add("Family");
|
||||
}
|
||||
}
|
||||
|
||||
return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
||||
{
|
||||
MediaTypes = new[] { MediaType.Video },
|
||||
|
@ -1430,13 +1479,75 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
|
||||
IsFolder = false,
|
||||
ExcludeLocationTypes = new[] { LocationType.Virtual },
|
||||
Limit = Math.Min(200, query.Limit ?? int.MaxValue),
|
||||
Limit = query.Limit,
|
||||
SortBy = new[] { ItemSortBy.DateCreated },
|
||||
SortOrder = SortOrder.Descending,
|
||||
EnableTotalRecordCount = query.EnableTotalRecordCount
|
||||
EnableTotalRecordCount = query.EnableTotalRecordCount,
|
||||
IncludeItemTypes = includeItemTypes.ToArray(),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(),
|
||||
Genres = genres.ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<QueryResult<BaseItemDto>> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
|
||||
if (user != null && !IsLiveTvEnabled(user))
|
||||
{
|
||||
return new QueryResult<BaseItemDto>();
|
||||
}
|
||||
|
||||
if (_services.Count > 1)
|
||||
{
|
||||
return new QueryResult<BaseItemDto>();
|
||||
}
|
||||
|
||||
if (user == null || (query.IsInProgress ?? false))
|
||||
{
|
||||
return new QueryResult<BaseItemDto>();
|
||||
}
|
||||
|
||||
var folders = EmbyTV.EmbyTV.Current.GetRecordingFolders()
|
||||
.SelectMany(i => i.Locations)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(i => _libraryManager.FindByPath(i, true))
|
||||
.Where(i => i != null)
|
||||
.Where(i => i.IsVisibleStandalone(user))
|
||||
.ToList();
|
||||
|
||||
if (folders.Count == 0)
|
||||
{
|
||||
return new QueryResult<BaseItemDto>();
|
||||
}
|
||||
|
||||
var includeItemTypes = new List<string>();
|
||||
var excludeItemTypes = new List<string>();
|
||||
|
||||
includeItemTypes.Add(typeof(Series).Name);
|
||||
|
||||
var internalResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
||||
{
|
||||
Recursive = true,
|
||||
AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
|
||||
Limit = query.Limit,
|
||||
SortBy = new[] { ItemSortBy.DateCreated },
|
||||
SortOrder = SortOrder.Descending,
|
||||
EnableTotalRecordCount = query.EnableTotalRecordCount,
|
||||
IncludeItemTypes = includeItemTypes.ToArray(),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray()
|
||||
});
|
||||
|
||||
RemoveFields(options);
|
||||
|
||||
var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = returnArray,
|
||||
TotalRecordCount = internalResult.TotalRecordCount
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
|
||||
|
@ -1492,6 +1603,30 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
recordings = recordings.Where(i => i.Status == val);
|
||||
}
|
||||
|
||||
if (query.IsMovie.HasValue)
|
||||
{
|
||||
var val = query.IsMovie.Value;
|
||||
recordings = recordings.Where(i => i.IsMovie == val);
|
||||
}
|
||||
|
||||
if (query.IsSeries.HasValue)
|
||||
{
|
||||
var val = query.IsSeries.Value;
|
||||
recordings = recordings.Where(i => i.IsSeries == val);
|
||||
}
|
||||
|
||||
if (query.IsKids.HasValue)
|
||||
{
|
||||
var val = query.IsKids.Value;
|
||||
recordings = recordings.Where(i => i.IsKids == val);
|
||||
}
|
||||
|
||||
if (query.IsSports.HasValue)
|
||||
{
|
||||
var val = query.IsSports.Value;
|
||||
recordings = recordings.Where(i => i.IsSports == val);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(query.SeriesTimerId))
|
||||
{
|
||||
var guid = new Guid(query.SeriesTimerId);
|
||||
|
@ -1950,16 +2085,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
dto.Number = channel.Number;
|
||||
dto.ChannelNumber = channel.Number;
|
||||
dto.ChannelType = channel.ChannelType;
|
||||
dto.ServiceName = GetService(channel).Name;
|
||||
dto.ServiceName = channel.ServiceName;
|
||||
|
||||
if (options.Fields.Contains(ItemFields.MediaSources))
|
||||
{
|
||||
dto.MediaSources = channel.GetMediaSources(true).ToList();
|
||||
}
|
||||
|
||||
var channelIdString = channel.Id.ToString("N");
|
||||
if (options.AddCurrentProgram)
|
||||
{
|
||||
var channelIdString = channel.Id.ToString("N");
|
||||
var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString));
|
||||
|
||||
if (currentProgram != null)
|
||||
|
@ -2091,6 +2226,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
|
||||
public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
|
||||
{
|
||||
var registration = await GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
|
||||
|
||||
if (!registration.IsValid)
|
||||
{
|
||||
_logger.Info("Creating series recordings requires an active Emby Premiere subscription.");
|
||||
return;
|
||||
}
|
||||
|
||||
var service = GetService(timer.ServiceName);
|
||||
|
||||
var info = await _tvDtoService.GetSeriesTimerInfo(timer, true, this, cancellationToken).ConfigureAwait(false);
|
||||
|
@ -2653,33 +2796,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
public Task<MBRegistrationRecord> GetRegistrationInfo(string channelId, string programId, string feature)
|
||||
public Task<MBRegistrationRecord> GetRegistrationInfo(string feature)
|
||||
{
|
||||
ILiveTvService service;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(programId))
|
||||
if (string.Equals(feature, "seriesrecordings", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var channel = GetInternalChannel(channelId);
|
||||
service = GetService(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
var program = GetInternalProgram(programId);
|
||||
service = GetService(program);
|
||||
feature = "embytvseriesrecordings";
|
||||
}
|
||||
|
||||
var hasRegistration = service as IHasRegistrationInfo;
|
||||
|
||||
if (hasRegistration != null)
|
||||
if (string.Equals(feature, "dvr", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return hasRegistration.GetRegistrationInfo(feature);
|
||||
var config = GetConfiguration();
|
||||
if (config.TunerHosts.Count(i => i.IsEnabled) > 0 &&
|
||||
config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0)
|
||||
{
|
||||
return Task.FromResult(new MBRegistrationRecord
|
||||
{
|
||||
IsRegistered = true,
|
||||
IsValid = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(new MBRegistrationRecord
|
||||
{
|
||||
IsValid = true,
|
||||
IsRegistered = true
|
||||
});
|
||||
return _security.GetRegistrationStatus(feature);
|
||||
}
|
||||
|
||||
public List<NameValuePair> GetSatIniMappings()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -70,7 +71,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
|||
}
|
||||
else if (!string.IsNullOrWhiteSpace(extInf) && !line.StartsWith("#", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var channel = GetChannelnfo(extInf, tunerHostId);
|
||||
var channel = GetChannelnfo(extInf, tunerHostId, line);
|
||||
channel.Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N");
|
||||
channel.Path = line;
|
||||
channels.Add(channel);
|
||||
|
@ -79,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
|||
}
|
||||
return channels;
|
||||
}
|
||||
private M3UChannel GetChannelnfo(string extInf, string tunerHostId)
|
||||
private M3UChannel GetChannelnfo(string extInf, string tunerHostId, string mediaUrl)
|
||||
{
|
||||
var titleIndex = extInf.LastIndexOf(',');
|
||||
var channel = new M3UChannel();
|
||||
|
@ -87,8 +88,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
|||
|
||||
channel.Number = extInf.Trim().Split(' ')[0] ?? "0";
|
||||
channel.Name = extInf.Substring(titleIndex + 1);
|
||||
|
||||
if(channel.Number == "-1") { channel.Number = "0"; }
|
||||
|
||||
//Check for channel number with the format from SatIp
|
||||
int number;
|
||||
|
@ -101,6 +100,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
|||
channel.Name = channel.Name.Substring(numberIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (string.Equals(channel.Number, "-1", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(mediaUrl))
|
||||
{
|
||||
channel.Number = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
|
||||
}
|
||||
|
||||
if (string.Equals(channel.Number, "-1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
channel.Number = "0";
|
||||
}
|
||||
|
||||
channel.ImageUrl = FindProperty("tvg-logo", extInf, null);
|
||||
channel.Number = FindProperty("tvg-id", extInf, channel.Number);
|
||||
channel.Number = FindProperty("channel-id", extInf, channel.Number);
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Copyright (C) <2007-2016> <Kay Diefenthal>
|
||||
|
||||
SatIp.RtspSample is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SatIp.RtspSample is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
|
||||
{
|
||||
public class ReportBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the length of the block.
|
||||
/// </summary>
|
||||
public int BlockLength { get { return (24); } }
|
||||
/// <summary>
|
||||
/// Get the synchronization source.
|
||||
/// </summary>
|
||||
public string SynchronizationSource { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the fraction lost.
|
||||
/// </summary>
|
||||
public int FractionLost { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the cumulative packets lost.
|
||||
/// </summary>
|
||||
public int CumulativePacketsLost { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the highest number received.
|
||||
/// </summary>
|
||||
public int HighestNumberReceived { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the inter arrival jitter.
|
||||
/// </summary>
|
||||
public int InterArrivalJitter { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the timestamp of the last report.
|
||||
/// </summary>
|
||||
public int LastReportTimeStamp { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the delay since the last report.
|
||||
/// </summary>
|
||||
public int DelaySinceLastReport { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the ReportBlock class.
|
||||
/// </summary>
|
||||
public ReportBlock() { }
|
||||
|
||||
/// <summary>
|
||||
/// Unpack the data in a packet.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer containing the packet.</param>
|
||||
/// <param name="offset">The offset to the first byte of the packet within the buffer.</param>
|
||||
/// <returns>An ErrorSpec instance if an error occurs; null otherwise.</returns>
|
||||
public void Process(byte[] buffer, int offset)
|
||||
{
|
||||
SynchronizationSource = Utils.ConvertBytesToString(buffer, offset, 4);
|
||||
FractionLost = buffer[offset + 4];
|
||||
CumulativePacketsLost = Utils.Convert3BytesToInt(buffer, offset + 5);
|
||||
HighestNumberReceived = Utils.Convert4BytesToInt(buffer, offset + 8);
|
||||
InterArrivalJitter = Utils.Convert4BytesToInt(buffer, offset + 12);
|
||||
LastReportTimeStamp = Utils.Convert4BytesToInt(buffer, offset + 16);
|
||||
DelaySinceLastReport = Utils.Convert4BytesToInt(buffer, offset + 20);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright (C) <2007-2016> <Kay Diefenthal>
|
||||
|
||||
SatIp.RtspSample is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SatIp.RtspSample is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
|
||||
{
|
||||
class RtcpAppPacket : RtcpPacket
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the synchronization source.
|
||||
/// </summary>
|
||||
public int SynchronizationSource { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the name.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the identity.
|
||||
/// </summary>
|
||||
public int Identity { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the variable data portion.
|
||||
/// </summary>
|
||||
public string Data { get; private set; }
|
||||
|
||||
public override void Parse(byte[] buffer, int offset)
|
||||
{
|
||||
base.Parse(buffer, offset);
|
||||
SynchronizationSource = Utils.Convert4BytesToInt(buffer, offset + 4);
|
||||
Name = Utils.ConvertBytesToString(buffer, offset + 8, 4);
|
||||
Identity = Utils.Convert2BytesToInt(buffer, offset + 12);
|
||||
|
||||
int dataLength = Utils.Convert2BytesToInt(buffer, offset + 14);
|
||||
if (dataLength != 0)
|
||||
Data = Utils.ConvertBytesToString(buffer, offset + 16, dataLength);
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("Application Specific.\n");
|
||||
sb.AppendFormat("Version : {0} .\n", Version);
|
||||
sb.AppendFormat("Padding : {0} .\n", Padding);
|
||||
sb.AppendFormat("Report Count : {0} .\n", ReportCount);
|
||||
sb.AppendFormat("PacketType: {0} .\n", Type);
|
||||
sb.AppendFormat("Length : {0} .\n", Length);
|
||||
sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource);
|
||||
sb.AppendFormat("Name : {0} .\n", Name);
|
||||
sb.AppendFormat("Identity : {0} .\n", Identity);
|
||||
sb.AppendFormat("Data : {0} .\n", Data);
|
||||
sb.AppendFormat(".\n");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using System.Collections.ObjectModel;
|
||||
/*
|
||||
Copyright (C) <2007-2016> <Kay Diefenthal>
|
||||
|
||||
SatIp.RtspSample is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SatIp.RtspSample is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
|
||||
{
|
||||
public class RtcpByePacket :RtcpPacket
|
||||
{
|
||||
public Collection<string> SynchronizationSources { get; private set; }
|
||||
public string ReasonForLeaving { get; private set; }
|
||||
public override void Parse(byte[] buffer, int offset)
|
||||
{
|
||||
base.Parse(buffer, offset);
|
||||
SynchronizationSources = new Collection<string>();
|
||||
int index = 4;
|
||||
|
||||
while (SynchronizationSources.Count < ReportCount)
|
||||
{
|
||||
SynchronizationSources.Add(Utils.ConvertBytesToString(buffer, offset + index, 4));
|
||||
index += 4;
|
||||
}
|
||||
|
||||
if (index < Length)
|
||||
{
|
||||
int reasonLength = buffer[offset + index];
|
||||
ReasonForLeaving = Utils.ConvertBytesToString(buffer, offset + index + 1, reasonLength);
|
||||
}
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("ByeBye .\n");
|
||||
sb.AppendFormat("Version : {0} .\n", Version);
|
||||
sb.AppendFormat("Padding : {0} .\n", Padding);
|
||||
sb.AppendFormat("Report Count : {0} .\n", ReportCount);
|
||||
sb.AppendFormat("PacketType: {0} .\n", Type);
|
||||
sb.AppendFormat("Length : {0} .\n", Length);
|
||||
sb.AppendFormat("SynchronizationSources : {0} .\n", SynchronizationSources);
|
||||
sb.AppendFormat("ReasonForLeaving : {0} .\n", ReasonForLeaving);
|
||||
sb.AppendFormat(".\n");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
Copyright (C) <2007-2016> <Kay Diefenthal>
|
||||
|
||||
SatIp.RtspSample is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SatIp.RtspSample is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
|
||||
{
|
||||
public class RtcpListener
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private Thread _rtcpListenerThread;
|
||||
private AutoResetEvent _rtcpListenerThreadStopEvent = null;
|
||||
private UdpClient _udpClient;
|
||||
private IPEndPoint _multicastEndPoint;
|
||||
private IPEndPoint _serverEndPoint;
|
||||
private TransmissionMode _transmissionMode;
|
||||
|
||||
public RtcpListener(String address, int port, TransmissionMode mode,ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_transmissionMode = mode;
|
||||
switch (mode)
|
||||
{
|
||||
case TransmissionMode.Unicast:
|
||||
_udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse(address), port));
|
||||
_serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
break;
|
||||
case TransmissionMode.Multicast:
|
||||
_multicastEndPoint = new IPEndPoint(IPAddress.Parse(address), port);
|
||||
_serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
_udpClient = new UdpClient();
|
||||
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
|
||||
_udpClient.ExclusiveAddressUse = false;
|
||||
_udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, port));
|
||||
_udpClient.JoinMulticastGroup(_multicastEndPoint.Address);
|
||||
break;
|
||||
}
|
||||
//StartRtcpListenerThread();
|
||||
}
|
||||
|
||||
public void StartRtcpListenerThread()
|
||||
{
|
||||
// Kill the existing thread if it is in "zombie" state.
|
||||
if (_rtcpListenerThread != null && !_rtcpListenerThread.IsAlive)
|
||||
{
|
||||
StopRtcpListenerThread();
|
||||
}
|
||||
|
||||
if (_rtcpListenerThread == null)
|
||||
{
|
||||
_logger.Info("SAT>IP : starting new RTCP listener thread");
|
||||
_rtcpListenerThreadStopEvent = new AutoResetEvent(false);
|
||||
_rtcpListenerThread = new Thread(new ThreadStart(RtcpListenerThread));
|
||||
_rtcpListenerThread.Name = string.Format("SAT>IP tuner RTCP listener");
|
||||
_rtcpListenerThread.IsBackground = true;
|
||||
_rtcpListenerThread.Priority = ThreadPriority.Lowest;
|
||||
_rtcpListenerThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void StopRtcpListenerThread()
|
||||
{
|
||||
if (_rtcpListenerThread != null)
|
||||
{
|
||||
if (!_rtcpListenerThread.IsAlive)
|
||||
{
|
||||
_logger.Info("SAT>IP : aborting old RTCP listener thread");
|
||||
_rtcpListenerThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
_rtcpListenerThreadStopEvent.Set();
|
||||
if (!_rtcpListenerThread.Join(400 * 2))
|
||||
{
|
||||
_logger.Info("SAT>IP : failed to join RTCP listener thread, aborting thread");
|
||||
_rtcpListenerThread.Abort();
|
||||
}
|
||||
}
|
||||
_rtcpListenerThread = null;
|
||||
if (_rtcpListenerThreadStopEvent != null)
|
||||
{
|
||||
_rtcpListenerThreadStopEvent.Close();
|
||||
_rtcpListenerThreadStopEvent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RtcpListenerThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
bool receivedGoodBye = false;
|
||||
try
|
||||
{
|
||||
_udpClient.Client.ReceiveTimeout = 400;
|
||||
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
while (!receivedGoodBye && !_rtcpListenerThreadStopEvent.WaitOne(1))
|
||||
{
|
||||
byte[] packets = _udpClient.Receive(ref serverEndPoint);
|
||||
if (packets == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
while (offset < packets.Length)
|
||||
{
|
||||
switch (packets[offset + 1])
|
||||
{
|
||||
case 200: //sr
|
||||
var sr = new RtcpSenderReportPacket();
|
||||
sr.Parse(packets, offset);
|
||||
offset += sr.Length;
|
||||
break;
|
||||
case 201: //rr
|
||||
var rr = new RtcpReceiverReportPacket();
|
||||
rr.Parse(packets, offset);
|
||||
offset += rr.Length;
|
||||
break;
|
||||
case 202: //sd
|
||||
var sd = new RtcpSourceDescriptionPacket();
|
||||
sd.Parse(packets, offset);
|
||||
offset += sd.Length;
|
||||
break;
|
||||
case 203: // bye
|
||||
var bye = new RtcpByePacket();
|
||||
bye.Parse(packets, offset);
|
||||
receivedGoodBye = true;
|
||||
OnPacketReceived(new RtcpPacketReceivedArgs(bye));
|
||||
offset += bye.Length;
|
||||
break;
|
||||
case 204: // app
|
||||
var app = new RtcpAppPacket();
|
||||
app.Parse(packets, offset);
|
||||
OnPacketReceived(new RtcpPacketReceivedArgs(app));
|
||||
offset += app.Length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
switch (_transmissionMode)
|
||||
{
|
||||
case TransmissionMode.Multicast:
|
||||
_udpClient.DropMulticastGroup(_multicastEndPoint.Address);
|
||||
_udpClient.Close();
|
||||
break;
|
||||
case TransmissionMode.Unicast:
|
||||
_udpClient.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Info(string.Format("SAT>IP : RTCP listener thread exception"), ex);
|
||||
return;
|
||||
}
|
||||
_logger.Info("SAT>IP : RTCP listener thread stopping");
|
||||
}
|
||||
public delegate void PacketReceivedHandler(object sender, RtcpPacketReceivedArgs e);
|
||||
public event PacketReceivedHandler PacketReceived;
|
||||
public class RtcpPacketReceivedArgs : EventArgs
|
||||
{
|
||||
public Object Packet { get; private set; }
|
||||
|
||||
public RtcpPacketReceivedArgs(Object packet)
|
||||
{
|
||||
Packet = packet;
|
||||
}
|
||||
}
|
||||
protected void OnPacketReceived(RtcpPacketReceivedArgs args)
|
||||
{
|
||||
if (PacketReceived != null)
|
||||
{
|
||||
PacketReceived(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
Copyright (C) <2007-2016> <Kay Diefenthal>
|
||||
|
||||
SatIp.RtspSample is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SatIp.RtspSample is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
|
||||
{
|
||||
public abstract class RtcpPacket
|
||||
{
|
||||
public int Version { get; private set; }
|
||||
public bool Padding { get; private set; }
|
||||
public int ReportCount { get; private set; }
|
||||
public int Type { get; private set; }
|
||||
public int Length { get; private set; }
|
||||
|
||||
public virtual void Parse(byte[] buffer, int offset)
|
||||
{
|
||||
Version = buffer[offset] >> 6;
|
||||
Padding = (buffer[offset] & 0x20) != 0;
|
||||
ReportCount = buffer[offset] & 0x1f;
|
||||
Type = buffer[offset + 1];
|
||||
Length = (Utils.Convert2BytesToInt(buffer, offset + 2) * 4) + 4;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
using System.Collections.ObjectModel;
|
||||
/*
|
||||
Copyright (C) <2007-2016> <Kay Diefenthal>
|
||||
|
||||
SatIp.RtspSample is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SatIp.RtspSample is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
|
||||
{
|
||||
public class RtcpReceiverReportPacket :RtcpPacket
|
||||
{
|
||||
public string SynchronizationSource { get; private set; }
|
||||
public Collection<ReportBlock> ReportBlocks { get; private set; }
|
||||
public byte[] ProfileExtension { get; private set; }
|
||||
public override void Parse(byte[] buffer, int offset)
|
||||
{
|
||||
base.Parse(buffer, offset);
|
||||
SynchronizationSource = Utils.ConvertBytesToString(buffer, offset + 4, 4);
|
||||
|
||||
ReportBlocks = new Collection<ReportBlock>();
|
||||
int index = 8;
|
||||
|
||||
while (ReportBlocks.Count < ReportCount)
|
||||
{
|
||||
ReportBlock reportBlock = new ReportBlock();
|
||||
reportBlock.Process(buffer, offset + index);
|
||||
ReportBlocks.Add(reportBlock);
|
||||
index += reportBlock.BlockLength;
|
||||
}
|
||||
|
||||
if (index < Length)
|
||||
{
|
||||
ProfileExtension = new byte[Length - index];
|
||||
|
||||
for (int extensionIndex = 0; index < Length; index++)
|
||||
{
|
||||
ProfileExtension[extensionIndex] = buffer[offset + index];
|
||||
extensionIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("Receiver Report.\n");
|
||||
sb.AppendFormat("Version : {0} .\n", Version);
|
||||
sb.AppendFormat("Padding : {0} .\n", Padding);
|
||||
sb.AppendFormat("Report Count : {0} .\n", ReportCount);
|
||||
sb.AppendFormat("PacketType: {0} .\n", Type);
|
||||
sb.AppendFormat("Length : {0} .\n", Length);
|
||||
sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource);
|
||||
sb.AppendFormat(".\n");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
using System.Collections.ObjectModel;
|
||||
/*
|
||||
Copyright (C) <2007-2016> <Kay Diefenthal>
|
||||
|
||||
SatIp.RtspSample is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
SatIp.RtspSample is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
|
||||
{
|
||||
public class RtcpSenderReportPacket : RtcpPacket
|
||||
{
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Get the synchronization source.
|
||||
/// </summary>
|
||||
public int SynchronizationSource { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the NPT timestamp.
|
||||
/// </summary>
|
||||
public long NPTTimeStamp { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the RTP timestamp.
|
||||
/// </summary>
|
||||
public int RTPTimeStamp { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the packet count.
|
||||
/// </summary>
|
||||
public int SenderPacketCount { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the octet count.
|
||||
/// </summary>
|
||||
public int SenderOctetCount { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the list of report blocks.
|
||||
/// </summary>
|
||||
public Collection<ReportBlock> ReportBlocks { get; private set; }
|
||||
/// <summary>
|
||||
/// Get the profile extension data.
|
||||
/// </summary>
|
||||
public byte[] ProfileExtension { get; private set; }
|
||||
#endregion
|
||||
|
||||
public override void Parse(byte[] buffer, int offset)
|
||||
{
|
||||
base.Parse(buffer, offset);
|
||||
SynchronizationSource = Utils.Convert4BytesToInt(buffer, offset + 4);
|
||||
NPTTimeStamp = Utils.Convert8BytesToLong(buffer, offset + 8);
|
||||
RTPTimeStamp = Utils.Convert4BytesToInt(buffer, offset + 16);
|
||||
SenderPacketCount = Utils.Convert4BytesToInt(buffer, offset + 20);
|
||||
SenderOctetCount = Utils.Convert4BytesToInt(buffer, offset + 24);
|
||||
|
||||
ReportBlocks = new Collection<ReportBlock>();
|
||||
int index = 28;
|
||||
|
||||
while (ReportBlocks.Count < ReportCount)
|
||||
{
|
||||
ReportBlock reportBlock = new ReportBlock();
|
||||
reportBlock.Process(buffer, offset + index);
|
||||
ReportBlocks.Add(reportBlock);
|
||||
index += reportBlock.BlockLength;
|
||||
}
|
||||
|
||||
if (index < Length)
|
||||
{
|
||||
ProfileExtension = new byte[Length - index];
|
||||
|
||||
for (int extensionIndex = 0; index < Length; index++)
|
||||
{
|
||||
ProfileExtension[extensionIndex] = buffer[offset + index];
|
||||
extensionIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("Sender Report.\n");
|
||||
sb.AppendFormat("Version : {0} .\n", Version);
|
||||
sb.AppendFormat("Padding : {0} .\n", Padding);
|
||||
sb.AppendFormat("Report Count : {0} .\n", ReportCount);
|
||||
sb.AppendFormat("PacketType: {0} .\n", Type);
|
||||
sb.AppendFormat("Length : {0} .\n", Length);
|
||||
sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource);
|
||||
sb.AppendFormat("NTP Timestamp : {0} .\n", Utils.NptTimestampToDateTime(NPTTimeStamp));
|
||||
sb.AppendFormat("RTP Timestamp : {0} .\n", RTPTimeStamp);
|
||||
sb.AppendFormat("Sender PacketCount : {0} .\n", SenderPacketCount);
|
||||
sb.AppendFormat("Sender Octet Count : {0} .\n", SenderOctetCount);
|
||||
sb.AppendFormat(".\n");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user