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()
};
if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName))
if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName) &&
item.SourceType == SourceType.Library)
{
var inheritedContentType = _libraryManager.GetInheritedContentType(item);
var configuredContentType = _libraryManager.GetConfiguredContentType(item);
if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || !string.IsNullOrWhiteSpace(configuredContentType))
if (string.IsNullOrWhiteSpace(inheritedContentType) || !string.IsNullOrWhiteSpace(configuredContentType))
{
info.ContentTypeOptions = GetContentTypeOptions(true);
info.ContentType = configuredContentType;

@ -25,6 +25,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Controller.Configuration;
namespace MediaBrowser.Api.Library
{
@ -288,12 +289,13 @@ namespace MediaBrowser.Api.Library
private readonly ITVSeriesManager _tvManager;
private readonly ILibraryMonitor _libraryMonitor;
private readonly IFileSystem _fileSystem;
private readonly IServerConfigurationManager _config;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary>
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, IServerConfigurationManager config)
{
_itemRepo = itemRepo;
_libraryManager = libraryManager;
@ -307,6 +309,7 @@ namespace MediaBrowser.Api.Library
_tvManager = tvManager;
_libraryMonitor = libraryMonitor;
_fileSystem = fileSystem;
_config = config;
}
public object Get(GetSimilarItems request)
@ -377,7 +380,7 @@ namespace MediaBrowser.Api.Library
if (item is Movie || (program != null && program.IsMovie) || item is Trailer)
{
return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService)
return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _config)
{
AuthorizationContext = AuthorizationContext,
Logger = Logger,

@ -155,12 +155,72 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; }
public bool? IsMovie { get; set; }
public bool? IsSeries { get; set; }
public bool? IsKids { get; set; }
public bool? IsSports { get; set; }
public GetRecordings()
{
EnableTotalRecordCount = true;
}
}
[Route("/LiveTv/Recordings/Series", "GET", Summary = "Gets live tv recordings")]
[Authenticated]
public class GetRecordingSeries : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
{
[ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ChannelId { get; set; }
[ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string UserId { get; set; }
[ApiMember(Name = "GroupId", Description = "Optional filter by recording group.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string GroupId { get; set; }
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? StartIndex { get; set; }
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? Limit { get; set; }
[ApiMember(Name = "Status", Description = "Optional filter by recording status.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public RecordingStatus? Status { get; set; }
[ApiMember(Name = "Status", Description = "Optional filter by recordings that are in progress, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsInProgress { get; set; }
[ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string SeriesTimerId { get; set; }
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableImages { get; set; }
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? ImageTypeLimit { get; set; }
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string EnableImageTypes { get; set; }
/// <summary>
/// Fields to return within the items, in addition to basic information
/// </summary>
/// <value>The fields.</value>
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string Fields { get; set; }
public bool EnableTotalRecordCount { get; set; }
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; }
public GetRecordingSeries()
{
EnableTotalRecordCount = true;
}
}
[Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
[Authenticated]
public class GetRecordingGroups : IReturn<QueryResult<BaseItemDto>>
@ -535,12 +595,6 @@ namespace MediaBrowser.Api.LiveTv
[Authenticated]
public class GetLiveTvRegistrationInfo : IReturn<MBRegistrationRecord>
{
[ApiMember(Name = "ChannelId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ChannelId { get; set; }
[ApiMember(Name = "ProgramId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ProgramId { get; set; }
[ApiMember(Name = "Feature", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Feature { get; set; }
}
@ -592,7 +646,7 @@ namespace MediaBrowser.Api.LiveTv
public async Task<object> Get(GetLiveTvRegistrationInfo request)
{
var result = await _liveTvManager.GetRegistrationInfo(request.ChannelId, request.ProgramId, request.Feature).ConfigureAwait(false);
var result = await _liveTvManager.GetRegistrationInfo(request.Feature).ConfigureAwait(false);
return ToOptimizedResult(result);
}
@ -854,6 +908,32 @@ namespace MediaBrowser.Api.LiveTv
options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
var result = await _liveTvManager.GetRecordings(new RecordingQuery
{
ChannelId = request.ChannelId,
UserId = request.UserId,
GroupId = request.GroupId,
StartIndex = request.StartIndex,
Limit = request.Limit,
Status = request.Status,
SeriesTimerId = request.SeriesTimerId,
IsInProgress = request.IsInProgress,
EnableTotalRecordCount = request.EnableTotalRecordCount,
IsMovie = request.IsMovie,
IsSeries = request.IsSeries,
IsKids = request.IsKids,
IsSports = request.IsSports
}, options, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public async Task<object> Get(GetRecordingSeries request)
{
var options = GetDtoOptions(request);
options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
var result = await _liveTvManager.GetRecordingSeries(new RecordingQuery
{
ChannelId = request.ChannelId,
UserId = request.UserId,

@ -14,6 +14,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.LiveTv;
namespace MediaBrowser.Api.Movies
@ -88,6 +89,7 @@ namespace MediaBrowser.Api.Movies
private readonly IItemRepository _itemRepo;
private readonly IDtoService _dtoService;
private readonly IServerConfigurationManager _config;
/// <summary>
/// Initializes a new instance of the <see cref="MoviesService" /> class.
@ -97,13 +99,14 @@ namespace MediaBrowser.Api.Movies
/// <param name="libraryManager">The library manager.</param>
/// <param name="itemRepo">The item repo.</param>
/// <param name="dtoService">The dto service.</param>
public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IServerConfigurationManager config)
{
_userManager = userManager;
_userDataRepository = userDataRepository;
_libraryManager = libraryManager;
_itemRepo = itemRepo;
_dtoService = dtoService;
_config = config;
}
/// <summary>
@ -146,15 +149,17 @@ namespace MediaBrowser.Api.Movies
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
var itemTypes = new List<string> { typeof(Movie).Name };
if (_config.Configuration.EnableExternalContentInSuggestions)
{
itemTypes.Add(typeof(Trailer).Name);
itemTypes.Add(typeof(LiveTvProgram).Name);
}
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Limit = request.Limit,
IncludeItemTypes = new[]
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true,
SimilarTo = item,
EnableGroupByMetadataKey = true
@ -198,14 +203,16 @@ namespace MediaBrowser.Api.Movies
var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList();
var itemTypes = new List<string> { typeof(Movie).Name };
if (_config.Configuration.EnableExternalContentInSuggestions)
{
itemTypes.Add(typeof(Trailer).Name);
itemTypes.Add(typeof(LiveTvProgram).Name);
}
var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
IncludeItemTypes = new[]
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true,
SortBy = new[] { ItemSortBy.Random },
SortOrder = SortOrder.Descending,
@ -278,6 +285,13 @@ namespace MediaBrowser.Api.Movies
private IEnumerable<RecommendationDto> GetWithDirector(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var itemTypes = new List<string> { typeof(Movie).Name };
if (_config.Configuration.EnableExternalContentInSuggestions)
{
itemTypes.Add(typeof(Trailer).Name);
itemTypes.Add(typeof(LiveTvProgram).Name);
}
foreach (var name in names)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
@ -286,12 +300,7 @@ namespace MediaBrowser.Api.Movies
// Account for duplicates by imdb id, since the database doesn't support this yet
Limit = itemLimit + 2,
PersonTypes = new[] { PersonType.Director },
IncludeItemTypes = new[]
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true,
EnableGroupByMetadataKey = true
@ -314,6 +323,13 @@ namespace MediaBrowser.Api.Movies
private IEnumerable<RecommendationDto> GetWithActor(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var itemTypes = new List<string> { typeof(Movie).Name };
if (_config.Configuration.EnableExternalContentInSuggestions)
{
itemTypes.Add(typeof(Trailer).Name);
itemTypes.Add(typeof(LiveTvProgram).Name);
}
foreach (var name in names)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
@ -321,12 +337,7 @@ namespace MediaBrowser.Api.Movies
Person = name,
// Account for duplicates by imdb id, since the database doesn't support this yet
Limit = itemLimit + 2,
IncludeItemTypes = new[]
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true,
EnableGroupByMetadataKey = true
@ -349,17 +360,19 @@ namespace MediaBrowser.Api.Movies
private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var itemTypes = new List<string> { typeof(Movie).Name };
if (_config.Configuration.EnableExternalContentInSuggestions)
{
itemTypes.Add(typeof(Trailer).Name);
itemTypes.Add(typeof(LiveTvProgram).Name);
}
foreach (var item in baselineItems)
{
var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Limit = itemLimit,
IncludeItemTypes = new[]
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true,
SimilarTo = item,
EnableGroupByMetadataKey = true

@ -337,44 +337,60 @@ namespace MediaBrowser.Api.Playback
/// Gets the video bitrate to specify on the command line
/// </summary>
/// <param name="state">The state.</param>
/// <param name="videoCodec">The video codec.</param>
/// <param name="videoEncoder">The video codec.</param>
/// <returns>System.String.</returns>
protected string GetVideoQualityParam(StreamState state, string videoCodec)
protected string GetVideoQualityParam(StreamState state, string videoEncoder)
{
var param = string.Empty;
var isVc1 = state.VideoStream != null &&
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
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";
}
// h264 (h264_qsv)
else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
{
param = "-preset 7 -look_ahead 0";
param += "-preset 7 -look_ahead 0";
}
// h264 (h264_nvenc)
else if (string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{
param = "-preset default";
param += "-preset default";
}
// webm
else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase))
{
// Values 0-3, 0 being highest quality but slower
var profileScore = 0;
@ -394,30 +410,30 @@ namespace MediaBrowser.Api.Playback
profileScore = Math.Min(profileScore, 2);
// http://www.webmproject.org/docs/encoder-parameters/
param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}",
param += string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}",
profileScore.ToString(UsCulture),
crf,
qmin,
qmax);
}
else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase))
{
param = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
param += "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
}
// asf/wmv
else if (string.Equals(videoCodec, "wmv2", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase))
{
param = "-qmin 2";
param += "-qmin 2";
}
else if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase))
{
param = "-mbd 2";
param += "-mbd 2";
}
param += GetVideoBitrateParam(state, videoCodec);
param += GetVideoBitrateParam(state, videoEncoder);
var framerate = GetFramerateParam(state);
if (framerate.HasValue)
@ -432,8 +448,8 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrEmpty(state.VideoRequest.Profile))
{
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
// not supported by h264_omx
param += " -profile:v " + state.VideoRequest.Profile;
@ -442,11 +458,13 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrEmpty(state.VideoRequest.Level))
{
var level = NormalizeTranscodingLevel(state.OutputVideoCodec, state.VideoRequest.Level);
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{
switch (state.VideoRequest.Level)
switch (level)
{
case "30":
param += " -level 3";
@ -476,20 +494,20 @@ namespace MediaBrowser.Api.Playback
param += " -level 5.2";
break;
default:
param += " -level " + state.VideoRequest.Level;
param += " -level " + level;
break;
}
}
else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
{
param += " -level " + state.VideoRequest.Level;
param += " -level " + level;
}
}
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt yuv420p " + param;
}
@ -497,6 +515,25 @@ namespace MediaBrowser.Api.Playback
return param;
}
private string NormalizeTranscodingLevel(string videoCodec, string level)
{
double requestLevel;
// Clients may direct play higher than level 41, but there's no reason to transcode higher
if (double.TryParse(level, NumberStyles.Any, UsCulture, out requestLevel))
{
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
{
if (requestLevel > 41)
{
return "41";
}
}
}
return level;
}
protected string GetAudioFilterParam(StreamState state, bool isHls)
{
var volParam = string.Empty;
@ -1160,17 +1197,21 @@ namespace MediaBrowser.Api.Playback
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
}
if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive)
if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited)
{
await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
if (state.ReadInputAtNativeFramerate)
if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited)
{
await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
}
}
StartThrottler(state, transcodingJob);
if (!transcodingJob.HasExited)
{
StartThrottler(state, transcodingJob);
}
ReportUsage(state);
return transcodingJob;
@ -1770,6 +1811,15 @@ namespace MediaBrowser.Api.Playback
// state.SegmentLength = 6;
//}
if (state.VideoRequest != null)
{
if (!string.IsNullOrWhiteSpace(state.VideoRequest.VideoCodec))
{
state.SupportedVideoCodecs = state.VideoRequest.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
state.VideoRequest.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault();
}
}
if (!string.IsNullOrWhiteSpace(request.AudioCodec))
{
state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
@ -2012,7 +2062,7 @@ namespace MediaBrowser.Api.Playback
}
// Source and target codecs must match
if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase))
if (string.IsNullOrEmpty(videoStream.Codec) || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase))
{
return false;
}

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

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

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

@ -142,9 +142,15 @@ namespace MediaBrowser.Common.Implementations.Security
}
set
{
if (value != LicenseFile.RegKey)
var newValue = value;
if (newValue != null)
{
LicenseFile.RegKey = value;
newValue = newValue.Trim();
}
if (newValue != LicenseFile.RegKey)
{
LicenseFile.RegKey = newValue;
LicenseFile.Save();
// re-load registration info

@ -14,16 +14,14 @@ namespace MediaBrowser.Common.Implementations.Updates
{
private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _jsonSerializer;
private TimeSpan _cacheLength;
public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer, TimeSpan cacheLength)
public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer)
{
_httpClient = httpClient;
_jsonSerializer = jsonSerializer;
_cacheLength = cacheLength;
}
public async Task<CheckForUpdateResult> CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, CancellationToken cancellationToken)
public async Task<CheckForUpdateResult> CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, TimeSpan cacheLength, CancellationToken cancellationToken)
{
var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
@ -35,10 +33,10 @@ namespace MediaBrowser.Common.Implementations.Updates
UserAgent = "Emby/3.0"
};
if (_cacheLength.Ticks > 0)
if (cacheLength.Ticks > 0)
{
options.CacheMode = CacheMode.Unconditional;
options.CacheLength = _cacheLength;
options.CacheLength = cacheLength;
}
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
@ -110,12 +108,6 @@ namespace MediaBrowser.Common.Implementations.Updates
UserAgent = "Emby/3.0"
};
if (_cacheLength.Ticks > 0)
{
options.CacheMode = CacheMode.Unconditional;
options.CacheLength = _cacheLength;
}
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
{
var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);

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

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

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

@ -1057,10 +1057,20 @@ namespace MediaBrowser.Controller.Entities
/// <returns>IList{BaseItem}.</returns>
public IList<BaseItem> GetRecursiveChildren()
{
return GetRecursiveChildren(i => true);
return GetRecursiveChildren(true);
}
public IList<BaseItem> GetRecursiveChildren(bool includeLinkedChildren)
{
return GetRecursiveChildren(i => true, includeLinkedChildren);
}
public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter)
{
return GetRecursiveChildren(filter, true);
}
public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter, bool includeLinkedChildren)
{
var result = new Dictionary<Guid, BaseItem>();

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

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

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

@ -89,5 +89,7 @@ namespace MediaBrowser.Controller
string GetLocalApiUrl(IPAddress ipAddress);
void LaunchUrl(string url);
void EnableLoopback(string appName);
}
}

@ -566,5 +566,8 @@ namespace MediaBrowser.Controller.Library
QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
void RegisterIgnoredPath(string path);
void UnRegisterIgnoredPath(string path);
}
}

@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Library
}
}
class TextComparer : IComparer<string>, IEqualityComparer<string>
public class DistinctNameComparer : IComparer<string>, IEqualityComparer<string>
{
public int Compare(string x, string y)
{
@ -63,7 +63,7 @@ namespace MediaBrowser.Controller.Library
return 0;
}
return string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace);
return string.Compare(x.RemoveDiacritics(), y.RemoveDiacritics(), StringComparison.OrdinalIgnoreCase);
}
public bool Equals(string x, string y)

@ -1,15 +0,0 @@
using MediaBrowser.Model.Entities;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.LiveTv
{
public interface IHasRegistrationInfo
{
/// <summary>
/// Gets the registration information.
/// </summary>
/// <param name="feature">The feature.</param>
/// <returns>Task&lt;MBRegistrationRecord&gt;.</returns>
Task<MBRegistrationRecord> GetRegistrationInfo(string feature);
}
}

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

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

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

@ -23,14 +23,18 @@ namespace MediaBrowser.Controller.Providers
/// The logger
/// </summary>
protected ILogger Logger { get; private set; }
protected IProviderManager ProviderManager { get; private set; }
private Dictionary<string, string> _validProviderIds;
/// <summary>
/// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
public BaseItemXmlParser(ILogger logger)
public BaseItemXmlParser(ILogger logger, IProviderManager providerManager)
{
Logger = logger;
ProviderManager = providerManager;
}
/// <summary>
@ -60,6 +64,22 @@ namespace MediaBrowser.Controller.Providers
ValidationType = ValidationType.None
};
_validProviderIds = _validProviderIds = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
var idInfos = ProviderManager.GetExternalIdInfos(item.Item);
foreach (var info in idInfos)
{
var id = info.Key + "Id";
if (!_validProviderIds.ContainsKey(id))
{
_validProviderIds.Add(id, info.Key);
}
}
//Additional Mappings
_validProviderIds.Add("IMDB", "Imdb");
//Fetch(item, metadataFile, settings, Encoding.GetEncoding("ISO-8859-1"), cancellationToken);
Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken);
}
@ -657,14 +677,6 @@ namespace MediaBrowser.Controller.Providers
break;
}
case "TvDbId":
var tvdbId = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(tvdbId))
{
item.SetProviderId(MetadataProviders.Tvdb, tvdbId);
}
break;
case "VoteCount":
{
var val = reader.ReadElementContentAsString();
@ -679,95 +691,7 @@ namespace MediaBrowser.Controller.Providers
}
break;
}
case "MusicBrainzAlbumId":
{
var mbz = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(mbz))
{
item.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbz);
}
break;
}
case "MusicBrainzAlbumArtistId":
{
var mbz = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(mbz))
{
item.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, mbz);
}
break;
}
case "MusicBrainzArtistId":
{
var mbz = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(mbz))
{
item.SetProviderId(MetadataProviders.MusicBrainzArtist, mbz);
}
break;
}
case "MusicBrainzReleaseGroupId":
{
var mbz = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(mbz))
{
item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, mbz);
}
break;
}
case "TVRageId":
{
var id = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(id))
{
item.SetProviderId(MetadataProviders.TvRage, id);
}
break;
}
case "TvMazeId":
{
var id = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(id))
{
item.SetProviderId(MetadataProviders.TvMaze, id);
}
break;
}
case "AudioDbArtistId":
{
var id = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(id))
{
item.SetProviderId(MetadataProviders.AudioDbArtist, id);
}
break;
}
case "AudioDbAlbumId":
{
var id = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(id))
{
item.SetProviderId(MetadataProviders.AudioDbAlbum, id);
}
break;
}
case "RottenTomatoesId":
var rtId = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(rtId))
{
item.SetProviderId(MetadataProviders.RottenTomatoes, rtId);
}
break;
case "TMDbId":
var tmdb = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(tmdb))
{
item.SetProviderId(MetadataProviders.Tmdb, tmdb);
}
break;
case "TMDbCollectionId":
case "CollectionNumber":
var tmdbCollection = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(tmdbCollection))
{
@ -775,30 +699,6 @@ namespace MediaBrowser.Controller.Providers
}
break;
case "TVcomId":
var TVcomId = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(TVcomId))
{
item.SetProviderId(MetadataProviders.Tvcom, TVcomId);
}
break;
case "Zap2ItId":
var zap2ItId = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(zap2ItId))
{
item.SetProviderId(MetadataProviders.Zap2It, zap2ItId);
}
break;
case "IMDB":
var imDbId = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(imDbId))
{
item.SetProviderId(MetadataProviders.Imdb, imDbId);
}
break;
case "Genres":
{
using (var subtree = reader.ReadSubtree())
@ -890,8 +790,25 @@ namespace MediaBrowser.Controller.Providers
}
default:
reader.Skip();
break;
{
string readerName = reader.Name;
string providerIdValue;
if (_validProviderIds.TryGetValue(readerName, out providerIdValue))
{
var id = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(id))
{
item.SetProviderId(providerIdValue, id);
}
}
else
{
reader.Skip();
}
break;
}
}
}

@ -483,7 +483,9 @@ namespace MediaBrowser.Dlna.PlayTo
{
if (OnDeviceUnavailable != null)
{
_logger.Debug("Disposing device due to loss of connection");
OnDeviceUnavailable();
return;
}
}
if (_successiveStopCount >= maxSuccessiveStopReturns)

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

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

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

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

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

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

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

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

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

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

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

@ -43,7 +43,7 @@
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,aac,pcm,mp3" videoCodec="mpeg4,h264" type="Video" />
<DirectPlayProfile container="avi" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm,dts" videoCodec="mpeg4,h264" type="Video" />
<DirectPlayProfile container="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
<DirectPlayProfile container="wmv,asf" type="Video" />
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" />

@ -43,7 +43,7 @@
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,aac,pcm,mp3" videoCodec="mpeg4,h264" type="Video" />
<DirectPlayProfile container="avi" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm,dts" videoCodec="mpeg4,h264" type="Video" />
<DirectPlayProfile container="m2ts,mts" audioCodec="aac,mp3,ac3,dca,dts" videoCodec="h264,mpeg4,vc1" type="Video" />
<DirectPlayProfile container="wmv,asf" type="Video" />
<DirectPlayProfile container="mp3,m4a,wma,wav" type="Audio" />

@ -36,11 +36,11 @@
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
<DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video" type="Video" />
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm,dca" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
<DirectPlayProfile container="ts,m2ts" audioCodec="ac3,dca,mp2,mp3,aac,dca" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
<DirectPlayProfile container="mp4,mov" audioCodec="ac3,aac,mp2,mp3,dca" videoCodec="h264,mpeg4" type="Video" />
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
<DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video" type="Video" />
<DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
<DirectPlayProfile container="ts,m2ts" audioCodec="ac3,dca,mp2,mp3,aac,dts" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
<DirectPlayProfile container="mp4,mov" audioCodec="ac3,aac,mp2,mp3,dca,dts" videoCodec="h264,mpeg4" type="Video" />
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="vc1" type="Video" />
<DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />

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

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

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

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

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

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

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

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

@ -1,48 +0,0 @@
using System.Xml;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
namespace MediaBrowser.LocalMetadata.Parsers
{
public class SeasonXmlParser : BaseItemXmlParser<Season>
{
public SeasonXmlParser(ILogger logger)
: base(logger)
{
}
/// <summary>
/// Fetches the data from XML node.
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="result">The result.</param>
protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Season> result)
{
var item = result.Item;
switch (reader.Name)
{
case "SeasonNumber":
{
var number = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(number))
{
int num;
if (int.TryParse(number, out num))
{
item.IndexNumber = num;
}
}
break;
}
default:
base.FetchDataFromXmlNode(reader, result);
break;
}
}
}
}

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

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

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

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

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

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

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

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

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

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

@ -1,44 +0,0 @@
using System.IO;
using System.Threading;
using CommonIO;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.LocalMetadata.Parsers;
using MediaBrowser.Model.Logging;
namespace MediaBrowser.LocalMetadata.Providers
{
/// <summary>
/// Class SeriesProviderFromXml
/// </summary>
public class SeasonXmlProvider : BaseXmlProvider<Season>, IHasOrder
{
private readonly ILogger _logger;
public SeasonXmlProvider(IFileSystem fileSystem, ILogger logger)
: base(fileSystem)
{
_logger = logger;
}
protected override void Fetch(MetadataResult<Season> result, string path, CancellationToken cancellationToken)
{
new SeasonXmlParser(_logger).Fetch(result, path, cancellationToken);
}
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "season.xml"));
}
public int Order
{
get
{
// After Xbmc
return 1;
}
}
}
}

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

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

@ -133,7 +133,7 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <param name="xmlTagsUsed">The XML tags used.</param>
public static void Save(StringBuilder xml, string path, List<string> xmlTagsUsed, IServerConfigurationManager config, IFileSystem fileSystem)
{
if (fileSystem.FileExists(path))
if (fileSystem.FileExists(path))
{
var position = xml.ToString().LastIndexOf("</", StringComparison.OrdinalIgnoreCase);
xml.Insert(position, GetCustomTags(path, xmlTagsUsed));
@ -145,7 +145,7 @@ namespace MediaBrowser.LocalMetadata.Savers
//Add the new node to the document.
xmlDocument.InsertBefore(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "yes"), xmlDocument.DocumentElement);
fileSystem.CreateDirectory(Path.GetDirectoryName(path));
fileSystem.CreateDirectory(Path.GetDirectoryName(path));
var wasHidden = false;
@ -445,121 +445,18 @@ namespace MediaBrowser.LocalMetadata.Savers
builder.Append("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>");
}
var imdb = item.GetProviderId(MetadataProviders.Imdb);
if (!string.IsNullOrEmpty(imdb))
{
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))
if (item.ProviderIds != null)
{
var tvdb = item.GetProviderId(MetadataProviders.Tvdb);
if (!string.IsNullOrEmpty(tvdb))
foreach (var providerKey in item.ProviderIds.Keys)
{
builder.Append("<TvDbId>" + SecurityElement.Escape(tvdb) + "</TvDbId>");
var providerId = item.ProviderIds[providerKey];
if (!string.IsNullOrEmpty(providerId))
{
builder.Append(string.Format("<{0}>{1}</{0}>", providerKey + "Id", SecurityElement.Escape(providerId)));
}
}
}
var externalId = item.GetProviderId(MetadataProviders.Tvcom);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<TVcomId>" + SecurityElement.Escape(externalId) + "</TVcomId>");
}
externalId = item.GetProviderId(MetadataProviders.RottenTomatoes);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<RottenTomatoesId>" + SecurityElement.Escape(externalId) + "</RottenTomatoesId>");
}
externalId = item.GetProviderId(MetadataProviders.Zap2It);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<Zap2ItId>" + SecurityElement.Escape(externalId) + "</Zap2ItId>");
}
externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbum);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<MusicBrainzAlbumId>" + SecurityElement.Escape(externalId) + "</MusicBrainzAlbumId>");
}
externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<MusicBrainzAlbumArtistId>" + SecurityElement.Escape(externalId) + "</MusicBrainzAlbumArtistId>");
}
externalId = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<MusicBrainzArtistId>" + SecurityElement.Escape(externalId) + "</MusicBrainzArtistId>");
}
externalId = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<MusicBrainzReleaseGroupId>" + SecurityElement.Escape(externalId) + "</MusicBrainzReleaseGroupId>");
}
externalId = item.GetProviderId(MetadataProviders.Gamesdb);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<GamesDbId>" + SecurityElement.Escape(externalId) + "</GamesDbId>");
}
externalId = item.GetProviderId(MetadataProviders.TmdbCollection);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<TMDbCollectionId>" + SecurityElement.Escape(externalId) + "</TMDbCollectionId>");
}
externalId = item.GetProviderId(MetadataProviders.AudioDbArtist);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<AudioDbArtistId>" + SecurityElement.Escape(externalId) + "</AudioDbArtistId>");
}
externalId = item.GetProviderId(MetadataProviders.AudioDbAlbum);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<AudioDbAlbumId>" + SecurityElement.Escape(externalId) + "</AudioDbAlbumId>");
}
externalId = item.GetProviderId(MetadataProviders.TvRage);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<TVRageId>" + SecurityElement.Escape(externalId) + "</TVRageId>");
}
externalId = item.GetProviderId(MetadataProviders.TvMaze);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<TvMazeId>" + SecurityElement.Escape(externalId) + "</TvMazeId>");
}
var hasTagline = item as IHasTaglines;
if (hasTagline != null)
{

@ -481,6 +481,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
if (state.IsVideoRequest)
{
var encodingOptions = GetEncodingOptions();
var videoEncoder = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, encodingOptions);
if (videoEncoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1)
{
arg = "-hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device " + encodingOptions.VaapiDevice + " " + arg;
}
}
return arg.Trim();
}
@ -585,23 +595,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// Gets the video bitrate to specify on the command line
/// </summary>
/// <param name="state">The state.</param>
/// <param name="videoCodec">The video codec.</param>
/// <param name="videoEncoder">The video codec.</param>
/// <returns>System.String.</returns>
protected string GetVideoQualityParam(EncodingJob state, string videoCodec)
protected string GetVideoQualityParam(EncodingJob state, string videoEncoder)
{
var param = string.Empty;
var isVc1 = state.VideoStream != null &&
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
{
param = "-preset superfast";
param += " -crf 23";
}
else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
{
param = "-preset fast";
@ -609,20 +619,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
// h264 (h264_qsv)
else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
{
param = "-preset 7 -look_ahead 0";
}
// h264 (h264_nvenc)
else if (string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{
param = "-preset llhq";
}
// webm
else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase))
{
// Values 0-3, 0 being highest quality but slower
var profileScore = 0;
@ -649,23 +659,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
qmax);
}
else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase))
{
param = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
}
// asf/wmv
else if (string.Equals(videoCodec, "wmv2", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase))
{
param = "-qmin 2";
}
else if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase))
{
param = "-mbd 2";
}
param += GetVideoBitrateParam(state, videoCodec);
param += GetVideoBitrateParam(state, videoEncoder);
var framerate = GetFramerateParam(state);
if (framerate.HasValue)
@ -680,8 +690,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrEmpty(state.Options.Profile))
{
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
// not supported by h264_omx
param += " -profile:v " + state.Options.Profile;
@ -692,9 +702,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrEmpty(levelString))
{
levelString = NormalizeTranscodingLevel(state.OutputVideoCodec, levelString);
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{
switch (levelString)
{
@ -730,16 +742,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
break;
}
}
else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
{
param += " -level " + levelString;
}
}
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt yuv420p " + param;
}
@ -747,6 +759,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
return param;
}
private string NormalizeTranscodingLevel(string videoCodec, string level)
{
double requestLevel;
// Clients may direct play higher than level 41, but there's no reason to transcode higher
if (double.TryParse(level, NumberStyles.Any, UsCulture, out requestLevel))
{
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
{
if (requestLevel > 41)
{
return "41";
}
}
}
return level;
}
protected string GetVideoBitrateParam(EncodingJob state, string videoCodec)
{
var bitrate = state.OutputVideoBitrate;

@ -928,7 +928,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
StartProcess(processWrapper);
ranToCompletion = process.WaitForExit(10000);
var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
if (timeoutMs <= 0)
{
timeoutMs = Environment.Is64BitOperatingSystem ? (Environment.ProcessorCount > 2 ? 14000 : 20000) : 40000;
}
ranToCompletion = process.WaitForExit(timeoutMs);
if (!ranToCompletion)
{

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

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

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

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

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

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

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

@ -68,6 +68,10 @@ namespace MediaBrowser.Model.LiveTv
/// <value>The fields.</value>
public ItemFields[] Fields { get; set; }
public bool? EnableImages { get; set; }
public bool? IsMovie { get; set; }
public bool? IsSeries { get; set; }
public bool? IsKids { get; set; }
public bool? IsSports { get; set; }
public int? ImageTypeLimit { get; set; }
public ImageType[] EnableImageTypes { get; set; }

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

@ -1,5 +1,6 @@
using System.Collections.Generic;
using CommonIO;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@ -21,4 +22,17 @@ namespace MediaBrowser.Providers.Folders
{
}
}
public class ManualCollectionsFolderMetadataService : MetadataService<ManualCollectionsFolder, ItemLookupInfo>
{
protected override void MergeData(MetadataResult<ManualCollectionsFolder> source, MetadataResult<ManualCollectionsFolder> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
public ManualCollectionsFolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
}
}
}

@ -261,11 +261,18 @@ namespace MediaBrowser.Providers.MediaInfo
NormalizeChapterNames(chapters);
var libraryOptions = _libraryManager.GetLibraryOptions(video);
var extractDuringScan = chapterOptions.ExtractDuringLibraryScan;
if (libraryOptions != null && libraryOptions.SchemaVersion >= 2)
{
extractDuringScan = libraryOptions.ExtractChapterImagesDuringLibraryScan;
}
await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
{
Chapters = chapters,
Video = video,
ExtractImages = chapterOptions.ExtractDuringLibraryScan,
ExtractImages = extractDuringScan,
SaveChapters = false
}, cancellationToken).ConfigureAwait(false);

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

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

@ -530,6 +530,19 @@ namespace MediaBrowser.Server.Implementations.Channels
return GetChannelFeaturesDto(channel, channelProvider, channelProvider.GetChannelFeatures());
}
public bool SupportsSync(string channelId)
{
if (string.IsNullOrWhiteSpace(channelId))
{
throw new ArgumentNullException("channelId");
}
//var channel = GetChannel(channelId);
var channelProvider = GetChannelProvider(channelId);
return channelProvider.GetChannelFeatures().SupportsContentDownloading;
}
public ChannelFeatures GetChannelFeaturesDto(Channel channel,
IChannel provider,
InternalChannelFeatures features)
@ -1450,6 +1463,24 @@ namespace MediaBrowser.Server.Implementations.Channels
return result;
}
internal IChannel GetChannelProvider(string internalChannelId)
{
if (internalChannelId == null)
{
throw new ArgumentNullException("internalChannelId");
}
var result = GetAllChannels()
.FirstOrDefault(i => string.Equals(GetInternalChannelId(i.Name).ToString("N"), internalChannelId, StringComparison.OrdinalIgnoreCase));
if (result == null)
{
throw new ResourceNotFoundException("No channel provider found for channel id " + internalChannelId);
}
return result;
}
private IEnumerable<BaseItem> ApplyFilters(IEnumerable<BaseItem> items, IEnumerable<ItemFilter> filters, User user)
{
foreach (var filter in filters.OrderByDescending(f => (int)f))

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

@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
LoadCachedAddress();
_timer = new PeriodicTimer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3));
_timer = new PeriodicTimer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(1));
((ConnectManager)_connectManager).Start();
}

@ -1168,6 +1168,26 @@ namespace MediaBrowser.Server.Implementations.Dto
};
})
.ToList();
// Include artists that are not in the database yet, e.g., just added via metadata editor
var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
dto.ArtistItems.AddRange(hasArtist.Artists
.Except(foundArtists, new DistinctNameComparer())
.Select(i =>
{
var artist = _libraryManager.GetArtist(i);
if (artist != null)
{
return new NameIdPair
{
Name = artist.Name,
Id = artist.Id.ToString("N")
};
}
return null;
}).Where(i => i != null));
}
var hasAlbumArtist = item as IHasAlbumArtist;

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

@ -71,14 +71,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer
HostConfig.Instance.MapExceptionToStatusCode = new Dictionary<Type, int>
{
{typeof (InvalidOperationException), 422},
{typeof (InvalidOperationException), 500},
{typeof (NotImplementedException), 500},
{typeof (ResourceNotFoundException), 404},
{typeof (FileNotFoundException), 404},
{typeof (DirectoryNotFoundException), 404},
{typeof (SecurityException), 401},
{typeof (PaymentRequiredException), 402},
{typeof (UnauthorizedAccessException), 500},
{typeof (ApplicationException), 500}
{typeof (ApplicationException), 500},
{typeof (PlatformNotSupportedException), 500},
{typeof (NotSupportedException), 500}
};
HostConfig.Instance.GlobalResponseHeaders = new Dictionary<string, string>();
@ -99,14 +102,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer
// new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()),
//}));
PreRequestFilters.Add((httpReq, httpRes) =>
{
//Handles Request and closes Responses after emitting global HTTP Headers
if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
{
httpRes.EndRequest(); //add a 'using ServiceStack;'
}
});
//PreRequestFilters.Add((httpReq, httpRes) =>
//{
// //Handles Request and closes Responses after emitting global HTTP Headers
// if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
// {
// httpRes.EndRequest(); //add a 'using ServiceStack;'
// }
//});
HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
}
@ -400,6 +403,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return;
}
if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
{
httpRes.StatusCode = 200;
httpRes.AddHeader("Access-Control-Allow-Origin", "*");
httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
httpRes.ContentType = "text/html";
httpRes.Close();
}
var operationName = httpReq.OperationName;
var localPath = url.LocalPath;

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

@ -401,7 +401,7 @@ namespace MediaBrowser.Server.Implementations.Library
var locationType = item.LocationType;
var children = item.IsFolder
? ((Folder)item).GetRecursiveChildren().ToList()
? ((Folder)item).GetRecursiveChildren(false).ToList()
: new List<BaseItem>();
foreach (var metadataPath in GetMetadataPaths(item, children))
@ -621,9 +621,38 @@ namespace MediaBrowser.Server.Implementations.Library
return ResolveItem(args, resolvers);
}
private readonly List<string> _ignoredPaths = new List<string>();
public void RegisterIgnoredPath(string path)
{
lock (_ignoredPaths)
{
_ignoredPaths.Add(path);
}
}
public void UnRegisterIgnoredPath(string path)
{
lock (_ignoredPaths)
{
_ignoredPaths.Remove(path);
}
}
public bool IgnoreFile(FileSystemMetadata file, BaseItem parent)
{
return EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent));
if (EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent)))
{
return true;
}
//lock (_ignoredPaths)
{
if (_ignoredPaths.Contains(file.FullName, StringComparer.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
public IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)

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

@ -120,8 +120,8 @@ namespace MediaBrowser.Server.Implementations.Library
}, cancellationToken).ConfigureAwait(false);
var channels = channelResult.Items;
if (user.Configuration.EnableChannelView && channels.Length > 0)
if (_config.Configuration.EnableChannelView && channels.Length > 0)
{
list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false));
}

@ -33,7 +33,7 @@ using Microsoft.Win32;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public class EmbyTV : ILiveTvService, ISupportsNewTimerIds, IHasRegistrationInfo, IDisposable
public class EmbyTV : ILiveTvService, ISupportsNewTimerIds, IDisposable
{
private readonly IApplicationHost _appHpst;
private readonly ILogger _logger;
@ -46,7 +46,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly LiveTvManager _liveTvManager;
private readonly IFileSystem _fileSystem;
private readonly ISecurityManager _security;
private readonly ILibraryMonitor _libraryMonitor;
private readonly ILibraryManager _libraryManager;
@ -62,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement)
public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement)
{
Current = this;
@ -71,7 +70,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_httpClient = httpClient;
_config = config;
_fileSystem = fileSystem;
_security = security;
_libraryManager = libraryManager;
_libraryMonitor = libraryMonitor;
_providerManager = providerManager;
@ -851,29 +849,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var recordPath = RecordingPath;
var config = GetConfiguration();
if (info.IsMovie)
{
var customRecordingPath = config.MovieRecordingPath;
var allowSubfolder = true;
if (!string.IsNullOrWhiteSpace(customRecordingPath))
{
allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase);
recordPath = customRecordingPath;
}
if (allowSubfolder && config.EnableRecordingSubfolders)
{
recordPath = Path.Combine(recordPath, "Movies");
}
var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
if (info.ProductionYear.HasValue)
{
folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
}
recordPath = Path.Combine(recordPath, folderName);
}
else if (info.IsSeries)
if (info.IsSeries)
{
var customRecordingPath = config.SeriesRecordingPath;
var allowSubfolder = true;
@ -910,6 +886,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recordPath = Path.Combine(recordPath, folderName);
}
}
else if (info.IsMovie)
{
var customRecordingPath = config.MovieRecordingPath;
var allowSubfolder = true;
if (!string.IsNullOrWhiteSpace(customRecordingPath))
{
allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase);
recordPath = customRecordingPath;
}
if (allowSubfolder && config.EnableRecordingSubfolders)
{
recordPath = Path.Combine(recordPath, "Movies");
}
var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
if (info.ProductionYear.HasValue)
{
folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
}
recordPath = Path.Combine(recordPath, folderName);
}
else if (info.IsKids)
{
if (config.EnableRecordingSubfolders)
@ -995,6 +993,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
recordPath = EnsureFileUnique(recordPath, timer.Id);
_libraryManager.RegisterIgnoredPath(recordPath);
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
_fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
activeRecordingInfo.Path = recordPath;
@ -1046,6 +1045,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
semaphore.Release();
}
_libraryManager.UnRegisterIgnoredPath(recordPath);
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
ActiveRecordingInfo removed;
@ -1114,7 +1114,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (config.EnableRecordingEncoding)
{
var regInfo = await _security.GetRegistrationStatus("embytvrecordingconversion").ConfigureAwait(false);
var regInfo = await _liveTvManager.GetRegistrationInfo("embytvrecordingconversion").ConfigureAwait(false);
if (regInfo.IsValid)
{
@ -1171,8 +1171,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers)
{
var newTimers = GetTimersForSeries(seriesTimer, epgData, true).ToList();
var registration = await GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
var registration = await _liveTvManager.GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
if (registration.IsValid)
{
@ -1349,20 +1349,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
public Task<MBRegistrationRecord> GetRegistrationInfo(string feature)
{
if (string.Equals(feature, "seriesrecordings", StringComparison.OrdinalIgnoreCase))
{
return _security.GetRegistrationStatus("embytvseriesrecordings");
}
return Task.FromResult(new MBRegistrationRecord
{
IsValid = true,
IsRegistered = true
});
}
public List<VirtualFolderInfo> GetRecordingFolders()
{
var list = new List<VirtualFolderInfo>();

@ -46,18 +46,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_httpClient = httpClient;
}
private string OutputFormat
{
get
{
var format = _liveTvOptions.RecordingEncodingFormat;
if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase))
{
return "mkv";
}
return "mp4";
}
}
public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile)
{
return Path.ChangeExtension(targetFile, ".mp4");
return Path.ChangeExtension(targetFile, "." + OutputFormat);
}
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
if (mediaSource.Path.IndexOf("m3u8", StringComparison.OrdinalIgnoreCase) != -1)
{
await RecordWithoutTempFile(mediaSource, targetFile, duration, onStarted, cancellationToken)
.ConfigureAwait(false);
return;
}
var tempfile = Path.Combine(_appPaths.TranscodingTempPath, Guid.NewGuid().ToString("N") + ".ts");
try
{
await RecordInternal(mediaSource, tempfile, targetFile, duration, onStarted, cancellationToken)
await RecordWithTempFile(mediaSource, tempfile, targetFile, duration, onStarted, cancellationToken)
.ConfigureAwait(false);
}
finally
@ -73,7 +96,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
public async Task RecordInternal(MediaSourceInfo mediaSource, string tempFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
private async Task RecordWithoutTempFile(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
var durationToken = new CancellationTokenSource(duration);
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
await RecordFromFile(mediaSource, mediaSource.Path, targetFile, duration, onStarted, cancellationToken).ConfigureAwait(false);
_logger.Info("Recording completed to file {0}", targetFile);
}
private async Task RecordWithTempFile(MediaSourceInfo mediaSource, string tempFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
var httpRequestOptions = new HttpRequestOptions()
{
@ -215,15 +248,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private string GetAudioArgs(MediaSourceInfo mediaSource)
{
// do not copy aac because many players have difficulty with aac_latm
var copyAudio = new[] { "mp3" };
var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty;
if (copyAudio.Contains(inputAudioCodec, StringComparer.OrdinalIgnoreCase))
{
return "-codec:a:0 copy";
}
// do not copy aac because many players have difficulty with aac_latm
if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings && !string.Equals(inputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase))
{
return "-codec:a:0 copy";

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

@ -31,7 +31,11 @@ using CommonIO;
using IniParser;
using IniParser.Model;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Security;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Events;
using MediaBrowser.Server.Implementations.LiveTv.Listings;
namespace MediaBrowser.Server.Implementations.LiveTv
{
@ -49,6 +53,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly ITaskManager _taskManager;
private readonly IJsonSerializer _jsonSerializer;
private readonly IProviderManager _providerManager;
private readonly ISecurityManager _security;
private readonly IDtoService _dtoService;
private readonly ILocalizationManager _localization;
@ -71,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem)
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem, ISecurityManager security)
{
_config = config;
_logger = logger;
@ -83,6 +88,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_jsonSerializer = jsonSerializer;
_providerManager = providerManager;
_fileSystem = fileSystem;
_security = security;
_dtoService = dtoService;
_userDataManager = userDataManager;
@ -1423,6 +1429,49 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return new QueryResult<BaseItem>();
}
var includeItemTypes = new List<string>();
var excludeItemTypes = new List<string>();
var genres = new List<string>();
if (query.IsMovie.HasValue)
{
if (query.IsMovie.Value)
{
includeItemTypes.Add(typeof(Movie).Name);
}
else
{
excludeItemTypes.Add(typeof(Movie).Name);
}
}
if (query.IsSeries.HasValue)
{
if (query.IsSeries.Value)
{
includeItemTypes.Add(typeof(Episode).Name);
}
else
{
excludeItemTypes.Add(typeof(Episode).Name);
}
}
if (query.IsSports.HasValue)
{
if (query.IsSports.Value)
{
genres.Add("Sports");
}
}
if (query.IsKids.HasValue)
{
if (query.IsKids.Value)
{
genres.Add("Kids");
genres.Add("Children");
genres.Add("Family");
}
}
return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{
MediaTypes = new[] { MediaType.Video },
@ -1430,13 +1479,75 @@ namespace MediaBrowser.Server.Implementations.LiveTv
AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
IsFolder = false,
ExcludeLocationTypes = new[] { LocationType.Virtual },
Limit = Math.Min(200, query.Limit ?? int.MaxValue),
Limit = query.Limit,
SortBy = new[] { ItemSortBy.DateCreated },
SortOrder = SortOrder.Descending,
EnableTotalRecordCount = query.EnableTotalRecordCount
EnableTotalRecordCount = query.EnableTotalRecordCount,
IncludeItemTypes = includeItemTypes.ToArray(),
ExcludeItemTypes = excludeItemTypes.ToArray(),
Genres = genres.ToArray()
});
}
public async Task<QueryResult<BaseItemDto>> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
if (user != null && !IsLiveTvEnabled(user))
{
return new QueryResult<BaseItemDto>();
}
if (_services.Count > 1)
{
return new QueryResult<BaseItemDto>();
}
if (user == null || (query.IsInProgress ?? false))
{
return new QueryResult<BaseItemDto>();
}
var folders = EmbyTV.EmbyTV.Current.GetRecordingFolders()
.SelectMany(i => i.Locations)
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(i => _libraryManager.FindByPath(i, true))
.Where(i => i != null)
.Where(i => i.IsVisibleStandalone(user))
.ToList();
if (folders.Count == 0)
{
return new QueryResult<BaseItemDto>();
}
var includeItemTypes = new List<string>();
var excludeItemTypes = new List<string>();
includeItemTypes.Add(typeof(Series).Name);
var internalResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{
Recursive = true,
AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
Limit = query.Limit,
SortBy = new[] { ItemSortBy.DateCreated },
SortOrder = SortOrder.Descending,
EnableTotalRecordCount = query.EnableTotalRecordCount,
IncludeItemTypes = includeItemTypes.ToArray(),
ExcludeItemTypes = excludeItemTypes.ToArray()
});
RemoveFields(options);
var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
return new QueryResult<BaseItemDto>
{
Items = returnArray,
TotalRecordCount = internalResult.TotalRecordCount
};
}
public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@ -1492,6 +1603,30 @@ namespace MediaBrowser.Server.Implementations.LiveTv
recordings = recordings.Where(i => i.Status == val);
}
if (query.IsMovie.HasValue)
{
var val = query.IsMovie.Value;
recordings = recordings.Where(i => i.IsMovie == val);
}
if (query.IsSeries.HasValue)
{
var val = query.IsSeries.Value;
recordings = recordings.Where(i => i.IsSeries == val);
}
if (query.IsKids.HasValue)
{
var val = query.IsKids.Value;
recordings = recordings.Where(i => i.IsKids == val);
}
if (query.IsSports.HasValue)
{
var val = query.IsSports.Value;
recordings = recordings.Where(i => i.IsSports == val);
}
if (!string.IsNullOrEmpty(query.SeriesTimerId))
{
var guid = new Guid(query.SeriesTimerId);
@ -1950,16 +2085,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.Number = channel.Number;
dto.ChannelNumber = channel.Number;
dto.ChannelType = channel.ChannelType;
dto.ServiceName = GetService(channel).Name;
dto.ServiceName = channel.ServiceName;
if (options.Fields.Contains(ItemFields.MediaSources))
{
dto.MediaSources = channel.GetMediaSources(true).ToList();
}
var channelIdString = channel.Id.ToString("N");
if (options.AddCurrentProgram)
{
var channelIdString = channel.Id.ToString("N");
var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString));
if (currentProgram != null)
@ -2091,6 +2226,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
{
var registration = await GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
if (!registration.IsValid)
{
_logger.Info("Creating series recordings requires an active Emby Premiere subscription.");
return;
}
var service = GetService(timer.ServiceName);
var info = await _tvDtoService.GetSeriesTimerInfo(timer, true, this, cancellationToken).ConfigureAwait(false);
@ -2653,33 +2796,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
}
public Task<MBRegistrationRecord> GetRegistrationInfo(string channelId, string programId, string feature)
public Task<MBRegistrationRecord> GetRegistrationInfo(string feature)
{
ILiveTvService service;
if (string.IsNullOrWhiteSpace(programId))
{
var channel = GetInternalChannel(channelId);
service = GetService(channel);
}
else
if (string.Equals(feature, "seriesrecordings", StringComparison.OrdinalIgnoreCase))
{
var program = GetInternalProgram(programId);
service = GetService(program);
feature = "embytvseriesrecordings";
}
var hasRegistration = service as IHasRegistrationInfo;
if (hasRegistration != null)
if (string.Equals(feature, "dvr", StringComparison.OrdinalIgnoreCase))
{
return hasRegistration.GetRegistrationInfo(feature);
var config = GetConfiguration();
if (config.TunerHosts.Count(i => i.IsEnabled) > 0 &&
config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0)
{
return Task.FromResult(new MBRegistrationRecord
{
IsRegistered = true,
IsValid = true
});
}
}
return Task.FromResult(new MBRegistrationRecord
{
IsValid = true,
IsRegistered = true
});
return _security.GetRegistrationStatus(feature);
}
public List<NameValuePair> GetSatIniMappings()

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

@ -0,0 +1,79 @@
/*
Copyright (C) <2007-2016> <Kay Diefenthal>
SatIp.RtspSample is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SatIp.RtspSample is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
*/
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
{
public class ReportBlock
{
/// <summary>
/// Get the length of the block.
/// </summary>
public int BlockLength { get { return (24); } }
/// <summary>
/// Get the synchronization source.
/// </summary>
public string SynchronizationSource { get; private set; }
/// <summary>
/// Get the fraction lost.
/// </summary>
public int FractionLost { get; private set; }
/// <summary>
/// Get the cumulative packets lost.
/// </summary>
public int CumulativePacketsLost { get; private set; }
/// <summary>
/// Get the highest number received.
/// </summary>
public int HighestNumberReceived { get; private set; }
/// <summary>
/// Get the inter arrival jitter.
/// </summary>
public int InterArrivalJitter { get; private set; }
/// <summary>
/// Get the timestamp of the last report.
/// </summary>
public int LastReportTimeStamp { get; private set; }
/// <summary>
/// Get the delay since the last report.
/// </summary>
public int DelaySinceLastReport { get; private set; }
/// <summary>
/// Initialize a new instance of the ReportBlock class.
/// </summary>
public ReportBlock() { }
/// <summary>
/// Unpack the data in a packet.
/// </summary>
/// <param name="buffer">The buffer containing the packet.</param>
/// <param name="offset">The offset to the first byte of the packet within the buffer.</param>
/// <returns>An ErrorSpec instance if an error occurs; null otherwise.</returns>
public void Process(byte[] buffer, int offset)
{
SynchronizationSource = Utils.ConvertBytesToString(buffer, offset, 4);
FractionLost = buffer[offset + 4];
CumulativePacketsLost = Utils.Convert3BytesToInt(buffer, offset + 5);
HighestNumberReceived = Utils.Convert4BytesToInt(buffer, offset + 8);
InterArrivalJitter = Utils.Convert4BytesToInt(buffer, offset + 12);
LastReportTimeStamp = Utils.Convert4BytesToInt(buffer, offset + 16);
DelaySinceLastReport = Utils.Convert4BytesToInt(buffer, offset + 20);
}
}
}

@ -0,0 +1,68 @@
/*
Copyright (C) <2007-2016> <Kay Diefenthal>
SatIp.RtspSample is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SatIp.RtspSample is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Text;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
{
class RtcpAppPacket : RtcpPacket
{
/// <summary>
/// Get the synchronization source.
/// </summary>
public int SynchronizationSource { get; private set; }
/// <summary>
/// Get the name.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Get the identity.
/// </summary>
public int Identity { get; private set; }
/// <summary>
/// Get the variable data portion.
/// </summary>
public string Data { get; private set; }
public override void Parse(byte[] buffer, int offset)
{
base.Parse(buffer, offset);
SynchronizationSource = Utils.Convert4BytesToInt(buffer, offset + 4);
Name = Utils.ConvertBytesToString(buffer, offset + 8, 4);
Identity = Utils.Convert2BytesToInt(buffer, offset + 12);
int dataLength = Utils.Convert2BytesToInt(buffer, offset + 14);
if (dataLength != 0)
Data = Utils.ConvertBytesToString(buffer, offset + 16, dataLength);
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Application Specific.\n");
sb.AppendFormat("Version : {0} .\n", Version);
sb.AppendFormat("Padding : {0} .\n", Padding);
sb.AppendFormat("Report Count : {0} .\n", ReportCount);
sb.AppendFormat("PacketType: {0} .\n", Type);
sb.AppendFormat("Length : {0} .\n", Length);
sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource);
sb.AppendFormat("Name : {0} .\n", Name);
sb.AppendFormat("Identity : {0} .\n", Identity);
sb.AppendFormat("Data : {0} .\n", Data);
sb.AppendFormat(".\n");
return sb.ToString();
}
}
}

@ -0,0 +1,59 @@
using System.Collections.ObjectModel;
/*
Copyright (C) <2007-2016> <Kay Diefenthal>
SatIp.RtspSample is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SatIp.RtspSample is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Text;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
{
public class RtcpByePacket :RtcpPacket
{
public Collection<string> SynchronizationSources { get; private set; }
public string ReasonForLeaving { get; private set; }
public override void Parse(byte[] buffer, int offset)
{
base.Parse(buffer, offset);
SynchronizationSources = new Collection<string>();
int index = 4;
while (SynchronizationSources.Count < ReportCount)
{
SynchronizationSources.Add(Utils.ConvertBytesToString(buffer, offset + index, 4));
index += 4;
}
if (index < Length)
{
int reasonLength = buffer[offset + index];
ReasonForLeaving = Utils.ConvertBytesToString(buffer, offset + index + 1, reasonLength);
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("ByeBye .\n");
sb.AppendFormat("Version : {0} .\n", Version);
sb.AppendFormat("Padding : {0} .\n", Padding);
sb.AppendFormat("Report Count : {0} .\n", ReportCount);
sb.AppendFormat("PacketType: {0} .\n", Type);
sb.AppendFormat("Length : {0} .\n", Length);
sb.AppendFormat("SynchronizationSources : {0} .\n", SynchronizationSources);
sb.AppendFormat("ReasonForLeaving : {0} .\n", ReasonForLeaving);
sb.AppendFormat(".\n");
return sb.ToString();
}
}
}

@ -0,0 +1,203 @@
/*
Copyright (C) <2007-2016> <Kay Diefenthal>
SatIp.RtspSample is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SatIp.RtspSample is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MediaBrowser.Model.Logging;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
{
public class RtcpListener
{
private readonly ILogger _logger;
private Thread _rtcpListenerThread;
private AutoResetEvent _rtcpListenerThreadStopEvent = null;
private UdpClient _udpClient;
private IPEndPoint _multicastEndPoint;
private IPEndPoint _serverEndPoint;
private TransmissionMode _transmissionMode;
public RtcpListener(String address, int port, TransmissionMode mode,ILogger logger)
{
_logger = logger;
_transmissionMode = mode;
switch (mode)
{
case TransmissionMode.Unicast:
_udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse(address), port));
_serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
break;
case TransmissionMode.Multicast:
_multicastEndPoint = new IPEndPoint(IPAddress.Parse(address), port);
_serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
_udpClient = new UdpClient();
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
_udpClient.ExclusiveAddressUse = false;
_udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, port));
_udpClient.JoinMulticastGroup(_multicastEndPoint.Address);
break;
}
//StartRtcpListenerThread();
}
public void StartRtcpListenerThread()
{
// Kill the existing thread if it is in "zombie" state.
if (_rtcpListenerThread != null && !_rtcpListenerThread.IsAlive)
{
StopRtcpListenerThread();
}
if (_rtcpListenerThread == null)
{
_logger.Info("SAT>IP : starting new RTCP listener thread");
_rtcpListenerThreadStopEvent = new AutoResetEvent(false);
_rtcpListenerThread = new Thread(new ThreadStart(RtcpListenerThread));
_rtcpListenerThread.Name = string.Format("SAT>IP tuner RTCP listener");
_rtcpListenerThread.IsBackground = true;
_rtcpListenerThread.Priority = ThreadPriority.Lowest;
_rtcpListenerThread.Start();
}
}
public void StopRtcpListenerThread()
{
if (_rtcpListenerThread != null)
{
if (!_rtcpListenerThread.IsAlive)
{
_logger.Info("SAT>IP : aborting old RTCP listener thread");
_rtcpListenerThread.Abort();
}
else
{
_rtcpListenerThreadStopEvent.Set();
if (!_rtcpListenerThread.Join(400 * 2))
{
_logger.Info("SAT>IP : failed to join RTCP listener thread, aborting thread");
_rtcpListenerThread.Abort();
}
}
_rtcpListenerThread = null;
if (_rtcpListenerThreadStopEvent != null)
{
_rtcpListenerThreadStopEvent.Close();
_rtcpListenerThreadStopEvent = null;
}
}
}
private void RtcpListenerThread()
{
try
{
bool receivedGoodBye = false;
try
{
_udpClient.Client.ReceiveTimeout = 400;
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
while (!receivedGoodBye && !_rtcpListenerThreadStopEvent.WaitOne(1))
{
byte[] packets = _udpClient.Receive(ref serverEndPoint);
if (packets == null)
{
continue;
}
int offset = 0;
while (offset < packets.Length)
{
switch (packets[offset + 1])
{
case 200: //sr
var sr = new RtcpSenderReportPacket();
sr.Parse(packets, offset);
offset += sr.Length;
break;
case 201: //rr
var rr = new RtcpReceiverReportPacket();
rr.Parse(packets, offset);
offset += rr.Length;
break;
case 202: //sd
var sd = new RtcpSourceDescriptionPacket();
sd.Parse(packets, offset);
offset += sd.Length;
break;
case 203: // bye
var bye = new RtcpByePacket();
bye.Parse(packets, offset);
receivedGoodBye = true;
OnPacketReceived(new RtcpPacketReceivedArgs(bye));
offset += bye.Length;
break;
case 204: // app
var app = new RtcpAppPacket();
app.Parse(packets, offset);
OnPacketReceived(new RtcpPacketReceivedArgs(app));
offset += app.Length;
break;
}
}
}
}
finally
{
switch (_transmissionMode)
{
case TransmissionMode.Multicast:
_udpClient.DropMulticastGroup(_multicastEndPoint.Address);
_udpClient.Close();
break;
case TransmissionMode.Unicast:
_udpClient.Close();
break;
}
}
}
catch (ThreadAbortException)
{
}
catch (Exception ex)
{
_logger.Info(string.Format("SAT>IP : RTCP listener thread exception"), ex);
return;
}
_logger.Info("SAT>IP : RTCP listener thread stopping");
}
public delegate void PacketReceivedHandler(object sender, RtcpPacketReceivedArgs e);
public event PacketReceivedHandler PacketReceived;
public class RtcpPacketReceivedArgs : EventArgs
{
public Object Packet { get; private set; }
public RtcpPacketReceivedArgs(Object packet)
{
Packet = packet;
}
}
protected void OnPacketReceived(RtcpPacketReceivedArgs args)
{
if (PacketReceived != null)
{
PacketReceived(this, args);
}
}
}
}

@ -0,0 +1,37 @@
/*
Copyright (C) <2007-2016> <Kay Diefenthal>
SatIp.RtspSample is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SatIp.RtspSample is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
*/
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
{
public abstract class RtcpPacket
{
public int Version { get; private set; }
public bool Padding { get; private set; }
public int ReportCount { get; private set; }
public int Type { get; private set; }
public int Length { get; private set; }
public virtual void Parse(byte[] buffer, int offset)
{
Version = buffer[offset] >> 6;
Padding = (buffer[offset] & 0x20) != 0;
ReportCount = buffer[offset] & 0x1f;
Type = buffer[offset + 1];
Length = (Utils.Convert2BytesToInt(buffer, offset + 2) * 4) + 4;
}
}
}

@ -0,0 +1,68 @@
using System.Collections.ObjectModel;
/*
Copyright (C) <2007-2016> <Kay Diefenthal>
SatIp.RtspSample is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SatIp.RtspSample is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Text;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
{
public class RtcpReceiverReportPacket :RtcpPacket
{
public string SynchronizationSource { get; private set; }
public Collection<ReportBlock> ReportBlocks { get; private set; }
public byte[] ProfileExtension { get; private set; }
public override void Parse(byte[] buffer, int offset)
{
base.Parse(buffer, offset);
SynchronizationSource = Utils.ConvertBytesToString(buffer, offset + 4, 4);
ReportBlocks = new Collection<ReportBlock>();
int index = 8;
while (ReportBlocks.Count < ReportCount)
{
ReportBlock reportBlock = new ReportBlock();
reportBlock.Process(buffer, offset + index);
ReportBlocks.Add(reportBlock);
index += reportBlock.BlockLength;
}
if (index < Length)
{
ProfileExtension = new byte[Length - index];
for (int extensionIndex = 0; index < Length; index++)
{
ProfileExtension[extensionIndex] = buffer[offset + index];
extensionIndex++;
}
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Receiver Report.\n");
sb.AppendFormat("Version : {0} .\n", Version);
sb.AppendFormat("Padding : {0} .\n", Padding);
sb.AppendFormat("Report Count : {0} .\n", ReportCount);
sb.AppendFormat("PacketType: {0} .\n", Type);
sb.AppendFormat("Length : {0} .\n", Length);
sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource);
sb.AppendFormat(".\n");
return sb.ToString();
}
}
}

@ -0,0 +1,105 @@
using System.Collections.ObjectModel;
/*
Copyright (C) <2007-2016> <Kay Diefenthal>
SatIp.RtspSample is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SatIp.RtspSample is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Text;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
{
public class RtcpSenderReportPacket : RtcpPacket
{
#region Properties
/// <summary>
/// Get the synchronization source.
/// </summary>
public int SynchronizationSource { get; private set; }
/// <summary>
/// Get the NPT timestamp.
/// </summary>
public long NPTTimeStamp { get; private set; }
/// <summary>
/// Get the RTP timestamp.
/// </summary>
public int RTPTimeStamp { get; private set; }
/// <summary>
/// Get the packet count.
/// </summary>
public int SenderPacketCount { get; private set; }
/// <summary>
/// Get the octet count.
/// </summary>
public int SenderOctetCount { get; private set; }
/// <summary>
/// Get the list of report blocks.
/// </summary>
public Collection<ReportBlock> ReportBlocks { get; private set; }
/// <summary>
/// Get the profile extension data.
/// </summary>
public byte[] ProfileExtension { get; private set; }
#endregion
public override void Parse(byte[] buffer, int offset)
{
base.Parse(buffer, offset);
SynchronizationSource = Utils.Convert4BytesToInt(buffer, offset + 4);
NPTTimeStamp = Utils.Convert8BytesToLong(buffer, offset + 8);
RTPTimeStamp = Utils.Convert4BytesToInt(buffer, offset + 16);
SenderPacketCount = Utils.Convert4BytesToInt(buffer, offset + 20);
SenderOctetCount = Utils.Convert4BytesToInt(buffer, offset + 24);
ReportBlocks = new Collection<ReportBlock>();
int index = 28;
while (ReportBlocks.Count < ReportCount)
{
ReportBlock reportBlock = new ReportBlock();
reportBlock.Process(buffer, offset + index);
ReportBlocks.Add(reportBlock);
index += reportBlock.BlockLength;
}
if (index < Length)
{
ProfileExtension = new byte[Length - index];
for (int extensionIndex = 0; index < Length; index++)
{
ProfileExtension[extensionIndex] = buffer[offset + index];
extensionIndex++;
}
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Sender Report.\n");
sb.AppendFormat("Version : {0} .\n", Version);
sb.AppendFormat("Padding : {0} .\n", Padding);
sb.AppendFormat("Report Count : {0} .\n", ReportCount);
sb.AppendFormat("PacketType: {0} .\n", Type);
sb.AppendFormat("Length : {0} .\n", Length);
sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource);
sb.AppendFormat("NTP Timestamp : {0} .\n", Utils.NptTimestampToDateTime(NPTTimeStamp));
sb.AppendFormat("RTP Timestamp : {0} .\n", RTPTimeStamp);
sb.AppendFormat("Sender PacketCount : {0} .\n", SenderPacketCount);
sb.AppendFormat("Sender Octet Count : {0} .\n", SenderOctetCount);
sb.AppendFormat(".\n");
return sb.ToString();
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save