This commit is contained in:
Luke Pulverenti 2016-10-12 15:44:48 -04:00
commit 673e2c9d0f
337 changed files with 10368 additions and 6073 deletions

View File

@ -829,18 +829,7 @@ namespace Emby.Drawing
// Run the enhancers sequentially in order of priority // Run the enhancers sequentially in order of priority
foreach (var enhancer in imageEnhancers) foreach (var enhancer in imageEnhancers)
{ {
var typeName = enhancer.GetType().Name; await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
try
{
await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.ErrorException("{0} failed enhancing {1}", ex, typeName, item.Name);
throw;
}
// Feed the output into the next enhancer as input // Feed the output into the next enhancer as input
inputPath = outputPath; inputPath = outputPath;

View File

@ -8,6 +8,7 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session; using MediaBrowser.Model.Session;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -15,6 +16,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api namespace MediaBrowser.Api
{ {
@ -43,7 +45,13 @@ namespace MediaBrowser.Api
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IMediaSourceManager _mediaSourceManager; private readonly IMediaSourceManager _mediaSourceManager;
public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1); /// <summary>
/// The active transcoding jobs
/// </summary>
private readonly List<TranscodingJob> _activeTranscodingJobs = new List<TranscodingJob>();
private readonly Dictionary<string, SemaphoreSlim> _transcodingLocks =
new Dictionary<string, SemaphoreSlim>();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ApiEntryPoint" /> class. /// Initializes a new instance of the <see cref="ApiEntryPoint" /> class.
@ -66,6 +74,21 @@ namespace MediaBrowser.Api
_sessionManager.PlaybackStart += _sessionManager_PlaybackStart; _sessionManager.PlaybackStart += _sessionManager_PlaybackStart;
} }
public SemaphoreSlim GetTranscodingLock(string outputPath)
{
lock (_transcodingLocks)
{
SemaphoreSlim result;
if (!_transcodingLocks.TryGetValue(outputPath, out result))
{
result = new SemaphoreSlim(1, 1);
_transcodingLocks[outputPath] = result;
}
return result;
}
}
private void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e) private void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
{ {
if (!string.IsNullOrWhiteSpace(e.PlaySessionId)) if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
@ -147,11 +170,6 @@ namespace MediaBrowser.Api
} }
} }
/// <summary>
/// The active transcoding jobs
/// </summary>
private readonly List<TranscodingJob> _activeTranscodingJobs = new List<TranscodingJob>();
/// <summary> /// <summary>
/// Called when [transcode beginning]. /// Called when [transcode beginning].
/// </summary> /// </summary>
@ -187,7 +205,8 @@ namespace MediaBrowser.Api
CancellationTokenSource = cancellationTokenSource, CancellationTokenSource = cancellationTokenSource,
Id = transcodingJobId, Id = transcodingJobId,
PlaySessionId = playSessionId, PlaySessionId = playSessionId,
LiveStreamId = liveStreamId LiveStreamId = liveStreamId,
MediaSource = state.MediaSource
}; };
_activeTranscodingJobs.Add(job); _activeTranscodingJobs.Add(job);
@ -256,6 +275,11 @@ namespace MediaBrowser.Api
} }
} }
lock (_transcodingLocks)
{
_transcodingLocks.Remove(path);
}
if (!string.IsNullOrWhiteSpace(state.Request.DeviceId)) if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
{ {
_sessionManager.ClearTranscodingInfo(state.Request.DeviceId); _sessionManager.ClearTranscodingInfo(state.Request.DeviceId);
@ -281,6 +305,14 @@ namespace MediaBrowser.Api
} }
} }
public TranscodingJob GetTranscodingJob(string playSessionId)
{
lock (_activeTranscodingJobs)
{
return _activeTranscodingJobs.FirstOrDefault(j => string.Equals(j.PlaySessionId, playSessionId, StringComparison.OrdinalIgnoreCase));
}
}
/// <summary> /// <summary>
/// Called when [transcode begin request]. /// Called when [transcode begin request].
/// </summary> /// </summary>
@ -487,6 +519,11 @@ namespace MediaBrowser.Api
} }
} }
lock (_transcodingLocks)
{
_transcodingLocks.Remove(job.Path);
}
lock (job.ProcessLock) lock (job.ProcessLock)
{ {
if (job.TranscodingThrottler != null) if (job.TranscodingThrottler != null)
@ -530,7 +567,7 @@ namespace MediaBrowser.Api
{ {
try try
{ {
await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false); await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -656,6 +693,7 @@ namespace MediaBrowser.Api
/// Gets or sets the path. /// Gets or sets the path.
/// </summary> /// </summary>
/// <value>The path.</value> /// <value>The path.</value>
public MediaSourceInfo MediaSource { get; set; }
public string Path { get; set; } public string Path { get; set; }
/// <summary> /// <summary>
/// Gets or sets the type. /// Gets or sets the type.
@ -751,12 +789,12 @@ namespace MediaBrowser.Api
{ {
if (KillTimer == null) if (KillTimer == null)
{ {
Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer = new Timer(callback, this, intervalMs, Timeout.Infinite); KillTimer = new Timer(callback, this, intervalMs, Timeout.Infinite);
} }
else else
{ {
Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer.Change(intervalMs, Timeout.Infinite); KillTimer.Change(intervalMs, Timeout.Infinite);
} }
} }
@ -775,7 +813,7 @@ namespace MediaBrowser.Api
{ {
var intervalMs = PingTimeout; var intervalMs = PingTimeout;
Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer.Change(intervalMs, Timeout.Infinite); KillTimer.Change(intervalMs, Timeout.Infinite);
} }
} }

View File

@ -7,6 +7,8 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
namespace MediaBrowser.Api.Dlna namespace MediaBrowser.Api.Dlna
{ {
@ -109,13 +111,15 @@ namespace MediaBrowser.Api.Dlna
private readonly IMediaReceiverRegistrar _mediaReceiverRegistrar; private readonly IMediaReceiverRegistrar _mediaReceiverRegistrar;
private const string XMLContentType = "text/xml; charset=UTF-8"; private const string XMLContentType = "text/xml; charset=UTF-8";
private readonly IMemoryStreamProvider _memoryStreamProvider;
public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IMediaReceiverRegistrar mediaReceiverRegistrar) public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IMediaReceiverRegistrar mediaReceiverRegistrar, IMemoryStreamProvider memoryStreamProvider)
{ {
_dlnaManager = dlnaManager; _dlnaManager = dlnaManager;
_contentDirectory = contentDirectory; _contentDirectory = contentDirectory;
_connectionManager = connectionManager; _connectionManager = connectionManager;
_mediaReceiverRegistrar = mediaReceiverRegistrar; _mediaReceiverRegistrar = mediaReceiverRegistrar;
_memoryStreamProvider = memoryStreamProvider;
} }
public object Get(GetDescriptionXml request) public object Get(GetDescriptionXml request)
@ -201,7 +205,7 @@ namespace MediaBrowser.Api.Dlna
{ {
using (var response = _dlnaManager.GetIcon(request.Filename)) using (var response = _dlnaManager.GetIcon(request.Filename))
{ {
using (var ms = new MemoryStream()) using (var ms = _memoryStreamProvider.CreateNew())
{ {
response.Stream.CopyTo(ms); response.Stream.CopyTo(ms);

View File

@ -4,6 +4,7 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using ServiceStack; using ServiceStack;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -104,7 +105,13 @@ namespace MediaBrowser.Api
MediaTypes = request.GetMediaTypes(), MediaTypes = request.GetMediaTypes(),
IncludeItemTypes = request.GetIncludeItemTypes(), IncludeItemTypes = request.GetIncludeItemTypes(),
Recursive = true, Recursive = true,
EnableTotalRecordCount = false EnableTotalRecordCount = false,
DtoOptions = new Controller.Dto.DtoOptions
{
Fields = new List<ItemFields> { ItemFields.Genres, ItemFields.Tags },
EnableImages = false,
EnableUserData = false
}
}; };
return query; return query;

View File

@ -200,6 +200,8 @@ namespace MediaBrowser.Api
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
var dtoOptions = GetDtoOptions(request);
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{ {
Limit = request.Limit, Limit = request.Limit,
@ -207,12 +209,11 @@ namespace MediaBrowser.Api
{ {
typeof(Game).Name typeof(Game).Name
}, },
SimilarTo = item SimilarTo = item,
DtoOptions = dtoOptions
}).ToList(); }).ToList();
var dtoOptions = GetDtoOptions(request);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(), Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),

View File

@ -273,7 +273,8 @@ namespace MediaBrowser.Api.Images
{ {
var result = await _httpClient.GetResponse(new HttpRequestOptions var result = await _httpClient.GetResponse(new HttpRequestOptions
{ {
Url = url Url = url,
BufferContent = false
}).ConfigureAwait(false); }).ConfigureAwait(false);

View File

@ -243,11 +243,7 @@ namespace MediaBrowser.Api
hasBudget.Revenue = request.Revenue; hasBudget.Revenue = request.Revenue;
} }
var hasOriginalTitle = item as IHasOriginalTitle; item.OriginalTitle = string.IsNullOrWhiteSpace(request.OriginalTitle) ? null : request.OriginalTitle;
if (hasOriginalTitle != null)
{
hasOriginalTitle.OriginalTitle = hasOriginalTitle.OriginalTitle;
}
var hasCriticRating = item as IHasCriticRating; var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null) if (hasCriticRating != null)
@ -278,10 +274,9 @@ namespace MediaBrowser.Api
item.Tags = request.Tags; item.Tags = request.Tags;
var hasTaglines = item as IHasTaglines; if (request.Taglines != null)
if (hasTaglines != null)
{ {
hasTaglines.Taglines = request.Taglines; item.Tagline = request.Taglines.FirstOrDefault();
} }
var hasShortOverview = item as IHasShortOverview; var hasShortOverview = item as IHasShortOverview;
@ -308,8 +303,6 @@ namespace MediaBrowser.Api
item.OfficialRating = string.IsNullOrWhiteSpace(request.OfficialRating) ? null : request.OfficialRating; item.OfficialRating = string.IsNullOrWhiteSpace(request.OfficialRating) ? null : request.OfficialRating;
item.CustomRating = request.CustomRating; item.CustomRating = request.CustomRating;
SetProductionLocations(item, request);
item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode; item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
item.PreferredMetadataLanguage = request.PreferredMetadataLanguage; item.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
@ -417,23 +410,5 @@ namespace MediaBrowser.Api
series.AirTime = request.AirTime; series.AirTime = request.AirTime;
} }
} }
private void SetProductionLocations(BaseItem item, BaseItemDto request)
{
var hasProductionLocations = item as IHasProductionLocations;
if (hasProductionLocations != null)
{
hasProductionLocations.ProductionLocations = request.ProductionLocations;
}
var person = item as Person;
if (person != null)
{
person.PlaceOfBirth = request.ProductionLocations == null
? null
: request.ProductionLocations.FirstOrDefault();
}
}
} }
} }

View File

@ -1,30 +0,0 @@
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Net;
using ServiceStack;
using System.Linq;
namespace MediaBrowser.Api.Library
{
[Route("/Providers/Chapters", "GET")]
public class GetChapterProviders : IReturnVoid
{
}
[Authenticated]
public class ChapterService : BaseApiService
{
private readonly IChapterManager _chapterManager;
public ChapterService(IChapterManager chapterManager)
{
_chapterManager = chapterManager;
}
public object Get(GetChapterProviders request)
{
var result = _chapterManager.GetProviders().ToList();
return ToOptimizedResult(result);
}
}
}

View File

@ -835,14 +835,14 @@ namespace MediaBrowser.Api.Library
: (Folder)_libraryManager.RootFolder) : (Folder)_libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id); : _libraryManager.GetItemById(request.Id);
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null) while (item.ThemeSongIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
{ {
item = item.GetParent(); item = item.GetParent();
} }
var dtoOptions = GetDtoOptions(request); var dtoOptions = GetDtoOptions(request);
var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById) var dtos = item.ThemeSongIds.Select(_libraryManager.GetItemById)
.Where(i => i != null) .Where(i => i != null)
.OrderBy(i => i.SortName) .OrderBy(i => i.SortName)
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item)); .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
@ -879,14 +879,14 @@ namespace MediaBrowser.Api.Library
: (Folder)_libraryManager.RootFolder) : (Folder)_libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id); : _libraryManager.GetItemById(request.Id);
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null) while (item.ThemeVideoIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
{ {
item = item.GetParent(); item = item.GetParent();
} }
var dtoOptions = GetDtoOptions(request); var dtoOptions = GetDtoOptions(request);
var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById) var dtos = item.ThemeVideoIds.Select(_libraryManager.GetItemById)
.Where(i => i != null) .Where(i => i != null)
.OrderBy(i => i.SortName) .OrderBy(i => i.SortName)
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item)); .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
@ -901,30 +901,6 @@ namespace MediaBrowser.Api.Library
}; };
} }
private List<Guid> GetThemeVideoIds(BaseItem item)
{
var i = item as IHasThemeMedia;
if (i != null)
{
return i.ThemeVideoIds;
}
return new List<Guid>();
}
private List<Guid> GetThemeSongIds(BaseItem item)
{
var i = item as IHasThemeMedia;
if (i != null)
{
return i.ThemeSongIds;
}
return new List<Guid>();
}
private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly CultureInfo _usCulture = new CultureInfo("en-US");
public object Get(GetYearIndex request) public object Get(GetYearIndex request)

View File

@ -112,6 +112,8 @@ namespace MediaBrowser.Api.Library
/// <value>The name.</value> /// <value>The name.</value>
public string Path { get; set; } public string Path { get; set; }
public MediaPathInfo PathInfo { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether [refresh library]. /// Gets or sets a value indicating whether [refresh library].
/// </summary> /// </summary>
@ -119,6 +121,18 @@ namespace MediaBrowser.Api.Library
public bool RefreshLibrary { get; set; } public bool RefreshLibrary { get; set; }
} }
[Route("/Library/VirtualFolders/Paths/Update", "POST")]
public class UpdateMediaPath : IReturnVoid
{
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }
public MediaPathInfo PathInfo { get; set; }
}
[Route("/Library/VirtualFolders/Paths", "DELETE")] [Route("/Library/VirtualFolders/Paths", "DELETE")]
public class RemoveMediaPath : IReturnVoid public class RemoveMediaPath : IReturnVoid
{ {
@ -212,7 +226,12 @@ namespace MediaBrowser.Api.Library
{ {
var libraryOptions = request.LibraryOptions ?? new LibraryOptions(); var libraryOptions = request.LibraryOptions ?? new LibraryOptions();
_libraryManager.AddVirtualFolder(request.Name, request.CollectionType, request.Paths, libraryOptions, request.RefreshLibrary); if (request.Paths != null && request.Paths.Length > 0)
{
libraryOptions.PathInfos = request.Paths.Select(i => new MediaPathInfo { Path = i }).ToArray();
}
_libraryManager.AddVirtualFolder(request.Name, request.CollectionType, libraryOptions, request.RefreshLibrary);
} }
/// <summary> /// <summary>
@ -308,7 +327,16 @@ namespace MediaBrowser.Api.Library
try try
{ {
_libraryManager.AddMediaPath(request.Name, request.Path); var mediaPath = request.PathInfo;
if (mediaPath == null)
{
mediaPath = new MediaPathInfo
{
Path = request.Path
};
}
_libraryManager.AddMediaPath(request.Name, mediaPath);
} }
finally finally
{ {
@ -332,6 +360,20 @@ namespace MediaBrowser.Api.Library
} }
} }
/// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Post(UpdateMediaPath request)
{
if (string.IsNullOrWhiteSpace(request.Name))
{
throw new ArgumentNullException("request");
}
_libraryManager.UpdateMediaPath(request.Name, request.PathInfo);
}
/// <summary> /// <summary>
/// Deletes the specified request. /// Deletes the specified request.
/// </summary> /// </summary>

View File

@ -12,9 +12,14 @@ using ServiceStack;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Api.Playback.Progressive;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
namespace MediaBrowser.Api.LiveTv namespace MediaBrowser.Api.LiveTv
{ {
@ -44,6 +49,21 @@ namespace MediaBrowser.Api.LiveTv
[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")] [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; } public int? StartIndex { get; set; }
[ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsMovie { get; set; }
[ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsSeries { get; set; }
[ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsNews { get; set; }
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsKids { get; set; }
[ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsSports { get; set; }
/// <summary> /// <summary>
/// The maximum number of items to return /// The maximum number of items to return
/// </summary> /// </summary>
@ -85,6 +105,26 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; } public bool? EnableUserData { get; set; }
public string SortBy { get; set; }
public SortOrder? SortOrder { get; set; }
/// <summary>
/// Gets the order by.
/// </summary>
/// <returns>IEnumerable{ItemSortBy}.</returns>
public string[] GetOrderBy()
{
var val = SortBy;
if (string.IsNullOrEmpty(val))
{
return new string[] { };
}
return val.Split(',');
}
public GetChannels() public GetChannels()
{ {
AddCurrentProgram = true; AddCurrentProgram = true;
@ -159,6 +199,7 @@ namespace MediaBrowser.Api.LiveTv
public bool? IsSeries { get; set; } public bool? IsSeries { get; set; }
public bool? IsKids { get; set; } public bool? IsKids { get; set; }
public bool? IsSports { get; set; } public bool? IsSports { get; set; }
public bool? IsNews { get; set; }
public GetRecordings() public GetRecordings()
{ {
@ -275,6 +316,8 @@ namespace MediaBrowser.Api.LiveTv
public string SeriesTimerId { get; set; } public string SeriesTimerId { get; set; }
public bool? IsActive { get; set; } public bool? IsActive { get; set; }
public bool? IsScheduled { get; set; }
} }
[Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")] [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")]
@ -305,6 +348,12 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsMovie { get; set; } public bool? IsMovie { get; set; }
[ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsSeries { get; set; }
[ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsNews { get; set; }
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsKids { get; set; } public bool? IsKids { get; set; }
@ -340,6 +389,8 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; } public bool? EnableUserData { get; set; }
public string SeriesTimerId { get; set; }
/// <summary> /// <summary>
/// Fields to return within the items, in addition to basic information /// Fields to return within the items, in addition to basic information
/// </summary> /// </summary>
@ -376,15 +427,21 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? HasAired { get; set; } public bool? HasAired { get; set; }
[ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsSports { get; set; } public bool? IsSeries { get; set; }
[ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsMovie { get; set; } public bool? IsMovie { get; set; }
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsNews { get; set; }
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsKids { get; set; } public bool? IsKids { get; set; }
[ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsSports { get; set; }
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableImages { get; set; } public bool? EnableImages { get; set; }
@ -613,16 +670,30 @@ namespace MediaBrowser.Api.LiveTv
} }
[Route("/LiveTv/LiveStreamFiles/{Id}/stream.{Container}", "GET", Summary = "Gets a live tv channel")]
public class GetLiveStreamFile
{
public string Id { get; set; }
public string Container { get; set; }
}
[Route("/LiveTv/LiveRecordings/{Id}/stream", "GET", Summary = "Gets a live tv channel")]
public class GetLiveRecordingFile
{
public string Id { get; set; }
}
public class LiveTvService : BaseApiService public class LiveTvService : BaseApiService
{ {
private readonly ILiveTvManager _liveTvManager; private readonly ILiveTvManager _liveTvManager;
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly IDtoService _dtoService; private readonly IDtoService _dtoService;
private readonly IFileSystem _fileSystem;
public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService) public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem)
{ {
_liveTvManager = liveTvManager; _liveTvManager = liveTvManager;
_userManager = userManager; _userManager = userManager;
@ -630,6 +701,41 @@ namespace MediaBrowser.Api.LiveTv
_httpClient = httpClient; _httpClient = httpClient;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_dtoService = dtoService; _dtoService = dtoService;
_fileSystem = fileSystem;
}
public async Task<object> Get(GetLiveRecordingFile request)
{
var path = EmbyTV.Current.GetActiveRecordingPath(request.Id);
if (path == null)
{
throw new FileNotFoundException();
}
var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path);
var streamSource = new ProgressiveFileCopier(_fileSystem, path, outputHeaders, null, Logger, CancellationToken.None)
{
AllowEndOfFile = false
};
return ResultFactory.GetAsyncStreamWriter(streamSource);
}
public async Task<object> Get(GetLiveStreamFile request)
{
var directStreamProvider = (await EmbyTV.Current.GetLiveStream(request.Id).ConfigureAwait(false)) as IDirectStreamProvider;
var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container);
var streamSource = new ProgressiveFileCopier(directStreamProvider, outputHeaders, null, Logger, CancellationToken.None)
{
AllowEndOfFile = false
};
return ResultFactory.GetAsyncStreamWriter(streamSource);
} }
public object Get(GetDefaultListingProvider request) public object Get(GetDefaultListingProvider request)
@ -702,7 +808,8 @@ namespace MediaBrowser.Api.LiveTv
var response = await _httpClient.Get(new HttpRequestOptions var response = await _httpClient.Get(new HttpRequestOptions
{ {
Url = "https://json.schedulesdirect.org/20141201/available/countries" Url = "https://json.schedulesdirect.org/20141201/available/countries",
BufferContent = false
}).ConfigureAwait(false); }).ConfigureAwait(false);
@ -786,6 +893,13 @@ namespace MediaBrowser.Api.LiveTv
IsLiked = request.IsLiked, IsLiked = request.IsLiked,
IsDisliked = request.IsDisliked, IsDisliked = request.IsDisliked,
EnableFavoriteSorting = request.EnableFavoriteSorting, EnableFavoriteSorting = request.EnableFavoriteSorting,
IsMovie = request.IsMovie,
IsSeries = request.IsSeries,
IsNews = request.IsNews,
IsKids = request.IsKids,
IsSports = request.IsSports,
SortBy = request.GetOrderBy(),
SortOrder = request.SortOrder ?? SortOrder.Ascending,
AddCurrentProgram = request.AddCurrentProgram AddCurrentProgram = request.AddCurrentProgram
}, CancellationToken.None).ConfigureAwait(false); }, CancellationToken.None).ConfigureAwait(false);
@ -868,9 +982,12 @@ namespace MediaBrowser.Api.LiveTv
query.Limit = request.Limit; query.Limit = request.Limit;
query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
query.SortOrder = request.SortOrder; query.SortOrder = request.SortOrder;
query.IsNews = request.IsNews;
query.IsMovie = request.IsMovie; query.IsMovie = request.IsMovie;
query.IsSeries = request.IsSeries;
query.IsKids = request.IsKids; query.IsKids = request.IsKids;
query.IsSports = request.IsSports; query.IsSports = request.IsSports;
query.SeriesTimerId = request.SeriesTimerId;
query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
@ -886,8 +1003,10 @@ namespace MediaBrowser.Api.LiveTv
IsAiring = request.IsAiring, IsAiring = request.IsAiring,
Limit = request.Limit, Limit = request.Limit,
HasAired = request.HasAired, HasAired = request.HasAired,
IsSeries = request.IsSeries,
IsMovie = request.IsMovie, IsMovie = request.IsMovie,
IsKids = request.IsKids, IsKids = request.IsKids,
IsNews = request.IsNews,
IsSports = request.IsSports, IsSports = request.IsSports,
EnableTotalRecordCount = request.EnableTotalRecordCount EnableTotalRecordCount = request.EnableTotalRecordCount
}; };
@ -919,6 +1038,7 @@ namespace MediaBrowser.Api.LiveTv
IsInProgress = request.IsInProgress, IsInProgress = request.IsInProgress,
EnableTotalRecordCount = request.EnableTotalRecordCount, EnableTotalRecordCount = request.EnableTotalRecordCount,
IsMovie = request.IsMovie, IsMovie = request.IsMovie,
IsNews = request.IsNews,
IsSeries = request.IsSeries, IsSeries = request.IsSeries,
IsKids = request.IsKids, IsKids = request.IsKids,
IsSports = request.IsSports IsSports = request.IsSports
@ -975,7 +1095,8 @@ namespace MediaBrowser.Api.LiveTv
{ {
ChannelId = request.ChannelId, ChannelId = request.ChannelId,
SeriesTimerId = request.SeriesTimerId, SeriesTimerId = request.SeriesTimerId,
IsActive = request.IsActive IsActive = request.IsActive,
IsScheduled = request.IsScheduled
}, CancellationToken.None).ConfigureAwait(false); }, CancellationToken.None).ConfigureAwait(false);

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -11,9 +11,10 @@
<AssemblyName>MediaBrowser.Api</AssemblyName> <AssemblyName>MediaBrowser.Api</AssemblyName>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<ReleaseVersion> <ReleaseVersion>
</ReleaseVersion> </ReleaseVersion>
<TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -79,7 +80,6 @@
<Compile Include="Dlna\DlnaService.cs" /> <Compile Include="Dlna\DlnaService.cs" />
<Compile Include="FilterService.cs" /> <Compile Include="FilterService.cs" />
<Compile Include="IHasDtoOptions.cs" /> <Compile Include="IHasDtoOptions.cs" />
<Compile Include="Library\ChapterService.cs" />
<Compile Include="Playback\MediaInfoService.cs" /> <Compile Include="Playback\MediaInfoService.cs" />
<Compile Include="Playback\TranscodingThrottler.cs" /> <Compile Include="Playback\TranscodingThrottler.cs" />
<Compile Include="PlaylistService.cs" /> <Compile Include="PlaylistService.cs" />
@ -198,6 +198,10 @@
<Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project> <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name> <Name>MediaBrowser.Model</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
<Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
<Name>MediaBrowser.Server.Implementations</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />

View File

@ -156,18 +156,19 @@ namespace MediaBrowser.Api.Movies
itemTypes.Add(typeof(LiveTvProgram).Name); itemTypes.Add(typeof(LiveTvProgram).Name);
} }
var dtoOptions = GetDtoOptions(request);
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{ {
Limit = request.Limit, Limit = request.Limit,
IncludeItemTypes = itemTypes.ToArray(), IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true, IsMovie = true,
SimilarTo = item, SimilarTo = item,
EnableGroupByMetadataKey = true EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
}).ToList(); }).ToList();
var dtoOptions = GetDtoOptions(request);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(), Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
@ -198,7 +199,8 @@ namespace MediaBrowser.Api.Movies
Limit = 7, Limit = 7,
ParentId = parentIdGuid, ParentId = parentIdGuid,
Recursive = true, Recursive = true,
IsPlayed = true IsPlayed = true,
DtoOptions = dtoOptions
}; };
var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList(); var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList();
@ -221,7 +223,8 @@ namespace MediaBrowser.Api.Movies
ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(), ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(),
EnableGroupByMetadataKey = true, EnableGroupByMetadataKey = true,
ParentId = parentIdGuid, ParentId = parentIdGuid,
Recursive = true Recursive = true,
DtoOptions = dtoOptions
}).ToList(); }).ToList();
@ -302,7 +305,8 @@ namespace MediaBrowser.Api.Movies
PersonTypes = new[] { PersonType.Director }, PersonTypes = new[] { PersonType.Director },
IncludeItemTypes = itemTypes.ToArray(), IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true, IsMovie = true,
EnableGroupByMetadataKey = true EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
}).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
.Take(itemLimit) .Take(itemLimit)
@ -339,7 +343,8 @@ namespace MediaBrowser.Api.Movies
Limit = itemLimit + 2, Limit = itemLimit + 2,
IncludeItemTypes = itemTypes.ToArray(), IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true, IsMovie = true,
EnableGroupByMetadataKey = true EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
}).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
.Take(itemLimit) .Take(itemLimit)
@ -375,7 +380,8 @@ namespace MediaBrowser.Api.Movies
IncludeItemTypes = itemTypes.ToArray(), IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true, IsMovie = true,
SimilarTo = item, SimilarTo = item,
EnableGroupByMetadataKey = true EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
}).ToList(); }).ToList();

View File

@ -46,7 +46,7 @@ namespace MediaBrowser.Api
/// </summary> /// </summary>
/// <value>The name.</value> /// <value>The name.</value>
[ApiMember(Name = "PackageType", Description = "Optional package type filter (System/UserInstalled)", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "PackageType", Description = "Optional package type filter (System/UserInstalled)", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public PackageType? PackageType { get; set; } public string PackageType { get; set; }
[ApiMember(Name = "TargetSystems", Description = "Optional. Filter by target system type. Allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET", AllowMultiple = true)] [ApiMember(Name = "TargetSystems", Description = "Optional. Filter by target system type. Allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET", AllowMultiple = true)]
public string TargetSystems { get; set; } public string TargetSystems { get; set; }
@ -72,7 +72,7 @@ namespace MediaBrowser.Api
/// </summary> /// </summary>
/// <value>The name.</value> /// <value>The name.</value>
[ApiMember(Name = "PackageType", Description = "Package type filter (System/UserInstalled)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "PackageType", Description = "Package type filter (System/UserInstalled)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public PackageType PackageType { get; set; } public string PackageType { get; set; }
} }
/// <summary> /// <summary>
@ -149,12 +149,12 @@ namespace MediaBrowser.Api
{ {
var result = new List<PackageVersionInfo>(); var result = new List<PackageVersionInfo>();
if (request.PackageType == PackageType.UserInstalled || request.PackageType == PackageType.All) if (string.Equals(request.PackageType, "UserInstalled", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
{ {
result.AddRange(_installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, false, CancellationToken.None).Result.ToList()); result.AddRange(_installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, false, CancellationToken.None).Result.ToList());
} }
else if (request.PackageType == PackageType.System || request.PackageType == PackageType.All) else if (string.Equals(request.PackageType, "System", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
{ {
var updateCheckResult = _appHost.CheckForApplicationUpdate(CancellationToken.None, new Progress<double>()).Result; var updateCheckResult = _appHost.CheckForApplicationUpdate(CancellationToken.None, new Progress<double>()).Result;

View File

@ -367,6 +367,8 @@ namespace MediaBrowser.Api.Playback
{ {
param += " -crf 23"; param += " -crf 23";
} }
param += " -tune zerolatency";
} }
else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase)) else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
@ -461,13 +463,15 @@ namespace MediaBrowser.Api.Playback
var level = NormalizeTranscodingLevel(state.OutputVideoCodec, state.VideoRequest.Level); var level = NormalizeTranscodingLevel(state.OutputVideoCodec, state.VideoRequest.Level);
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format // h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
// also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
{ {
switch (level) switch (level)
{ {
case "30": case "30":
param += " -level 3"; param += " -level 3.0";
break; break;
case "31": case "31":
param += " -level 3.1"; param += " -level 3.1";
@ -476,7 +480,7 @@ namespace MediaBrowser.Api.Playback
param += " -level 3.2"; param += " -level 3.2";
break; break;
case "40": case "40":
param += " -level 4"; param += " -level 4.0";
break; break;
case "41": case "41":
param += " -level 4.1"; param += " -level 4.1";
@ -485,7 +489,7 @@ namespace MediaBrowser.Api.Playback
param += " -level 4.2"; param += " -level 4.2";
break; break;
case "50": case "50":
param += " -level 5"; param += " -level 5.0";
break; break;
case "51": case "51":
param += " -level 5.1"; param += " -level 5.1";
@ -767,7 +771,20 @@ namespace MediaBrowser.Api.Playback
if (request.Width.HasValue || request.Height.HasValue || request.MaxHeight.HasValue || request.MaxWidth.HasValue) if (request.Width.HasValue || request.Height.HasValue || request.MaxHeight.HasValue || request.MaxWidth.HasValue)
{ {
outputSizeParam = GetOutputSizeParam(state, outputVideoCodec).TrimEnd('"'); outputSizeParam = GetOutputSizeParam(state, outputVideoCodec).TrimEnd('"');
outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase));
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase));
}
else
{
outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase));
}
}
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && outputSizeParam.Length == 0)
{
outputSizeParam = ",format=nv12|vaapi,hwupload";
} }
var videoSizeParam = string.Empty; var videoSizeParam = string.Empty;
@ -802,10 +819,10 @@ namespace MediaBrowser.Api.Playback
{ {
if (state.PlayableStreamFileNames.Count > 0) if (state.PlayableStreamFileNames.Count > 0)
{ {
return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
} }
return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol); return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol);
} }
/// <summary> /// <summary>
@ -1022,7 +1039,15 @@ namespace MediaBrowser.Api.Playback
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions(); var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
if (GetVideoEncoder(state).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) if (GetVideoEncoder(state).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1)
{ {
arg = "-hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
var hwOutputFormat = "vaapi";
if (hasGraphicalSubs)
{
hwOutputFormat = "yuv420p";
}
arg = "-hwaccel vaapi -hwaccel_output_format " + hwOutputFormat + " -vaapi_device " + encodingOptions.VaapiDevice + " " + arg;
} }
} }
@ -1219,7 +1244,7 @@ namespace MediaBrowser.Api.Playback
private void StartThrottler(StreamState state, TranscodingJob transcodingJob) private void StartThrottler(StreamState state, TranscodingJob transcodingJob)
{ {
if (EnableThrottling(state) && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) if (EnableThrottling(state))
{ {
transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager); transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager);
state.TranscodingThrottler.Start(); state.TranscodingThrottler.Start();
@ -1832,26 +1857,37 @@ namespace MediaBrowser.Api.Playback
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase); state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
var archivable = item as IArchivable; MediaSourceInfo mediaSource = null;
state.IsInputArchive = archivable != null && archivable.IsArchive;
MediaSourceInfo mediaSource;
if (string.IsNullOrWhiteSpace(request.LiveStreamId)) if (string.IsNullOrWhiteSpace(request.LiveStreamId))
{ {
var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList(); TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ?
ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId)
: null;
mediaSource = string.IsNullOrEmpty(request.MediaSourceId) if (currentJob != null)
? mediaSources.First()
: mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId));
if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase))
{ {
mediaSource = mediaSources.First(); mediaSource = currentJob.MediaSource;
}
if (mediaSource == null)
{
var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList();
mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
? mediaSources.First()
: mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId));
if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase))
{
mediaSource = mediaSources.First();
}
} }
} }
else else
{ {
mediaSource = await MediaSourceManager.GetLiveStream(request.LiveStreamId, cancellationToken).ConfigureAwait(false); var liveStreamInfo = await MediaSourceManager.GetLiveStreamWithDirectStreamProvider(request.LiveStreamId, cancellationToken).ConfigureAwait(false);
mediaSource = liveStreamInfo.Item1;
state.DirectStreamProvider = liveStreamInfo.Item2;
} }
var videoRequest = request as VideoStreamRequest; var videoRequest = request as VideoStreamRequest;
@ -2294,7 +2330,8 @@ namespace MediaBrowser.Api.Playback
state.TargetRefFrames, state.TargetRefFrames,
state.TargetVideoStreamCount, state.TargetVideoStreamCount,
state.TargetAudioStreamCount, state.TargetAudioStreamCount,
state.TargetVideoCodecTag); state.TargetVideoCodecTag,
state.IsTargetAVC);
if (mediaProfile != null) if (mediaProfile != null)
{ {
@ -2429,7 +2466,8 @@ namespace MediaBrowser.Api.Playback
Url = "https://mb3admin.com/admin/service/transcoding/report", Url = "https://mb3admin.com/admin/service/transcoding/report",
CancellationToken = CancellationToken.None, CancellationToken = CancellationToken.None,
LogRequest = false, LogRequest = false,
LogErrors = false LogErrors = false,
BufferContent = false
}; };
options.RequestContent = JsonSerializer.SerializeToString(dict); options.RequestContent = JsonSerializer.SerializeToString(dict);
options.RequestContentType = "application/json"; options.RequestContentType = "application/json";
@ -2512,7 +2550,8 @@ namespace MediaBrowser.Api.Playback
state.TargetRefFrames, state.TargetRefFrames,
state.TargetVideoStreamCount, state.TargetVideoStreamCount,
state.TargetAudioStreamCount, state.TargetAudioStreamCount,
state.TargetVideoCodecTag state.TargetVideoCodecTag,
state.IsTargetAVC
).FirstOrDefault() ?? string.Empty; ).FirstOrDefault() ?? string.Empty;
} }
@ -2567,6 +2606,7 @@ namespace MediaBrowser.Api.Playback
inputModifier += " " + GetFastSeekCommandLineParameter(state.Request); inputModifier += " " + GetFastSeekCommandLineParameter(state.Request);
inputModifier = inputModifier.Trim(); inputModifier = inputModifier.Trim();
//inputModifier += " -fflags +genpts+ignidx+igndts";
if (state.VideoRequest != null && genPts) if (state.VideoRequest != null && genPts)
{ {
inputModifier += " -fflags +genpts"; inputModifier += " -fflags +genpts";

View File

@ -87,7 +87,8 @@ namespace MediaBrowser.Api.Playback.Hls
if (!FileSystem.FileExists(playlist)) if (!FileSystem.FileExists(playlist))
{ {
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(playlist);
await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
try try
{ {
if (!FileSystem.FileExists(playlist)) if (!FileSystem.FileExists(playlist))
@ -104,13 +105,13 @@ namespace MediaBrowser.Api.Playback.Hls
throw; throw;
} }
var waitForSegments = state.SegmentLength >= 10 ? 2 : 3; var waitForSegments = state.SegmentLength >= 10 ? 2 : (state.SegmentLength > 3 || !isLive ? 3 : 3);
await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false); await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false);
} }
} }
finally finally
{ {
ApiEntryPoint.Instance.TranscodingStartLock.Release(); transcodingLock.Release();
} }
} }
@ -128,10 +129,9 @@ namespace MediaBrowser.Api.Playback.Hls
var audioBitrate = state.OutputAudioBitrate ?? 0; var audioBitrate = state.OutputAudioBitrate ?? 0;
var videoBitrate = state.OutputVideoBitrate ?? 0; var videoBitrate = state.OutputVideoBitrate ?? 0;
var appendBaselineStream = false;
var baselineStreamBitrate = 64000; var baselineStreamBitrate = 64000;
var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, appendBaselineStream, baselineStreamBitrate); var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, baselineStreamBitrate);
job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType); job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
@ -151,9 +151,10 @@ namespace MediaBrowser.Api.Playback.Hls
{ {
var text = reader.ReadToEnd(); var text = reader.ReadToEnd();
text = text.Replace("#EXTM3U", "#EXTM3U\n#EXT-X-PLAYLIST-TYPE:EVENT");
var newDuration = "#EXT-X-TARGETDURATION:" + segmentLength.ToString(UsCulture); var newDuration = "#EXT-X-TARGETDURATION:" + segmentLength.ToString(UsCulture);
// ffmpeg pads the reported length by a full second
text = text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength + 1).ToString(UsCulture), newDuration, StringComparison.OrdinalIgnoreCase); text = text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength + 1).ToString(UsCulture), newDuration, StringComparison.OrdinalIgnoreCase);
return text; return text;
@ -161,7 +162,7 @@ namespace MediaBrowser.Api.Playback.Hls
} }
} }
private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, bool includeBaselineStream, int baselineStreamBitrate) private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, int baselineStreamBitrate)
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
@ -175,14 +176,6 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "/stream.m3u8"); var playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "/stream.m3u8");
builder.AppendLine(playlistUrl); builder.AppendLine(playlistUrl);
// Low bitrate stream
if (includeBaselineStream)
{
builder.AppendLine("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + baselineStreamBitrate.ToString(UsCulture));
playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "-low/stream.m3u8");
builder.AppendLine(playlistUrl);
}
return builder.ToString(); return builder.ToString();
} }
@ -190,32 +183,41 @@ namespace MediaBrowser.Api.Playback.Hls
{ {
Logger.Debug("Waiting for {0} segments in {1}", segmentCount, playlist); Logger.Debug("Waiting for {0} segments in {1}", segmentCount, playlist);
while (true) while (!cancellationToken.IsCancellationRequested)
{ {
// Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written try
using (var fileStream = GetPlaylistFileStream(playlist))
{ {
using (var reader = new StreamReader(fileStream)) // Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
using (var fileStream = GetPlaylistFileStream(playlist))
{ {
var count = 0; using (var reader = new StreamReader(fileStream))
while (!reader.EndOfStream)
{ {
var line = await reader.ReadLineAsync().ConfigureAwait(false); var count = 0;
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1) while (!reader.EndOfStream)
{ {
count++; var line = await reader.ReadLineAsync().ConfigureAwait(false);
if (count >= segmentCount)
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
{ {
Logger.Debug("Finished waiting for {0} segments in {1}", segmentCount, playlist); count++;
return; if (count >= segmentCount)
{
Logger.Debug("Finished waiting for {0} segments in {1}", segmentCount, playlist);
return;
}
} }
} }
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
} }
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
} }
} }
catch (IOException)
{
// May get an error if the file is locked
}
await Task.Delay(50, cancellationToken).ConfigureAwait(false);
} }
} }

View File

@ -171,14 +171,15 @@ namespace MediaBrowser.Api.Playback.Hls
return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false); return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
} }
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(playlistPath);
await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
var released = false; var released = false;
try try
{ {
if (FileSystem.FileExists(segmentPath)) if (FileSystem.FileExists(segmentPath))
{ {
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
ApiEntryPoint.Instance.TranscodingStartLock.Release(); transcodingLock.Release();
released = true; released = true;
return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false); return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
} }
@ -242,7 +243,7 @@ namespace MediaBrowser.Api.Playback.Hls
{ {
if (!released) if (!released)
{ {
ApiEntryPoint.Instance.TranscodingStartLock.Release(); transcodingLock.Release();
} }
} }
@ -906,6 +907,7 @@ namespace MediaBrowser.Api.Playback.Hls
).Trim(); ).Trim();
} }
// TODO: check libavformat version for 57 50.100 and use -hls_flags split_by_time
return string.Format("{0}{11} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7} -start_number {8} -hls_list_size {9} -y \"{10}\"", return string.Format("{0}{11} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7} -start_number {8} -hls_list_size {9} -y \"{10}\"",
inputModifier, inputModifier,
GetInputArgument(state), GetInputArgument(state),

View File

@ -68,8 +68,6 @@ namespace MediaBrowser.Api.Playback.Hls
[Api(Description = "Gets an Http live streaming segment file. Internal use only.")] [Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
public class GetHlsVideoSegmentLegacy : VideoStreamRequest public class GetHlsVideoSegmentLegacy : VideoStreamRequest
{ {
// TODO: Deprecate with new iOS app
public string PlaylistId { get; set; } public string PlaylistId { get; set; }
/// <summary> /// <summary>
@ -113,7 +111,7 @@ namespace MediaBrowser.Api.Playback.Hls
var file = request.SegmentId + Path.GetExtension(Request.PathInfo); var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, file); file = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, file);
var normalizedPlaylistId = request.PlaylistId.Replace("-low", string.Empty); var normalizedPlaylistId = request.PlaylistId;
var playlistPath = Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*") var playlistPath = Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*")
.FirstOrDefault(i => string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1); .FirstOrDefault(i => string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1);

View File

@ -113,6 +113,8 @@ namespace MediaBrowser.Api.Playback.Hls
args += GetGraphicalSubtitleParam(state, codec); args += GetGraphicalSubtitleParam(state, codec);
} }
args += " -flags -global_header";
return args; return args;
} }

View File

@ -107,7 +107,7 @@ namespace MediaBrowser.Api.Playback
{ {
var authInfo = AuthorizationContext.GetAuthorizationInfo(Request); var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
var result = await _mediaSourceManager.OpenLiveStream(request, false, CancellationToken.None).ConfigureAwait(false); var result = await _mediaSourceManager.OpenLiveStream(request, true, CancellationToken.None).ConfigureAwait(false);
var profile = request.DeviceProfile; var profile = request.DeviceProfile;
if (profile == null) if (profile == null)
@ -140,7 +140,7 @@ namespace MediaBrowser.Api.Playback
public void Post(CloseMediaSource request) public void Post(CloseMediaSource request)
{ {
var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId, CancellationToken.None); var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId);
Task.WaitAll(task); Task.WaitAll(task);
} }

View File

@ -17,6 +17,7 @@ using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
using ServiceStack;
namespace MediaBrowser.Api.Playback.Progressive namespace MediaBrowser.Api.Playback.Progressive
{ {
@ -26,12 +27,10 @@ namespace MediaBrowser.Api.Playback.Progressive
public abstract class BaseProgressiveStreamingService : BaseStreamingService public abstract class BaseProgressiveStreamingService : BaseStreamingService
{ {
protected readonly IImageProcessor ImageProcessor; protected readonly IImageProcessor ImageProcessor;
protected readonly IHttpClient HttpClient;
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer) protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
{ {
ImageProcessor = imageProcessor; ImageProcessor = imageProcessor;
HttpClient = httpClient;
} }
/// <summary> /// <summary>
@ -122,6 +121,25 @@ namespace MediaBrowser.Api.Playback.Progressive
var responseHeaders = new Dictionary<string, string>(); var responseHeaders = new Dictionary<string, string>();
if (request.Static && state.DirectStreamProvider != null)
{
AddDlnaHeaders(state, responseHeaders, true);
using (state)
{
var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
// TODO: Don't hardcode this
outputHeaders["Content-Type"] = MediaBrowser.Model.Net.MimeTypes.GetMimeType("file.ts");
var streamSource = new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, CancellationToken.None)
{
AllowEndOfFile = false
};
return ResultFactory.GetAsyncStreamWriter(streamSource);
}
}
// Static remote stream // Static remote stream
if (request.Static && state.InputProtocol == MediaProtocol.Http) if (request.Static && state.InputProtocol == MediaProtocol.Http)
{ {
@ -129,8 +147,7 @@ namespace MediaBrowser.Api.Playback.Progressive
using (state) using (state)
{ {
return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource) return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).ConfigureAwait(false);
.ConfigureAwait(false);
} }
} }
@ -154,6 +171,19 @@ namespace MediaBrowser.Api.Playback.Progressive
using (state) using (state)
{ {
if (state.MediaSource.IsInfiniteStream)
{
var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
outputHeaders["Content-Type"] = contentType;
var streamSource = new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, Logger, CancellationToken.None)
{
AllowEndOfFile = false
};
return ResultFactory.GetAsyncStreamWriter(streamSource);
}
TimeSpan? cacheDuration = null; TimeSpan? cacheDuration = null;
if (!string.IsNullOrEmpty(request.Tag)) if (!string.IsNullOrEmpty(request.Tag))
@ -345,7 +375,8 @@ namespace MediaBrowser.Api.Playback.Progressive
return streamResult; return streamResult;
} }
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(outputPath);
await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
try try
{ {
TranscodingJob job; TranscodingJob job;
@ -376,7 +407,7 @@ namespace MediaBrowser.Api.Playback.Progressive
} }
finally finally
{ {
ApiEntryPoint.Instance.TranscodingStartLock.Release(); transcodingLock.Release();
} }
} }

View File

@ -7,6 +7,7 @@ using CommonIO;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using System.Collections.Generic; using System.Collections.Generic;
using ServiceStack.Web; using ServiceStack.Web;
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Api.Playback.Progressive namespace MediaBrowser.Api.Playback.Progressive
{ {
@ -23,6 +24,10 @@ namespace MediaBrowser.Api.Playback.Progressive
private const int BufferSize = 81920; private const int BufferSize = 81920;
private long _bytesWritten = 0; private long _bytesWritten = 0;
public long StartPosition { get; set; }
public bool AllowEndOfFile = true;
private IDirectStreamProvider _directStreamProvider;
public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken) public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken)
{ {
@ -34,6 +39,15 @@ namespace MediaBrowser.Api.Playback.Progressive
_cancellationToken = cancellationToken; _cancellationToken = cancellationToken;
} }
public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken)
{
_directStreamProvider = directStreamProvider;
_outputHeaders = outputHeaders;
_job = job;
_logger = logger;
_cancellationToken = cancellationToken;
}
public IDictionary<string, string> Options public IDictionary<string, string> Options
{ {
get get
@ -42,17 +56,33 @@ namespace MediaBrowser.Api.Playback.Progressive
} }
} }
private Stream GetInputStream()
{
return _fileSystem.GetFileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
}
public async Task WriteToAsync(Stream outputStream) public async Task WriteToAsync(Stream outputStream)
{ {
try try
{ {
if (_directStreamProvider != null)
{
await _directStreamProvider.CopyToAsync(outputStream, _cancellationToken).ConfigureAwait(false);
return;
}
var eofCount = 0; var eofCount = 0;
using (var fs = _fileSystem.GetFileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) using (var inputStream = GetInputStream())
{ {
while (eofCount < 15) if (StartPosition > 0)
{ {
var bytesRead = await CopyToAsyncInternal(fs, outputStream, BufferSize, _cancellationToken).ConfigureAwait(false); inputStream.Position = StartPosition;
}
while (eofCount < 15 || !AllowEndOfFile)
{
var bytesRead = await CopyToAsyncInternal(inputStream, outputStream, BufferSize, _cancellationToken).ConfigureAwait(false);
//var position = fs.Position; //var position = fs.Position;
//_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);

View File

@ -37,6 +37,7 @@ namespace MediaBrowser.Api.Playback
/// </summary> /// </summary>
/// <value>The log file stream.</value> /// <value>The log file stream.</value>
public Stream LogFileStream { get; set; } public Stream LogFileStream { get; set; }
public IDirectStreamProvider DirectStreamProvider { get; set; }
public string InputContainer { get; set; } public string InputContainer { get; set; }
@ -62,7 +63,6 @@ namespace MediaBrowser.Api.Playback
get { return Request is VideoStreamRequest; } get { return Request is VideoStreamRequest; }
} }
public bool IsInputVideo { get; set; } public bool IsInputVideo { get; set; }
public bool IsInputArchive { get; set; }
public VideoType VideoType { get; set; } public VideoType VideoType { get; set; }
public IsoType? IsoType { get; set; } public IsoType? IsoType { get; set; }
@ -88,9 +88,17 @@ namespace MediaBrowser.Api.Playback
return 10; return 10;
} }
if (!RunTimeTicks.HasValue)
{
return 3;
}
return 6; return 6;
} }
if (!RunTimeTicks.HasValue)
{
return 3;
}
return 3; return 3;
} }
} }
@ -217,7 +225,7 @@ namespace MediaBrowser.Api.Playback
{ {
try try
{ {
await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false); await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -508,5 +516,18 @@ namespace MediaBrowser.Api.Playback
return false; return false;
} }
} }
public bool? IsTargetAVC
{
get
{
if (Request.Static)
{
return VideoStream == null ? null : VideoStream.IsAVC;
}
return true;
}
}
} }
} }

View File

@ -517,10 +517,6 @@ namespace MediaBrowser.Api.Reports
internalHeader = HeaderMetadata.Album; internalHeader = HeaderMetadata.Album;
break; break;
case HeaderMetadata.Countries:
option.Column = (i, r) => this.GetListAsString(this.GetObject<IHasProductionLocations, List<string>>(i, (x) => x.ProductionLocations));
break;
case HeaderMetadata.Disc: case HeaderMetadata.Disc:
option.Column = (i, r) => i.ParentIndexNumber; option.Column = (i, r) => i.ParentIndexNumber;
break; break;

View File

@ -36,7 +36,6 @@ namespace MediaBrowser.Api.Reports
result = this.GetResultStudios(result, items, topItem); result = this.GetResultStudios(result, items, topItem);
result = this.GetResultPersons(result, items, topItem); result = this.GetResultPersons(result, items, topItem);
result = this.GetResultProductionYears(result, items, topItem); result = this.GetResultProductionYears(result, items, topItem);
result = this.GetResulProductionLocations(result, items, topItem);
result = this.GetResultCommunityRatings(result, items, topItem); result = this.GetResultCommunityRatings(result, items, topItem);
result = this.GetResultParentalRatings(result, items, topItem); result = this.GetResultParentalRatings(result, items, topItem);
@ -100,30 +99,6 @@ namespace MediaBrowser.Api.Reports
} }
} }
/// <summary> Gets resul production locations. </summary>
/// <param name="result"> The result. </param>
/// <param name="items"> The items. </param>
/// <param name="topItem"> The top item. </param>
/// <returns> The resul production locations. </returns>
private ReportStatResult GetResulProductionLocations(ReportStatResult result, BaseItem[] items, int topItem = 5)
{
this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.Countries), topItem,
items.OfType<IHasProductionLocations>()
.Where(x => x.ProductionLocations != null)
.SelectMany(x => x.ProductionLocations)
.GroupBy(x => x)
.OrderByDescending(x => x.Count())
.Take(topItem)
.Select(x => new ReportStatItem
{
Name = x.Key.ToString(),
Value = x.Count().ToString()
})
);
return result;
}
/// <summary> Gets result community ratings. </summary> /// <summary> Gets result community ratings. </summary>
/// <param name="result"> The result. </param> /// <param name="result"> The result. </param>
/// <param name="items"> The items. </param> /// <param name="items"> The items. </param>

View File

@ -81,7 +81,8 @@ namespace MediaBrowser.Api
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(), IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(),
Recursive = true Recursive = true,
DtoOptions = dtoOptions
}; };
// ExcludeArtistIds // ExcludeArtistIds

View File

@ -88,8 +88,6 @@ namespace MediaBrowser.Api
var result = new StartupConfiguration var result = new StartupConfiguration
{ {
UICulture = _config.Configuration.UICulture, UICulture = _config.Configuration.UICulture,
EnableInternetProviders = _config.Configuration.EnableInternetProviders,
SaveLocalMeta = _config.Configuration.SaveLocalMeta,
MetadataCountryCode = _config.Configuration.MetadataCountryCode, MetadataCountryCode = _config.Configuration.MetadataCountryCode,
PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
}; };
@ -116,15 +114,16 @@ namespace MediaBrowser.Api
config.EnableLocalizedGuids = true; config.EnableLocalizedGuids = true;
config.EnableStandaloneMusicKeys = true; config.EnableStandaloneMusicKeys = true;
config.EnableCaseSensitiveItemIds = true; config.EnableCaseSensitiveItemIds = true;
//config.EnableFolderView = true; config.EnableFolderView = true;
config.SchemaVersion = 109; config.SchemaVersion = 109;
config.EnableSimpleArtistDetection = true;
config.SkipDeserializationForBasicTypes = true;
config.SkipDeserializationForPrograms = true;
} }
public void Post(UpdateStartupConfiguration request) public void Post(UpdateStartupConfiguration request)
{ {
_config.Configuration.UICulture = request.UICulture; _config.Configuration.UICulture = request.UICulture;
_config.Configuration.EnableInternetProviders = request.EnableInternetProviders;
_config.Configuration.SaveLocalMeta = request.SaveLocalMeta;
_config.Configuration.MetadataCountryCode = request.MetadataCountryCode; _config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
_config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage; _config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
_config.SaveConfiguration(); _config.SaveConfiguration();
@ -215,8 +214,6 @@ namespace MediaBrowser.Api
public class StartupConfiguration public class StartupConfiguration
{ {
public string UICulture { get; set; } public string UICulture { get; set; }
public bool EnableInternetProviders { get; set; }
public bool SaveLocalMeta { get; set; }
public string MetadataCountryCode { get; set; } public string MetadataCountryCode { get; set; }
public string PreferredMetadataLanguage { get; set; } public string PreferredMetadataLanguage { get; set; }
public string LiveTvTunerType { get; set; } public string LiveTvTunerType { get; set; }

View File

@ -148,7 +148,7 @@ namespace MediaBrowser.Api.Subtitles
{ {
var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));
var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, false).ConfigureAwait(false); var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, null, false, CancellationToken.None).ConfigureAwait(false);
var builder = new StringBuilder(); var builder = new StringBuilder();

View File

@ -302,6 +302,8 @@ namespace MediaBrowser.Api
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
var dtoOptions = GetDtoOptions(request);
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{ {
Limit = request.Limit, Limit = request.Limit,
@ -309,12 +311,11 @@ namespace MediaBrowser.Api
{ {
typeof(Series).Name typeof(Series).Name
}, },
SimilarTo = item SimilarTo = item,
DtoOptions = dtoOptions
}).ToList(); }).ToList();
var dtoOptions = GetDtoOptions(request);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(), Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
@ -333,6 +334,8 @@ namespace MediaBrowser.Api
var parentIdGuid = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId); var parentIdGuid = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId);
var options = GetDtoOptions(request);
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{ {
IncludeItemTypes = new[] { typeof(Episode).Name }, IncludeItemTypes = new[] { typeof(Episode).Name },
@ -342,12 +345,11 @@ namespace MediaBrowser.Api
StartIndex = request.StartIndex, StartIndex = request.StartIndex,
Limit = request.Limit, Limit = request.Limit,
ParentId = parentIdGuid, ParentId = parentIdGuid,
Recursive = true Recursive = true,
DtoOptions = options
}).ToList(); }).ToList();
var options = GetDtoOptions(request);
var returnItems = (await _dtoService.GetBaseItemDtos(itemsResult, options, user).ConfigureAwait(false)).ToArray(); var returnItems = (await _dtoService.GetBaseItemDtos(itemsResult, options, user).ConfigureAwait(false)).ToArray();
var result = new ItemsResult var result = new ItemsResult

View File

@ -205,6 +205,7 @@ namespace MediaBrowser.Api.UserLibrary
private void SetItemCounts(BaseItemDto dto, ItemCounts counts) private void SetItemCounts(BaseItemDto dto, ItemCounts counts)
{ {
dto.ChildCount = counts.ItemCount; dto.ChildCount = counts.ItemCount;
dto.ProgramCount = counts.ProgramCount;
dto.SeriesCount = counts.SeriesCount; dto.SeriesCount = counts.SeriesCount;
dto.EpisodeCount = counts.EpisodeCount; dto.EpisodeCount = counts.EpisodeCount;
dto.MovieCount = counts.MovieCount; dto.MovieCount = counts.MovieCount;

View File

@ -99,8 +99,10 @@ namespace MediaBrowser.Api.UserLibrary
private async Task<ItemsResult> GetItems(GetItems request) private async Task<ItemsResult> GetItems(GetItems request)
{ {
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
var result = await GetQueryResult(request, user).ConfigureAwait(false); var dtoOptions = GetDtoOptions(request);
var result = await GetQueryResult(request, dtoOptions, user).ConfigureAwait(false);
if (result == null) if (result == null)
{ {
@ -112,8 +114,6 @@ namespace MediaBrowser.Api.UserLibrary
throw new InvalidOperationException("GetItemsToSerialize result.Items returned null"); throw new InvalidOperationException("GetItemsToSerialize result.Items returned null");
} }
var dtoOptions = GetDtoOptions(request);
var dtoList = await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false); var dtoList = await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false);
if (dtoList == null) if (dtoList == null)
@ -131,24 +131,31 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary> /// <summary>
/// Gets the items to serialize. /// Gets the items to serialize.
/// </summary> /// </summary>
/// <param name="request">The request.</param> private async Task<QueryResult<BaseItem>> GetQueryResult(GetItems request, DtoOptions dtoOptions, User user)
/// <param name="user">The user.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
private async Task<QueryResult<BaseItem>> GetQueryResult(GetItems request, User user)
{ {
var item = string.IsNullOrEmpty(request.ParentId) ? var item = string.IsNullOrEmpty(request.ParentId) ?
user == null ? _libraryManager.RootFolder : user.RootFolder : null :
_libraryManager.GetItemById(request.ParentId); _libraryManager.GetItemById(request.ParentId);
if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase)) if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase))
{ {
//item = user == null ? _libraryManager.RootFolder : user.RootFolder; if (item == null || user != null)
{
item = _libraryManager.RootFolder.Children.OfType<Folder>().FirstOrDefault(i => string.Equals(i.GetType().Name, "PlaylistsFolder", StringComparison.OrdinalIgnoreCase));
}
} }
else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase)) else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
{ {
item = user == null ? _libraryManager.RootFolder : user.RootFolder; item = user == null ? _libraryManager.RootFolder : user.RootFolder;
} }
if (item == null)
{
item = string.IsNullOrEmpty(request.ParentId) ?
user == null ? _libraryManager.RootFolder : user.RootFolder :
_libraryManager.GetItemById(request.ParentId);
}
// Default list type = children // Default list type = children
var folder = item as Folder; var folder = item as Folder;
@ -159,14 +166,14 @@ namespace MediaBrowser.Api.UserLibrary
if (request.Recursive || !string.IsNullOrEmpty(request.Ids) || user == null) if (request.Recursive || !string.IsNullOrEmpty(request.Ids) || user == null)
{ {
return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); return await folder.GetItems(GetItemsQuery(request, dtoOptions, user)).ConfigureAwait(false);
} }
var userRoot = item as UserRootFolder; var userRoot = item as UserRootFolder;
if (userRoot == null) if (userRoot == null)
{ {
return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); return await folder.GetItems(GetItemsQuery(request, dtoOptions, user)).ConfigureAwait(false);
} }
IEnumerable<BaseItem> items = folder.GetChildren(user, true); IEnumerable<BaseItem> items = folder.GetChildren(user, true);
@ -180,7 +187,7 @@ namespace MediaBrowser.Api.UserLibrary
}; };
} }
private InternalItemsQuery GetItemsQuery(GetItems request, User user) private InternalItemsQuery GetItemsQuery(GetItems request, DtoOptions dtoOptions, User user)
{ {
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
@ -241,7 +248,8 @@ namespace MediaBrowser.Api.UserLibrary
AiredDuringSeason = request.AiredDuringSeason, AiredDuringSeason = request.AiredDuringSeason,
AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater, AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater,
EnableTotalRecordCount = request.EnableTotalRecordCount, EnableTotalRecordCount = request.EnableTotalRecordCount,
ExcludeItemIds = request.GetExcludeItemIds() ExcludeItemIds = request.GetExcludeItemIds(),
DtoOptions = dtoOptions
}; };
if (!string.IsNullOrWhiteSpace(request.Ids)) if (!string.IsNullOrWhiteSpace(request.Ids))

View File

@ -30,6 +30,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
using MediaBrowser.Common.IO;
namespace MediaBrowser.Common.Implementations namespace MediaBrowser.Common.Implementations
{ {
@ -192,6 +193,8 @@ namespace MediaBrowser.Common.Implementations
get { return Environment.OSVersion.VersionString; } get { return Environment.OSVersion.VersionString; }
} }
public IMemoryStreamProvider MemoryStreamProvider { get; set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class. /// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
/// </summary> /// </summary>
@ -231,6 +234,8 @@ namespace MediaBrowser.Common.Implementations
JsonSerializer = CreateJsonSerializer(); JsonSerializer = CreateJsonSerializer();
MemoryStreamProvider = new MemoryStreamProvider();
OnLoggerLoaded(true); OnLoggerLoaded(true);
LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false); LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false);
@ -456,6 +461,7 @@ namespace MediaBrowser.Common.Implementations
RegisterSingleInstance(JsonSerializer); RegisterSingleInstance(JsonSerializer);
RegisterSingleInstance(XmlSerializer); RegisterSingleInstance(XmlSerializer);
RegisterSingleInstance(MemoryStreamProvider);
RegisterSingleInstance(LogManager); RegisterSingleInstance(LogManager);
RegisterSingleInstance(Logger); RegisterSingleInstance(Logger);
@ -464,7 +470,7 @@ namespace MediaBrowser.Common.Implementations
RegisterSingleInstance(FileSystemManager); RegisterSingleInstance(FileSystemManager);
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager); HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamProvider);
RegisterSingleInstance(HttpClient); RegisterSingleInstance(HttpClient);
NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager")); NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager"));

View File

@ -42,6 +42,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
private readonly IApplicationPaths _appPaths; private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IMemoryStreamProvider _memoryStreamProvider;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HttpClientManager" /> class. /// Initializes a new instance of the <see cref="HttpClientManager" /> class.
@ -52,7 +53,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// <exception cref="System.ArgumentNullException">appPaths /// <exception cref="System.ArgumentNullException">appPaths
/// or /// or
/// logger</exception> /// logger</exception>
public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem) public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IMemoryStreamProvider memoryStreamProvider)
{ {
if (appPaths == null) if (appPaths == null)
{ {
@ -65,6 +66,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
_logger = logger; _logger = logger;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_memoryStreamProvider = memoryStreamProvider;
_appPaths = appPaths; _appPaths = appPaths;
// http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
@ -269,6 +271,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
Url = url, Url = url,
ResourcePool = resourcePool, ResourcePool = resourcePool,
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
BufferContent = resourcePool != null
}); });
} }
@ -293,12 +296,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// </exception> /// </exception>
public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod) public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod)
{ {
HttpResponseInfo response;
if (options.CacheMode == CacheMode.None) if (options.CacheMode == CacheMode.None)
{ {
response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false); return await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
return response;
} }
var url = options.Url; var url = options.Url;
@ -306,7 +306,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash); var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false); var response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false);
if (response != null) if (response != null)
{ {
return response; return response;
@ -332,7 +332,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
{ {
using (var stream = _fileSystem.GetFileStream(responseCachePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) using (var stream = _fileSystem.GetFileStream(responseCachePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
{ {
var memoryStream = new MemoryStream(); var memoryStream = _memoryStreamProvider.CreateNew();
await stream.CopyToAsync(memoryStream).ConfigureAwait(false); await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0; memoryStream.Position = 0;
@ -366,7 +366,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
using (var responseStream = response.Content) using (var responseStream = response.Content)
{ {
var memoryStream = new MemoryStream(); var memoryStream = _memoryStreamProvider.CreateNew();
await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false); await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0; memoryStream.Position = 0;
@ -458,7 +458,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
using (var stream = httpResponse.GetResponseStream()) using (var stream = httpResponse.GetResponseStream())
{ {
var memoryStream = new MemoryStream(); var memoryStream = _memoryStreamProvider.CreateNew();
await stream.CopyToAsync(memoryStream).ConfigureAwait(false); await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
@ -553,7 +553,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
{ {
Url = url, Url = url,
ResourcePool = resourcePool, ResourcePool = resourcePool,
CancellationToken = cancellationToken CancellationToken = cancellationToken,
BufferContent = resourcePool != null
}, postData); }, postData);
} }
@ -563,7 +564,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// </summary> /// </summary>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
/// <returns>Task{System.String}.</returns> /// <returns>Task{System.String}.</returns>
/// <exception cref="System.ArgumentNullException">progress</exception>
public async Task<string> GetTempFile(HttpRequestOptions options) public async Task<string> GetTempFile(HttpRequestOptions options)
{ {
var response = await GetTempFileResponse(options).ConfigureAwait(false); var response = await GetTempFileResponse(options).ConfigureAwait(false);

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Common.IO;
using Microsoft.IO;
namespace MediaBrowser.Common.Implementations.IO
{
public class MemoryStreamProvider : IMemoryStreamProvider
{
readonly RecyclableMemoryStreamManager _manager = new RecyclableMemoryStreamManager();
public MemoryStream CreateNew()
{
return _manager.GetStream();
}
public MemoryStream CreateNew(int capacity)
{
return _manager.GetStream("RecyclableMemoryStream", capacity);
}
public MemoryStream CreateNew(byte[] buffer)
{
return _manager.GetStream("RecyclableMemoryStream", buffer, 0, buffer.Length);
}
}
}

View File

@ -72,6 +72,11 @@ namespace MediaBrowser.Common.Implementations.Logging
/// <param name="paramList">The param list.</param> /// <param name="paramList">The param list.</param>
public void Debug(string message, params object[] paramList) public void Debug(string message, params object[] paramList)
{ {
if (_logManager.LogSeverity == LogSeverity.Info)
{
return;
}
_logger.Debug(message, paramList); _logger.Debug(message, paramList);
} }
@ -137,6 +142,11 @@ namespace MediaBrowser.Common.Implementations.Logging
/// <param name="additionalContent">Content of the additional.</param> /// <param name="additionalContent">Content of the additional.</param>
public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent) public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent)
{ {
if (severity == LogSeverity.Debug && _logManager.LogSeverity == LogSeverity.Info)
{
return;
}
additionalContent.Insert(0, message + Environment.NewLine); additionalContent.Insert(0, message + Environment.NewLine);
const char tabChar = '\t'; const char tabChar = '\t';

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -14,6 +14,7 @@
<ProductVersion>10.0.0</ProductVersion> <ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -23,7 +24,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@ -51,11 +52,15 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath> <HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.1.0.0\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MoreLinq"> <Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath> <HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
</Reference> </Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath> <HintPath>..\packages\NLog.4.3.8\lib\net45\NLog.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Patterns.Logging"> <Reference Include="Patterns.Logging">
@ -65,8 +70,8 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath> <HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
</Reference> </Reference>
<Reference Include="SimpleInjector, Version=3.2.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL"> <Reference Include="SimpleInjector, Version=3.2.2.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.3.2.0\lib\net45\SimpleInjector.dll</HintPath> <HintPath>..\packages\SimpleInjector.3.2.2\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
@ -75,6 +80,9 @@
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Net" /> <Reference Include="System.Net" />
<Reference Include="System.Text.Json">
<HintPath>..\ThirdParty\fastjsonparser\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="ServiceStack.Text"> <Reference Include="ServiceStack.Text">
<HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath> <HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath>
@ -93,6 +101,7 @@
<Compile Include="HttpClientManager\HttpClientInfo.cs" /> <Compile Include="HttpClientManager\HttpClientInfo.cs" />
<Compile Include="HttpClientManager\HttpClientManager.cs" /> <Compile Include="HttpClientManager\HttpClientManager.cs" />
<Compile Include="IO\IsoManager.cs" /> <Compile Include="IO\IsoManager.cs" />
<Compile Include="IO\MemoryStreamProvider.cs" />
<Compile Include="Logging\LogHelper.cs" /> <Compile Include="Logging\LogHelper.cs" />
<Compile Include="Logging\NLogger.cs" /> <Compile Include="Logging\NLogger.cs" />
<Compile Include="Logging\NlogManager.cs" /> <Compile Include="Logging\NlogManager.cs" />

View File

@ -390,13 +390,13 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
try try
{ {
var localTask = ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress);
if (options != null && options.MaxRuntimeMs.HasValue) if (options != null && options.MaxRuntimeMs.HasValue)
{ {
CurrentCancellationTokenSource.CancelAfter(options.MaxRuntimeMs.Value); CurrentCancellationTokenSource.CancelAfter(options.MaxRuntimeMs.Value);
} }
var localTask = ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress);
await localTask.ConfigureAwait(false); await localTask.ConfigureAwait(false);
status = TaskCompletionStatus.Completed; status = TaskCompletionStatus.Completed;

View File

@ -169,7 +169,8 @@ namespace MediaBrowser.Common.Implementations.Security
var options = new HttpRequestOptions() var options = new HttpRequestOptions()
{ {
Url = AppstoreRegUrl, Url = AppstoreRegUrl,
CancellationToken = CancellationToken.None CancellationToken = CancellationToken.None,
BufferContent = false
}; };
options.RequestHeaders.Add("X-Emby-Token", _appHost.SystemId); options.RequestHeaders.Add("X-Emby-Token", _appHost.SystemId);
options.RequestContent = parameters; options.RequestContent = parameters;
@ -269,7 +270,8 @@ namespace MediaBrowser.Common.Implementations.Security
Url = MBValidateUrl, Url = MBValidateUrl,
// Seeing block length errors // Seeing block length errors
EnableHttpCompression = false EnableHttpCompression = false,
BufferContent = false
}; };
options.SetPostData(data); options.SetPostData(data);

View File

@ -30,7 +30,8 @@ namespace MediaBrowser.Common.Implementations.Updates
Url = url, Url = url,
EnableKeepAlive = false, EnableKeepAlive = false,
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
UserAgent = "Emby/3.0" UserAgent = "Emby/3.0",
BufferContent = false
}; };
if (cacheLength.Ticks > 0) if (cacheLength.Ticks > 0)
@ -105,7 +106,8 @@ namespace MediaBrowser.Common.Implementations.Updates
Url = url, Url = url,
EnableKeepAlive = false, EnableKeepAlive = false,
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
UserAgent = "Emby/3.0" UserAgent = "Emby/3.0",
BufferContent = false
}; };
using (var stream = await _httpClient.Get(options).ConfigureAwait(false)) using (var stream = await _httpClient.Get(options).ConfigureAwait(false))

View File

@ -148,14 +148,10 @@ namespace MediaBrowser.Common.Implementations.Updates
/// <summary> /// <summary>
/// Gets all available packages. /// Gets all available packages.
/// </summary> /// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="withRegistration">if set to <c>true</c> [with registration].</param>
/// <param name="packageType">Type of the package.</param>
/// <param name="applicationVersion">The application version.</param>
/// <returns>Task{List{PackageInfo}}.</returns> /// <returns>Task{List{PackageInfo}}.</returns>
public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken, public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
bool withRegistration = true, bool withRegistration = true,
PackageType? packageType = null, string packageType = null,
Version applicationVersion = null) Version applicationVersion = null)
{ {
var data = new Dictionary<string, string> var data = new Dictionary<string, string>
@ -293,7 +289,7 @@ namespace MediaBrowser.Common.Implementations.Updates
return packages; return packages;
} }
protected IEnumerable<PackageInfo> FilterPackages(List<PackageInfo> packages, PackageType? packageType, Version applicationVersion) protected IEnumerable<PackageInfo> FilterPackages(List<PackageInfo> packages, string packageType, Version applicationVersion)
{ {
foreach (var package in packages) foreach (var package in packages)
{ {
@ -301,9 +297,9 @@ namespace MediaBrowser.Common.Implementations.Updates
.OrderByDescending(GetPackageVersion).ToList(); .OrderByDescending(GetPackageVersion).ToList();
} }
if (packageType.HasValue) if (!string.IsNullOrWhiteSpace(packageType))
{ {
packages = packages.Where(p => p.type == packageType.Value).ToList(); packages = packages.Where(p => string.Equals(p.type, packageType, StringComparison.OrdinalIgnoreCase)).ToList();
} }
// If an app version was supplied, filter the versions for each package to only include supported versions // If an app version was supplied, filter the versions for each package to only include supported versions

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" /> <package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
<package id="Microsoft.IO.RecyclableMemoryStream" version="1.1.0.0" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" /> <package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="NLog" version="4.3.6" targetFramework="net45" /> <package id="NLog" version="4.3.8" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" /> <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
<package id="SimpleInjector" version="3.2.0" targetFramework="net45" /> <package id="SimpleInjector" version="3.2.2" targetFramework="net45" />
</packages> </packages>

View File

@ -0,0 +1,11 @@
using System.IO;
namespace MediaBrowser.Common.IO
{
public interface IMemoryStreamProvider
{
MemoryStream CreateNew();
MemoryStream CreateNew(int capacity);
MemoryStream CreateNew(byte[] buffer);
}
}

View File

@ -60,6 +60,7 @@
<Compile Include="Extensions\BaseExtensions.cs" /> <Compile Include="Extensions\BaseExtensions.cs" />
<Compile Include="Extensions\ResourceNotFoundException.cs" /> <Compile Include="Extensions\ResourceNotFoundException.cs" />
<Compile Include="IDependencyContainer.cs" /> <Compile Include="IDependencyContainer.cs" />
<Compile Include="IO\IMemoryStreamProvider.cs" />
<Compile Include="IO\ProgressStream.cs" /> <Compile Include="IO\ProgressStream.cs" />
<Compile Include="IO\StreamDefaults.cs" /> <Compile Include="IO\StreamDefaults.cs" />
<Compile Include="Configuration\IApplicationPaths.cs" /> <Compile Include="Configuration\IApplicationPaths.cs" />

View File

@ -51,7 +51,7 @@ namespace MediaBrowser.Common.Updates
/// <returns>Task{List{PackageInfo}}.</returns> /// <returns>Task{List{PackageInfo}}.</returns>
Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken, Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
bool withRegistration = true, bool withRegistration = true,
PackageType? packageType = null, string packageType = null,
Version applicationVersion = null); Version applicationVersion = null);
/// <summary> /// <summary>

View File

@ -134,15 +134,5 @@ namespace MediaBrowser.Controller.Channels
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>BaseItemDto.</returns> /// <returns>BaseItemDto.</returns>
Task<BaseItemDto> GetChannelFolder(string userId, CancellationToken cancellationToken); Task<BaseItemDto> GetChannelFolder(string userId, CancellationToken cancellationToken);
/// <summary>
/// Downloads the channel item.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="destinationPath">The destination path.</param>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task DownloadChannelItem(BaseItem item, string destinationPath, IProgress<double> progress, CancellationToken cancellationToken);
} }
} }

View File

@ -1,19 +0,0 @@
using MediaBrowser.Model.Chapters;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Chapters
{
public class ChapterResponse
{
/// <summary>
/// Gets or sets the chapters.
/// </summary>
/// <value>The chapters.</value>
public List<RemoteChapterInfo> Chapters { get; set; }
public ChapterResponse()
{
Chapters = new List<RemoteChapterInfo>();
}
}
}

View File

@ -1,31 +0,0 @@
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Chapters
{
public class ChapterSearchRequest : IHasProviderIds
{
public string Language { get; set; }
public VideoContentType ContentType { get; set; }
public string MediaPath { get; set; }
public string SeriesName { get; set; }
public string Name { get; set; }
public int? IndexNumber { get; set; }
public int? IndexNumberEnd { get; set; }
public int? ParentIndexNumber { get; set; }
public int? ProductionYear { get; set; }
public long? RuntimeTicks { get; set; }
public Dictionary<string, string> ProviderIds { get; set; }
public bool SearchAllProviders { get; set; }
public ChapterSearchRequest()
{
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
}

View File

@ -1,6 +1,4 @@
using MediaBrowser.Controller.Entities; using System.Collections.Generic;
using MediaBrowser.Model.Chapters;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
@ -13,12 +11,6 @@ namespace MediaBrowser.Controller.Chapters
/// </summary> /// </summary>
public interface IChapterManager public interface IChapterManager
{ {
/// <summary>
/// Adds the parts.
/// </summary>
/// <param name="chapterProviders">The chapter providers.</param>
void AddParts(IEnumerable<IChapterProvider> chapterProviders);
/// <summary> /// <summary>
/// Gets the chapters. /// Gets the chapters.
/// </summary> /// </summary>
@ -35,43 +27,6 @@ namespace MediaBrowser.Controller.Chapters
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken); Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken);
/// <summary>
/// Searches the specified video.
/// </summary>
/// <param name="video">The video.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteChapterResult}}.</returns>
Task<IEnumerable<RemoteChapterResult>> Search(Video video, CancellationToken cancellationToken);
/// <summary>
/// Searches the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteChapterResult}}.</returns>
Task<IEnumerable<RemoteChapterResult>> Search(ChapterSearchRequest request, CancellationToken cancellationToken);
/// <summary>
/// Gets the chapters.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{ChapterResponse}.</returns>
Task<ChapterResponse> GetChapters(string id, CancellationToken cancellationToken);
/// <summary>
/// Gets the providers.
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <returns>IEnumerable{ChapterProviderInfo}.</returns>
IEnumerable<ChapterProviderInfo> GetProviders(string itemId);
/// <summary>
/// Gets the providers.
/// </summary>
/// <returns>IEnumerable{ChapterProviderInfo}.</returns>
IEnumerable<ChapterProviderInfo> GetProviders();
/// <summary> /// <summary>
/// Gets the configuration. /// Gets the configuration.
/// </summary> /// </summary>

View File

@ -1,39 +0,0 @@
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Chapters;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Chapters
{
public interface IChapterProvider
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
string Name { get; }
/// <summary>
/// Gets the supported media types.
/// </summary>
/// <value>The supported media types.</value>
IEnumerable<VideoContentType> SupportedMediaTypes { get; }
/// <summary>
/// Searches the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteChapterResult}}.</returns>
Task<IEnumerable<RemoteChapterResult>> Search(ChapterSearchRequest request, CancellationToken cancellationToken);
/// <summary>
/// Gets the chapters.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{ChapterResponse}.</returns>
Task<ChapterResponse> GetChapters(string id, CancellationToken cancellationToken);
}
}

View File

@ -1,10 +1,20 @@
using System; using System;
using System.Collections.Generic;
using System.Net;
using MediaBrowser.Model.Events;
namespace MediaBrowser.Controller.Dlna namespace MediaBrowser.Controller.Dlna
{ {
public interface IDeviceDiscovery public interface IDeviceDiscovery
{ {
event EventHandler<SsdpMessageEventArgs> DeviceDiscovered; event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered;
event EventHandler<SsdpMessageEventArgs> DeviceLeft; event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceLeft;
}
public class UpnpDeviceInfo
{
public Uri Location { get; set; }
public Dictionary<string, string> Headers { get; set; }
public IPEndPoint LocalEndPoint { get; set; }
} }
} }

View File

@ -4,6 +4,5 @@ namespace MediaBrowser.Controller.Dlna
{ {
public interface ISsdpHandler public interface ISsdpHandler
{ {
event EventHandler<SsdpMessageEventArgs> MessageReceived;
} }
} }

View File

@ -34,11 +34,26 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
public override bool IsPhysicalRoot
{
get { return true; }
}
public override bool CanDelete() public override bool CanDelete()
{ {
return false; return false;
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return false;
}
}
/// <summary> /// <summary>
/// The _virtual children /// The _virtual children
/// </summary> /// </summary>

View File

@ -23,8 +23,7 @@ namespace MediaBrowser.Controller.Entities.Audio
IHasMusicGenres, IHasMusicGenres,
IHasLookupInfo<SongInfo>, IHasLookupInfo<SongInfo>,
IHasMediaSources, IHasMediaSources,
IThemeMedia, IThemeMedia
IArchivable
{ {
public List<ChannelMediaInfo> ChannelMediaSources { get; set; } public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
@ -60,10 +59,19 @@ namespace MediaBrowser.Controller.Entities.Audio
AlbumArtists = new List<string>(); AlbumArtists = new List<string>();
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return true;
}
}
[IgnoreDataMember] [IgnoreDataMember]
public override bool SupportsAddingToPlaylist public override bool SupportsAddingToPlaylist
{ {
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; } get { return true; }
} }
[IgnoreDataMember] [IgnoreDataMember]
@ -84,21 +92,6 @@ namespace MediaBrowser.Controller.Entities.Audio
} }
} }
[IgnoreDataMember]
public bool IsArchive
{
get
{
if (string.IsNullOrWhiteSpace(Path))
{
return false;
}
var ext = System.IO.Path.GetExtension(Path) ?? string.Empty;
return new[] { ".zip", ".rar", ".7z" }.Contains(ext, StringComparer.OrdinalIgnoreCase);
}
}
public override bool CanDownload() public override bool CanDownload()
{ {
var locationType = LocationType; var locationType = LocationType;
@ -262,7 +255,7 @@ namespace MediaBrowser.Controller.Entities.Audio
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File, Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
MediaStreams = MediaSourceManager.GetMediaStreams(i.Id).ToList(), MediaStreams = MediaSourceManager.GetMediaStreams(i.Id).ToList(),
Name = i.Name, Name = i.Name,
Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path, Path = enablePathSubstituion ? GetMappedPath(i, i.Path, locationType) : i.Path,
RunTimeTicks = i.RunTimeTicks, RunTimeTicks = i.RunTimeTicks,
Container = i.Container, Container = i.Container,
Size = i.Size Size = i.Size

View File

@ -17,6 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary> /// </summary>
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
{ {
public List<string> AlbumArtists { get; set; }
public List<string> Artists { get; set; }
public MusicAlbum() public MusicAlbum()
{ {
Artists = new List<string>(); Artists = new List<string>();
@ -48,6 +51,15 @@ namespace MediaBrowser.Controller.Entities.Audio
} }
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return false;
}
}
[IgnoreDataMember] [IgnoreDataMember]
public override bool SupportsCumulativeRunTimeTicks public override bool SupportsCumulativeRunTimeTicks
{ {
@ -83,8 +95,6 @@ namespace MediaBrowser.Controller.Entities.Audio
get { return false; } get { return false; }
} }
public List<string> AlbumArtists { get; set; }
/// <summary> /// <summary>
/// Gets the tracks. /// Gets the tracks.
/// </summary> /// </summary>
@ -103,8 +113,6 @@ namespace MediaBrowser.Controller.Entities.Audio
return Tracks; return Tracks;
} }
public List<string> Artists { get; set; }
public override List<string> GetUserDataKeys() public override List<string> GetUserDataKeys()
{ {
var list = base.GetUserDataKeys(); var list = base.GetUserDataKeys();

View File

@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary> /// <summary>
/// Class MusicArtist /// Class MusicArtist
/// </summary> /// </summary>
public class MusicArtist : Folder, IMetadataContainer, IItemByName, IHasMusicGenres, IHasDualAccess, IHasProductionLocations, IHasLookupInfo<ArtistInfo> public class MusicArtist : Folder, IMetadataContainer, IItemByName, IHasMusicGenres, IHasDualAccess, IHasLookupInfo<ArtistInfo>
{ {
[IgnoreDataMember] [IgnoreDataMember]
public bool IsAccessedByName public bool IsAccessedByName
@ -24,8 +24,6 @@ namespace MediaBrowser.Controller.Entities.Audio
get { return ParentId == Guid.Empty; } get { return ParentId == Guid.Empty; }
} }
public List<string> ProductionLocations { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
public override bool IsFolder public override bool IsFolder
{ {
@ -50,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio
get { return true; } get { return true; }
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return false;
}
}
public override bool CanDelete() public override bool CanDelete()
{ {
return !IsAccessedByName; return !IsAccessedByName;
@ -111,11 +118,6 @@ namespace MediaBrowser.Controller.Entities.Audio
return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
} }
public MusicArtist()
{
ProductionLocations = new List<string>();
}
public override List<string> GetUserDataKeys() public override List<string> GetUserDataKeys()
{ {
var list = base.GetUserDataKeys(); var list = base.GetUserDataKeys();

View File

@ -37,6 +37,8 @@ namespace MediaBrowser.Controller.Entities
{ {
protected BaseItem() protected BaseItem()
{ {
ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>();
Keywords = new List<string>(); Keywords = new List<string>();
Tags = new List<string>(); Tags = new List<string>();
Genres = new List<string>(); Genres = new List<string>();
@ -44,6 +46,8 @@ namespace MediaBrowser.Controller.Entities
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
LockedFields = new List<MetadataFields>(); LockedFields = new List<MetadataFields>();
ImageInfos = new List<ItemImageInfo>(); ImageInfos = new List<ItemImageInfo>();
InheritedTags = new List<string>();
ProductionLocations = new List<string>();
} }
public static readonly char[] SlugReplaceChars = { '?', '/', '&' }; public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
@ -64,6 +68,9 @@ namespace MediaBrowser.Controller.Entities
public static string ThemeSongFilename = "theme"; public static string ThemeSongFilename = "theme";
public static string ThemeVideosFolderName = "backdrops"; public static string ThemeVideosFolderName = "backdrops";
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
public string PreferredMetadataCountryCode { get; set; } public string PreferredMetadataCountryCode { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
@ -72,6 +79,8 @@ namespace MediaBrowser.Controller.Entities
public long? Size { get; set; } public long? Size { get; set; }
public string Container { get; set; } public string Container { get; set; }
public string ShortOverview { get; set; } public string ShortOverview { get; set; }
[IgnoreDataMember]
public string Tagline { get; set; }
public List<ItemImageInfo> ImageInfos { get; set; } public List<ItemImageInfo> ImageInfos { get; set; }
@ -114,6 +123,31 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember] [IgnoreDataMember]
public bool IsInMixedFolder { get; set; } public bool IsInMixedFolder { get; set; }
[IgnoreDataMember]
protected virtual bool SupportsIsInMixedFolderDetection
{
get { return false; }
}
[IgnoreDataMember]
public virtual bool SupportsPlayedStatus
{
get
{
return false;
}
}
public bool DetectIsInMixedFolder()
{
if (SupportsIsInMixedFolderDetection)
{
}
return IsInMixedFolder;
}
[IgnoreDataMember] [IgnoreDataMember]
public virtual bool SupportsRemoteImageDownloading public virtual bool SupportsRemoteImageDownloading
{ {
@ -254,6 +288,19 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
public string ExternalSeriesId { get; set; }
[IgnoreDataMember]
public string ExternalSeriesIdLegacy
{
get { return this.GetProviderId("ProviderExternalSeriesId"); }
set
{
this.SetProviderId("ProviderExternalSeriesId", value);
}
}
/// <summary> /// <summary>
/// Gets or sets the etag. /// Gets or sets the etag.
/// </summary> /// </summary>
@ -408,7 +455,7 @@ namespace MediaBrowser.Controller.Entities
public virtual bool IsInternetMetadataEnabled() public virtual bool IsInternetMetadataEnabled()
{ {
return ConfigurationManager.Configuration.EnableInternetProviders; return LibraryManager.GetLibraryOptions(this).EnableInternetProviders;
} }
public virtual bool CanDelete() public virtual bool CanDelete()
@ -784,6 +831,9 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember] [IgnoreDataMember]
public int InheritedParentalRatingValue { get; set; } public int InheritedParentalRatingValue { get; set; }
[IgnoreDataMember]
public List<string> InheritedTags { get; set; }
/// <summary> /// <summary>
/// Gets or sets the critic rating. /// Gets or sets the critic rating.
/// </summary> /// </summary>
@ -841,6 +891,7 @@ namespace MediaBrowser.Controller.Entities
public List<string> Tags { get; set; } public List<string> Tags { get; set; }
public List<string> Keywords { get; set; } public List<string> Keywords { get; set; }
public List<string> ProductionLocations { get; set; }
/// <summary> /// <summary>
/// Gets or sets the home page URL. /// Gets or sets the home page URL.
@ -956,7 +1007,7 @@ namespace MediaBrowser.Controller.Entities
/// Loads the theme songs. /// Loads the theme songs.
/// </summary> /// </summary>
/// <returns>List{Audio.Audio}.</returns> /// <returns>List{Audio.Audio}.</returns>
private IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) private static IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{ {
var files = fileSystemChildren.Where(i => i.IsDirectory) var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) .Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
@ -992,7 +1043,7 @@ namespace MediaBrowser.Controller.Entities
/// Loads the video backdrops. /// Loads the video backdrops.
/// </summary> /// </summary>
/// <returns>List{Video}.</returns> /// <returns>List{Video}.</returns>
private IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) private static IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{ {
var files = fileSystemChildren.Where(i => i.IsDirectory) var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) .Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
@ -1078,6 +1129,12 @@ namespace MediaBrowser.Controller.Entities
get { return true; } get { return true; }
} }
[IgnoreDataMember]
public virtual bool SupportsThemeMedia
{
get { return false; }
}
/// <summary> /// <summary>
/// Refreshes owned items such as trailers, theme videos, special features, etc. /// Refreshes owned items such as trailers, theme videos, special features, etc.
/// Returns true or false indicating if changes were found. /// Returns true or false indicating if changes were found.
@ -1096,14 +1153,13 @@ namespace MediaBrowser.Controller.Entities
if (LocationType == LocationType.FileSystem && GetParent() != null) if (LocationType == LocationType.FileSystem && GetParent() != null)
{ {
var hasThemeMedia = this as IHasThemeMedia; if (SupportsThemeMedia)
if (hasThemeMedia != null)
{ {
if (!IsInMixedFolder) if (!DetectIsInMixedFolder())
{ {
themeSongsChanged = await RefreshThemeSongs(hasThemeMedia, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); themeSongsChanged = await RefreshThemeSongs(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
themeVideosChanged = await RefreshThemeVideos(hasThemeMedia, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); themeVideosChanged = await RefreshThemeVideos(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
} }
} }
@ -1141,7 +1197,7 @@ namespace MediaBrowser.Controller.Entities
return itemsChanged; return itemsChanged;
} }
private async Task<bool> RefreshThemeVideos(IHasThemeMedia item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) private static async Task<bool> RefreshThemeVideos(BaseItem item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{ {
var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService).ToList(); var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService).ToList();
@ -1172,7 +1228,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// Refreshes the theme songs. /// Refreshes the theme songs.
/// </summary> /// </summary>
private async Task<bool> RefreshThemeSongs(IHasThemeMedia item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) private static async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{ {
var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService).ToList(); var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService).ToList();
var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList(); var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();
@ -1249,7 +1305,15 @@ namespace MediaBrowser.Controller.Entities
{ {
var current = this; var current = this;
return current.IsInMixedFolder == newItem.IsInMixedFolder; if (!SupportsIsInMixedFolderDetection)
{
if (current.IsInMixedFolder != newItem.IsInMixedFolder)
{
return false;
}
}
return true;
} }
public void AfterMetadataRefresh() public void AfterMetadataRefresh()
@ -1324,7 +1388,9 @@ namespace MediaBrowser.Controller.Entities
return false; return false;
} }
return ConfigurationManager.Configuration.SaveLocalMeta; var libraryOptions = LibraryManager.GetLibraryOptions(this);
return libraryOptions.SaveLocalMetadata;
} }
/// <summary> /// <summary>
@ -2107,14 +2173,11 @@ namespace MediaBrowser.Controller.Entities
return hasChanges; return hasChanges;
} }
protected static string GetMappedPath(string path, LocationType locationType) protected static string GetMappedPath(BaseItem item, string path, LocationType locationType)
{ {
if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
{ {
foreach (var map in ConfigurationManager.Configuration.PathSubstitutions) return LibraryManager.GetPathAfterNetworkSubstitution(path, item);
{
path = LibraryManager.SubstitutePath(path, map.From, map.To);
}
} }
return path; return path;

View File

@ -38,6 +38,15 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return false;
}
}
public override bool CanDelete() public override bool CanDelete()
{ {
return false; return false;
@ -48,24 +57,14 @@ namespace MediaBrowser.Controller.Entities
private static readonly Dictionary<string, LibraryOptions> LibraryOptions = new Dictionary<string, LibraryOptions>(); private static readonly Dictionary<string, LibraryOptions> LibraryOptions = new Dictionary<string, LibraryOptions>();
public LibraryOptions GetLibraryOptions() public LibraryOptions GetLibraryOptions()
{ {
lock (LibraryOptions) return GetLibraryOptions(Path);
{
LibraryOptions options;
if (!LibraryOptions.TryGetValue(Path, out options))
{
options = LoadLibraryOptions();
LibraryOptions[Path] = options;
}
return options;
}
} }
private LibraryOptions LoadLibraryOptions() private static LibraryOptions LoadLibraryOptions(string path)
{ {
try try
{ {
var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(Path)) as LibraryOptions; var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
if (result == null) if (result == null)
{ {
@ -100,13 +99,28 @@ namespace MediaBrowser.Controller.Entities
SaveLibraryOptions(Path, options); SaveLibraryOptions(Path, options);
} }
public static LibraryOptions GetLibraryOptions(string path)
{
lock (LibraryOptions)
{
LibraryOptions options;
if (!LibraryOptions.TryGetValue(path, out options))
{
options = LoadLibraryOptions(path);
LibraryOptions[path] = options;
}
return options;
}
}
public static void SaveLibraryOptions(string path, LibraryOptions options) public static void SaveLibraryOptions(string path, LibraryOptions options)
{ {
lock (LibraryOptions) lock (LibraryOptions)
{ {
LibraryOptions[path] = options; LibraryOptions[path] = options;
options.SchemaVersion = 2; options.SchemaVersion = 3;
XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path)); XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path));
} }
} }

View File

@ -22,13 +22,18 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// Class Folder /// Class Folder
/// </summary> /// </summary>
public class Folder : BaseItem, IHasThemeMedia public class Folder : BaseItem
{ {
public static IUserManager UserManager { get; set; } public static IUserManager UserManager { get; set; }
public static IUserViewManager UserViewManager { get; set; } public static IUserViewManager UserViewManager { get; set; }
public List<Guid> ThemeSongIds { get; set; } /// <summary>
public List<Guid> ThemeVideoIds { get; set; } /// Gets or sets a value indicating whether this instance is root.
/// </summary>
/// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value>
public bool IsRoot { get; set; }
public virtual List<LinkedChild> LinkedChildren { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
public DateTime? DateLastMediaAdded { get; set; } public DateTime? DateLastMediaAdded { get; set; }
@ -36,9 +41,12 @@ namespace MediaBrowser.Controller.Entities
public Folder() public Folder()
{ {
LinkedChildren = new List<LinkedChild>(); LinkedChildren = new List<LinkedChild>();
}
ThemeSongIds = new List<Guid>(); [IgnoreDataMember]
ThemeVideoIds = new List<Guid>(); public override bool SupportsThemeMedia
{
get { return true; }
} }
[IgnoreDataMember] [IgnoreDataMember]
@ -47,6 +55,21 @@ namespace MediaBrowser.Controller.Entities
get { return false; } get { return false; }
} }
[IgnoreDataMember]
public virtual bool IsPhysicalRoot
{
get { return false; }
}
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return true;
}
}
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is folder. /// Gets a value indicating whether this instance is folder.
/// </summary> /// </summary>
@ -117,19 +140,6 @@ namespace MediaBrowser.Controller.Entities
return true; return true;
} }
/// <summary>
/// Gets or sets a value indicating whether this instance is physical root.
/// </summary>
/// <value><c>true</c> if this instance is physical root; otherwise, <c>false</c>.</value>
public bool IsPhysicalRoot { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is root.
/// </summary>
/// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value>
public bool IsRoot { get; set; }
public virtual List<LinkedChild> LinkedChildren { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
protected virtual bool SupportsShortcutChildren protected virtual bool SupportsShortcutChildren
{ {
@ -178,8 +188,6 @@ namespace MediaBrowser.Controller.Entities
item.SetParent(null); item.SetParent(null);
} }
#region Indexing
/// <summary> /// <summary>
/// Returns the valid set of index by options for this folder type. /// Returns the valid set of index by options for this folder type.
/// Override or extend to modify. /// Override or extend to modify.
@ -207,8 +215,6 @@ namespace MediaBrowser.Controller.Entities
get { return GetIndexByOptions(); } get { return GetIndexByOptions(); }
} }
#endregion
/// <summary> /// <summary>
/// Gets the actual children. /// Gets the actual children.
/// </summary> /// </summary>
@ -801,18 +807,6 @@ namespace MediaBrowser.Controller.Entities
return true; return true;
} }
if (query.HasThemeSong.HasValue)
{
Logger.Debug("Query requires post-filtering due to HasThemeSong");
return true;
}
if (query.HasThemeVideo.HasValue)
{
Logger.Debug("Query requires post-filtering due to HasThemeVideo");
return true;
}
// Filter by VideoType // Filter by VideoType
if (query.VideoTypes.Length > 0) if (query.VideoTypes.Length > 0)
{ {
@ -1149,29 +1143,19 @@ namespace MediaBrowser.Controller.Entities
return LinkedChildren return LinkedChildren
.Select(i => .Select(i =>
{ {
var requiresPostFilter = true;
if (!string.IsNullOrWhiteSpace(i.Path))
{
requiresPostFilter = false;
if (!locations.Any(l => FileSystem.ContainsSubPath(l, i.Path)))
{
return null;
}
}
var child = GetLinkedChild(i); var child = GetLinkedChild(i);
if (requiresPostFilter && child != null) if (child != null)
{ {
if (string.IsNullOrWhiteSpace(child.Path)) var childLocationType = child.LocationType;
if (childLocationType == LocationType.Remote || childLocationType == LocationType.Virtual)
{ {
Logger.Debug("Found LinkedChild with null path: {0}", child.Name); if (!child.IsVisibleStandalone(user))
return child; {
return null;
}
} }
else if (childLocationType == LocationType.FileSystem && !locations.Any(l => FileSystem.ContainsSubPath(l, child.Path)))
if (!locations.Any(l => FileSystem.ContainsSubPath(l, child.Path)))
{ {
return null; return null;
} }

View File

@ -8,19 +8,14 @@ using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
public class Game : BaseItem, IHasTrailers, IHasThemeMedia, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo> public class Game : BaseItem, IHasTrailers, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
{ {
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
public Game() public Game()
{ {
MultiPartGameFiles = new List<string>(); MultiPartGameFiles = new List<string>();
RemoteTrailers = new List<MediaUrl>(); RemoteTrailers = new List<MediaUrl>();
LocalTrailerIds = new List<Guid>(); LocalTrailerIds = new List<Guid>();
RemoteTrailerIds = new List<Guid>(); RemoteTrailerIds = new List<Guid>();
ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>();
} }
public List<Guid> LocalTrailerIds { get; set; } public List<Guid> LocalTrailerIds { get; set; }
@ -39,6 +34,12 @@ namespace MediaBrowser.Controller.Entities
get { return true; } get { return true; }
} }
[IgnoreDataMember]
public override bool SupportsThemeMedia
{
get { return true; }
}
/// <summary> /// <summary>
/// Gets or sets the remote trailers. /// Gets or sets the remote trailers.
/// </summary> /// </summary>
@ -98,7 +99,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<string> GetDeletePaths() public override IEnumerable<string> GetDeletePaths()
{ {
if (!IsInMixedFolder) if (!DetectIsInMixedFolder())
{ {
return new[] { System.IO.Path.GetDirectoryName(Path) }; return new[] { System.IO.Path.GetDirectoryName(Path) };
} }

View File

@ -26,6 +26,15 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return false;
}
}
/// <summary> /// <summary>
/// Gets or sets the game system. /// Gets or sets the game system.
/// </summary> /// </summary>

View File

@ -1,8 +0,0 @@

namespace MediaBrowser.Controller.Entities
{
public interface IArchivable
{
bool IsArchive { get; }
}
}

View File

@ -150,11 +150,7 @@ namespace MediaBrowser.Controller.Entities
/// <value><c>true</c> if [supports local metadata]; otherwise, <c>false</c>.</value> /// <value><c>true</c> if [supports local metadata]; otherwise, <c>false</c>.</value>
bool SupportsLocalMetadata { get; } bool SupportsLocalMetadata { get; }
/// <summary> bool DetectIsInMixedFolder();
/// Gets a value indicating whether this instance is in mixed folder.
/// </summary>
/// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value>
bool IsInMixedFolder { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is locked. /// Gets a value indicating whether this instance is locked.

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
@ -62,5 +63,7 @@ namespace MediaBrowser.Controller.Entities
int? GetInheritedParentalRatingValue(); int? GetInheritedParentalRatingValue();
int InheritedParentalRatingValue { get; set; } int InheritedParentalRatingValue { get; set; }
List<string> GetInheritedTags();
List<string> InheritedTags { get; set; }
} }
} }

View File

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasProductionLocations
/// </summary>
public interface IHasProductionLocations
{
/// <summary>
/// Gets or sets the production locations.
/// </summary>
/// <value>The production locations.</value>
List<string> ProductionLocations { get; set; }
}
public static class ProductionLocationExtensions
{
public static void AddProductionLocation(this IHasProductionLocations item, string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException("name");
}
if (!item.ProductionLocations.Contains(name, StringComparer.OrdinalIgnoreCase))
{
item.ProductionLocations.Add(name);
}
}
}
}

View File

@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasTaglines
/// </summary>
public interface IHasTaglines
{
/// <summary>
/// Gets or sets the taglines.
/// </summary>
/// <value>The taglines.</value>
List<string> Taglines { get; set; }
}
public static class TaglineExtensions
{
/// <summary>
/// Adds the tagline.
/// </summary>
/// <param name="tagline">The tagline.</param>
/// <exception cref="System.ArgumentNullException">tagline</exception>
public static void AddTagline(this IHasTaglines item, string tagline)
{
if (string.IsNullOrWhiteSpace(tagline))
{
throw new ArgumentNullException("tagline");
}
if (!item.Taglines.Contains(tagline, StringComparer.OrdinalIgnoreCase))
{
item.Taglines.Add(tagline);
}
}
}
}

View File

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasThemeMedia
/// </summary>
public interface IHasThemeMedia
{
/// <summary>
/// Gets or sets the theme song ids.
/// </summary>
/// <value>The theme song ids.</value>
List<Guid> ThemeSongIds { get; set; }
/// <summary>
/// Gets or sets the theme video ids.
/// </summary>
/// <value>The theme video ids.</value>
List<Guid> ThemeVideoIds { get; set; }
}
}

View File

@ -20,5 +20,7 @@ namespace MediaBrowser.Controller.Entities
Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user); Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
bool EnableRememberingTrackSelections { get; } bool EnableRememberingTrackSelections { get; }
bool SupportsPlayedStatus { get; }
} }
} }

View File

@ -2,6 +2,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using System.Linq;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
@ -101,6 +104,8 @@ namespace MediaBrowser.Controller.Entities
public bool? IsMovie { get; set; } public bool? IsMovie { get; set; }
public bool? IsSports { get; set; } public bool? IsSports { get; set; }
public bool? IsKids { get; set; } public bool? IsKids { get; set; }
public bool? IsNews { get; set; }
public bool? IsSeries { get; set; }
public int? MinPlayers { get; set; } public int? MinPlayers { get; set; }
public int? MaxPlayers { get; set; } public int? MaxPlayers { get; set; }
@ -137,6 +142,7 @@ namespace MediaBrowser.Controller.Entities
public DayOfWeek[] AirDays { get; set; } public DayOfWeek[] AirDays { get; set; }
public SeriesStatus[] SeriesStatuses { get; set; } public SeriesStatus[] SeriesStatuses { get; set; }
public string AlbumArtistStartsWithOrGreater { get; set; } public string AlbumArtistStartsWithOrGreater { get; set; }
public string ExternalSeriesId { get; set; }
public string[] AlbumNames { get; set; } public string[] AlbumNames { get; set; }
public string[] ArtistNames { get; set; } public string[] ArtistNames { get; set; }
@ -149,11 +155,53 @@ namespace MediaBrowser.Controller.Entities
public Dictionary<string, string> ExcludeProviderIds { get; set; } public Dictionary<string, string> ExcludeProviderIds { get; set; }
public bool EnableGroupByMetadataKey { get; set; } public bool EnableGroupByMetadataKey { get; set; }
public List<Tuple<string, SortOrder>> OrderBy { get; set; }
public DateTime? MinDateCreated { get; set; }
public DateTime? MinDateLastSaved { get; set; }
public DtoOptions DtoOptions { get; set; }
public bool HasField(ItemFields name)
{
var fields = DtoOptions.Fields;
switch (name)
{
case ItemFields.ThemeSongIds:
case ItemFields.ThemeVideoIds:
case ItemFields.ProductionLocations:
case ItemFields.Keywords:
case ItemFields.Taglines:
case ItemFields.ShortOverview:
case ItemFields.CustomRating:
case ItemFields.DateCreated:
case ItemFields.SortName:
case ItemFields.Overview:
case ItemFields.OfficialRatingDescription:
case ItemFields.HomePageUrl:
case ItemFields.VoteCount:
case ItemFields.DisplayMediaType:
case ItemFields.ServiceName:
case ItemFields.Genres:
case ItemFields.Studios:
case ItemFields.Settings:
case ItemFields.OriginalTitle:
case ItemFields.Tags:
case ItemFields.DateLastMediaAdded:
case ItemFields.CriticRatingSummary:
return fields.Count == 0 || fields.Contains(name);
default:
return true;
}
}
public InternalItemsQuery() public InternalItemsQuery()
{ {
GroupByPresentationUniqueKey = true; GroupByPresentationUniqueKey = true;
EnableTotalRecordCount = true; EnableTotalRecordCount = true;
DtoOptions = new DtoOptions();
AlbumNames = new string[] { }; AlbumNames = new string[] { };
ArtistNames = new string[] { }; ArtistNames = new string[] { };
ExcludeArtistIds = new string[] { }; ExcludeArtistIds = new string[] { };
@ -191,6 +239,7 @@ namespace MediaBrowser.Controller.Entities
TrailerTypes = new TrailerType[] { }; TrailerTypes = new TrailerType[] { };
AirDays = new DayOfWeek[] { }; AirDays = new DayOfWeek[] { };
SeriesStatuses = new SeriesStatus[] { }; SeriesStatuses = new SeriesStatus[] { };
OrderBy = new List<Tuple<string, SortOrder>>();
} }
public InternalItemsQuery(User user) public InternalItemsQuery(User user)

View File

@ -15,24 +15,17 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <summary> /// <summary>
/// Class Movie /// Class Movie
/// </summary> /// </summary>
public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasProductionLocations, IHasBudget, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasBudget, IHasTrailers, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
{ {
public List<Guid> SpecialFeatureIds { get; set; } public List<Guid> SpecialFeatureIds { get; set; }
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
public List<string> ProductionLocations { get; set; }
public Movie() public Movie()
{ {
SpecialFeatureIds = new List<Guid>(); SpecialFeatureIds = new List<Guid>();
RemoteTrailers = new List<MediaUrl>(); RemoteTrailers = new List<MediaUrl>();
LocalTrailerIds = new List<Guid>(); LocalTrailerIds = new List<Guid>();
RemoteTrailerIds = new List<Guid>(); RemoteTrailerIds = new List<Guid>();
ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>();
Taglines = new List<string>(); Taglines = new List<string>();
ProductionLocations = new List<string>();
} }
public string AwardSummary { get; set; } public string AwardSummary { get; set; }
@ -75,13 +68,22 @@ namespace MediaBrowser.Controller.Entities.Movies
set { TmdbCollectionName = value; } set { TmdbCollectionName = value; }
} }
[IgnoreDataMember]
protected override bool SupportsIsInMixedFolderDetection
{
get
{
return false;
}
}
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{ {
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
// Must have a parent to have special features // Must have a parent to have special features
// In other words, it must be part of the Parent/Child tree // In other words, it must be part of the Parent/Child tree
if (LocationType == LocationType.FileSystem && GetParent() != null && !IsInMixedFolder) if (LocationType == LocationType.FileSystem && GetParent() != null && !DetectIsInMixedFolder())
{ {
var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@ -119,7 +121,7 @@ namespace MediaBrowser.Controller.Entities.Movies
{ {
var info = GetItemLookupInfo<MovieInfo>(); var info = GetItemLookupInfo<MovieInfo>();
if (!IsInMixedFolder) if (!DetectIsInMixedFolder())
{ {
info.Name = System.IO.Path.GetFileName(ContainingFolderPath); info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
} }
@ -145,7 +147,7 @@ namespace MediaBrowser.Controller.Entities.Movies
else else
{ {
// Try to get the year from the folder name // Try to get the year from the folder name
if (!IsInMixedFolder) if (!DetectIsInMixedFolder())
{ {
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));

View File

@ -6,7 +6,7 @@ using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasProductionLocations, IHasBudget, IHasLookupInfo<MusicVideoInfo> public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasBudget, IHasLookupInfo<MusicVideoInfo>
{ {
/// <summary> /// <summary>
/// Gets or sets the budget. /// Gets or sets the budget.
@ -19,12 +19,10 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
/// <value>The revenue.</value> /// <value>The revenue.</value>
public double? Revenue { get; set; } public double? Revenue { get; set; }
public List<string> ProductionLocations { get; set; }
public List<string> Artists { get; set; } public List<string> Artists { get; set; }
public MusicVideo() public MusicVideo()
{ {
ProductionLocations = new List<string>();
Artists = new List<string>(); Artists = new List<string>();
} }
@ -37,6 +35,15 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
protected override bool SupportsIsInMixedFolderDetection
{
get
{
return true;
}
}
public override UnratedItem GetBlockUnratedType() public override UnratedItem GetBlockUnratedType()
{ {
return UnratedItem.Music; return UnratedItem.Music;
@ -65,7 +72,7 @@ namespace MediaBrowser.Controller.Entities
else else
{ {
// Try to get the year from the folder name // Try to get the year from the folder name
if (!IsInMixedFolder) if (!DetectIsInMixedFolder())
{ {
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));

View File

@ -1,19 +1,11 @@
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
public class Photo : BaseItem, IHasTaglines public class Photo : BaseItem
{ {
public List<string> Taglines { get; set; }
public Photo()
{
Taglines = new List<string>();
}
[IgnoreDataMember] [IgnoreDataMember]
public override bool SupportsLocalMetadata public override bool SupportsLocalMetadata
{ {
@ -37,13 +29,13 @@ namespace MediaBrowser.Controller.Entities
{ {
get get
{ {
return Album; return AlbumEntity;
} }
} }
[IgnoreDataMember] [IgnoreDataMember]
public PhotoAlbum Album public PhotoAlbum AlbumEntity
{ {
get get
{ {

View File

@ -16,6 +16,15 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return false;
}
}
protected override bool GetBlockUnratedValue(UserPolicy config) protected override bool GetBlockUnratedValue(UserPolicy config)
{ {
return config.BlockUnratedItems.Contains(UnratedItem.Other); return config.BlockUnratedItems.Contains(UnratedItem.Other);

View File

@ -154,8 +154,6 @@ namespace MediaBrowser.Controller.Entities.TV
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
var id = Guid.NewGuid().ToString("N");
var items = GetEpisodes(user).Where(filter); var items = GetEpisodes(user).Where(filter);
var result = PostFilterAndSort(items, query, false, false); var result = PostFilterAndSort(items, query, false, false);

View File

@ -17,17 +17,14 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary> /// <summary>
/// Class Series /// Class Series
/// </summary> /// </summary>
public class Series : Folder, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IHasSpecialFeatures, IMetadataContainer, IHasOriginalTitle public class Series : Folder, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IMetadataContainer, IHasOriginalTitle
{ {
public List<Guid> SpecialFeatureIds { get; set; }
public int? AnimeSeriesIndex { get; set; } public int? AnimeSeriesIndex { get; set; }
public Series() public Series()
{ {
AirDays = new List<DayOfWeek>(); AirDays = new List<DayOfWeek>();
SpecialFeatureIds = new List<Guid>();
RemoteTrailers = new List<MediaUrl>(); RemoteTrailers = new List<MediaUrl>();
LocalTrailerIds = new List<Guid>(); LocalTrailerIds = new List<Guid>();
RemoteTrailerIds = new List<Guid>(); RemoteTrailerIds = new List<Guid>();

View File

@ -10,16 +10,12 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// Class Trailer /// Class Trailer
/// </summary> /// </summary>
public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasTaglines, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo> public class Trailer : Video, IHasCriticRating, IHasBudget, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
{ {
public List<string> ProductionLocations { get; set; }
public Trailer() public Trailer()
{ {
RemoteTrailers = new List<MediaUrl>(); RemoteTrailers = new List<MediaUrl>();
Taglines = new List<string>();
Keywords = new List<string>(); Keywords = new List<string>();
ProductionLocations = new List<string>();
TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer }; TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer };
} }
@ -35,12 +31,6 @@ namespace MediaBrowser.Controller.Entities
get { return TrailerTypes.Contains(TrailerType.LocalTrailer); } get { return TrailerTypes.Contains(TrailerType.LocalTrailer); }
} }
/// <summary>
/// Gets or sets the taglines.
/// </summary>
/// <value>The taglines.</value>
public List<string> Taglines { get; set; }
/// <summary> /// <summary>
/// Gets or sets the budget. /// Gets or sets the budget.
/// </summary> /// </summary>
@ -64,7 +54,7 @@ namespace MediaBrowser.Controller.Entities
info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer); info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
if (!IsInMixedFolder && LocationType == LocationType.FileSystem) if (!DetectIsInMixedFolder() && LocationType == LocationType.FileSystem)
{ {
info.Name = System.IO.Path.GetFileName(ContainingFolderPath); info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
} }
@ -90,7 +80,7 @@ namespace MediaBrowser.Controller.Entities
else else
{ {
// Try to get the year from the folder name // Try to get the year from the folder name
if (!IsInMixedFolder) if (!DetectIsInMixedFolder())
{ {
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));

View File

@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return false;
}
}
private void ClearCache() private void ClearCache()
{ {
lock (_childIdsLock) lock (_childIdsLock)

View File

@ -13,7 +13,6 @@ namespace MediaBrowser.Controller.Entities
public class UserView : Folder public class UserView : Folder
{ {
public string ViewType { get; set; } public string ViewType { get; set; }
public Guid ParentId { get; set; }
public Guid DisplayParentId { get; set; } public Guid DisplayParentId { get; set; }
public Guid? UserId { get; set; } public Guid? UserId { get; set; }
@ -45,6 +44,15 @@ namespace MediaBrowser.Controller.Entities
return list; return list;
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return false;
}
}
public override int GetChildCount(User user) public override int GetChildCount(User user)
{ {
return GetChildren(user, true).Count(); return GetChildren(user, true).Count();

View File

@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities
Limit = query.Limit, Limit = query.Limit,
IsAiring = true IsAiring = true
}, CancellationToken.None).ConfigureAwait(false); }, new Dto.DtoOptions(), CancellationToken.None).ConfigureAwait(false);
return GetResult(result); return GetResult(result);
} }
@ -1497,13 +1497,7 @@ namespace MediaBrowser.Controller.Entities
{ {
var filterValue = query.HasThemeSong.Value; var filterValue = query.HasThemeSong.Value;
var themeCount = 0; var themeCount = item.ThemeSongIds.Count;
var iHasThemeMedia = item as IHasThemeMedia;
if (iHasThemeMedia != null)
{
themeCount = iHasThemeMedia.ThemeSongIds.Count;
}
var ok = filterValue ? themeCount > 0 : themeCount == 0; var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok) if (!ok)
@ -1516,13 +1510,7 @@ namespace MediaBrowser.Controller.Entities
{ {
var filterValue = query.HasThemeVideo.Value; var filterValue = query.HasThemeVideo.Value;
var themeCount = 0; var themeCount = item.ThemeVideoIds.Count;
var iHasThemeMedia = item as IHasThemeMedia;
if (iHasThemeMedia != null)
{
themeCount = iHasThemeMedia.ThemeVideoIds.Count;
}
var ok = filterValue ? themeCount > 0 : themeCount == 0; var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok) if (!ok)

View File

@ -25,8 +25,7 @@ namespace MediaBrowser.Controller.Entities
ISupportsPlaceHolders, ISupportsPlaceHolders,
IHasMediaSources, IHasMediaSources,
IHasShortOverview, IHasShortOverview,
IThemeMedia, IThemeMedia
IArchivable
{ {
[IgnoreDataMember] [IgnoreDataMember]
public string PrimaryVersionId { get; set; } public string PrimaryVersionId { get; set; }
@ -45,6 +44,24 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return true;
}
}
[IgnoreDataMember]
protected override bool SupportsIsInMixedFolderDetection
{
get
{
return true;
}
}
public override string CreatePresentationUniqueKey() public override string CreatePresentationUniqueKey()
{ {
if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
@ -64,6 +81,12 @@ namespace MediaBrowser.Controller.Entities
} }
} }
[IgnoreDataMember]
public override bool SupportsThemeMedia
{
get { return true; }
}
public int? TotalBitrate { get; set; } public int? TotalBitrate { get; set; }
public ExtraType? ExtraType { get; set; } public ExtraType? ExtraType { get; set; }
@ -165,7 +188,7 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember] [IgnoreDataMember]
public override bool SupportsAddingToPlaylist public override bool SupportsAddingToPlaylist
{ {
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; } get { return true; }
} }
[IgnoreDataMember] [IgnoreDataMember]
@ -197,21 +220,6 @@ namespace MediaBrowser.Controller.Entities
get { return LocalAlternateVersions.Count > 0; } get { return LocalAlternateVersions.Count > 0; }
} }
[IgnoreDataMember]
public bool IsArchive
{
get
{
if (string.IsNullOrWhiteSpace(Path))
{
return false;
}
var ext = System.IO.Path.GetExtension(Path) ?? string.Empty;
return new[] { ".zip", ".rar", ".7z" }.Contains(ext, StringComparer.OrdinalIgnoreCase);
}
}
public IEnumerable<Guid> GetAdditionalPartIds() public IEnumerable<Guid> GetAdditionalPartIds()
{ {
return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video))); return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
@ -480,7 +488,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<string> GetDeletePaths() public override IEnumerable<string> GetDeletePaths()
{ {
if (!IsInMixedFolder) if (!DetectIsInMixedFolder())
{ {
return new[] { ContainingFolderPath }; return new[] { ContainingFolderPath };
} }
@ -600,7 +608,7 @@ namespace MediaBrowser.Controller.Entities
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File, Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
MediaStreams = mediaStreams, MediaStreams = mediaStreams,
Name = GetMediaSourceName(i, mediaStreams), Name = GetMediaSourceName(i, mediaStreams),
Path = enablePathSubstitution ? GetMappedPath(i.Path, locationType) : i.Path, Path = enablePathSubstitution ? GetMappedPath(i, i.Path, locationType) : i.Path,
RunTimeTicks = i.RunTimeTicks, RunTimeTicks = i.RunTimeTicks,
Video3DFormat = i.Video3DFormat, Video3DFormat = i.Video3DFormat,
VideoType = i.VideoType, VideoType = i.VideoType,

View File

@ -506,6 +506,8 @@ namespace MediaBrowser.Controller.Library
/// <returns>QueryResult&lt;BaseItem&gt;.</returns> /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
QueryResult<BaseItem> QueryItems(InternalItemsQuery query); QueryResult<BaseItem> QueryItems(InternalItemsQuery query);
string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem = null);
/// <summary> /// <summary>
/// Substitutes the path. /// Substitutes the path.
/// </summary> /// </summary>
@ -554,9 +556,10 @@ namespace MediaBrowser.Controller.Library
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool IgnoreFile(FileSystemMetadata file, BaseItem parent); bool IgnoreFile(FileSystemMetadata file, BaseItem parent);
void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, LibraryOptions options, bool refreshLibrary); void AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary);
void RemoveVirtualFolder(string name, bool refreshLibrary); void RemoveVirtualFolder(string name, bool refreshLibrary);
void AddMediaPath(string virtualFolderName, string path); void AddMediaPath(string virtualFolderName, MediaPathInfo path);
void UpdateMediaPath(string virtualFolderName, MediaPathInfo path);
void RemoveMediaPath(string virtualFolderName, string path); void RemoveMediaPath(string virtualFolderName, string path);
QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query); QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);

View File

@ -7,6 +7,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO;
namespace MediaBrowser.Controller.Library namespace MediaBrowser.Controller.Library
{ {
@ -60,11 +61,8 @@ namespace MediaBrowser.Controller.Library
/// <summary> /// <summary>
/// Gets the static media source. /// Gets the static media source.
/// </summary> /// </summary>
/// <param name="item">The item.</param>
/// <param name="mediaSourceId">The media source identifier.</param>
/// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
/// <returns>MediaSourceInfo.</returns> /// <returns>MediaSourceInfo.</returns>
Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution); Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Opens the media source. /// Opens the media source.
@ -82,6 +80,8 @@ namespace MediaBrowser.Controller.Library
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns> /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
Task<MediaSourceInfo> GetLiveStream(string id, CancellationToken cancellationToken); Task<MediaSourceInfo> GetLiveStream(string id, CancellationToken cancellationToken);
Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Pings the media source. /// Pings the media source.
@ -95,8 +95,12 @@ namespace MediaBrowser.Controller.Library
/// Closes the media source. /// Closes the media source.
/// </summary> /// </summary>
/// <param name="id">The live stream identifier.</param> /// <param name="id">The live stream identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task CloseLiveStream(string id, CancellationToken cancellationToken); Task CloseLiveStream(string id);
}
public interface IDirectStreamProvider
{
Task CopyToAsync(Stream stream, CancellationToken cancellationToken);
} }
} }

View File

@ -3,6 +3,7 @@ using MediaBrowser.Model.Dto;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System;
namespace MediaBrowser.Controller.Library namespace MediaBrowser.Controller.Library
{ {
@ -22,14 +23,13 @@ namespace MediaBrowser.Controller.Library
/// <param name="openToken">The open token.</param> /// <param name="openToken">The open token.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns> /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
Task<MediaSourceInfo> OpenMediaSource(string openToken, CancellationToken cancellationToken); Task<Tuple<MediaSourceInfo,IDirectStreamProvider>> OpenMediaSource(string openToken, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Closes the media source. /// Closes the media source.
/// </summary> /// </summary>
/// <param name="liveStreamId">The live stream identifier.</param> /// <param name="liveStreamId">The live stream identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken); Task CloseMediaSource(string liveStreamId);
} }
} }

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Events; using MediaBrowser.Model.Events;
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
@ -37,7 +38,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{SeriesTimerInfoDto}.</returns> /// <returns>Task{SeriesTimerInfoDto}.</returns>
Task<SeriesTimerInfoDto> GetNewTimerDefaults(string programId, CancellationToken cancellationToken); Task<SeriesTimerInfoDto> GetNewTimerDefaults(string programId, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Deletes the recording. /// Deletes the recording.
/// </summary> /// </summary>
@ -51,7 +52,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="recording">The recording.</param> /// <param name="recording">The recording.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task DeleteRecording(BaseItem recording); Task DeleteRecording(BaseItem recording);
/// <summary> /// <summary>
/// Cancels the timer. /// Cancels the timer.
/// </summary> /// </summary>
@ -83,7 +84,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <returns>Task{RecordingInfoDto}.</returns> /// <returns>Task{RecordingInfoDto}.</returns>
Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null); Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null);
/// <summary> /// <summary>
/// Gets the timer. /// Gets the timer.
/// </summary> /// </summary>
@ -125,14 +126,14 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{QueryResult{SeriesTimerInfoDto}}.</returns> /// <returns>Task{QueryResult{SeriesTimerInfoDto}}.</returns>
Task<QueryResult<SeriesTimerInfoDto>> GetSeriesTimers(SeriesTimerQuery query, CancellationToken cancellationToken); Task<QueryResult<SeriesTimerInfoDto>> GetSeriesTimers(SeriesTimerQuery query, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the channel. /// Gets the channel.
/// </summary> /// </summary>
/// <param name="id">The identifier.</param> /// <param name="id">The identifier.</param>
/// <returns>Channel.</returns> /// <returns>Channel.</returns>
LiveTvChannel GetInternalChannel(string id); LiveTvChannel GetInternalChannel(string id);
/// <summary> /// <summary>
/// Gets the recording. /// Gets the recording.
/// </summary> /// </summary>
@ -156,8 +157,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="mediaSourceId">The media source identifier.</param> /// <param name="mediaSourceId">The media source identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{StreamResponseInfo}.</returns> /// <returns>Task{StreamResponseInfo}.</returns>
Task<MediaSourceInfo> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken); Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the program. /// Gets the program.
/// </summary> /// </summary>
@ -220,9 +221,8 @@ namespace MediaBrowser.Controller.LiveTv
/// Closes the live stream. /// Closes the live stream.
/// </summary> /// </summary>
/// <param name="id">The identifier.</param> /// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task CloseLiveStream(string id, CancellationToken cancellationToken); Task CloseLiveStream(string id);
/// <summary> /// <summary>
/// Gets the guide information. /// Gets the guide information.
@ -242,10 +242,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary> /// <summary>
/// Gets the recommended programs internal. /// Gets the recommended programs internal.
/// </summary> /// </summary>
/// <param name="query">The query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;QueryResult&lt;LiveTvProgram&gt;&gt;.</returns> /// <returns>Task&lt;QueryResult&lt;LiveTvProgram&gt;&gt;.</returns>
Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken); Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the live tv information. /// Gets the live tv information.
@ -303,18 +301,12 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary> /// <summary>
/// Gets the recording media sources. /// Gets the recording media sources.
/// </summary> /// </summary>
/// <param name="id">The identifier.</param> Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(IHasMediaSources item, CancellationToken cancellationToken);
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(string id, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the channel media sources. /// Gets the channel media sources.
/// </summary> /// </summary>
/// <param name="id">The identifier.</param> Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(IHasMediaSources item, CancellationToken cancellationToken);
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(string id, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Adds the information to recording dto. /// Adds the information to recording dto.
@ -331,8 +323,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="fields">The fields.</param> /// <param name="fields">The fields.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task AddInfoToProgramDto(List<Tuple<BaseItem,BaseItemDto>> programs, List<ItemFields> fields, User user = null); Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> programs, List<ItemFields> fields, User user = null);
/// <summary> /// <summary>
/// Saves the tuner host. /// Saves the tuner host.
/// </summary> /// </summary>
@ -395,7 +387,7 @@ namespace MediaBrowser.Controller.LiveTv
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken); Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken); Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
List<IListingsProvider> ListingProviders { get;} List<IListingsProvider> ListingProviders { get; }
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled; event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled; event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;

View File

@ -33,6 +33,7 @@ namespace MediaBrowser.Controller.LiveTv
bool CanDelete(User user); bool CanDelete(User user);
string SeriesTimerId { get; set; } string SeriesTimerId { get; set; }
string TimerId { get; set; }
RecordingStatus Status { get; set; } RecordingStatus Status { get; set; }
DateTime? EndDate { get; set; } DateTime? EndDate { get; set; }
DateTime DateLastSaved { get; set; } DateTime DateLastSaved { get; set; }

View File

@ -4,6 +4,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
@ -245,4 +246,14 @@ namespace MediaBrowser.Controller.LiveTv
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken); Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken);
} }
public interface ISupportsDirectStreamProvider
{
Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetChannelStreamWithDirectStreamProvider(string channelId, string streamId, CancellationToken cancellationToken);
}
public interface ISupportsUpdatingDefaults
{
Task UpdateTimerDefaults(SeriesTimerInfo info, CancellationToken cancellationToken);
}
} }

View File

@ -22,9 +22,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary> /// <summary>
/// Gets the channels. /// Gets the channels.
/// </summary> /// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;IEnumerable&lt;ChannelInfo&gt;&gt;.</returns> /// <returns>Task&lt;IEnumerable&lt;ChannelInfo&gt;&gt;.</returns>
Task<IEnumerable<ChannelInfo>> GetChannels(CancellationToken cancellationToken); Task<IEnumerable<ChannelInfo>> GetChannels(bool enableCache, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the tuner infos. /// Gets the tuner infos.
/// </summary> /// </summary>
@ -38,7 +37,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="streamId">The stream identifier.</param> /// <param name="streamId">The stream identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns> /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
Task<Tuple<MediaSourceInfo,SemaphoreSlim>> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken); Task<LiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the channel stream media sources. /// Gets the channel stream media sources.
/// </summary> /// </summary>
@ -46,8 +45,6 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;List&lt;MediaSourceInfo&gt;&gt;.</returns> /// <returns>Task&lt;List&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
string ApplyDuration(string streamPath, TimeSpan duration);
} }
public interface IConfigurableTunerHost public interface IConfigurableTunerHost
{ {

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.LiveTv
{
public class LiveStream
{
public MediaSourceInfo OriginalMediaSource { get; set; }
public MediaSourceInfo OpenedMediaSource { get; set; }
public int ConsumerCount {
get { return SharedStreamIds.Count; }
}
public ITunerHost TunerHost { get; set; }
public string OriginalStreamId { get; set; }
public bool EnableStreamSharing { get; set; }
public string UniqueId = Guid.NewGuid().ToString("N");
public List<string> SharedStreamIds = new List<string>();
public LiveStream(MediaSourceInfo mediaSource)
{
OriginalMediaSource = mediaSource;
OpenedMediaSource = mediaSource;
EnableStreamSharing = true;
}
public Task Open(CancellationToken cancellationToken)
{
return OpenInternal(cancellationToken);
}
protected virtual Task OpenInternal(CancellationToken cancellationToken)
{
return Task.FromResult(true);
}
public virtual Task Close()
{
return Task.FromResult(true);
}
}
}

View File

@ -20,6 +20,7 @@ namespace MediaBrowser.Controller.LiveTv
[IgnoreDataMember] [IgnoreDataMember]
public bool IsSeries { get; set; } public bool IsSeries { get; set; }
public string SeriesTimerId { get; set; } public string SeriesTimerId { get; set; }
public string TimerId { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
public DateTime StartDate { get; set; } public DateTime StartDate { get; set; }
public RecordingStatus Status { get; set; } public RecordingStatus Status { get; set; }
@ -112,7 +113,7 @@ namespace MediaBrowser.Controller.LiveTv
public override bool CanDelete() public override bool CanDelete()
{ {
return true; return Status == RecordingStatus.Completed;
} }
public override bool IsAuthorizedToDelete(User user) public override bool IsAuthorizedToDelete(User user)

View File

@ -5,11 +5,12 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization; using System.Runtime.Serialization;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
public class LiveTvChannel : BaseItem, IHasMediaSources public class LiveTvChannel : BaseItem, IHasMediaSources, IHasProgramAttributes
{ {
public override List<string> GetUserDataKeys() public override List<string> GetUserDataKeys()
{ {
@ -81,10 +82,10 @@ namespace MediaBrowser.Controller.LiveTv
if (!string.IsNullOrEmpty(Number)) if (!string.IsNullOrEmpty(Number))
{ {
double.TryParse(Number, out number); double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number);
} }
return number.ToString("000-") + (Name ?? string.Empty); return number.ToString("00000-") + (Name ?? string.Empty);
} }
[IgnoreDataMember] [IgnoreDataMember]
@ -137,5 +138,56 @@ namespace MediaBrowser.Controller.LiveTv
{ {
return false; return false;
} }
[IgnoreDataMember]
public bool IsMovie { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is sports.
/// </summary>
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
[IgnoreDataMember]
public bool IsSports { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is series.
/// </summary>
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
[IgnoreDataMember]
public bool IsSeries { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is live.
/// </summary>
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
[IgnoreDataMember]
public bool IsLive { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is news.
/// </summary>
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
[IgnoreDataMember]
public bool IsNews { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is kids.
/// </summary>
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
[IgnoreDataMember]
public bool IsKids { get; set; }
[IgnoreDataMember]
public bool IsPremiere { get; set; }
[IgnoreDataMember]
public bool IsRepeat { get; set; }
/// <summary>
/// Gets or sets the episode title.
/// </summary>
/// <value>The episode title.</value>
[IgnoreDataMember]
public string EpisodeTitle { get; set; }
} }
} }

View File

@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.LiveTv
[IgnoreDataMember] [IgnoreDataMember]
public bool IsSeries { get; set; } public bool IsSeries { get; set; }
public string SeriesTimerId { get; set; } public string SeriesTimerId { get; set; }
public string TimerId { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
public DateTime StartDate { get; set; } public DateTime StartDate { get; set; }
public RecordingStatus Status { get; set; } public RecordingStatus Status { get; set; }
@ -53,6 +54,24 @@ namespace MediaBrowser.Controller.LiveTv
} }
} }
[IgnoreDataMember]
protected override bool SupportsIsInMixedFolderDetection
{
get
{
return false;
}
}
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return Status == RecordingStatus.Completed && base.SupportsPlayedStatus;
}
}
[IgnoreDataMember] [IgnoreDataMember]
public override LocationType LocationType public override LocationType LocationType
{ {
@ -111,7 +130,7 @@ namespace MediaBrowser.Controller.LiveTv
public override bool CanDelete() public override bool CanDelete()
{ {
return true; return Status == RecordingStatus.Completed;
} }
public override bool IsAuthorizedToDelete(User user) public override bool IsAuthorizedToDelete(User user)

View File

@ -107,6 +107,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <value>The image URL.</value> /// <value>The image URL.</value>
public string ImageUrl { get; set; } public string ImageUrl { get; set; }
public string LogoImageUrl { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether this instance has image. /// Gets or sets a value indicating whether this instance has image.
/// </summary> /// </summary>

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using MediaBrowser.Model.LiveTv;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
@ -26,6 +27,8 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary> /// </summary>
public string Name { get; set; } public string Name { get; set; }
public string ServiceName { get; set; }
/// <summary> /// <summary>
/// Description of the recording. /// Description of the recording.
/// </summary> /// </summary>
@ -53,6 +56,11 @@ namespace MediaBrowser.Controller.LiveTv
/// <value><c>true</c> if [record any channel]; otherwise, <c>false</c>.</value> /// <value><c>true</c> if [record any channel]; otherwise, <c>false</c>.</value>
public bool RecordAnyChannel { get; set; } public bool RecordAnyChannel { get; set; }
public int KeepUpTo { get; set; }
public KeepUntil KeepUntil { get; set; }
public bool SkipEpisodesInLibrary { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether [record new only]. /// Gets or sets a value indicating whether [record new only].
/// </summary> /// </summary>
@ -104,6 +112,8 @@ namespace MediaBrowser.Controller.LiveTv
public SeriesTimerInfo() public SeriesTimerInfo()
{ {
Days = new List<DayOfWeek>(); Days = new List<DayOfWeek>();
SkipEpisodesInLibrary = true;
KeepUntil = KeepUntil.UntilDeleted;
} }
} }
} }

View File

@ -1,10 +1,17 @@
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using System; using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
public class TimerInfo public class TimerInfo
{ {
public TimerInfo()
{
Genres = new List<string>();
KeepUntil = KeepUntil.UntilDeleted;
}
/// <summary> /// <summary>
/// Id of the recording. /// Id of the recording.
/// </summary> /// </summary>
@ -15,7 +22,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary> /// </summary>
/// <value>The series timer identifier.</value> /// <value>The series timer identifier.</value>
public string SeriesTimerId { get; set; } public string SeriesTimerId { get; set; }
/// <summary> /// <summary>
/// ChannelId of the recording. /// ChannelId of the recording.
/// </summary> /// </summary>
@ -26,7 +33,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary> /// </summary>
/// <value>The program identifier.</value> /// <value>The program identifier.</value>
public string ProgramId { get; set; } public string ProgramId { get; set; }
/// <summary> /// <summary>
/// Name of the recording. /// Name of the recording.
/// </summary> /// </summary>
@ -76,11 +83,36 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary> /// </summary>
/// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value> /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
public bool IsPostPaddingRequired { get; set; } public bool IsPostPaddingRequired { get; set; }
/// <summary> /// <summary>
/// Gets or sets the priority. /// Gets or sets the priority.
/// </summary> /// </summary>
/// <value>The priority.</value> /// <value>The priority.</value>
public int Priority { get; set; } public int Priority { get; set; }
// Program properties
public int? SeasonNumber { get; set; }
/// <summary>
/// Gets or sets the episode number.
/// </summary>
/// <value>The episode number.</value>
public int? EpisodeNumber { get; set; }
public bool IsMovie { get; set; }
public bool IsKids { get; set; }
public bool IsSports { get; set; }
public bool IsNews { get; set; }
public int? ProductionYear { get; set; }
public string EpisodeTitle { get; set; }
public DateTime? OriginalAirDate { get; set; }
public bool IsProgramSeries { get; set; }
public bool IsRepeat { get; set; }
public string HomePageUrl { get; set; }
public float? CommunityRating { get; set; }
public string ShortOverview { get; set; }
public string OfficialRating { get; set; }
public List<string> Genres { get; set; }
public string RecordingPath { get; set; }
public KeepUntil KeepUntil { get; set; }
} }
} }

View File

@ -91,10 +91,7 @@
<Compile Include="Channels\InternalChannelItemQuery.cs" /> <Compile Include="Channels\InternalChannelItemQuery.cs" />
<Compile Include="Channels\IRequiresMediaInfoCallback.cs" /> <Compile Include="Channels\IRequiresMediaInfoCallback.cs" />
<Compile Include="Channels\ISearchableChannel.cs" /> <Compile Include="Channels\ISearchableChannel.cs" />
<Compile Include="Chapters\ChapterSearchRequest.cs" />
<Compile Include="Chapters\IChapterManager.cs" /> <Compile Include="Chapters\IChapterManager.cs" />
<Compile Include="Chapters\IChapterProvider.cs" />
<Compile Include="Chapters\ChapterResponse.cs" />
<Compile Include="Collections\CollectionCreationOptions.cs" /> <Compile Include="Collections\CollectionCreationOptions.cs" />
<Compile Include="Collections\CollectionEvents.cs" /> <Compile Include="Collections\CollectionEvents.cs" />
<Compile Include="Collections\ICollectionManager.cs" /> <Compile Include="Collections\ICollectionManager.cs" />
@ -135,7 +132,6 @@
<Compile Include="Entities\Game.cs" /> <Compile Include="Entities\Game.cs" />
<Compile Include="Entities\GameGenre.cs" /> <Compile Include="Entities\GameGenre.cs" />
<Compile Include="Entities\GameSystem.cs" /> <Compile Include="Entities\GameSystem.cs" />
<Compile Include="Entities\IArchivable.cs" />
<Compile Include="Entities\IByReferenceItem.cs" /> <Compile Include="Entities\IByReferenceItem.cs" />
<Compile Include="Entities\IHasAspectRatio.cs" /> <Compile Include="Entities\IHasAspectRatio.cs" />
<Compile Include="Entities\IHasBudget.cs" /> <Compile Include="Entities\IHasBudget.cs" />
@ -147,15 +143,12 @@
<Compile Include="Entities\IHasMediaSources.cs" /> <Compile Include="Entities\IHasMediaSources.cs" />
<Compile Include="Entities\IHasMetascore.cs" /> <Compile Include="Entities\IHasMetascore.cs" />
<Compile Include="Entities\IHasOriginalTitle.cs" /> <Compile Include="Entities\IHasOriginalTitle.cs" />
<Compile Include="Entities\IHasProductionLocations.cs" />
<Compile Include="Entities\IHasProgramAttributes.cs" /> <Compile Include="Entities\IHasProgramAttributes.cs" />
<Compile Include="Entities\IHasScreenshots.cs" /> <Compile Include="Entities\IHasScreenshots.cs" />
<Compile Include="Entities\IHasSeries.cs" /> <Compile Include="Entities\IHasSeries.cs" />
<Compile Include="Entities\IHasShortOverview.cs" /> <Compile Include="Entities\IHasShortOverview.cs" />
<Compile Include="Entities\IHasSpecialFeatures.cs" /> <Compile Include="Entities\IHasSpecialFeatures.cs" />
<Compile Include="Entities\IHasStartDate.cs" /> <Compile Include="Entities\IHasStartDate.cs" />
<Compile Include="Entities\IHasTaglines.cs" />
<Compile Include="Entities\IHasThemeMedia.cs" />
<Compile Include="Entities\IHasTrailers.cs" /> <Compile Include="Entities\IHasTrailers.cs" />
<Compile Include="Entities\IHasUserData.cs" /> <Compile Include="Entities\IHasUserData.cs" />
<Compile Include="Entities\IHiddenFromDisplay.cs" /> <Compile Include="Entities\IHiddenFromDisplay.cs" />
@ -201,6 +194,7 @@
<Compile Include="Library\UserDataSaveEventArgs.cs" /> <Compile Include="Library\UserDataSaveEventArgs.cs" />
<Compile Include="LiveTv\IListingsProvider.cs" /> <Compile Include="LiveTv\IListingsProvider.cs" />
<Compile Include="LiveTv\ITunerHost.cs" /> <Compile Include="LiveTv\ITunerHost.cs" />
<Compile Include="LiveTv\LiveStream.cs" />
<Compile Include="LiveTv\RecordingGroup.cs" /> <Compile Include="LiveTv\RecordingGroup.cs" />
<Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" /> <Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" />
<Compile Include="LiveTv\ILiveTvRecording.cs" /> <Compile Include="LiveTv\ILiveTvRecording.cs" />
@ -266,7 +260,6 @@
<Compile Include="Playlists\IPlaylistManager.cs" /> <Compile Include="Playlists\IPlaylistManager.cs" />
<Compile Include="Playlists\Playlist.cs" /> <Compile Include="Playlists\Playlist.cs" />
<Compile Include="Plugins\ILocalizablePlugin.cs" /> <Compile Include="Plugins\ILocalizablePlugin.cs" />
<Compile Include="Power\IPowerManagement.cs" />
<Compile Include="Providers\AlbumInfo.cs" /> <Compile Include="Providers\AlbumInfo.cs" />
<Compile Include="Providers\ArtistInfo.cs" /> <Compile Include="Providers\ArtistInfo.cs" />
<Compile Include="Providers\BookInfo.cs" /> <Compile Include="Providers\BookInfo.cs" />
@ -290,9 +283,7 @@
<Compile Include="Providers\IHasItemChangeMonitor.cs" /> <Compile Include="Providers\IHasItemChangeMonitor.cs" />
<Compile Include="Providers\IHasLookupInfo.cs" /> <Compile Include="Providers\IHasLookupInfo.cs" />
<Compile Include="Providers\IHasOrder.cs" /> <Compile Include="Providers\IHasOrder.cs" />
<Compile Include="Providers\IImageFileSaver.cs" />
<Compile Include="Providers\IImageProvider.cs" /> <Compile Include="Providers\IImageProvider.cs" />
<Compile Include="Providers\IImageSaver.cs" />
<Compile Include="Providers\ILocalImageFileProvider.cs" /> <Compile Include="Providers\ILocalImageFileProvider.cs" />
<Compile Include="Providers\ILocalMetadataProvider.cs" /> <Compile Include="Providers\ILocalMetadataProvider.cs" />
<Compile Include="Providers\ImageRefreshMode.cs" /> <Compile Include="Providers\ImageRefreshMode.cs" />
@ -319,7 +310,6 @@
<Compile Include="Providers\SongInfo.cs" /> <Compile Include="Providers\SongInfo.cs" />
<Compile Include="Providers\TrailerInfo.cs" /> <Compile Include="Providers\TrailerInfo.cs" />
<Compile Include="Providers\VideoContentType.cs" /> <Compile Include="Providers\VideoContentType.cs" />
<Compile Include="RelatedMedia\IRelatedMediaProvider.cs" />
<Compile Include="Security\AuthenticationInfo.cs" /> <Compile Include="Security\AuthenticationInfo.cs" />
<Compile Include="Security\AuthenticationInfoQuery.cs" /> <Compile Include="Security\AuthenticationInfoQuery.cs" />
<Compile Include="Security\IAuthenticationRepository.cs" /> <Compile Include="Security\IAuthenticationRepository.cs" />

View File

@ -45,9 +45,9 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="offset">The offset.</param> /// <param name="offset">The offset.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Stream}.</returns> /// <returns>Task{Stream}.</returns>
Task<string> ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
Task<string> ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken); Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Extracts the video images on interval. /// Extracts the video images on interval.
@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="inputFiles">The input files.</param> /// <param name="inputFiles">The input files.</param>
/// <param name="protocol">The protocol.</param> /// <param name="protocol">The protocol.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol); string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol);
/// <summary> /// <summary>
/// Gets the input argument. /// Gets the input argument.

View File

@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding
public IIsoMount MountedIso { get; set; } public IIsoMount MountedIso { get; set; }
public VideoType VideoType { get; set; } public VideoType VideoType { get; set; }
public List<string> PlayableStreamFileNames { get; set; } public List<string> PlayableStreamFileNames { get; set; }
public int AnalyzeDurationSections { get; set; }
public MediaInfoRequest() public MediaInfoRequest()
{ {

View File

@ -120,7 +120,7 @@ namespace MediaBrowser.Controller.Net
var cancellationTokenSource = new CancellationTokenSource(); var cancellationTokenSource = new CancellationTokenSource();
Logger.Info("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); Logger.Debug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name);
var timer = SendOnTimer ? var timer = SendOnTimer ?
new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) :
@ -267,7 +267,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="connection">The connection.</param> /// <param name="connection">The connection.</param>
private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> connection) private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> connection)
{ {
Logger.Info("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name);
var timer = connection.Item3; var timer = connection.Item3;

View File

@ -11,14 +11,6 @@ namespace MediaBrowser.Controller.Net
/// </summary> /// </summary>
public interface IHttpResultFactory public interface IHttpResultFactory
{ {
/// <summary>
/// Throws the error.
/// </summary>
/// <param name="statusCode">The status code.</param>
/// <param name="errorMessage">The error message.</param>
/// <param name="responseHeaders">The response headers.</param>
void ThrowError(int statusCode, string errorMessage, IDictionary<string, string> responseHeaders = null);
/// <summary> /// <summary>
/// Gets the result. /// Gets the result.
/// </summary> /// </summary>

View File

@ -31,6 +31,15 @@ namespace MediaBrowser.Controller.Playlists
} }
} }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
{
return string.Equals(MediaType, "Video", StringComparison.OrdinalIgnoreCase);
}
}
[IgnoreDataMember] [IgnoreDataMember]
public override bool AlwaysScanInternalMetadataPath public override bool AlwaysScanInternalMetadataPath
{ {
@ -198,15 +207,15 @@ namespace MediaBrowser.Controller.Playlists
public override bool IsVisible(User user) public override bool IsVisible(User user)
{ {
if (base.IsVisible(user)) var userId = user.Id.ToString("N");
{
var userId = user.Id.ToString("N");
return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) || return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) ||
string.Equals(OwnerUserId, userId, StringComparison.OrdinalIgnoreCase); string.Equals(OwnerUserId, userId, StringComparison.OrdinalIgnoreCase);
} }
return false; public override bool IsVisibleStandalone(User user)
{
return IsVisible(user);
} }
} }
} }

View File

@ -1,13 +0,0 @@
using System;
namespace MediaBrowser.Controller.Power
{
public interface IPowerManagement
{
/// <summary>
/// Schedules the wake.
/// </summary>
/// <param name="utcTime">The UTC time.</param>
void ScheduleWake(DateTime utcTime);
}
}

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