Merge pull request #2151 from MediaBrowser/beta

Beta
pull/1154/head
Luke 8 years ago committed by GitHub
commit 080a6511dc

@ -70,12 +70,13 @@ namespace MediaBrowser.Api
Cultures = _localizationManager.GetCultures().ToList() 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 inheritedContentType = _libraryManager.GetInheritedContentType(item);
var configuredContentType = _libraryManager.GetConfiguredContentType(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.ContentTypeOptions = GetContentTypeOptions(true);
info.ContentType = configuredContentType; info.ContentType = configuredContentType;

@ -25,6 +25,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
using MediaBrowser.Controller.Configuration;
namespace MediaBrowser.Api.Library namespace MediaBrowser.Api.Library
{ {
@ -288,12 +289,13 @@ namespace MediaBrowser.Api.Library
private readonly ITVSeriesManager _tvManager; private readonly ITVSeriesManager _tvManager;
private readonly ILibraryMonitor _libraryMonitor; private readonly ILibraryMonitor _libraryMonitor;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IServerConfigurationManager _config;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LibraryService" /> class. /// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary> /// </summary>
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, 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; _itemRepo = itemRepo;
_libraryManager = libraryManager; _libraryManager = libraryManager;
@ -307,6 +309,7 @@ namespace MediaBrowser.Api.Library
_tvManager = tvManager; _tvManager = tvManager;
_libraryMonitor = libraryMonitor; _libraryMonitor = libraryMonitor;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_config = config;
} }
public object Get(GetSimilarItems request) public object Get(GetSimilarItems request)
@ -377,7 +380,7 @@ namespace MediaBrowser.Api.Library
if (item is Movie || (program != null && program.IsMovie) || item is Trailer) 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, AuthorizationContext = AuthorizationContext,
Logger = Logger, 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")] [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; } 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() public GetRecordings()
{ {
EnableTotalRecordCount = true; 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")] [Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
[Authenticated] [Authenticated]
public class GetRecordingGroups : IReturn<QueryResult<BaseItemDto>> public class GetRecordingGroups : IReturn<QueryResult<BaseItemDto>>
@ -535,12 +595,6 @@ namespace MediaBrowser.Api.LiveTv
[Authenticated] [Authenticated]
public class GetLiveTvRegistrationInfo : IReturn<MBRegistrationRecord> 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")] [ApiMember(Name = "Feature", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Feature { get; set; } public string Feature { get; set; }
} }
@ -592,7 +646,7 @@ namespace MediaBrowser.Api.LiveTv
public async Task<object> Get(GetLiveTvRegistrationInfo request) 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); return ToOptimizedResult(result);
} }
@ -854,6 +908,32 @@ namespace MediaBrowser.Api.LiveTv
options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId; options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
var result = await _liveTvManager.GetRecordings(new RecordingQuery 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, ChannelId = request.ChannelId,
UserId = request.UserId, UserId = request.UserId,

@ -14,6 +14,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.LiveTv;
namespace MediaBrowser.Api.Movies namespace MediaBrowser.Api.Movies
@ -88,6 +89,7 @@ namespace MediaBrowser.Api.Movies
private readonly IItemRepository _itemRepo; private readonly IItemRepository _itemRepo;
private readonly IDtoService _dtoService; private readonly IDtoService _dtoService;
private readonly IServerConfigurationManager _config;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MoviesService" /> class. /// 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="libraryManager">The library manager.</param>
/// <param name="itemRepo">The item repo.</param> /// <param name="itemRepo">The item repo.</param>
/// <param name="dtoService">The dto service.</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; _userManager = userManager;
_userDataRepository = userDataRepository; _userDataRepository = userDataRepository;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_itemRepo = itemRepo; _itemRepo = itemRepo;
_dtoService = dtoService; _dtoService = dtoService;
_config = config;
} }
/// <summary> /// <summary>
@ -146,15 +149,17 @@ namespace MediaBrowser.Api.Movies
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); _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) var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{ {
Limit = request.Limit, Limit = request.Limit,
IncludeItemTypes = new[] IncludeItemTypes = itemTypes.ToArray(),
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true, IsMovie = true,
SimilarTo = item, SimilarTo = item,
EnableGroupByMetadataKey = true EnableGroupByMetadataKey = true
@ -198,14 +203,16 @@ namespace MediaBrowser.Api.Movies
var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList(); 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) var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
{ {
IncludeItemTypes = new[] IncludeItemTypes = itemTypes.ToArray(),
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true, IsMovie = true,
SortBy = new[] { ItemSortBy.Random }, SortBy = new[] { ItemSortBy.Random },
SortOrder = SortOrder.Descending, 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) 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) foreach (var name in names)
{ {
var items = _libraryManager.GetItemList(new InternalItemsQuery(user) 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 // Account for duplicates by imdb id, since the database doesn't support this yet
Limit = itemLimit + 2, Limit = itemLimit + 2,
PersonTypes = new[] { PersonType.Director }, PersonTypes = new[] { PersonType.Director },
IncludeItemTypes = new[] IncludeItemTypes = itemTypes.ToArray(),
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true, IsMovie = true,
EnableGroupByMetadataKey = 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) 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) foreach (var name in names)
{ {
var items = _libraryManager.GetItemList(new InternalItemsQuery(user) var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
@ -321,12 +337,7 @@ namespace MediaBrowser.Api.Movies
Person = name, Person = name,
// Account for duplicates by imdb id, since the database doesn't support this yet // Account for duplicates by imdb id, since the database doesn't support this yet
Limit = itemLimit + 2, Limit = itemLimit + 2,
IncludeItemTypes = new[] IncludeItemTypes = itemTypes.ToArray(),
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true, IsMovie = true,
EnableGroupByMetadataKey = 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) 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) foreach (var item in baselineItems)
{ {
var similar = _libraryManager.GetItemList(new InternalItemsQuery(user) var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
{ {
Limit = itemLimit, Limit = itemLimit,
IncludeItemTypes = new[] IncludeItemTypes = itemTypes.ToArray(),
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true, IsMovie = true,
SimilarTo = item, SimilarTo = item,
EnableGroupByMetadataKey = true EnableGroupByMetadataKey = true

@ -337,44 +337,60 @@ namespace MediaBrowser.Api.Playback
/// Gets the video bitrate to specify on the command line /// Gets the video bitrate to specify on the command line
/// </summary> /// </summary>
/// <param name="state">The state.</param> /// <param name="state">The state.</param>
/// <param name="videoCodec">The video codec.</param> /// <param name="videoEncoder">The video codec.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
protected string GetVideoQualityParam(StreamState state, string videoCodec) protected string GetVideoQualityParam(StreamState state, string videoEncoder)
{ {
var param = string.Empty; var param = string.Empty;
var isVc1 = state.VideoStream != null && var isVc1 = state.VideoStream != null &&
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase); string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
{ {
param = "-preset superfast"; if (!string.IsNullOrWhiteSpace(encodingOptions.H264Preset))
{
param += "-preset " + encodingOptions.H264Preset;
}
else
{
param += "-preset superfast";
}
param += " -crf 23"; 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"; param += " -crf 28";
} }
// h264 (h264_qsv) // 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) // 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 // 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 // Values 0-3, 0 being highest quality but slower
var profileScore = 0; var profileScore = 0;
@ -394,30 +410,30 @@ namespace MediaBrowser.Api.Playback
profileScore = Math.Min(profileScore, 2); profileScore = Math.Min(profileScore, 2);
// http://www.webmproject.org/docs/encoder-parameters/ // 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), profileScore.ToString(UsCulture),
crf, crf,
qmin, qmin,
qmax); 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 // 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); var framerate = GetFramerateParam(state);
if (framerate.HasValue) if (framerate.HasValue)
@ -432,8 +448,8 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrEmpty(state.VideoRequest.Profile)) if (!string.IsNullOrEmpty(state.VideoRequest.Profile))
{ {
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) && if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{ {
// not supported by h264_omx // not supported by h264_omx
param += " -profile:v " + state.VideoRequest.Profile; param += " -profile:v " + state.VideoRequest.Profile;
@ -442,11 +458,13 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrEmpty(state.VideoRequest.Level)) 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 // 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) || if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{ {
switch (state.VideoRequest.Level) switch (level)
{ {
case "30": case "30":
param += " -level 3"; param += " -level 3";
@ -476,20 +494,20 @@ namespace MediaBrowser.Api.Playback
param += " -level 5.2"; param += " -level 5.2";
break; break;
default: default:
param += " -level " + state.VideoRequest.Level; param += " -level " + level;
break; 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) && if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{ {
param = "-pix_fmt yuv420p " + param; param = "-pix_fmt yuv420p " + param;
} }
@ -497,6 +515,25 @@ namespace MediaBrowser.Api.Playback
return param; 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) protected string GetAudioFilterParam(StreamState state, bool isHls)
{ {
var volParam = string.Empty; var volParam = string.Empty;
@ -1160,17 +1197,21 @@ namespace MediaBrowser.Api.Playback
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false); 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); await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
if (state.ReadInputAtNativeFramerate) if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited)
{ {
await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false); await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
} }
} }
StartThrottler(state, transcodingJob); if (!transcodingJob.HasExited)
{
StartThrottler(state, transcodingJob);
}
ReportUsage(state); ReportUsage(state);
return transcodingJob; return transcodingJob;
@ -1770,6 +1811,15 @@ namespace MediaBrowser.Api.Playback
// state.SegmentLength = 6; // 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)) if (!string.IsNullOrWhiteSpace(request.AudioCodec))
{ {
state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); 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 // 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; return false;
} }

@ -17,6 +17,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Api.Playback namespace MediaBrowser.Api.Playback
{ {
@ -70,8 +71,9 @@ namespace MediaBrowser.Api.Playback
private readonly INetworkManager _networkManager; private readonly INetworkManager _networkManager;
private readonly IMediaEncoder _mediaEncoder; private readonly IMediaEncoder _mediaEncoder;
private readonly IUserManager _userManager; 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; _mediaSourceManager = mediaSourceManager;
_deviceManager = deviceManager; _deviceManager = deviceManager;
@ -80,6 +82,7 @@ namespace MediaBrowser.Api.Playback
_networkManager = networkManager; _networkManager = networkManager;
_mediaEncoder = mediaEncoder; _mediaEncoder = mediaEncoder;
_userManager = userManager; _userManager = userManager;
_json = json;
} }
public object Get(GetBitrateTestBytes request) public object Get(GetBitrateTestBytes request)
@ -147,6 +150,8 @@ namespace MediaBrowser.Api.Playback
var profile = request.DeviceProfile; var profile = request.DeviceProfile;
//Logger.Info("GetPostedPlaybackInfo profile: {0}", _json.SerializeToString(profile));
if (profile == null) if (profile == null)
{ {
var caps = _deviceManager.GetCapabilities(authInfo.DeviceId); var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);

@ -112,6 +112,7 @@ namespace MediaBrowser.Api.Playback
public string OutputVideoSync = "-1"; public string OutputVideoSync = "-1";
public List<string> SupportedAudioCodecs { get; set; } public List<string> SupportedAudioCodecs { get; set; }
public List<string> SupportedVideoCodecs { get; set; }
public string UserAgent { get; set; } public string UserAgent { get; set; }
public StreamState(IMediaSourceManager mediaSourceManager, ILogger logger) public StreamState(IMediaSourceManager mediaSourceManager, ILogger logger)
@ -119,6 +120,7 @@ namespace MediaBrowser.Api.Playback
_mediaSourceManager = mediaSourceManager; _mediaSourceManager = mediaSourceManager;
_logger = logger; _logger = logger;
SupportedAudioCodecs = new List<string>(); SupportedAudioCodecs = new List<string>();
SupportedVideoCodecs = new List<string>();
PlayableStreamFileNames = new List<string>(); PlayableStreamFileNames = new List<string>();
RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
} }

@ -478,7 +478,7 @@ namespace MediaBrowser.Api
} }
else else
{ {
episodes = series.GetSeasonEpisodes(user, season); episodes = series.GetSeasonEpisodes(season, user);
} }
} }
else else

@ -142,9 +142,15 @@ namespace MediaBrowser.Common.Implementations.Security
} }
set 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(); LicenseFile.Save();
// re-load registration info // re-load registration info

@ -14,16 +14,14 @@ namespace MediaBrowser.Common.Implementations.Updates
{ {
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
private TimeSpan _cacheLength;
public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer, TimeSpan cacheLength) public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_jsonSerializer = jsonSerializer; _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); 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" UserAgent = "Emby/3.0"
}; };
if (_cacheLength.Ticks > 0) if (cacheLength.Ticks > 0)
{ {
options.CacheMode = CacheMode.Unconditional; options.CacheMode = CacheMode.Unconditional;
options.CacheLength = _cacheLength; options.CacheLength = cacheLength;
} }
using (var stream = await _httpClient.Get(options).ConfigureAwait(false)) using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
@ -110,12 +108,6 @@ namespace MediaBrowser.Common.Implementations.Updates
UserAgent = "Emby/3.0" UserAgent = "Emby/3.0"
}; };
if (_cacheLength.Ticks > 0)
{
options.CacheMode = CacheMode.Unconditional;
options.CacheLength = _cacheLength;
}
using (var stream = await _httpClient.Get(options).ConfigureAwait(false)) using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
{ {
var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream); var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);

@ -31,6 +31,8 @@ namespace MediaBrowser.Controller.Channels
/// <returns>ChannelFeatures.</returns> /// <returns>ChannelFeatures.</returns>
ChannelFeatures GetChannelFeatures(string id); ChannelFeatures GetChannelFeatures(string id);
bool SupportsSync(string channelId);
/// <summary> /// <summary>
/// Gets all channel features. /// Gets all channel features.
/// </summary> /// </summary>

@ -1,6 +1,6 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Server.Implementations.Collections namespace MediaBrowser.Controller.Collections
{ {
public class ManualCollectionsFolder : BasePluginFolder, IHiddenFromDisplay public class ManualCollectionsFolder : BasePluginFolder, IHiddenFromDisplay
{ {

@ -106,7 +106,7 @@ namespace MediaBrowser.Controller.Entities
{ {
LibraryOptions[path] = options; LibraryOptions[path] = options;
options.SchemaVersion = 1; options.SchemaVersion = 2;
XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path)); XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path));
} }
} }

@ -1057,10 +1057,20 @@ namespace MediaBrowser.Controller.Entities
/// <returns>IList{BaseItem}.</returns> /// <returns>IList{BaseItem}.</returns>
public IList<BaseItem> GetRecursiveChildren() 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) 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>(); var result = new Dictionary<Guid, BaseItem>();

@ -85,9 +85,7 @@ namespace MediaBrowser.Controller.Entities.TV
public override int GetChildCount(User user) public override int GetChildCount(User user)
{ {
Logger.Debug("Season {0} getting child cound", (Path ?? Name));
var result = GetChildren(user, true).Count(); var result = GetChildren(user, true).Count();
Logger.Debug("Season {0} child cound: ", result);
return result; return result;
} }
@ -158,13 +156,10 @@ namespace MediaBrowser.Controller.Entities.TV
var id = Guid.NewGuid().ToString("N"); var id = Guid.NewGuid().ToString("N");
Logger.Debug("Season.GetItemsInternal entering GetEpisodes. Request id: " + id);
var items = GetEpisodes(user).Where(filter); var items = GetEpisodes(user).Where(filter);
Logger.Debug("Season.GetItemsInternal entering PostFilterAndSort. Request id: " + id);
var result = PostFilterAndSort(items, query, false, false); var result = PostFilterAndSort(items, query, false, false);
Logger.Debug("Season.GetItemsInternal complete. Request id: " + id);
return Task.FromResult(result); return Task.FromResult(result);
} }
@ -185,34 +180,12 @@ namespace MediaBrowser.Controller.Entities.TV
public IEnumerable<Episode> GetEpisodes(Series series, User user, IEnumerable<Episode> allSeriesEpisodes) 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() public IEnumerable<Episode> GetEpisodes()
{ {
var episodes = GetRecursiveChildren().OfType<Episode>(); return Series.GetSeasonEpisodes(this, null, null);
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;
} }
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren) public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)

@ -209,7 +209,6 @@ namespace MediaBrowser.Controller.Entities.TV
var seriesKey = GetUniqueSeriesKey(this); var seriesKey = GetUniqueSeriesKey(this);
Logger.Debug("GetSeasons SeriesKey: {0}", seriesKey);
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
AncestorWithPresentationUniqueKey = seriesKey, AncestorWithPresentationUniqueKey = seriesKey,
@ -267,7 +266,6 @@ namespace MediaBrowser.Controller.Entities.TV
public IEnumerable<Episode> GetEpisodes(User user) public IEnumerable<Episode> GetEpisodes(User user)
{ {
var seriesKey = GetUniqueSeriesKey(this); var seriesKey = GetUniqueSeriesKey(this);
Logger.Debug("GetEpisodes seriesKey: {0}", seriesKey);
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
@ -291,8 +289,6 @@ namespace MediaBrowser.Controller.Entities.TV
var allItems = LibraryManager.GetItemList(query).ToList(); var allItems = LibraryManager.GetItemList(query).ToList();
Logger.Debug("GetEpisodes return {0} items from database", allItems.Count);
var allSeriesEpisodes = allItems.OfType<Episode>().ToList(); var allSeriesEpisodes = allItems.OfType<Episode>().ToList();
var allEpisodes = allItems.OfType<Season>() var allEpisodes = allItems.OfType<Season>()
@ -373,27 +369,9 @@ namespace MediaBrowser.Controller.Entities.TV
progress.Report(100); progress.Report(100);
} }
private IEnumerable<Episode> GetAllEpisodes(User user) public IEnumerable<Episode> GetSeasonEpisodes(Season parentSeason, 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)
{ {
var seriesKey = GetUniqueSeriesKey(this); var seriesKey = GetUniqueSeriesKey(this);
Logger.Debug("GetSeasonEpisodes seriesKey: {0}", seriesKey);
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
@ -401,34 +379,35 @@ namespace MediaBrowser.Controller.Entities.TV
IncludeItemTypes = new[] { typeof(Episode).Name }, IncludeItemTypes = new[] { typeof(Episode).Name },
SortBy = new[] { ItemSortBy.SortName } SortBy = new[] { ItemSortBy.SortName }
}; };
var config = user.Configuration; if (user != null)
if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
{ {
query.IsVirtualItem = false; var config = user.Configuration;
} if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
else if (!config.DisplayMissingEpisodes) {
{ query.IsVirtualItem = false;
query.IsMissing = false; }
} else if (!config.DisplayMissingEpisodes)
else if (!config.DisplayUnairedEpisodes) {
{ query.IsMissing = false;
query.IsVirtualUnaired = false; }
else if (!config.DisplayUnairedEpisodes)
{
query.IsVirtualUnaired = false;
}
} }
var allItems = LibraryManager.GetItemList(query).OfType<Episode>(); 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) if (allSeriesEpisodes == null)
{ {
Logger.Debug("GetSeasonEpisodes allSeriesEpisodes is null"); return GetSeasonEpisodes(parentSeason, user);
return GetSeasonEpisodes(user, parentSeason);
} }
Logger.Debug("GetSeasonEpisodes FilterEpisodesBySeason");
var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons); var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons);
var sortBy = (parentSeason.IndexNumber ?? -1) == 0 ? ItemSortBy.SortName : ItemSortBy.AiredEpisodeOrder; var sortBy = (parentSeason.IndexNumber ?? -1) == 0 ? ItemSortBy.SortName : ItemSortBy.AiredEpisodeOrder;

@ -64,7 +64,7 @@ namespace MediaBrowser.Controller.Entities
info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer); info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
if (!IsInMixedFolder) if (!IsInMixedFolder && LocationType == LocationType.FileSystem)
{ {
info.Name = System.IO.Path.GetFileName(ContainingFolderPath); info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
} }

@ -89,5 +89,7 @@ namespace MediaBrowser.Controller
string GetLocalApiUrl(IPAddress ipAddress); string GetLocalApiUrl(IPAddress ipAddress);
void LaunchUrl(string url); 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>> GetArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query); QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(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) public int Compare(string x, string y)
{ {
@ -63,7 +63,7 @@ namespace MediaBrowser.Controller.Library
return 0; 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) 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&lt;MBRegistrationRecord&gt;.</returns>
Task<MBRegistrationRecord> GetRegistrationInfo(string feature);
}
}

@ -108,6 +108,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>QueryResult{RecordingInfoDto}.</returns> /// <returns>QueryResult{RecordingInfoDto}.</returns>
Task<QueryResult<BaseItemDto>> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken); Task<QueryResult<BaseItemDto>> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken);
Task<QueryResult<BaseItemDto>> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the timers. /// Gets the timers.
@ -364,11 +365,9 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary> /// <summary>
/// Gets the registration information. /// Gets the registration information.
/// </summary> /// </summary>
/// <param name="channelId">The channel identifier.</param>
/// <param name="programId">The program identifier.</param>
/// <param name="feature">The feature.</param> /// <param name="feature">The feature.</param>
/// <returns>Task&lt;MBRegistrationRecord&gt;.</returns> /// <returns>Task&lt;MBRegistrationRecord&gt;.</returns>
Task<MBRegistrationRecord> GetRegistrationInfo(string channelId, string programId, string feature); Task<MBRegistrationRecord> GetRegistrationInfo(string feature);
/// <summary> /// <summary>
/// Adds the channel information. /// Adds the channel information.

@ -1,6 +1,7 @@
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.LiveTv 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> /// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
public bool? IsHD { get; set; } public bool? IsHD { get; set; }
public bool? Is3D { get; set; }
/// <summary> /// <summary>
/// Gets or sets the audio. /// Gets or sets the audio.
/// </summary> /// </summary>
@ -84,6 +87,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value> /// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
public bool IsRepeat { get; set; } public bool IsRepeat { get; set; }
public bool IsSubjectToBlackout { get; set; }
/// <summary> /// <summary>
/// Gets or sets the episode title. /// Gets or sets the episode title.
/// </summary> /// </summary>
@ -144,6 +149,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value> /// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
public bool IsKids { get; set; } public bool IsKids { get; set; }
public bool IsEducational { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether this instance is premiere. /// Gets or sets a value indicating whether this instance is premiere.
/// </summary> /// </summary>

@ -98,6 +98,7 @@
<Compile Include="Collections\CollectionCreationOptions.cs" /> <Compile Include="Collections\CollectionCreationOptions.cs" />
<Compile Include="Collections\CollectionEvents.cs" /> <Compile Include="Collections\CollectionEvents.cs" />
<Compile Include="Collections\ICollectionManager.cs" /> <Compile Include="Collections\ICollectionManager.cs" />
<Compile Include="Collections\ManualCollectionsFolder.cs" />
<Compile Include="Connect\ConnectSupporterSummary.cs" /> <Compile Include="Connect\ConnectSupporterSummary.cs" />
<Compile Include="Connect\IConnectManager.cs" /> <Compile Include="Connect\IConnectManager.cs" />
<Compile Include="Connect\UserLinkResult.cs" /> <Compile Include="Connect\UserLinkResult.cs" />
@ -198,7 +199,6 @@
<Compile Include="Library\NameExtensions.cs" /> <Compile Include="Library\NameExtensions.cs" />
<Compile Include="Library\PlaybackStopEventArgs.cs" /> <Compile Include="Library\PlaybackStopEventArgs.cs" />
<Compile Include="Library\UserDataSaveEventArgs.cs" /> <Compile Include="Library\UserDataSaveEventArgs.cs" />
<Compile Include="LiveTv\IHasRegistrationInfo.cs" />
<Compile Include="LiveTv\IListingsProvider.cs" /> <Compile Include="LiveTv\IListingsProvider.cs" />
<Compile Include="LiveTv\ITunerHost.cs" /> <Compile Include="LiveTv\ITunerHost.cs" />
<Compile Include="LiveTv\RecordingGroup.cs" /> <Compile Include="LiveTv\RecordingGroup.cs" />

@ -23,14 +23,18 @@ namespace MediaBrowser.Controller.Providers
/// The logger /// The logger
/// </summary> /// </summary>
protected ILogger Logger { get; private set; } protected ILogger Logger { get; private set; }
protected IProviderManager ProviderManager { get; private set; }
private Dictionary<string, string> _validProviderIds;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class. /// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
/// </summary> /// </summary>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
public BaseItemXmlParser(ILogger logger) public BaseItemXmlParser(ILogger logger, IProviderManager providerManager)
{ {
Logger = logger; Logger = logger;
ProviderManager = providerManager;
} }
/// <summary> /// <summary>
@ -60,6 +64,22 @@ namespace MediaBrowser.Controller.Providers
ValidationType = ValidationType.None 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.GetEncoding("ISO-8859-1"), cancellationToken);
Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken); Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken);
} }
@ -657,14 +677,6 @@ namespace MediaBrowser.Controller.Providers
break; break;
} }
case "TvDbId":
var tvdbId = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(tvdbId))
{
item.SetProviderId(MetadataProviders.Tvdb, tvdbId);
}
break;
case "VoteCount": case "VoteCount":
{ {
var val = reader.ReadElementContentAsString(); var val = reader.ReadElementContentAsString();
@ -679,95 +691,7 @@ namespace MediaBrowser.Controller.Providers
} }
break; break;
} }
case "MusicBrainzAlbumId": case "CollectionNumber":
{
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":
var tmdbCollection = reader.ReadElementContentAsString(); var tmdbCollection = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(tmdbCollection)) if (!string.IsNullOrWhiteSpace(tmdbCollection))
{ {
@ -775,30 +699,6 @@ namespace MediaBrowser.Controller.Providers
} }
break; 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": case "Genres":
{ {
using (var subtree = reader.ReadSubtree()) using (var subtree = reader.ReadSubtree())
@ -890,8 +790,25 @@ namespace MediaBrowser.Controller.Providers
} }
default: 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) if (OnDeviceUnavailable != null)
{ {
_logger.Debug("Disposing device due to loss of connection");
OnDeviceUnavailable(); OnDeviceUnavailable();
return;
} }
} }
if (_successiveStopCount >= maxSuccessiveStopReturns) if (_successiveStopCount >= maxSuccessiveStopReturns)

@ -66,7 +66,7 @@ namespace MediaBrowser.Dlna.Profiles
{ {
Container = "mkv", Container = "mkv",
VideoCodec = "h264,mpeg2video", VideoCodec = "h264,mpeg2video",
AudioCodec = "aac,ac3,dca,mp3,mp2,pcm", AudioCodec = "aac,ac3,dca,mp3,mp2,pcm,dts",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },

@ -65,14 +65,14 @@ namespace MediaBrowser.Dlna.Profiles
{ {
Container = "avi", Container = "avi",
VideoCodec = "h264,mpeg4,mjpeg", VideoCodec = "h264,mpeg4,mjpeg",
AudioCodec = "mp3,ac3,dca", AudioCodec = "mp3,ac3,dca,dts",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mkv", Container = "mkv",
VideoCodec = "h264,mpeg4,mjpeg4", VideoCodec = "h264,mpeg4,mjpeg4",
AudioCodec = "mp3,ac3,dca,aac", AudioCodec = "mp3,ac3,dca,aac,dts",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
@ -300,7 +300,7 @@ namespace MediaBrowser.Dlna.Profiles
new CodecProfile new CodecProfile
{ {
Type = CodecType.VideoAudio, Type = CodecType.VideoAudio,
Codec = "ac3,wmav2,dca,aac,mp3", Codec = "ac3,wmav2,dca,aac,mp3,dts",
Conditions = new[] Conditions = new[]
{ {

@ -115,7 +115,7 @@ namespace MediaBrowser.Dlna.Profiles
{ {
Container = "mkv", Container = "mkv",
VideoCodec = "mpeg4,h264", VideoCodec = "mpeg4,h264",
AudioCodec = "ac3,dca,aac,mp3,pcm", AudioCodec = "ac3,dca,aac,mp3,pcm,dts",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile

@ -115,7 +115,7 @@ namespace MediaBrowser.Dlna.Profiles
{ {
Container = "mkv", Container = "mkv",
VideoCodec = "mpeg4,h264", VideoCodec = "mpeg4,h264",
AudioCodec = "ac3,dca,aac,mp3,pcm", AudioCodec = "ac3,dca,aac,mp3,pcm,dts",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile

@ -103,7 +103,7 @@ namespace MediaBrowser.Dlna.Profiles
{ {
Container = "mkv", Container = "mkv",
VideoCodec = "mpeg4,h264", VideoCodec = "mpeg4,h264",
AudioCodec = "ac3,dca,aac,mp3,pcm", AudioCodec = "ac3,dca,aac,mp3,pcm,dts",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile

@ -103,7 +103,7 @@ namespace MediaBrowser.Dlna.Profiles
{ {
Container = "mkv", Container = "mkv",
VideoCodec = "mpeg4,h264", VideoCodec = "mpeg4,h264",
AudioCodec = "ac3,dca,aac,mp3,pcm", AudioCodec = "ac3,dca,aac,mp3,pcm,dts",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile

@ -58,7 +58,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "avi", Container = "avi",
Type = DlnaProfileType.Video, Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
AudioCodec = "ac3,dca,mp2,mp3,pcm,dca" AudioCodec = "ac3,dca,mp2,mp3,pcm,dts"
}, },
new DirectPlayProfile new DirectPlayProfile
@ -66,7 +66,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "mpeg", Container = "mpeg",
Type = DlnaProfileType.Video, Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video", VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "ac3,dca,mp2,mp3,pcm,dca" AudioCodec = "ac3,dca,mp2,mp3,pcm,dts"
}, },
new DirectPlayProfile new DirectPlayProfile
@ -74,7 +74,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "mkv", Container = "mkv",
Type = DlnaProfileType.Video, Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
AudioCodec = "ac3,dca,aac,mp2,mp3,pcm,dca" AudioCodec = "ac3,dca,aac,mp2,mp3,pcm,dts"
}, },
new DirectPlayProfile new DirectPlayProfile
@ -82,7 +82,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "ts,m2ts", Container = "ts,m2ts",
Type = DlnaProfileType.Video, Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,h264,vc1", VideoCodec = "mpeg1video,mpeg2video,h264,vc1",
AudioCodec = "ac3,dca,mp2,mp3,aac,dca" AudioCodec = "ac3,dca,mp2,mp3,aac,dts"
}, },
new DirectPlayProfile new DirectPlayProfile
@ -90,7 +90,7 @@ namespace MediaBrowser.Dlna.Profiles
Container = "mp4,mov", Container = "mp4,mov",
Type = DlnaProfileType.Video, Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4", VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,aac,mp2,mp3,dca" AudioCodec = "ac3,aac,mp2,mp3,dca,dts"
}, },
new DirectPlayProfile new DirectPlayProfile

@ -39,7 +39,7 @@
</XmlRootAttributes> </XmlRootAttributes>
<DirectPlayProfiles> <DirectPlayProfiles>
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,pcm_dvd" videoCodec="mpeg2video,mpeg4" type="Video" /> <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="ts" audioCodec="aac,mp3,mp2" videoCodec="h264,mpeg2video" type="Video" />
<DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" /> <DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" />
<DirectPlayProfile container="mov" audioCodec="aac,pcm" videoCodec="h264" type="Video" /> <DirectPlayProfile container="mov" audioCodec="aac,pcm" videoCodec="h264" type="Video" />

@ -38,8 +38,8 @@
</XmlRootAttributes> </XmlRootAttributes>
<DirectPlayProfiles> <DirectPlayProfiles>
<DirectPlayProfile container="asf" audioCodec="mp3,ac3,wmav2,wmapro,wmavoice" videoCodec="h264,mpeg4,mjpeg" type="Video" /> <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="avi" audioCodec="mp3,ac3,dca,dts" videoCodec="h264,mpeg4,mjpeg" type="Video" />
<DirectPlayProfile container="mkv" audioCodec="mp3,ac3,dca,aac" videoCodec="h264,mpeg4,mjpeg4" 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="mp4" audioCodec="mp3,aac" videoCodec="h264,mpeg4" type="Video" />
<DirectPlayProfile container="3gp" audioCodec="aac,he-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" /> <DirectPlayProfile container="mpg,mpeg" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
@ -100,7 +100,7 @@
</Conditions> </Conditions>
<ApplyConditions /> <ApplyConditions />
</CodecProfile> </CodecProfile>
<CodecProfile type="VideoAudio" codec="ac3,wmav2,dca,aac,mp3"> <CodecProfile type="VideoAudio" codec="ac3,wmav2,dca,aac,mp3,dts">
<Conditions> <Conditions>
<ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" /> <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
</Conditions> </Conditions>

@ -45,7 +45,7 @@
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" /> <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="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="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="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
<DirectPlayProfile container="wmv,asf" type="Video" /> <DirectPlayProfile container="wmv,asf" type="Video" />
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" /> <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="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="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="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="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
<DirectPlayProfile container="wmv,asf" type="Video" /> <DirectPlayProfile container="wmv,asf" type="Video" />
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" /> <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="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="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="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="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
<DirectPlayProfile container="wmv,asf" type="Video" /> <DirectPlayProfile container="wmv,asf" type="Video" />
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" /> <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="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="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="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="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
<DirectPlayProfile container="wmv,asf" type="Video" /> <DirectPlayProfile container="wmv,asf" type="Video" />
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" /> <DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" />

@ -36,11 +36,11 @@
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests> <IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes /> <XmlRootAttributes />
<DirectPlayProfiles> <DirectPlayProfiles>
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" 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,dca" videoCodec="mpeg1video,mpeg2video" 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,dca" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" 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,dca" videoCodec="mpeg1video,mpeg2video,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" videoCodec="h264,mpeg4" 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="wmav2,wmapro" videoCodec="vc1" type="Video" />
<DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" /> <DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" /> <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />

@ -63,7 +63,6 @@
<Compile Include="Parsers\MovieXmlParser.cs" /> <Compile Include="Parsers\MovieXmlParser.cs" />
<Compile Include="Parsers\MusicVideoXmlParser.cs" /> <Compile Include="Parsers\MusicVideoXmlParser.cs" />
<Compile Include="Parsers\PlaylistXmlParser.cs" /> <Compile Include="Parsers\PlaylistXmlParser.cs" />
<Compile Include="Parsers\SeasonXmlParser.cs" />
<Compile Include="Parsers\SeriesXmlParser.cs" /> <Compile Include="Parsers\SeriesXmlParser.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Providers\BoxSetXmlProvider.cs" /> <Compile Include="Providers\BoxSetXmlProvider.cs" />
@ -75,7 +74,6 @@
<Compile Include="Providers\MusicVideoXmlProvider.cs" /> <Compile Include="Providers\MusicVideoXmlProvider.cs" />
<Compile Include="Providers\PersonXmlProvider.cs" /> <Compile Include="Providers\PersonXmlProvider.cs" />
<Compile Include="Providers\PlaylistXmlProvider.cs" /> <Compile Include="Providers\PlaylistXmlProvider.cs" />
<Compile Include="Providers\SeasonXmlProvider.cs" />
<Compile Include="Providers\SeriesXmlProvider.cs" /> <Compile Include="Providers\SeriesXmlProvider.cs" />
<Compile Include="Providers\VideoXmlProvider.cs" /> <Compile Include="Providers\VideoXmlProvider.cs" />
<Compile Include="Savers\BoxSetXmlSaver.cs" /> <Compile Include="Savers\BoxSetXmlSaver.cs" />

@ -9,8 +9,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
{ {
public class BoxSetXmlParser : BaseItemXmlParser<BoxSet> public class BoxSetXmlParser : BaseItemXmlParser<BoxSet>
{ {
public BoxSetXmlParser(ILogger logger) public BoxSetXmlParser(ILogger logger, IProviderManager providerManager)
: base(logger) : base(logger, providerManager)
{ {
} }

@ -20,8 +20,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
private List<LocalImageInfo> _imagesFound; private List<LocalImageInfo> _imagesFound;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
public EpisodeXmlParser(ILogger logger, IFileSystem fileSystem) public EpisodeXmlParser(ILogger logger, IFileSystem fileSystem, IProviderManager providerManager)
: base(logger) : base(logger, providerManager)
{ {
_fileSystem = fileSystem; _fileSystem = fileSystem;
} }

@ -10,8 +10,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
{ {
public class GameSystemXmlParser : BaseItemXmlParser<GameSystem> public class GameSystemXmlParser : BaseItemXmlParser<GameSystem>
{ {
public GameSystemXmlParser(ILogger logger) public GameSystemXmlParser(ILogger logger, IProviderManager providerManager)
: base(logger) : base(logger, providerManager)
{ {
} }

@ -16,8 +16,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
{ {
private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly CultureInfo _usCulture = new CultureInfo("en-US");
public GameXmlParser(ILogger logger) public GameXmlParser(ILogger logger, IProviderManager providerManager)
: base(logger) : base(logger, providerManager)
{ {
} }

@ -12,8 +12,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
public class BaseVideoXmlParser<T> : BaseItemXmlParser<T> public class BaseVideoXmlParser<T> : BaseItemXmlParser<T>
where T : Video where T : Video
{ {
public BaseVideoXmlParser(ILogger logger) public BaseVideoXmlParser(ILogger logger, IProviderManager providerManager)
: base(logger) : base(logger, providerManager)
{ {
} }
@ -50,15 +50,15 @@ namespace MediaBrowser.LocalMetadata.Parsers
public class MovieXmlParser : BaseVideoXmlParser<Movie> 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 class VideoXmlParser : BaseVideoXmlParser<Video>
{ {
public VideoXmlParser(ILogger logger) public VideoXmlParser(ILogger logger, IProviderManager providerManager)
: base(logger) : base(logger, providerManager)
{ {
} }
} }

@ -12,8 +12,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
/// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class. /// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
/// </summary> /// </summary>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
public MusicVideoXmlParser(ILogger logger) public MusicVideoXmlParser(ILogger logger, IProviderManager providerManager)
: base(logger) : base(logger, providerManager)
{ {
} }

@ -11,8 +11,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
{ {
public class PlaylistXmlParser : BaseItemXmlParser<Playlist> public class PlaylistXmlParser : BaseItemXmlParser<Playlist>
{ {
public PlaylistXmlParser(ILogger logger) public PlaylistXmlParser(ILogger logger, IProviderManager providerManager)
: base(logger) : 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. /// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
/// </summary> /// </summary>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
public SeriesXmlParser(ILogger logger) public SeriesXmlParser(ILogger logger, IProviderManager providerManager)
: base(logger) : base(logger, providerManager)
{ {
} }

@ -14,16 +14,18 @@ namespace MediaBrowser.LocalMetadata.Providers
public class BoxSetXmlProvider : BaseXmlProvider<BoxSet> public class BoxSetXmlProvider : BaseXmlProvider<BoxSet>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger) public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<BoxSet> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -13,11 +13,13 @@ namespace MediaBrowser.LocalMetadata.Providers
public class EpisodeXmlProvider : BaseXmlProvider<Episode> public class EpisodeXmlProvider : BaseXmlProvider<Episode>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public EpisodeXmlProvider(IFileSystem fileSystem, ILogger logger) public EpisodeXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<Episode> result, string path, CancellationToken cancellationToken) 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 images = new List<LocalImageInfo>();
var chapters = new List<ChapterInfo>(); 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; result.Images = images;
} }

@ -13,16 +13,18 @@ namespace MediaBrowser.LocalMetadata.Providers
public class FolderXmlProvider : BaseXmlProvider<Folder> public class FolderXmlProvider : BaseXmlProvider<Folder>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public FolderXmlProvider(IFileSystem fileSystem, ILogger logger) public FolderXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<Folder> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -11,16 +11,18 @@ namespace MediaBrowser.LocalMetadata.Providers
public class GameSystemXmlProvider : BaseXmlProvider<GameSystem> public class GameSystemXmlProvider : BaseXmlProvider<GameSystem>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public GameSystemXmlProvider(IFileSystem fileSystem, ILogger logger) public GameSystemXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<GameSystem> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -11,16 +11,18 @@ namespace MediaBrowser.LocalMetadata.Providers
public class GameXmlProvider : BaseXmlProvider<Game> public class GameXmlProvider : BaseXmlProvider<Game>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public GameXmlProvider(IFileSystem fileSystem, ILogger logger) public GameXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<Game> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -11,16 +11,18 @@ namespace MediaBrowser.LocalMetadata.Providers
public class MovieXmlProvider : BaseXmlProvider<Movie> public class MovieXmlProvider : BaseXmlProvider<Movie>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public MovieXmlProvider(IFileSystem fileSystem, ILogger logger) public MovieXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<Movie> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -10,16 +10,18 @@ namespace MediaBrowser.LocalMetadata.Providers
class MusicVideoXmlProvider : BaseXmlProvider<MusicVideo> class MusicVideoXmlProvider : BaseXmlProvider<MusicVideo>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public MusicVideoXmlProvider(IFileSystem fileSystem, ILogger logger) public MusicVideoXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<MusicVideo> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -10,16 +10,18 @@ namespace MediaBrowser.LocalMetadata.Providers
public class PersonXmlProvider : BaseXmlProvider<Person> public class PersonXmlProvider : BaseXmlProvider<Person>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public PersonXmlProvider(IFileSystem fileSystem, ILogger logger) public PersonXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<Person> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -11,16 +11,18 @@ namespace MediaBrowser.LocalMetadata.Providers
class PlaylistXmlProvider : BaseXmlProvider<Playlist> class PlaylistXmlProvider : BaseXmlProvider<Playlist>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public PlaylistXmlProvider(IFileSystem fileSystem, ILogger logger) public PlaylistXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<Playlist> result, string path, CancellationToken cancellationToken) 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) 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 public class SeriesXmlProvider : BaseXmlProvider<Series>, IHasOrder
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public SeriesXmlProvider(IFileSystem fileSystem, ILogger logger) public SeriesXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<Series> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -10,16 +10,18 @@ namespace MediaBrowser.LocalMetadata.Providers
class VideoXmlProvider : BaseXmlProvider<Video> class VideoXmlProvider : BaseXmlProvider<Video>
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
public VideoXmlProvider(IFileSystem fileSystem, ILogger logger) public VideoXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager)
: base(fileSystem) : base(fileSystem)
{ {
_logger = logger; _logger = logger;
_providerManager = providerManager;
} }
protected override void Fetch(MetadataResult<Video> result, string path, CancellationToken cancellationToken) 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) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)

@ -133,7 +133,7 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <param name="xmlTagsUsed">The XML tags used.</param> /// <param name="xmlTagsUsed">The XML tags used.</param>
public static void Save(StringBuilder xml, string path, List<string> xmlTagsUsed, IServerConfigurationManager config, IFileSystem fileSystem) 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); var position = xml.ToString().LastIndexOf("</", StringComparison.OrdinalIgnoreCase);
xml.Insert(position, GetCustomTags(path, xmlTagsUsed)); xml.Insert(position, GetCustomTags(path, xmlTagsUsed));
@ -145,7 +145,7 @@ namespace MediaBrowser.LocalMetadata.Savers
//Add the new node to the document. //Add the new node to the document.
xmlDocument.InsertBefore(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "yes"), xmlDocument.DocumentElement); xmlDocument.InsertBefore(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "yes"), xmlDocument.DocumentElement);
fileSystem.CreateDirectory(Path.GetDirectoryName(path)); fileSystem.CreateDirectory(Path.GetDirectoryName(path));
var wasHidden = false; var wasHidden = false;
@ -445,121 +445,18 @@ namespace MediaBrowser.LocalMetadata.Savers
builder.Append("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>"); builder.Append("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>");
} }
var imdb = item.GetProviderId(MetadataProviders.Imdb); if (item.ProviderIds != null)
if (!string.IsNullOrEmpty(imdb))
{
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); foreach (var providerKey in item.ProviderIds.Keys)
if (!string.IsNullOrEmpty(tvdb))
{ {
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; var hasTagline = item as IHasTaglines;
if (hasTagline != null) 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(); return arg.Trim();
} }
@ -585,23 +595,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// Gets the video bitrate to specify on the command line /// Gets the video bitrate to specify on the command line
/// </summary> /// </summary>
/// <param name="state">The state.</param> /// <param name="state">The state.</param>
/// <param name="videoCodec">The video codec.</param> /// <param name="videoEncoder">The video codec.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
protected string GetVideoQualityParam(EncodingJob state, string videoCodec) protected string GetVideoQualityParam(EncodingJob state, string videoEncoder)
{ {
var param = string.Empty; var param = string.Empty;
var isVc1 = state.VideoStream != null && var isVc1 = state.VideoStream != null &&
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase); 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 = "-preset superfast";
param += " -crf 23"; 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";
@ -609,20 +619,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
// h264 (h264_qsv) // 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) // h264 (h264_nvenc)
else if (string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{ {
param = "-preset llhq"; param = "-preset llhq";
} }
// webm // 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 // Values 0-3, 0 being highest quality but slower
var profileScore = 0; var profileScore = 0;
@ -649,23 +659,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
qmax); 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 // 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); var framerate = GetFramerateParam(state);
if (framerate.HasValue) if (framerate.HasValue)
@ -680,8 +690,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrEmpty(state.Options.Profile)) if (!string.IsNullOrEmpty(state.Options.Profile))
{ {
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) && if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{ {
// not supported by h264_omx // not supported by h264_omx
param += " -profile:v " + state.Options.Profile; param += " -profile:v " + state.Options.Profile;
@ -692,9 +702,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrEmpty(levelString)) 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 // 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) || if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{ {
switch (levelString) switch (levelString)
{ {
@ -730,16 +742,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
break; break;
} }
} }
else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase)) else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
{ {
param += " -level " + levelString; param += " -level " + levelString;
} }
} }
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) && if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{ {
param = "-pix_fmt yuv420p " + param; param = "-pix_fmt yuv420p " + param;
} }
@ -747,6 +759,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
return param; 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) protected string GetVideoBitrateParam(EncodingJob state, string videoCodec)
{ {
var bitrate = state.OutputVideoBitrate; var bitrate = state.OutputVideoBitrate;

@ -928,7 +928,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
StartProcess(processWrapper); 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) if (!ranToCompletion)
{ {

@ -818,14 +818,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles
public string GetSubtitleFileCharacterSetFromLanguage(string language) public string GetSubtitleFileCharacterSetFromLanguage(string language)
{ {
// https://developer.xamarin.com/api/type/System.Text.Encoding/
switch (language.ToLower()) switch (language.ToLower())
{ {
case "hun":
return "windows-1252";
case "pol": case "pol":
case "cze": case "cze":
case "ces": case "ces":
case "slo": case "slo":
case "slk": case "slk":
case "hun":
case "slv": case "slv":
case "srp": case "srp":
case "hrv": case "hrv":

@ -11,6 +11,8 @@ namespace MediaBrowser.Model.Configuration
public string HardwareAccelerationType { get; set; } public string HardwareAccelerationType { get; set; }
public string EncoderAppPath { get; set; } public string EncoderAppPath { get; set; }
public string VaapiDevice { get; set; } public string VaapiDevice { get; set; }
public int H264Crf { get; set; }
public string H264Preset { get; set; }
public EncodingOptions() public EncodingOptions()
{ {
@ -19,6 +21,7 @@ namespace MediaBrowser.Model.Configuration
ThrottleDelaySeconds = 180; ThrottleDelaySeconds = 180;
EncodingThreadCount = -1; EncodingThreadCount = -1;
VaapiDevice = "/dev/dri/card0"; VaapiDevice = "/dev/dri/card0";
H264Crf = 23;
} }
} }
} }

@ -6,6 +6,8 @@
public bool EnablePhotos { get; set; } public bool EnablePhotos { get; set; }
public bool EnableRealtimeMonitor { get; set; } public bool EnableRealtimeMonitor { get; set; }
public int SchemaVersion { get; set; } public int SchemaVersion { get; set; }
public bool EnableChapterImageExtraction { get; set; }
public bool ExtractChapterImagesDuringLibraryScan { get; set; }
public LibraryOptions() public LibraryOptions()
{ {

@ -204,7 +204,10 @@ namespace MediaBrowser.Model.Configuration
public bool DisplayCollectionsView { get; set; } public bool DisplayCollectionsView { get; set; }
public string[] LocalNetworkAddresses { get; set; } public string[] LocalNetworkAddresses { get; set; }
public string[] CodecsUsed { get; set; } public string[] CodecsUsed { get; set; }
public bool EnableChannelView { get; set; }
public bool EnableExternalContentInSuggestions { get; set; }
public int ImageExtractionTimeoutMs { get; set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class. /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary> /// </summary>
@ -214,9 +217,11 @@ namespace MediaBrowser.Model.Configuration
Migrations = new string[] { }; Migrations = new string[] { };
CodecsUsed = new string[] { }; CodecsUsed = new string[] { };
SqliteCacheSize = 0; SqliteCacheSize = 0;
ImageExtractionTimeoutMs = 0;
EnableLocalizedGuids = true; EnableLocalizedGuids = true;
DisplaySpecialsWithinSeasons = true; DisplaySpecialsWithinSeasons = true;
EnableExternalContentInSuggestions = true;
ImageSavingConvention = ImageSavingConvention.Compatible; ImageSavingConvention = ImageSavingConvention.Compatible;
PublicPort = 8096; PublicPort = 8096;
@ -229,6 +234,7 @@ namespace MediaBrowser.Model.Configuration
EnableAnonymousUsageReporting = true; EnableAnonymousUsageReporting = true;
EnableAutomaticRestart = true; EnableAutomaticRestart = true;
EnableFolderView = true;
EnableUPnP = true; EnableUPnP = true;
SharingExpirationDays = 30; SharingExpirationDays = 30;

@ -41,7 +41,6 @@ namespace MediaBrowser.Model.Configuration
public string[] PlainFolderViews { get; set; } public string[] PlainFolderViews { get; set; }
public bool HidePlayedInLatest { get; set; } public bool HidePlayedInLatest { get; set; }
public bool EnableChannelView { get; set; }
public bool RememberAudioSelections { get; set; } public bool RememberAudioSelections { get; set; }
public bool RememberSubtitleSelections { get; set; } public bool RememberSubtitleSelections { get; set; }

@ -13,6 +13,7 @@ namespace MediaBrowser.Model.LiveTv
public string SeriesRecordingPath { get; set; } public string SeriesRecordingPath { get; set; }
public bool EnableAutoOrganize { get; set; } public bool EnableAutoOrganize { get; set; }
public bool EnableRecordingEncoding { get; set; } public bool EnableRecordingEncoding { get; set; }
public string RecordingEncodingFormat { get; set; }
public bool EnableRecordingSubfolders { get; set; } public bool EnableRecordingSubfolders { get; set; }
public bool EnableOriginalAudioWithEncodedRecordings { get; set; } public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
@ -31,6 +32,7 @@ namespace MediaBrowser.Model.LiveTv
TunerHosts = new List<TunerHostInfo>(); TunerHosts = new List<TunerHostInfo>();
ListingProviders = new List<ListingsProviderInfo>(); ListingProviders = new List<ListingsProviderInfo>();
MediaLocationsCreated = new string[] { }; MediaLocationsCreated = new string[] { };
RecordingEncodingFormat = "mp4";
} }
} }

@ -6,6 +6,7 @@
Stereo, Stereo,
Dolby, Dolby,
DolbyDigital, DolbyDigital,
Thx Thx,
Atmos
} }
} }

@ -68,6 +68,10 @@ namespace MediaBrowser.Model.LiveTv
/// <value>The fields.</value> /// <value>The fields.</value>
public ItemFields[] Fields { get; set; } public ItemFields[] Fields { get; set; }
public bool? EnableImages { 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 int? ImageTypeLimit { get; set; }
public ImageType[] EnableImageTypes { get; set; } public ImageType[] EnableImageTypes { get; set; }

@ -8,6 +8,8 @@ namespace MediaBrowser.Model.System
/// </summary> /// </summary>
public class SystemInfo : PublicSystemInfo public class SystemInfo : PublicSystemInfo
{ {
public PackageVersionClass SystemUpdateLevel { get; set; }
/// <summary> /// <summary>
/// Gets or sets the display name of the operating system. /// Gets or sets the display name of the operating system.
/// </summary> /// </summary>

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using CommonIO; using CommonIO;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; 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); 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 await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
{ {
Chapters = chapters, Chapters = chapters,
Video = video, Video = video,
ExtractImages = chapterOptions.ExtractDuringLibraryScan, ExtractImages = extractDuringScan,
SaveChapters = false SaveChapters = false
}, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false);

@ -6,6 +6,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Manager;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using CommonIO; using CommonIO;
namespace MediaBrowser.Providers.Music namespace MediaBrowser.Providers.Music
@ -21,7 +22,7 @@ namespace MediaBrowser.Providers.Music
if (replaceData || targetItem.Artists.Count == 0) if (replaceData || targetItem.Artists.Count == 0)
{ {
targetItem.Artists = sourceItem.Artists; targetItem.Artists = sourceItem.Artists.ToList();
} }
if (replaceData || string.IsNullOrEmpty(targetItem.Album)) if (replaceData || string.IsNullOrEmpty(targetItem.Album))

@ -138,8 +138,6 @@ namespace MediaBrowser.Providers.TV
.Where(i => i.LocationType == LocationType.Virtual) .Where(i => i.LocationType == LocationType.Virtual)
.ToList(); .ToList();
var episodes = series.GetRecursiveChildren().OfType<Episode>().ToList();
var seasonsToRemove = virtualSeasons var seasonsToRemove = virtualSeasons
.Where(i => .Where(i =>
{ {
@ -152,19 +150,15 @@ namespace MediaBrowser.Providers.TV
{ {
return true; return true;
} }
}
// If there are no episodes with this season number, delete it // If there are no episodes with this season number, delete it
if (episodes.All(e => !e.ParentIndexNumber.HasValue || e.ParentIndexNumber.Value != seasonNumber)) if (!i.GetEpisodes().Any())
{ {
return true; return true;
}
return false;
} }
// Season does not have a number return false;
// Remove if there are no episodes directly in series without a season number
return episodes.All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder);
}) })
.ToList(); .ToList();

@ -530,6 +530,19 @@ namespace MediaBrowser.Server.Implementations.Channels
return GetChannelFeaturesDto(channel, channelProvider, channelProvider.GetChannelFeatures()); 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, public ChannelFeatures GetChannelFeaturesDto(Channel channel,
IChannel provider, IChannel provider,
InternalChannelFeatures features) InternalChannelFeatures features)
@ -1450,6 +1463,24 @@ namespace MediaBrowser.Server.Implementations.Channels
return result; 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) private IEnumerable<BaseItem> ApplyFilters(IEnumerable<BaseItem> items, IEnumerable<ItemFilter> filters, User user)
{ {
foreach (var filter in filters.OrderByDescending(f => (int)f)) foreach (var filter in filters.OrderByDescending(f => (int)f))

@ -2,6 +2,7 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using System.IO; using System.IO;
using CommonIO; using CommonIO;
using MediaBrowser.Controller.Collections;
namespace MediaBrowser.Server.Implementations.Collections namespace MediaBrowser.Server.Implementations.Collections
{ {

@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{ {
LoadCachedAddress(); 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(); ((ConnectManager)_connectManager).Start();
} }

@ -1168,6 +1168,26 @@ namespace MediaBrowser.Server.Implementations.Dto
}; };
}) })
.ToList(); .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; var hasAlbumArtist = item as IHasAlbumArtist;

@ -92,11 +92,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
DeviceId = session.DeviceId DeviceId = session.DeviceId
}; };
// Report usage to remote server, except for web client, since we already have data on that ReportNewSession(info);
if (!string.Equals(info.AppName, "Dashboard", StringComparison.OrdinalIgnoreCase))
{
ReportNewSession(info);
}
return info; return info;
} }

@ -71,14 +71,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer
HostConfig.Instance.MapExceptionToStatusCode = new Dictionary<Type, int> HostConfig.Instance.MapExceptionToStatusCode = new Dictionary<Type, int>
{ {
{typeof (InvalidOperationException), 422}, {typeof (InvalidOperationException), 500},
{typeof (NotImplementedException), 500},
{typeof (ResourceNotFoundException), 404}, {typeof (ResourceNotFoundException), 404},
{typeof (FileNotFoundException), 404}, {typeof (FileNotFoundException), 404},
{typeof (DirectoryNotFoundException), 404}, {typeof (DirectoryNotFoundException), 404},
{typeof (SecurityException), 401}, {typeof (SecurityException), 401},
{typeof (PaymentRequiredException), 402}, {typeof (PaymentRequiredException), 402},
{typeof (UnauthorizedAccessException), 500}, {typeof (UnauthorizedAccessException), 500},
{typeof (ApplicationException), 500} {typeof (ApplicationException), 500},
{typeof (PlatformNotSupportedException), 500},
{typeof (NotSupportedException), 500}
}; };
HostConfig.Instance.GlobalResponseHeaders = new Dictionary<string, string>(); HostConfig.Instance.GlobalResponseHeaders = new Dictionary<string, string>();
@ -99,14 +102,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer
// new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()), // new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()),
//})); //}));
PreRequestFilters.Add((httpReq, httpRes) => //PreRequestFilters.Add((httpReq, httpRes) =>
{ //{
//Handles Request and closes Responses after emitting global HTTP Headers // //Handles Request and closes Responses after emitting global HTTP Headers
if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) // if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
{ // {
httpRes.EndRequest(); //add a 'using ServiceStack;' // httpRes.EndRequest(); //add a 'using ServiceStack;'
} // }
}); //});
HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse); HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
} }
@ -400,6 +403,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return; 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 operationName = httpReq.OperationName;
var localPath = url.LocalPath; var localPath = url.LocalPath;

@ -46,6 +46,14 @@ namespace MediaBrowser.Server.Implementations.IO
"TempSBE" "TempSBE"
}; };
private readonly IReadOnlyList<string> _alwaysIgnoreSubstrings = new List<string>
{
// Synology
"@eaDir",
".wd_tv",
".actors"
};
private readonly IReadOnlyList<string> _alwaysIgnoreExtensions = new List<string> private readonly IReadOnlyList<string> _alwaysIgnoreExtensions = new List<string>
{ {
// thumbs.db // thumbs.db
@ -421,10 +429,11 @@ namespace MediaBrowser.Server.Implementations.IO
} }
var filename = Path.GetFileName(path); var filename = Path.GetFileName(path);
var monitorPath = !string.IsNullOrEmpty(filename) && var monitorPath = !string.IsNullOrEmpty(filename) &&
!_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) && !_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 // Ignore certain files
var tempIgnorePaths = _tempIgnoredPaths.Keys.ToList(); var tempIgnorePaths = _tempIgnoredPaths.Keys.ToList();

@ -401,7 +401,7 @@ namespace MediaBrowser.Server.Implementations.Library
var locationType = item.LocationType; var locationType = item.LocationType;
var children = item.IsFolder var children = item.IsFolder
? ((Folder)item).GetRecursiveChildren().ToList() ? ((Folder)item).GetRecursiveChildren(false).ToList()
: new List<BaseItem>(); : new List<BaseItem>();
foreach (var metadataPath in GetMetadataPaths(item, children)) foreach (var metadataPath in GetMetadataPaths(item, children))
@ -621,9 +621,38 @@ namespace MediaBrowser.Server.Implementations.Library
return ResolveItem(args, resolvers); 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) 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) public IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)

@ -54,14 +54,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
{ {
if (args.IsDirectory) if (args.IsDirectory)
{ {
if (args.HasParent<Series>())
{
return null;
}
var collectionType = args.GetCollectionType(); var collectionType = args.GetCollectionType();
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{ {
if (args.HasParent<Series>())
{
return null;
}
var configuredContentType = _libraryManager.GetConfiguredContentType(args.Path); var configuredContentType = _libraryManager.GetConfiguredContentType(args.Path);
if (!string.Equals(configuredContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) if (!string.Equals(configuredContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{ {
@ -76,11 +76,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
{ {
if (string.IsNullOrWhiteSpace(collectionType)) if (string.IsNullOrWhiteSpace(collectionType))
{ {
if (args.HasParent<Series>())
{
return null;
}
if (args.Parent.IsRoot) if (args.Parent.IsRoot)
{ {
return null; return null;

@ -120,8 +120,8 @@ namespace MediaBrowser.Server.Implementations.Library
}, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false);
var channels = channelResult.Items; 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)); list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false));
} }

@ -33,7 +33,7 @@ using Microsoft.Win32;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV 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 IApplicationHost _appHpst;
private readonly ILogger _logger; private readonly ILogger _logger;
@ -46,7 +46,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly LiveTvManager _liveTvManager; private readonly LiveTvManager _liveTvManager;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly ISecurityManager _security;
private readonly ILibraryMonitor _libraryMonitor; private readonly ILibraryMonitor _libraryMonitor;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
@ -62,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings = private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase); 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; Current = this;
@ -71,7 +70,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_httpClient = httpClient; _httpClient = httpClient;
_config = config; _config = config;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_security = security;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_libraryMonitor = libraryMonitor; _libraryMonitor = libraryMonitor;
_providerManager = providerManager; _providerManager = providerManager;
@ -851,29 +849,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var recordPath = RecordingPath; var recordPath = RecordingPath;
var config = GetConfiguration(); var config = GetConfiguration();
if (info.IsMovie) if (info.IsSeries)
{
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)
{ {
var customRecordingPath = config.SeriesRecordingPath; var customRecordingPath = config.SeriesRecordingPath;
var allowSubfolder = true; var allowSubfolder = true;
@ -910,6 +886,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recordPath = Path.Combine(recordPath, folderName); 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) else if (info.IsKids)
{ {
if (config.EnableRecordingSubfolders) if (config.EnableRecordingSubfolders)
@ -995,6 +993,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath); recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
recordPath = EnsureFileUnique(recordPath, timer.Id); recordPath = EnsureFileUnique(recordPath, timer.Id);
_libraryManager.RegisterIgnoredPath(recordPath);
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath); _libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
_fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath)); _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
activeRecordingInfo.Path = recordPath; activeRecordingInfo.Path = recordPath;
@ -1046,6 +1045,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
semaphore.Release(); semaphore.Release();
} }
_libraryManager.UnRegisterIgnoredPath(recordPath);
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, true); _libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
ActiveRecordingInfo removed; ActiveRecordingInfo removed;
@ -1114,7 +1114,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (config.EnableRecordingEncoding) if (config.EnableRecordingEncoding)
{ {
var regInfo = await _security.GetRegistrationStatus("embytvrecordingconversion").ConfigureAwait(false); var regInfo = await _liveTvManager.GetRegistrationInfo("embytvrecordingconversion").ConfigureAwait(false);
if (regInfo.IsValid) if (regInfo.IsValid)
{ {
@ -1171,8 +1171,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers) private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers)
{ {
var newTimers = GetTimersForSeries(seriesTimer, epgData, true).ToList(); 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) 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() public List<VirtualFolderInfo> GetRecordingFolders()
{ {
var list = new List<VirtualFolderInfo>(); var list = new List<VirtualFolderInfo>();

@ -46,18 +46,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_httpClient = httpClient; _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) 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) 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"); var tempfile = Path.Combine(_appPaths.TranscodingTempPath, Guid.NewGuid().ToString("N") + ".ts");
try try
{ {
await RecordInternal(mediaSource, tempfile, targetFile, duration, onStarted, cancellationToken) await RecordWithTempFile(mediaSource, tempfile, targetFile, duration, onStarted, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
finally 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() var httpRequestOptions = new HttpRequestOptions()
{ {
@ -215,15 +248,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private string GetAudioArgs(MediaSourceInfo mediaSource) 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 mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty; var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty;
if (copyAudio.Contains(inputAudioCodec, StringComparer.OrdinalIgnoreCase)) // do not copy aac because many players have difficulty with aac_latm
{
return "-codec:a:0 copy";
}
if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings && !string.Equals(inputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase)) if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings && !string.Equals(inputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase))
{ {
return "-codec:a:0 copy"; return "-codec:a:0 copy";

@ -194,14 +194,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return station; 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));
channelName = NormalizeName(channelName); if (result != null)
{
return result;
}
}
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; return null;
@ -348,7 +356,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
if (programInfo.audioProperties != null) 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; audioType = ProgramAudio.DolbyDigital;
} }
@ -405,6 +417,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
if (programInfo.videoProperties != null) if (programInfo.videoProperties != null)
{ {
info.IsHD = programInfo.videoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase); info.IsHD = programInfo.videoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase);
info.Is3D = programInfo.videoProperties.Contains("3d", StringComparer.OrdinalIgnoreCase);
} }
if (details.contentRating != null && details.contentRating.Count > 0) if (details.contentRating != null && details.contentRating.Count > 0)
@ -785,9 +798,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
get { return "Schedules Direct"; } get { return "Schedules Direct"; }
} }
public static string TypeName = "SchedulesDirect";
public string Type public string Type
{ {
get { return "SchedulesDirect"; } get { return TypeName; }
} }
private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken) private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken)

@ -31,7 +31,11 @@ using CommonIO;
using IniParser; using IniParser;
using IniParser.Model; using IniParser.Model;
using MediaBrowser.Common.Events; using MediaBrowser.Common.Events;
using MediaBrowser.Common.Security;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Events; using MediaBrowser.Model.Events;
using MediaBrowser.Server.Implementations.LiveTv.Listings;
namespace MediaBrowser.Server.Implementations.LiveTv namespace MediaBrowser.Server.Implementations.LiveTv
{ {
@ -49,6 +53,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly ITaskManager _taskManager; private readonly ITaskManager _taskManager;
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
private readonly IProviderManager _providerManager; private readonly IProviderManager _providerManager;
private readonly ISecurityManager _security;
private readonly IDtoService _dtoService; private readonly IDtoService _dtoService;
private readonly ILocalizationManager _localization; private readonly ILocalizationManager _localization;
@ -71,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated; public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated; 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; _config = config;
_logger = logger; _logger = logger;
@ -83,6 +88,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_jsonSerializer = jsonSerializer; _jsonSerializer = jsonSerializer;
_providerManager = providerManager; _providerManager = providerManager;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_security = security;
_dtoService = dtoService; _dtoService = dtoService;
_userDataManager = userDataManager; _userDataManager = userDataManager;
@ -1423,6 +1429,49 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return new QueryResult<BaseItem>(); 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) return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{ {
MediaTypes = new[] { MediaType.Video }, MediaTypes = new[] { MediaType.Video },
@ -1430,13 +1479,75 @@ namespace MediaBrowser.Server.Implementations.LiveTv
AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(), AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
IsFolder = false, IsFolder = false,
ExcludeLocationTypes = new[] { LocationType.Virtual }, ExcludeLocationTypes = new[] { LocationType.Virtual },
Limit = Math.Min(200, query.Limit ?? int.MaxValue), Limit = query.Limit,
SortBy = new[] { ItemSortBy.DateCreated }, SortBy = new[] { ItemSortBy.DateCreated },
SortOrder = SortOrder.Descending, 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) public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, CancellationToken cancellationToken)
{ {
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); 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); 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)) if (!string.IsNullOrEmpty(query.SeriesTimerId))
{ {
var guid = new Guid(query.SeriesTimerId); var guid = new Guid(query.SeriesTimerId);
@ -1950,16 +2085,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.Number = channel.Number; dto.Number = channel.Number;
dto.ChannelNumber = channel.Number; dto.ChannelNumber = channel.Number;
dto.ChannelType = channel.ChannelType; dto.ChannelType = channel.ChannelType;
dto.ServiceName = GetService(channel).Name; dto.ServiceName = channel.ServiceName;
if (options.Fields.Contains(ItemFields.MediaSources)) if (options.Fields.Contains(ItemFields.MediaSources))
{ {
dto.MediaSources = channel.GetMediaSources(true).ToList(); dto.MediaSources = channel.GetMediaSources(true).ToList();
} }
var channelIdString = channel.Id.ToString("N");
if (options.AddCurrentProgram) if (options.AddCurrentProgram)
{ {
var channelIdString = channel.Id.ToString("N");
var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString)); var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString));
if (currentProgram != null) if (currentProgram != null)
@ -2091,6 +2226,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken) 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 service = GetService(timer.ServiceName);
var info = await _tvDtoService.GetSeriesTimerInfo(timer, true, this, cancellationToken).ConfigureAwait(false); 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.Equals(feature, "seriesrecordings", StringComparison.OrdinalIgnoreCase))
if (string.IsNullOrWhiteSpace(programId))
{
var channel = GetInternalChannel(channelId);
service = GetService(channel);
}
else
{ {
var program = GetInternalProgram(programId); feature = "embytvseriesrecordings";
service = GetService(program);
} }
var hasRegistration = service as IHasRegistrationInfo; if (string.Equals(feature, "dvr", StringComparison.OrdinalIgnoreCase))
if (hasRegistration != null)
{ {
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 return _security.GetRegistrationStatus(feature);
{
IsValid = true,
IsRegistered = true
});
} }
public List<NameValuePair> GetSatIniMappings() public List<NameValuePair> GetSatIniMappings()

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -70,7 +71,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
} }
else if (!string.IsNullOrWhiteSpace(extInf) && !line.StartsWith("#", StringComparison.OrdinalIgnoreCase)) 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.Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N");
channel.Path = line; channel.Path = line;
channels.Add(channel); channels.Add(channel);
@ -79,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
} }
return channels; return channels;
} }
private M3UChannel GetChannelnfo(string extInf, string tunerHostId) private M3UChannel GetChannelnfo(string extInf, string tunerHostId, string mediaUrl)
{ {
var titleIndex = extInf.LastIndexOf(','); var titleIndex = extInf.LastIndexOf(',');
var channel = new M3UChannel(); var channel = new M3UChannel();
@ -87,8 +88,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
channel.Number = extInf.Trim().Split(' ')[0] ?? "0"; channel.Number = extInf.Trim().Split(' ')[0] ?? "0";
channel.Name = extInf.Substring(titleIndex + 1); channel.Name = extInf.Substring(titleIndex + 1);
if(channel.Number == "-1") { channel.Number = "0"; }
//Check for channel number with the format from SatIp //Check for channel number with the format from SatIp
int number; int number;
@ -101,6 +100,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
channel.Name = channel.Name.Substring(numberIndex + 1); 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.ImageUrl = FindProperty("tvg-logo", extInf, null);
channel.Number = FindProperty("tvg-id", extInf, channel.Number); channel.Number = FindProperty("tvg-id", extInf, channel.Number);
channel.Number = FindProperty("channel-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…
Cancel
Save