Merge branch 'master' of https://github.com/MediaBrowser/Emby
This commit is contained in:
commit
673e2c9d0f
|
@ -829,18 +829,7 @@ namespace Emby.Drawing
|
|||
// Run the enhancers sequentially in order of priority
|
||||
foreach (var enhancer in imageEnhancers)
|
||||
{
|
||||
var typeName = enhancer.GetType().Name;
|
||||
|
||||
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;
|
||||
}
|
||||
await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
|
||||
|
||||
// Feed the output into the next enhancer as input
|
||||
inputPath = outputPath;
|
||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Model.Configuration;
|
|||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Session;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
@ -15,6 +16,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
||||
namespace MediaBrowser.Api
|
||||
{
|
||||
|
@ -43,7 +45,13 @@ namespace MediaBrowser.Api
|
|||
private readonly IFileSystem _fileSystem;
|
||||
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>
|
||||
/// Initializes a new instance of the <see cref="ApiEntryPoint" /> class.
|
||||
|
@ -66,6 +74,21 @@ namespace MediaBrowser.Api
|
|||
_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)
|
||||
{
|
||||
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>
|
||||
/// Called when [transcode beginning].
|
||||
/// </summary>
|
||||
|
@ -187,7 +205,8 @@ namespace MediaBrowser.Api
|
|||
CancellationTokenSource = cancellationTokenSource,
|
||||
Id = transcodingJobId,
|
||||
PlaySessionId = playSessionId,
|
||||
LiveStreamId = liveStreamId
|
||||
LiveStreamId = liveStreamId,
|
||||
MediaSource = state.MediaSource
|
||||
};
|
||||
|
||||
_activeTranscodingJobs.Add(job);
|
||||
|
@ -256,6 +275,11 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
}
|
||||
|
||||
lock (_transcodingLocks)
|
||||
{
|
||||
_transcodingLocks.Remove(path);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(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>
|
||||
/// Called when [transcode begin request].
|
||||
/// </summary>
|
||||
|
@ -487,6 +519,11 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
}
|
||||
|
||||
lock (_transcodingLocks)
|
||||
{
|
||||
_transcodingLocks.Remove(job.Path);
|
||||
}
|
||||
|
||||
lock (job.ProcessLock)
|
||||
{
|
||||
if (job.TranscodingThrottler != null)
|
||||
|
@ -530,7 +567,7 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
try
|
||||
{
|
||||
await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
|
||||
await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -656,6 +693,7 @@ namespace MediaBrowser.Api
|
|||
/// Gets or sets the path.
|
||||
/// </summary>
|
||||
/// <value>The path.</value>
|
||||
public MediaSourceInfo MediaSource { get; set; }
|
||||
public string Path { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the type.
|
||||
|
@ -751,12 +789,12 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -775,7 +813,7 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ using System.Globalization;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.IO;
|
||||
|
||||
namespace MediaBrowser.Api.Dlna
|
||||
{
|
||||
|
@ -109,13 +111,15 @@ namespace MediaBrowser.Api.Dlna
|
|||
private readonly IMediaReceiverRegistrar _mediaReceiverRegistrar;
|
||||
|
||||
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;
|
||||
_contentDirectory = contentDirectory;
|
||||
_connectionManager = connectionManager;
|
||||
_mediaReceiverRegistrar = mediaReceiverRegistrar;
|
||||
_memoryStreamProvider = memoryStreamProvider;
|
||||
}
|
||||
|
||||
public object Get(GetDescriptionXml request)
|
||||
|
@ -201,7 +205,7 @@ namespace MediaBrowser.Api.Dlna
|
|||
{
|
||||
using (var response = _dlnaManager.GetIcon(request.Filename))
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var ms = _memoryStreamProvider.CreateNew())
|
||||
{
|
||||
response.Stream.CopyTo(ms);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ using MediaBrowser.Controller.Net;
|
|||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -104,7 +105,13 @@ namespace MediaBrowser.Api
|
|||
MediaTypes = request.GetMediaTypes(),
|
||||
IncludeItemTypes = request.GetIncludeItemTypes(),
|
||||
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;
|
||||
|
|
|
@ -200,6 +200,8 @@ namespace MediaBrowser.Api
|
|||
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
|
||||
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Limit = request.Limit,
|
||||
|
@ -207,12 +209,11 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
typeof(Game).Name
|
||||
},
|
||||
SimilarTo = item
|
||||
SimilarTo = item,
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).ToList();
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
|
||||
|
|
|
@ -273,7 +273,8 @@ namespace MediaBrowser.Api.Images
|
|||
{
|
||||
var result = await _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
Url = url
|
||||
Url = url,
|
||||
BufferContent = false
|
||||
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
|
|
|
@ -243,11 +243,7 @@ namespace MediaBrowser.Api
|
|||
hasBudget.Revenue = request.Revenue;
|
||||
}
|
||||
|
||||
var hasOriginalTitle = item as IHasOriginalTitle;
|
||||
if (hasOriginalTitle != null)
|
||||
{
|
||||
hasOriginalTitle.OriginalTitle = hasOriginalTitle.OriginalTitle;
|
||||
}
|
||||
item.OriginalTitle = string.IsNullOrWhiteSpace(request.OriginalTitle) ? null : request.OriginalTitle;
|
||||
|
||||
var hasCriticRating = item as IHasCriticRating;
|
||||
if (hasCriticRating != null)
|
||||
|
@ -278,10 +274,9 @@ namespace MediaBrowser.Api
|
|||
|
||||
item.Tags = request.Tags;
|
||||
|
||||
var hasTaglines = item as IHasTaglines;
|
||||
if (hasTaglines != null)
|
||||
if (request.Taglines != null)
|
||||
{
|
||||
hasTaglines.Taglines = request.Taglines;
|
||||
item.Tagline = request.Taglines.FirstOrDefault();
|
||||
}
|
||||
|
||||
var hasShortOverview = item as IHasShortOverview;
|
||||
|
@ -308,8 +303,6 @@ namespace MediaBrowser.Api
|
|||
item.OfficialRating = string.IsNullOrWhiteSpace(request.OfficialRating) ? null : request.OfficialRating;
|
||||
item.CustomRating = request.CustomRating;
|
||||
|
||||
SetProductionLocations(item, request);
|
||||
|
||||
item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
|
||||
item.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
|
||||
|
||||
|
@ -417,23 +410,5 @@ namespace MediaBrowser.Api
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -835,14 +835,14 @@ namespace MediaBrowser.Api.Library
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _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();
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
|
||||
var dtos = item.ThemeSongIds.Select(_libraryManager.GetItemById)
|
||||
.Where(i => i != null)
|
||||
.OrderBy(i => i.SortName)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||
|
@ -879,14 +879,14 @@ namespace MediaBrowser.Api.Library
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _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();
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
|
||||
var dtos = item.ThemeVideoIds.Select(_libraryManager.GetItemById)
|
||||
.Where(i => i != null)
|
||||
.OrderBy(i => i.SortName)
|
||||
.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");
|
||||
|
||||
public object Get(GetYearIndex request)
|
||||
|
|
|
@ -112,6 +112,8 @@ namespace MediaBrowser.Api.Library
|
|||
/// <value>The name.</value>
|
||||
public string Path { get; set; }
|
||||
|
||||
public MediaPathInfo PathInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [refresh library].
|
||||
/// </summary>
|
||||
|
@ -119,6 +121,18 @@ namespace MediaBrowser.Api.Library
|
|||
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")]
|
||||
public class RemoveMediaPath : IReturnVoid
|
||||
{
|
||||
|
@ -212,7 +226,12 @@ namespace MediaBrowser.Api.Library
|
|||
{
|
||||
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>
|
||||
|
@ -308,7 +327,16 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
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
|
||||
{
|
||||
|
@ -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>
|
||||
/// Deletes the specified request.
|
||||
/// </summary>
|
||||
|
|
|
@ -12,9 +12,14 @@ using ServiceStack;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
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
|
||||
{
|
||||
|
@ -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")]
|
||||
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>
|
||||
/// The maximum number of items to return
|
||||
/// </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")]
|
||||
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()
|
||||
{
|
||||
AddCurrentProgram = true;
|
||||
|
@ -159,6 +199,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
public bool? IsSeries { get; set; }
|
||||
public bool? IsKids { get; set; }
|
||||
public bool? IsSports { get; set; }
|
||||
public bool? IsNews { get; set; }
|
||||
|
||||
public GetRecordings()
|
||||
{
|
||||
|
@ -275,6 +316,8 @@ namespace MediaBrowser.Api.LiveTv
|
|||
public string SeriesTimerId { get; set; }
|
||||
|
||||
public bool? IsActive { get; set; }
|
||||
|
||||
public bool? IsScheduled { get; set; }
|
||||
}
|
||||
|
||||
[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")]
|
||||
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; }
|
||||
|
||||
|
@ -340,6 +389,8 @@ namespace MediaBrowser.Api.LiveTv
|
|||
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableUserData { get; set; }
|
||||
|
||||
public string SeriesTimerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </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")]
|
||||
public bool? HasAired { 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 = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
|
||||
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; }
|
||||
|
||||
[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; }
|
||||
|
||||
[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")]
|
||||
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
|
||||
{
|
||||
private readonly ILiveTvManager _liveTvManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IConfigurationManager _config;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
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;
|
||||
_userManager = userManager;
|
||||
|
@ -630,6 +701,41 @@ namespace MediaBrowser.Api.LiveTv
|
|||
_httpClient = httpClient;
|
||||
_libraryManager = libraryManager;
|
||||
_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)
|
||||
|
@ -702,7 +808,8 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
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);
|
||||
|
||||
|
@ -786,6 +893,13 @@ namespace MediaBrowser.Api.LiveTv
|
|||
IsLiked = request.IsLiked,
|
||||
IsDisliked = request.IsDisliked,
|
||||
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
|
||||
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
|
@ -868,9 +982,12 @@ namespace MediaBrowser.Api.LiveTv
|
|||
query.Limit = request.Limit;
|
||||
query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
query.SortOrder = request.SortOrder;
|
||||
query.IsNews = request.IsNews;
|
||||
query.IsMovie = request.IsMovie;
|
||||
query.IsSeries = request.IsSeries;
|
||||
query.IsKids = request.IsKids;
|
||||
query.IsSports = request.IsSports;
|
||||
query.SeriesTimerId = request.SeriesTimerId;
|
||||
query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
|
||||
|
@ -886,8 +1003,10 @@ namespace MediaBrowser.Api.LiveTv
|
|||
IsAiring = request.IsAiring,
|
||||
Limit = request.Limit,
|
||||
HasAired = request.HasAired,
|
||||
IsSeries = request.IsSeries,
|
||||
IsMovie = request.IsMovie,
|
||||
IsKids = request.IsKids,
|
||||
IsNews = request.IsNews,
|
||||
IsSports = request.IsSports,
|
||||
EnableTotalRecordCount = request.EnableTotalRecordCount
|
||||
};
|
||||
|
@ -919,6 +1038,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
IsInProgress = request.IsInProgress,
|
||||
EnableTotalRecordCount = request.EnableTotalRecordCount,
|
||||
IsMovie = request.IsMovie,
|
||||
IsNews = request.IsNews,
|
||||
IsSeries = request.IsSeries,
|
||||
IsKids = request.IsKids,
|
||||
IsSports = request.IsSports
|
||||
|
@ -975,7 +1095,8 @@ namespace MediaBrowser.Api.LiveTv
|
|||
{
|
||||
ChannelId = request.ChannelId,
|
||||
SeriesTimerId = request.SeriesTimerId,
|
||||
IsActive = request.IsActive
|
||||
IsActive = request.IsActive,
|
||||
IsScheduled = request.IsScheduled
|
||||
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?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')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
@ -11,9 +11,10 @@
|
|||
<AssemblyName>MediaBrowser.Api</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||
<ReleaseVersion>
|
||||
</ReleaseVersion>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -79,7 +80,6 @@
|
|||
<Compile Include="Dlna\DlnaService.cs" />
|
||||
<Compile Include="FilterService.cs" />
|
||||
<Compile Include="IHasDtoOptions.cs" />
|
||||
<Compile Include="Library\ChapterService.cs" />
|
||||
<Compile Include="Playback\MediaInfoService.cs" />
|
||||
<Compile Include="Playback\TranscodingThrottler.cs" />
|
||||
<Compile Include="PlaylistService.cs" />
|
||||
|
@ -198,6 +198,10 @@
|
|||
<Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</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>
|
||||
<None Include="packages.config" />
|
||||
|
|
|
@ -156,18 +156,19 @@ namespace MediaBrowser.Api.Movies
|
|||
itemTypes.Add(typeof(LiveTvProgram).Name);
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Limit = request.Limit,
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
SimilarTo = item,
|
||||
EnableGroupByMetadataKey = true
|
||||
EnableGroupByMetadataKey = true,
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).ToList();
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
|
||||
|
@ -198,7 +199,8 @@ namespace MediaBrowser.Api.Movies
|
|||
Limit = 7,
|
||||
ParentId = parentIdGuid,
|
||||
Recursive = true,
|
||||
IsPlayed = true
|
||||
IsPlayed = true,
|
||||
DtoOptions = dtoOptions
|
||||
};
|
||||
|
||||
var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList();
|
||||
|
@ -221,7 +223,8 @@ namespace MediaBrowser.Api.Movies
|
|||
ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(),
|
||||
EnableGroupByMetadataKey = true,
|
||||
ParentId = parentIdGuid,
|
||||
Recursive = true
|
||||
Recursive = true,
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).ToList();
|
||||
|
||||
|
@ -302,7 +305,8 @@ namespace MediaBrowser.Api.Movies
|
|||
PersonTypes = new[] { PersonType.Director },
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
EnableGroupByMetadataKey = true
|
||||
EnableGroupByMetadataKey = true,
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
|
||||
.Take(itemLimit)
|
||||
|
@ -339,7 +343,8 @@ namespace MediaBrowser.Api.Movies
|
|||
Limit = itemLimit + 2,
|
||||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
EnableGroupByMetadataKey = true
|
||||
EnableGroupByMetadataKey = true,
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
|
||||
.Take(itemLimit)
|
||||
|
@ -375,7 +380,8 @@ namespace MediaBrowser.Api.Movies
|
|||
IncludeItemTypes = itemTypes.ToArray(),
|
||||
IsMovie = true,
|
||||
SimilarTo = item,
|
||||
EnableGroupByMetadataKey = true
|
||||
EnableGroupByMetadataKey = true,
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).ToList();
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[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)]
|
||||
public string TargetSystems { get; set; }
|
||||
|
@ -72,7 +72,7 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[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>
|
||||
|
@ -149,12 +149,12 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -367,6 +367,8 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
param += " -crf 23";
|
||||
}
|
||||
|
||||
param += " -tune zerolatency";
|
||||
}
|
||||
|
||||
else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -461,13 +463,15 @@ namespace MediaBrowser.Api.Playback
|
|||
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
|
||||
// also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307
|
||||
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)
|
||||
{
|
||||
case "30":
|
||||
param += " -level 3";
|
||||
param += " -level 3.0";
|
||||
break;
|
||||
case "31":
|
||||
param += " -level 3.1";
|
||||
|
@ -476,7 +480,7 @@ namespace MediaBrowser.Api.Playback
|
|||
param += " -level 3.2";
|
||||
break;
|
||||
case "40":
|
||||
param += " -level 4";
|
||||
param += " -level 4.0";
|
||||
break;
|
||||
case "41":
|
||||
param += " -level 4.1";
|
||||
|
@ -485,7 +489,7 @@ namespace MediaBrowser.Api.Playback
|
|||
param += " -level 4.2";
|
||||
break;
|
||||
case "50":
|
||||
param += " -level 5";
|
||||
param += " -level 5.0";
|
||||
break;
|
||||
case "51":
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
@ -802,10 +819,10 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
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>
|
||||
|
@ -1022,7 +1039,15 @@ namespace MediaBrowser.Api.Playback
|
|||
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
|
||||
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)
|
||||
{
|
||||
if (EnableThrottling(state) && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (EnableThrottling(state))
|
||||
{
|
||||
transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager);
|
||||
state.TranscodingThrottler.Start();
|
||||
|
@ -1832,26 +1857,37 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var archivable = item as IArchivable;
|
||||
state.IsInputArchive = archivable != null && archivable.IsArchive;
|
||||
|
||||
MediaSourceInfo mediaSource;
|
||||
MediaSourceInfo mediaSource = null;
|
||||
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)
|
||||
? mediaSources.First()
|
||||
: mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId));
|
||||
|
||||
if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase))
|
||||
if (currentJob != null)
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
@ -2294,7 +2330,8 @@ namespace MediaBrowser.Api.Playback
|
|||
state.TargetRefFrames,
|
||||
state.TargetVideoStreamCount,
|
||||
state.TargetAudioStreamCount,
|
||||
state.TargetVideoCodecTag);
|
||||
state.TargetVideoCodecTag,
|
||||
state.IsTargetAVC);
|
||||
|
||||
if (mediaProfile != null)
|
||||
{
|
||||
|
@ -2429,7 +2466,8 @@ namespace MediaBrowser.Api.Playback
|
|||
Url = "https://mb3admin.com/admin/service/transcoding/report",
|
||||
CancellationToken = CancellationToken.None,
|
||||
LogRequest = false,
|
||||
LogErrors = false
|
||||
LogErrors = false,
|
||||
BufferContent = false
|
||||
};
|
||||
options.RequestContent = JsonSerializer.SerializeToString(dict);
|
||||
options.RequestContentType = "application/json";
|
||||
|
@ -2512,7 +2550,8 @@ namespace MediaBrowser.Api.Playback
|
|||
state.TargetRefFrames,
|
||||
state.TargetVideoStreamCount,
|
||||
state.TargetAudioStreamCount,
|
||||
state.TargetVideoCodecTag
|
||||
state.TargetVideoCodecTag,
|
||||
state.IsTargetAVC
|
||||
|
||||
).FirstOrDefault() ?? string.Empty;
|
||||
}
|
||||
|
@ -2567,6 +2606,7 @@ namespace MediaBrowser.Api.Playback
|
|||
inputModifier += " " + GetFastSeekCommandLineParameter(state.Request);
|
||||
inputModifier = inputModifier.Trim();
|
||||
|
||||
//inputModifier += " -fflags +genpts+ignidx+igndts";
|
||||
if (state.VideoRequest != null && genPts)
|
||||
{
|
||||
inputModifier += " -fflags +genpts";
|
||||
|
|
|
@ -87,7 +87,8 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
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
|
||||
{
|
||||
if (!FileSystem.FileExists(playlist))
|
||||
|
@ -104,13 +105,13 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
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);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ApiEntryPoint.Instance.TranscodingStartLock.Release();
|
||||
transcodingLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,10 +129,9 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
var audioBitrate = state.OutputAudioBitrate ?? 0;
|
||||
var videoBitrate = state.OutputVideoBitrate ?? 0;
|
||||
|
||||
var appendBaselineStream = false;
|
||||
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);
|
||||
|
||||
|
@ -151,9 +151,10 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
var text = reader.ReadToEnd();
|
||||
|
||||
text = text.Replace("#EXTM3U", "#EXTM3U\n#EXT-X-PLAYLIST-TYPE:EVENT");
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
|
@ -175,14 +176,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
var playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "/stream.m3u8");
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -190,32 +183,41 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
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
|
||||
using (var fileStream = GetPlaylistFileStream(playlist))
|
||||
try
|
||||
{
|
||||
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;
|
||||
|
||||
while (!reader.EndOfStream)
|
||||
using (var reader = new StreamReader(fileStream))
|
||||
{
|
||||
var line = await reader.ReadLineAsync().ConfigureAwait(false);
|
||||
var count = 0;
|
||||
|
||||
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
count++;
|
||||
if (count >= segmentCount)
|
||||
var line = await reader.ReadLineAsync().ConfigureAwait(false);
|
||||
|
||||
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
Logger.Debug("Finished waiting for {0} segments in {1}", segmentCount, playlist);
|
||||
return;
|
||||
count++;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -171,14 +171,15 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
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;
|
||||
try
|
||||
{
|
||||
if (FileSystem.FileExists(segmentPath))
|
||||
{
|
||||
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
||||
ApiEntryPoint.Instance.TranscodingStartLock.Release();
|
||||
transcodingLock.Release();
|
||||
released = true;
|
||||
return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -242,7 +243,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
if (!released)
|
||||
{
|
||||
ApiEntryPoint.Instance.TranscodingStartLock.Release();
|
||||
transcodingLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -906,6 +907,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
).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}\"",
|
||||
inputModifier,
|
||||
GetInputArgument(state),
|
||||
|
|
|
@ -68,8 +68,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
[Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
|
||||
public class GetHlsVideoSegmentLegacy : VideoStreamRequest
|
||||
{
|
||||
// TODO: Deprecate with new iOS app
|
||||
|
||||
public string PlaylistId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -113,7 +111,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
|
||||
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, "*")
|
||||
.FirstOrDefault(i => string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1);
|
||||
|
|
|
@ -113,6 +113,8 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
args += GetGraphicalSubtitleParam(state, codec);
|
||||
}
|
||||
|
||||
args += " -flags -global_header";
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
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;
|
||||
if (profile == null)
|
||||
|
@ -140,7 +140,7 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
public void Post(CloseMediaSource request)
|
||||
{
|
||||
var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId, CancellationToken.None);
|
||||
var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId);
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ using System.IO;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using ServiceStack;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Progressive
|
||||
{
|
||||
|
@ -26,12 +27,10 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
public abstract class BaseProgressiveStreamingService : BaseStreamingService
|
||||
{
|
||||
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)
|
||||
{
|
||||
ImageProcessor = imageProcessor;
|
||||
HttpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -122,6 +121,25 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
|
||||
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
|
||||
if (request.Static && state.InputProtocol == MediaProtocol.Http)
|
||||
{
|
||||
|
@ -129,8 +147,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
|
||||
using (state)
|
||||
{
|
||||
return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource)
|
||||
.ConfigureAwait(false);
|
||||
return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,6 +171,19 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
|
||||
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;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Tag))
|
||||
|
@ -345,7 +375,8 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
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
|
||||
{
|
||||
TranscodingJob job;
|
||||
|
@ -376,7 +407,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
}
|
||||
finally
|
||||
{
|
||||
ApiEntryPoint.Instance.TranscodingStartLock.Release();
|
||||
transcodingLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ using CommonIO;
|
|||
using MediaBrowser.Controller.Net;
|
||||
using System.Collections.Generic;
|
||||
using ServiceStack.Web;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Progressive
|
||||
{
|
||||
|
@ -23,6 +24,10 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
private const int BufferSize = 81920;
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -34,6 +39,15 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
_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
|
||||
{
|
||||
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)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_directStreamProvider != null)
|
||||
{
|
||||
await _directStreamProvider.CopyToAsync(outputStream, _cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
//_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace MediaBrowser.Api.Playback
|
|||
/// </summary>
|
||||
/// <value>The log file stream.</value>
|
||||
public Stream LogFileStream { get; set; }
|
||||
public IDirectStreamProvider DirectStreamProvider { get; set; }
|
||||
|
||||
public string InputContainer { get; set; }
|
||||
|
||||
|
@ -62,7 +63,6 @@ namespace MediaBrowser.Api.Playback
|
|||
get { return Request is VideoStreamRequest; }
|
||||
}
|
||||
public bool IsInputVideo { get; set; }
|
||||
public bool IsInputArchive { get; set; }
|
||||
|
||||
public VideoType VideoType { get; set; }
|
||||
public IsoType? IsoType { get; set; }
|
||||
|
@ -88,9 +88,17 @@ namespace MediaBrowser.Api.Playback
|
|||
return 10;
|
||||
}
|
||||
|
||||
if (!RunTimeTicks.HasValue)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
if (!RunTimeTicks.HasValue)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +225,7 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
try
|
||||
{
|
||||
await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
|
||||
await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -508,5 +516,18 @@ namespace MediaBrowser.Api.Playback
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool? IsTargetAVC
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Request.Static)
|
||||
{
|
||||
return VideoStream == null ? null : VideoStream.IsAVC;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -517,10 +517,6 @@ namespace MediaBrowser.Api.Reports
|
|||
internalHeader = HeaderMetadata.Album;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Countries:
|
||||
option.Column = (i, r) => this.GetListAsString(this.GetObject<IHasProductionLocations, List<string>>(i, (x) => x.ProductionLocations));
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Disc:
|
||||
option.Column = (i, r) => i.ParentIndexNumber;
|
||||
break;
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace MediaBrowser.Api.Reports
|
|||
result = this.GetResultStudios(result, items, topItem);
|
||||
result = this.GetResultPersons(result, items, topItem);
|
||||
result = this.GetResultProductionYears(result, items, topItem);
|
||||
result = this.GetResulProductionLocations(result, items, topItem);
|
||||
result = this.GetResultCommunityRatings(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>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
|
|
|
@ -81,7 +81,8 @@ namespace MediaBrowser.Api
|
|||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(),
|
||||
Recursive = true
|
||||
Recursive = true,
|
||||
DtoOptions = dtoOptions
|
||||
};
|
||||
|
||||
// ExcludeArtistIds
|
||||
|
|
|
@ -88,8 +88,6 @@ namespace MediaBrowser.Api
|
|||
var result = new StartupConfiguration
|
||||
{
|
||||
UICulture = _config.Configuration.UICulture,
|
||||
EnableInternetProviders = _config.Configuration.EnableInternetProviders,
|
||||
SaveLocalMeta = _config.Configuration.SaveLocalMeta,
|
||||
MetadataCountryCode = _config.Configuration.MetadataCountryCode,
|
||||
PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
|
||||
};
|
||||
|
@ -116,15 +114,16 @@ namespace MediaBrowser.Api
|
|||
config.EnableLocalizedGuids = true;
|
||||
config.EnableStandaloneMusicKeys = true;
|
||||
config.EnableCaseSensitiveItemIds = true;
|
||||
//config.EnableFolderView = true;
|
||||
config.EnableFolderView = true;
|
||||
config.SchemaVersion = 109;
|
||||
config.EnableSimpleArtistDetection = true;
|
||||
config.SkipDeserializationForBasicTypes = true;
|
||||
config.SkipDeserializationForPrograms = true;
|
||||
}
|
||||
|
||||
public void Post(UpdateStartupConfiguration request)
|
||||
{
|
||||
_config.Configuration.UICulture = request.UICulture;
|
||||
_config.Configuration.EnableInternetProviders = request.EnableInternetProviders;
|
||||
_config.Configuration.SaveLocalMeta = request.SaveLocalMeta;
|
||||
_config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
|
||||
_config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
|
||||
_config.SaveConfiguration();
|
||||
|
@ -215,8 +214,6 @@ namespace MediaBrowser.Api
|
|||
public class StartupConfiguration
|
||||
{
|
||||
public string UICulture { get; set; }
|
||||
public bool EnableInternetProviders { get; set; }
|
||||
public bool SaveLocalMeta { get; set; }
|
||||
public string MetadataCountryCode { get; set; }
|
||||
public string PreferredMetadataLanguage { get; set; }
|
||||
public string LiveTvTunerType { get; set; }
|
||||
|
|
|
@ -148,7 +148,7 @@ namespace MediaBrowser.Api.Subtitles
|
|||
{
|
||||
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();
|
||||
|
||||
|
|
|
@ -302,6 +302,8 @@ namespace MediaBrowser.Api
|
|||
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
|
||||
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Limit = request.Limit,
|
||||
|
@ -309,12 +311,11 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
typeof(Series).Name
|
||||
},
|
||||
SimilarTo = item
|
||||
SimilarTo = item,
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).ToList();
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
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 options = GetDtoOptions(request);
|
||||
|
||||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
|
@ -342,12 +345,11 @@ namespace MediaBrowser.Api
|
|||
StartIndex = request.StartIndex,
|
||||
Limit = request.Limit,
|
||||
ParentId = parentIdGuid,
|
||||
Recursive = true
|
||||
Recursive = true,
|
||||
DtoOptions = options
|
||||
|
||||
}).ToList();
|
||||
|
||||
var options = GetDtoOptions(request);
|
||||
|
||||
var returnItems = (await _dtoService.GetBaseItemDtos(itemsResult, options, user).ConfigureAwait(false)).ToArray();
|
||||
|
||||
var result = new ItemsResult
|
||||
|
|
|
@ -205,6 +205,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
private void SetItemCounts(BaseItemDto dto, ItemCounts counts)
|
||||
{
|
||||
dto.ChildCount = counts.ItemCount;
|
||||
dto.ProgramCount = counts.ProgramCount;
|
||||
dto.SeriesCount = counts.SeriesCount;
|
||||
dto.EpisodeCount = counts.EpisodeCount;
|
||||
dto.MovieCount = counts.MovieCount;
|
||||
|
|
|
@ -100,7 +100,9 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
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)
|
||||
{
|
||||
|
@ -112,8 +114,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
throw new InvalidOperationException("GetItemsToSerialize result.Items returned null");
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtoList = await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false);
|
||||
|
||||
if (dtoList == null)
|
||||
|
@ -131,24 +131,31 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <summary>
|
||||
/// Gets the items to serialize.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
private async Task<QueryResult<BaseItem>> GetQueryResult(GetItems request, User user)
|
||||
private async Task<QueryResult<BaseItem>> GetQueryResult(GetItems request, DtoOptions dtoOptions, User user)
|
||||
{
|
||||
var item = string.IsNullOrEmpty(request.ParentId) ?
|
||||
user == null ? _libraryManager.RootFolder : user.RootFolder :
|
||||
null :
|
||||
_libraryManager.GetItemById(request.ParentId);
|
||||
|
||||
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))
|
||||
{
|
||||
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
|
||||
|
||||
var folder = item as Folder;
|
||||
|
@ -159,14 +166,14 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -241,7 +248,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
AiredDuringSeason = request.AiredDuringSeason,
|
||||
AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater,
|
||||
EnableTotalRecordCount = request.EnableTotalRecordCount,
|
||||
ExcludeItemIds = request.GetExcludeItemIds()
|
||||
ExcludeItemIds = request.GetExcludeItemIds(),
|
||||
DtoOptions = dtoOptions
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Ids))
|
||||
|
|
|
@ -30,6 +30,7 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.IO;
|
||||
|
||||
namespace MediaBrowser.Common.Implementations
|
||||
{
|
||||
|
@ -192,6 +193,8 @@ namespace MediaBrowser.Common.Implementations
|
|||
get { return Environment.OSVersion.VersionString; }
|
||||
}
|
||||
|
||||
public IMemoryStreamProvider MemoryStreamProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
|
||||
/// </summary>
|
||||
|
@ -231,6 +234,8 @@ namespace MediaBrowser.Common.Implementations
|
|||
|
||||
JsonSerializer = CreateJsonSerializer();
|
||||
|
||||
MemoryStreamProvider = new MemoryStreamProvider();
|
||||
|
||||
OnLoggerLoaded(true);
|
||||
LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false);
|
||||
|
||||
|
@ -456,6 +461,7 @@ namespace MediaBrowser.Common.Implementations
|
|||
|
||||
RegisterSingleInstance(JsonSerializer);
|
||||
RegisterSingleInstance(XmlSerializer);
|
||||
RegisterSingleInstance(MemoryStreamProvider);
|
||||
|
||||
RegisterSingleInstance(LogManager);
|
||||
RegisterSingleInstance(Logger);
|
||||
|
@ -464,7 +470,7 @@ namespace MediaBrowser.Common.Implementations
|
|||
|
||||
RegisterSingleInstance(FileSystemManager);
|
||||
|
||||
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager);
|
||||
HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamProvider);
|
||||
RegisterSingleInstance(HttpClient);
|
||||
|
||||
NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager"));
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IMemoryStreamProvider _memoryStreamProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpClientManager" /> class.
|
||||
|
@ -52,7 +53,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
/// <exception cref="System.ArgumentNullException">appPaths
|
||||
/// or
|
||||
/// logger</exception>
|
||||
public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
|
||||
public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IMemoryStreamProvider memoryStreamProvider)
|
||||
{
|
||||
if (appPaths == null)
|
||||
{
|
||||
|
@ -65,6 +66,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
_logger = logger;
|
||||
_fileSystem = fileSystem;
|
||||
_memoryStreamProvider = memoryStreamProvider;
|
||||
_appPaths = appPaths;
|
||||
|
||||
// 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,
|
||||
ResourcePool = resourcePool,
|
||||
CancellationToken = cancellationToken,
|
||||
BufferContent = resourcePool != null
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -293,12 +296,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
/// </exception>
|
||||
public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod)
|
||||
{
|
||||
HttpResponseInfo response;
|
||||
|
||||
if (options.CacheMode == CacheMode.None)
|
||||
{
|
||||
response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
|
||||
return response;
|
||||
return await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var url = options.Url;
|
||||
|
@ -306,7 +306,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
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)
|
||||
{
|
||||
return response;
|
||||
|
@ -332,7 +332,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
{
|
||||
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);
|
||||
memoryStream.Position = 0;
|
||||
|
@ -366,7 +366,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
using (var responseStream = response.Content)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
var memoryStream = _memoryStreamProvider.CreateNew();
|
||||
await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
||||
memoryStream.Position = 0;
|
||||
|
||||
|
@ -458,7 +458,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
using (var stream = httpResponse.GetResponseStream())
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
var memoryStream = _memoryStreamProvider.CreateNew();
|
||||
|
||||
await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
||||
|
||||
|
@ -553,7 +553,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
{
|
||||
Url = url,
|
||||
ResourcePool = resourcePool,
|
||||
CancellationToken = cancellationToken
|
||||
CancellationToken = cancellationToken,
|
||||
BufferContent = resourcePool != null
|
||||
|
||||
}, postData);
|
||||
}
|
||||
|
@ -563,7 +564,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>Task{System.String}.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">progress</exception>
|
||||
public async Task<string> GetTempFile(HttpRequestOptions options)
|
||||
{
|
||||
var response = await GetTempFileResponse(options).ConfigureAwait(false);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -72,6 +72,11 @@ namespace MediaBrowser.Common.Implementations.Logging
|
|||
/// <param name="paramList">The param list.</param>
|
||||
public void Debug(string message, params object[] paramList)
|
||||
{
|
||||
if (_logManager.LogSeverity == LogSeverity.Info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.Debug(message, paramList);
|
||||
}
|
||||
|
||||
|
@ -137,6 +142,11 @@ namespace MediaBrowser.Common.Implementations.Logging
|
|||
/// <param name="additionalContent">Content of the additional.</param>
|
||||
public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent)
|
||||
{
|
||||
if (severity == LogSeverity.Debug && _logManager.LogSeverity == LogSeverity.Info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
additionalContent.Insert(0, message + Environment.NewLine);
|
||||
|
||||
const char tabChar = '\t';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?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')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
@ -14,6 +14,7 @@
|
|||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -23,7 +24,7 @@
|
|||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
|
@ -51,11 +52,15 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
|
||||
</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">
|
||||
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
|
||||
</Reference>
|
||||
<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>
|
||||
</Reference>
|
||||
<Reference Include="Patterns.Logging">
|
||||
|
@ -65,8 +70,8 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SimpleInjector, Version=3.2.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SimpleInjector.3.2.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||
<Reference Include="SimpleInjector, Version=3.2.2.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SimpleInjector.3.2.2\lib\net45\SimpleInjector.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
|
@ -75,6 +80,9 @@
|
|||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Text.Json">
|
||||
<HintPath>..\ThirdParty\fastjsonparser\System.Text.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="ServiceStack.Text">
|
||||
<HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath>
|
||||
|
@ -93,6 +101,7 @@
|
|||
<Compile Include="HttpClientManager\HttpClientInfo.cs" />
|
||||
<Compile Include="HttpClientManager\HttpClientManager.cs" />
|
||||
<Compile Include="IO\IsoManager.cs" />
|
||||
<Compile Include="IO\MemoryStreamProvider.cs" />
|
||||
<Compile Include="Logging\LogHelper.cs" />
|
||||
<Compile Include="Logging\NLogger.cs" />
|
||||
<Compile Include="Logging\NlogManager.cs" />
|
||||
|
|
|
@ -390,13 +390,13 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
|
||||
try
|
||||
{
|
||||
var localTask = ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress);
|
||||
|
||||
if (options != null && options.MaxRuntimeMs.HasValue)
|
||||
{
|
||||
CurrentCancellationTokenSource.CancelAfter(options.MaxRuntimeMs.Value);
|
||||
}
|
||||
|
||||
var localTask = ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress);
|
||||
|
||||
await localTask.ConfigureAwait(false);
|
||||
|
||||
status = TaskCompletionStatus.Completed;
|
||||
|
|
|
@ -169,7 +169,8 @@ namespace MediaBrowser.Common.Implementations.Security
|
|||
var options = new HttpRequestOptions()
|
||||
{
|
||||
Url = AppstoreRegUrl,
|
||||
CancellationToken = CancellationToken.None
|
||||
CancellationToken = CancellationToken.None,
|
||||
BufferContent = false
|
||||
};
|
||||
options.RequestHeaders.Add("X-Emby-Token", _appHost.SystemId);
|
||||
options.RequestContent = parameters;
|
||||
|
@ -269,7 +270,8 @@ namespace MediaBrowser.Common.Implementations.Security
|
|||
Url = MBValidateUrl,
|
||||
|
||||
// Seeing block length errors
|
||||
EnableHttpCompression = false
|
||||
EnableHttpCompression = false,
|
||||
BufferContent = false
|
||||
};
|
||||
|
||||
options.SetPostData(data);
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
Url = url,
|
||||
EnableKeepAlive = false,
|
||||
CancellationToken = cancellationToken,
|
||||
UserAgent = "Emby/3.0"
|
||||
UserAgent = "Emby/3.0",
|
||||
BufferContent = false
|
||||
};
|
||||
|
||||
if (cacheLength.Ticks > 0)
|
||||
|
@ -105,7 +106,8 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
Url = url,
|
||||
EnableKeepAlive = false,
|
||||
CancellationToken = cancellationToken,
|
||||
UserAgent = "Emby/3.0"
|
||||
UserAgent = "Emby/3.0",
|
||||
BufferContent = false
|
||||
};
|
||||
|
||||
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
|
||||
|
|
|
@ -148,14 +148,10 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
/// <summary>
|
||||
/// Gets all available packages.
|
||||
/// </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>
|
||||
public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
|
||||
bool withRegistration = true,
|
||||
PackageType? packageType = null,
|
||||
string packageType = null,
|
||||
Version applicationVersion = null)
|
||||
{
|
||||
var data = new Dictionary<string, string>
|
||||
|
@ -293,7 +289,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
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)
|
||||
{
|
||||
|
@ -301,9 +297,9 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
.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
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<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="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="SimpleInjector" version="3.2.0" targetFramework="net45" />
|
||||
<package id="SimpleInjector" version="3.2.2" targetFramework="net45" />
|
||||
</packages>
|
11
MediaBrowser.Common/IO/IMemoryStreamProvider.cs
Normal file
11
MediaBrowser.Common/IO/IMemoryStreamProvider.cs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -60,6 +60,7 @@
|
|||
<Compile Include="Extensions\BaseExtensions.cs" />
|
||||
<Compile Include="Extensions\ResourceNotFoundException.cs" />
|
||||
<Compile Include="IDependencyContainer.cs" />
|
||||
<Compile Include="IO\IMemoryStreamProvider.cs" />
|
||||
<Compile Include="IO\ProgressStream.cs" />
|
||||
<Compile Include="IO\StreamDefaults.cs" />
|
||||
<Compile Include="Configuration\IApplicationPaths.cs" />
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace MediaBrowser.Common.Updates
|
|||
/// <returns>Task{List{PackageInfo}}.</returns>
|
||||
Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
|
||||
bool withRegistration = true,
|
||||
PackageType? packageType = null,
|
||||
string packageType = null,
|
||||
Version applicationVersion = null);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -134,15 +134,5 @@ namespace MediaBrowser.Controller.Channels
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>BaseItemDto.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Chapters;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
|
@ -13,12 +11,6 @@ namespace MediaBrowser.Controller.Chapters
|
|||
/// </summary>
|
||||
public interface IChapterManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the parts.
|
||||
/// </summary>
|
||||
/// <param name="chapterProviders">The chapter providers.</param>
|
||||
void AddParts(IEnumerable<IChapterProvider> chapterProviders);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the chapters.
|
||||
/// </summary>
|
||||
|
@ -35,43 +27,6 @@ namespace MediaBrowser.Controller.Chapters
|
|||
/// <returns>Task.</returns>
|
||||
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>
|
||||
/// Gets the configuration.
|
||||
/// </summary>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using MediaBrowser.Model.Events;
|
||||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public interface IDeviceDiscovery
|
||||
{
|
||||
event EventHandler<SsdpMessageEventArgs> DeviceDiscovered;
|
||||
event EventHandler<SsdpMessageEventArgs> DeviceLeft;
|
||||
event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered;
|
||||
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; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,5 @@ namespace MediaBrowser.Controller.Dlna
|
|||
{
|
||||
public interface ISsdpHandler
|
||||
{
|
||||
event EventHandler<SsdpMessageEventArgs> MessageReceived;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,11 +34,26 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool IsPhysicalRoot
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _virtual children
|
||||
/// </summary>
|
||||
|
|
|
@ -23,8 +23,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
IHasMusicGenres,
|
||||
IHasLookupInfo<SongInfo>,
|
||||
IHasMediaSources,
|
||||
IThemeMedia,
|
||||
IArchivable
|
||||
IThemeMedia
|
||||
{
|
||||
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||
|
||||
|
@ -60,10 +59,19 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
AlbumArtists = new List<string>();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
[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()
|
||||
{
|
||||
var locationType = LocationType;
|
||||
|
@ -262,7 +255,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
|
||||
MediaStreams = MediaSourceManager.GetMediaStreams(i.Id).ToList(),
|
||||
Name = i.Name,
|
||||
Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
|
||||
Path = enablePathSubstituion ? GetMappedPath(i, i.Path, locationType) : i.Path,
|
||||
RunTimeTicks = i.RunTimeTicks,
|
||||
Container = i.Container,
|
||||
Size = i.Size
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// </summary>
|
||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
|
||||
{
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
public MusicAlbum()
|
||||
{
|
||||
Artists = new List<string>();
|
||||
|
@ -48,6 +51,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsCumulativeRunTimeTicks
|
||||
{
|
||||
|
@ -83,8 +95,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
get { return false; }
|
||||
}
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tracks.
|
||||
/// </summary>
|
||||
|
@ -103,8 +113,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return Tracks;
|
||||
}
|
||||
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <summary>
|
||||
/// Class MusicArtist
|
||||
/// </summary>
|
||||
public class MusicArtist : Folder, IMetadataContainer, IItemByName, IHasMusicGenres, IHasDualAccess, IHasProductionLocations, IHasLookupInfo<ArtistInfo>
|
||||
public class MusicArtist : Folder, IMetadataContainer, IItemByName, IHasMusicGenres, IHasDualAccess, IHasLookupInfo<ArtistInfo>
|
||||
{
|
||||
[IgnoreDataMember]
|
||||
public bool IsAccessedByName
|
||||
|
@ -24,8 +24,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
get { return ParentId == Guid.Empty; }
|
||||
}
|
||||
|
||||
public List<string> ProductionLocations { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool IsFolder
|
||||
{
|
||||
|
@ -50,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
get { return true; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return !IsAccessedByName;
|
||||
|
@ -111,11 +118,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
|
||||
}
|
||||
|
||||
public MusicArtist()
|
||||
{
|
||||
ProductionLocations = new List<string>();
|
||||
}
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
|
|
@ -37,6 +37,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
protected BaseItem()
|
||||
{
|
||||
ThemeSongIds = new List<Guid>();
|
||||
ThemeVideoIds = new List<Guid>();
|
||||
Keywords = new List<string>();
|
||||
Tags = new List<string>();
|
||||
Genres = new List<string>();
|
||||
|
@ -44,6 +46,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
LockedFields = new List<MetadataFields>();
|
||||
ImageInfos = new List<ItemImageInfo>();
|
||||
InheritedTags = new List<string>();
|
||||
ProductionLocations = new List<string>();
|
||||
}
|
||||
|
||||
public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
|
||||
|
@ -64,6 +68,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
public static string ThemeSongFilename = "theme";
|
||||
public static string ThemeVideosFolderName = "backdrops";
|
||||
|
||||
public List<Guid> ThemeSongIds { get; set; }
|
||||
public List<Guid> ThemeVideoIds { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string PreferredMetadataCountryCode { get; set; }
|
||||
[IgnoreDataMember]
|
||||
|
@ -72,6 +79,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
public long? Size { get; set; }
|
||||
public string Container { get; set; }
|
||||
public string ShortOverview { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public string Tagline { get; set; }
|
||||
|
||||
public List<ItemImageInfo> ImageInfos { get; set; }
|
||||
|
||||
|
@ -114,6 +123,31 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
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]
|
||||
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>
|
||||
/// Gets or sets the etag.
|
||||
/// </summary>
|
||||
|
@ -408,7 +455,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public virtual bool IsInternetMetadataEnabled()
|
||||
{
|
||||
return ConfigurationManager.Configuration.EnableInternetProviders;
|
||||
return LibraryManager.GetLibraryOptions(this).EnableInternetProviders;
|
||||
}
|
||||
|
||||
public virtual bool CanDelete()
|
||||
|
@ -784,6 +831,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
public int InheritedParentalRatingValue { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<string> InheritedTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating.
|
||||
/// </summary>
|
||||
|
@ -841,6 +891,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
public List<string> Tags { get; set; }
|
||||
|
||||
public List<string> Keywords { get; set; }
|
||||
public List<string> ProductionLocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the home page URL.
|
||||
|
@ -956,7 +1007,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Loads the theme songs.
|
||||
/// </summary>
|
||||
/// <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)
|
||||
.Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -992,7 +1043,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Loads the video backdrops.
|
||||
/// </summary>
|
||||
/// <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)
|
||||
.Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -1078,6 +1129,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return true; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual bool SupportsThemeMedia
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes owned items such as trailers, theme videos, special features, etc.
|
||||
/// Returns true or false indicating if changes were found.
|
||||
|
@ -1096,14 +1153,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
if (LocationType == LocationType.FileSystem && GetParent() != null)
|
||||
{
|
||||
var hasThemeMedia = this as IHasThemeMedia;
|
||||
if (hasThemeMedia != null)
|
||||
if (SupportsThemeMedia)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
|
@ -1172,7 +1228,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// Refreshes the theme songs.
|
||||
/// </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 newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();
|
||||
|
@ -1249,7 +1305,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var current = this;
|
||||
|
||||
return current.IsInMixedFolder == newItem.IsInMixedFolder;
|
||||
if (!SupportsIsInMixedFolderDetection)
|
||||
{
|
||||
if (current.IsInMixedFolder != newItem.IsInMixedFolder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AfterMetadataRefresh()
|
||||
|
@ -1324,7 +1388,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
return ConfigurationManager.Configuration.SaveLocalMeta;
|
||||
var libraryOptions = LibraryManager.GetLibraryOptions(this);
|
||||
|
||||
return libraryOptions.SaveLocalMetadata;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2107,14 +2173,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
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)
|
||||
{
|
||||
foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
|
||||
{
|
||||
path = LibraryManager.SubstitutePath(path, map.From, map.To);
|
||||
}
|
||||
return LibraryManager.GetPathAfterNetworkSubstitution(path, item);
|
||||
}
|
||||
|
||||
return path;
|
||||
|
|
|
@ -38,6 +38,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
|
@ -48,24 +57,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
private static readonly Dictionary<string, LibraryOptions> LibraryOptions = new Dictionary<string, LibraryOptions>();
|
||||
public LibraryOptions GetLibraryOptions()
|
||||
{
|
||||
lock (LibraryOptions)
|
||||
{
|
||||
LibraryOptions options;
|
||||
if (!LibraryOptions.TryGetValue(Path, out options))
|
||||
{
|
||||
options = LoadLibraryOptions();
|
||||
LibraryOptions[Path] = options;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
return GetLibraryOptions(Path);
|
||||
}
|
||||
|
||||
private LibraryOptions LoadLibraryOptions()
|
||||
private static LibraryOptions LoadLibraryOptions(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(Path)) as LibraryOptions;
|
||||
var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
|
@ -100,13 +99,28 @@ namespace MediaBrowser.Controller.Entities
|
|||
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)
|
||||
{
|
||||
lock (LibraryOptions)
|
||||
{
|
||||
LibraryOptions[path] = options;
|
||||
|
||||
options.SchemaVersion = 2;
|
||||
options.SchemaVersion = 3;
|
||||
XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,18 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// Class Folder
|
||||
/// </summary>
|
||||
public class Folder : BaseItem, IHasThemeMedia
|
||||
public class Folder : BaseItem
|
||||
{
|
||||
public static IUserManager UserManager { get; set; }
|
||||
public static IUserViewManager UserViewManager { get; set; }
|
||||
|
||||
public List<Guid> ThemeSongIds { get; set; }
|
||||
public List<Guid> ThemeVideoIds { 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]
|
||||
public DateTime? DateLastMediaAdded { get; set; }
|
||||
|
@ -36,9 +41,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
public Folder()
|
||||
{
|
||||
LinkedChildren = new List<LinkedChild>();
|
||||
}
|
||||
|
||||
ThemeSongIds = new List<Guid>();
|
||||
ThemeVideoIds = new List<Guid>();
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsThemeMedia
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
@ -47,6 +55,21 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return false; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual bool IsPhysicalRoot
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is folder.
|
||||
/// </summary>
|
||||
|
@ -117,19 +140,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
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]
|
||||
protected virtual bool SupportsShortcutChildren
|
||||
{
|
||||
|
@ -178,8 +188,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
item.SetParent(null);
|
||||
}
|
||||
|
||||
#region Indexing
|
||||
|
||||
/// <summary>
|
||||
/// Returns the valid set of index by options for this folder type.
|
||||
/// Override or extend to modify.
|
||||
|
@ -207,8 +215,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return GetIndexByOptions(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actual children.
|
||||
/// </summary>
|
||||
|
@ -801,18 +807,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
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
|
||||
if (query.VideoTypes.Length > 0)
|
||||
{
|
||||
|
@ -1149,29 +1143,19 @@ namespace MediaBrowser.Controller.Entities
|
|||
return LinkedChildren
|
||||
.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);
|
||||
|
||||
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);
|
||||
return child;
|
||||
if (!child.IsVisibleStandalone(user))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!locations.Any(l => FileSystem.ContainsSubPath(l, child.Path)))
|
||||
else if (childLocationType == LocationType.FileSystem && !locations.Any(l => FileSystem.ContainsSubPath(l, child.Path)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -8,19 +8,14 @@ using System.Runtime.Serialization;
|
|||
|
||||
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()
|
||||
{
|
||||
MultiPartGameFiles = new List<string>();
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
RemoteTrailerIds = new List<Guid>();
|
||||
ThemeSongIds = new List<Guid>();
|
||||
ThemeVideoIds = new List<Guid>();
|
||||
}
|
||||
|
||||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
|
@ -39,6 +34,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return true; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsThemeMedia
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the remote trailers.
|
||||
/// </summary>
|
||||
|
@ -98,7 +99,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public override IEnumerable<string> GetDeletePaths()
|
||||
{
|
||||
if (!IsInMixedFolder)
|
||||
if (!DetectIsInMixedFolder())
|
||||
{
|
||||
return new[] { System.IO.Path.GetDirectoryName(Path) };
|
||||
}
|
||||
|
|
|
@ -26,6 +26,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the game system.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public interface IArchivable
|
||||
{
|
||||
bool IsArchive { get; }
|
||||
}
|
||||
}
|
|
@ -150,11 +150,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <value><c>true</c> if [supports local metadata]; otherwise, <c>false</c>.</value>
|
||||
bool SupportsLocalMetadata { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 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; }
|
||||
bool DetectIsInMixedFolder();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is locked.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -62,5 +63,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
int? GetInheritedParentalRatingValue();
|
||||
int InheritedParentalRatingValue { get; set; }
|
||||
List<string> GetInheritedTags();
|
||||
List<string> InheritedTags { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -20,5 +20,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
|
||||
|
||||
bool EnableRememberingTrackSelections { get; }
|
||||
|
||||
bool SupportsPlayedStatus { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -101,6 +104,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
public bool? IsMovie { get; set; }
|
||||
public bool? IsSports { get; set; }
|
||||
public bool? IsKids { get; set; }
|
||||
public bool? IsNews { get; set; }
|
||||
public bool? IsSeries { get; set; }
|
||||
|
||||
public int? MinPlayers { get; set; }
|
||||
public int? MaxPlayers { get; set; }
|
||||
|
@ -137,6 +142,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
public DayOfWeek[] AirDays { get; set; }
|
||||
public SeriesStatus[] SeriesStatuses { get; set; }
|
||||
public string AlbumArtistStartsWithOrGreater { get; set; }
|
||||
public string ExternalSeriesId { get; set; }
|
||||
|
||||
public string[] AlbumNames { get; set; }
|
||||
public string[] ArtistNames { get; set; }
|
||||
|
@ -149,11 +155,53 @@ namespace MediaBrowser.Controller.Entities
|
|||
public Dictionary<string, string> ExcludeProviderIds { 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()
|
||||
{
|
||||
GroupByPresentationUniqueKey = true;
|
||||
EnableTotalRecordCount = true;
|
||||
|
||||
DtoOptions = new DtoOptions();
|
||||
AlbumNames = new string[] { };
|
||||
ArtistNames = new string[] { };
|
||||
ExcludeArtistIds = new string[] { };
|
||||
|
@ -191,6 +239,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
TrailerTypes = new TrailerType[] { };
|
||||
AirDays = new DayOfWeek[] { };
|
||||
SeriesStatuses = new SeriesStatus[] { };
|
||||
OrderBy = new List<Tuple<string, SortOrder>>();
|
||||
}
|
||||
|
||||
public InternalItemsQuery(User user)
|
||||
|
|
|
@ -15,24 +15,17 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
/// <summary>
|
||||
/// Class Movie
|
||||
/// </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> ThemeSongIds { get; set; }
|
||||
public List<Guid> ThemeVideoIds { get; set; }
|
||||
public List<string> ProductionLocations { get; set; }
|
||||
|
||||
public Movie()
|
||||
{
|
||||
SpecialFeatureIds = new List<Guid>();
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
RemoteTrailerIds = new List<Guid>();
|
||||
ThemeSongIds = new List<Guid>();
|
||||
ThemeVideoIds = new List<Guid>();
|
||||
Taglines = new List<string>();
|
||||
ProductionLocations = new List<string>();
|
||||
}
|
||||
|
||||
public string AwardSummary { get; set; }
|
||||
|
@ -75,13 +68,22 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
set { TmdbCollectionName = value; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected override bool SupportsIsInMixedFolderDetection
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Must have a parent to have special features
|
||||
// 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);
|
||||
|
||||
|
@ -119,7 +121,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
{
|
||||
var info = GetItemLookupInfo<MovieInfo>();
|
||||
|
||||
if (!IsInMixedFolder)
|
||||
if (!DetectIsInMixedFolder())
|
||||
{
|
||||
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
|
||||
}
|
||||
|
@ -145,7 +147,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
else
|
||||
{
|
||||
// Try to get the year from the folder name
|
||||
if (!IsInMixedFolder)
|
||||
if (!DetectIsInMixedFolder())
|
||||
{
|
||||
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.Runtime.Serialization;
|
|||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasProductionLocations, IHasBudget, IHasLookupInfo<MusicVideoInfo>
|
||||
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasBudget, IHasLookupInfo<MusicVideoInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the budget.
|
||||
|
@ -19,12 +19,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
/// <value>The revenue.</value>
|
||||
public double? Revenue { get; set; }
|
||||
public List<string> ProductionLocations { get; set; }
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
public MusicVideo()
|
||||
{
|
||||
ProductionLocations = 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()
|
||||
{
|
||||
return UnratedItem.Music;
|
||||
|
@ -65,7 +72,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
else
|
||||
{
|
||||
// Try to get the year from the folder name
|
||||
if (!IsInMixedFolder)
|
||||
if (!DetectIsInMixedFolder())
|
||||
{
|
||||
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
|
||||
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
using MediaBrowser.Model.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
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]
|
||||
public override bool SupportsLocalMetadata
|
||||
{
|
||||
|
@ -37,13 +29,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
return Album;
|
||||
return AlbumEntity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[IgnoreDataMember]
|
||||
public PhotoAlbum Album
|
||||
public PhotoAlbum AlbumEntity
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -16,6 +16,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||
|
|
|
@ -154,8 +154,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
|
||||
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 result = PostFilterAndSort(items, query, false, false);
|
||||
|
|
|
@ -17,17 +17,14 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
/// <summary>
|
||||
/// Class Series
|
||||
/// </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 Series()
|
||||
{
|
||||
AirDays = new List<DayOfWeek>();
|
||||
|
||||
SpecialFeatureIds = new List<Guid>();
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
LocalTrailerIds = new List<Guid>();
|
||||
RemoteTrailerIds = new List<Guid>();
|
||||
|
|
|
@ -10,16 +10,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// Class Trailer
|
||||
/// </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()
|
||||
{
|
||||
RemoteTrailers = new List<MediaUrl>();
|
||||
Taglines = new List<string>();
|
||||
Keywords = new List<string>();
|
||||
ProductionLocations = new List<string>();
|
||||
TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer };
|
||||
}
|
||||
|
||||
|
@ -35,12 +31,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return TrailerTypes.Contains(TrailerType.LocalTrailer); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the taglines.
|
||||
/// </summary>
|
||||
/// <value>The taglines.</value>
|
||||
public List<string> Taglines { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the budget.
|
||||
/// </summary>
|
||||
|
@ -64,7 +54,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
|
||||
|
||||
if (!IsInMixedFolder && LocationType == LocationType.FileSystem)
|
||||
if (!DetectIsInMixedFolder() && LocationType == LocationType.FileSystem)
|
||||
{
|
||||
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
|
||||
}
|
||||
|
@ -90,7 +80,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
else
|
||||
{
|
||||
// Try to get the year from the folder name
|
||||
if (!IsInMixedFolder)
|
||||
if (!DetectIsInMixedFolder())
|
||||
{
|
||||
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
|
||||
|
||||
|
|
|
@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearCache()
|
||||
{
|
||||
lock (_childIdsLock)
|
||||
|
|
|
@ -13,7 +13,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
public class UserView : Folder
|
||||
{
|
||||
public string ViewType { get; set; }
|
||||
public Guid ParentId { get; set; }
|
||||
public Guid DisplayParentId { get; set; }
|
||||
|
||||
public Guid? UserId { get; set; }
|
||||
|
@ -45,6 +44,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
return list;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetChildCount(User user)
|
||||
{
|
||||
return GetChildren(user, true).Count();
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
Limit = query.Limit,
|
||||
IsAiring = true
|
||||
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
}, new Dto.DtoOptions(), CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return GetResult(result);
|
||||
}
|
||||
|
@ -1497,13 +1497,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var filterValue = query.HasThemeSong.Value;
|
||||
|
||||
var themeCount = 0;
|
||||
var iHasThemeMedia = item as IHasThemeMedia;
|
||||
|
||||
if (iHasThemeMedia != null)
|
||||
{
|
||||
themeCount = iHasThemeMedia.ThemeSongIds.Count;
|
||||
}
|
||||
var themeCount = item.ThemeSongIds.Count;
|
||||
var ok = filterValue ? themeCount > 0 : themeCount == 0;
|
||||
|
||||
if (!ok)
|
||||
|
@ -1516,13 +1510,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var filterValue = query.HasThemeVideo.Value;
|
||||
|
||||
var themeCount = 0;
|
||||
var iHasThemeMedia = item as IHasThemeMedia;
|
||||
|
||||
if (iHasThemeMedia != null)
|
||||
{
|
||||
themeCount = iHasThemeMedia.ThemeVideoIds.Count;
|
||||
}
|
||||
var themeCount = item.ThemeVideoIds.Count;
|
||||
var ok = filterValue ? themeCount > 0 : themeCount == 0;
|
||||
|
||||
if (!ok)
|
||||
|
|
|
@ -25,8 +25,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
ISupportsPlaceHolders,
|
||||
IHasMediaSources,
|
||||
IHasShortOverview,
|
||||
IThemeMedia,
|
||||
IArchivable
|
||||
IThemeMedia
|
||||
{
|
||||
[IgnoreDataMember]
|
||||
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()
|
||||
{
|
||||
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 ExtraType? ExtraType { get; set; }
|
||||
|
||||
|
@ -165,7 +188,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
|
@ -197,21 +220,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
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()
|
||||
{
|
||||
return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
|
||||
|
@ -480,7 +488,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public override IEnumerable<string> GetDeletePaths()
|
||||
{
|
||||
if (!IsInMixedFolder)
|
||||
if (!DetectIsInMixedFolder())
|
||||
{
|
||||
return new[] { ContainingFolderPath };
|
||||
}
|
||||
|
@ -600,7 +608,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
|
||||
MediaStreams = 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,
|
||||
Video3DFormat = i.Video3DFormat,
|
||||
VideoType = i.VideoType,
|
||||
|
|
|
@ -506,6 +506,8 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <returns>QueryResult<BaseItem>.</returns>
|
||||
QueryResult<BaseItem> QueryItems(InternalItemsQuery query);
|
||||
|
||||
string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem = null);
|
||||
|
||||
/// <summary>
|
||||
/// Substitutes the path.
|
||||
/// </summary>
|
||||
|
@ -554,9 +556,10 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
||||
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 AddMediaPath(string virtualFolderName, string path);
|
||||
void AddMediaPath(string virtualFolderName, MediaPathInfo path);
|
||||
void UpdateMediaPath(string virtualFolderName, MediaPathInfo path);
|
||||
void RemoveMediaPath(string virtualFolderName, string path);
|
||||
|
||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
|
||||
|
|
|
@ -7,6 +7,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
|
@ -60,11 +61,8 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <summary>
|
||||
/// Gets the static media source.
|
||||
/// </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>
|
||||
Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution);
|
||||
Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Opens the media source.
|
||||
|
@ -83,6 +81,8 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <returns>Task<MediaSourceInfo>.</returns>
|
||||
Task<MediaSourceInfo> GetLiveStream(string id, CancellationToken cancellationToken);
|
||||
|
||||
Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Pings the media source.
|
||||
/// </summary>
|
||||
|
@ -95,8 +95,12 @@ namespace MediaBrowser.Controller.Library
|
|||
/// Closes the media source.
|
||||
/// </summary>
|
||||
/// <param name="id">The live stream identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task CloseLiveStream(string id, CancellationToken cancellationToken);
|
||||
Task CloseLiveStream(string id);
|
||||
}
|
||||
|
||||
public interface IDirectStreamProvider
|
||||
{
|
||||
Task CopyToAsync(Stream stream, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using MediaBrowser.Model.Dto;
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
|
@ -22,14 +23,13 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="openToken">The open token.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<MediaSourceInfo>.</returns>
|
||||
Task<MediaSourceInfo> OpenMediaSource(string openToken, CancellationToken cancellationToken);
|
||||
Task<Tuple<MediaSourceInfo,IDirectStreamProvider>> OpenMediaSource(string openToken, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Closes the media source.
|
||||
/// </summary>
|
||||
/// <param name="liveStreamId">The live stream identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken);
|
||||
Task CloseMediaSource(string liveStreamId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ using System.Collections.Generic;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
|
@ -156,7 +157,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <param name="mediaSourceId">The media source identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <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>
|
||||
/// Gets the program.
|
||||
|
@ -220,9 +221,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// Closes the live stream.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task CloseLiveStream(string id, CancellationToken cancellationToken);
|
||||
Task CloseLiveStream(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the guide information.
|
||||
|
@ -242,10 +242,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <summary>
|
||||
/// Gets the recommended programs internal.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<QueryResult<LiveTvProgram>>.</returns>
|
||||
Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken);
|
||||
Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the live tv information.
|
||||
|
@ -303,18 +301,12 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <summary>
|
||||
/// Gets the recording media sources.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<IEnumerable<MediaSourceInfo>>.</returns>
|
||||
Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(string id, CancellationToken cancellationToken);
|
||||
Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(IHasMediaSources item, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel media sources.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<IEnumerable<MediaSourceInfo>>.</returns>
|
||||
Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(string id, CancellationToken cancellationToken);
|
||||
Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(IHasMediaSources item, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the information to recording dto.
|
||||
|
@ -331,7 +323,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <param name="fields">The fields.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <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>
|
||||
/// Saves the tuner host.
|
||||
|
@ -395,7 +387,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
Task<List<ChannelInfo>> GetChannelsForListingsProvider(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>> TimerCancelled;
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
bool CanDelete(User user);
|
||||
|
||||
string SeriesTimerId { get; set; }
|
||||
string TimerId { get; set; }
|
||||
RecordingStatus Status { get; set; }
|
||||
DateTime? EndDate { get; set; }
|
||||
DateTime DateLastSaved { get; set; }
|
||||
|
|
|
@ -4,6 +4,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
|
@ -245,4 +246,14 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <returns>Task.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <summary>
|
||||
/// Gets the channels.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<IEnumerable<ChannelInfo>>.</returns>
|
||||
Task<IEnumerable<ChannelInfo>> GetChannels(CancellationToken cancellationToken);
|
||||
Task<IEnumerable<ChannelInfo>> GetChannels(bool enableCache, CancellationToken cancellationToken);
|
||||
/// <summary>
|
||||
/// Gets the tuner infos.
|
||||
/// </summary>
|
||||
|
@ -38,7 +37,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <param name="streamId">The stream identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<MediaSourceInfo>.</returns>
|
||||
Task<Tuple<MediaSourceInfo,SemaphoreSlim>> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
|
||||
Task<LiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
|
||||
/// <summary>
|
||||
/// Gets the channel stream media sources.
|
||||
/// </summary>
|
||||
|
@ -46,8 +45,6 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<List<MediaSourceInfo>>.</returns>
|
||||
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
|
||||
|
||||
string ApplyDuration(string streamPath, TimeSpan duration);
|
||||
}
|
||||
public interface IConfigurableTunerHost
|
||||
{
|
||||
|
|
45
MediaBrowser.Controller/LiveTv/LiveStream.cs
Normal file
45
MediaBrowser.Controller/LiveTv/LiveStream.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
[IgnoreDataMember]
|
||||
public bool IsSeries { get; set; }
|
||||
public string SeriesTimerId { get; set; }
|
||||
public string TimerId { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public DateTime StartDate { get; set; }
|
||||
public RecordingStatus Status { get; set; }
|
||||
|
@ -112,7 +113,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return true;
|
||||
return Status == RecordingStatus.Completed;
|
||||
}
|
||||
|
||||
public override bool IsAuthorizedToDelete(User user)
|
||||
|
|
|
@ -5,11 +5,12 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvChannel : BaseItem, IHasMediaSources
|
||||
public class LiveTvChannel : BaseItem, IHasMediaSources, IHasProgramAttributes
|
||||
{
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
|
@ -81,10 +82,10 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
|
||||
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]
|
||||
|
@ -137,5 +138,56 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
[IgnoreDataMember]
|
||||
public bool IsSeries { get; set; }
|
||||
public string SeriesTimerId { get; set; }
|
||||
public string TimerId { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public DateTime StartDate { 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]
|
||||
public override LocationType LocationType
|
||||
{
|
||||
|
@ -111,7 +130,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return true;
|
||||
return Status == RecordingStatus.Completed;
|
||||
}
|
||||
|
||||
public override bool IsAuthorizedToDelete(User user)
|
||||
|
|
|
@ -107,6 +107,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <value>The image URL.</value>
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
public string LogoImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance has image.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
|
@ -26,6 +27,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the recording.
|
||||
/// </summary>
|
||||
|
@ -53,6 +56,11 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <value><c>true</c> if [record any channel]; otherwise, <c>false</c>.</value>
|
||||
public bool RecordAnyChannel { get; set; }
|
||||
|
||||
public int KeepUpTo { get; set; }
|
||||
public KeepUntil KeepUntil { get; set; }
|
||||
|
||||
public bool SkipEpisodesInLibrary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [record new only].
|
||||
/// </summary>
|
||||
|
@ -104,6 +112,8 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
public SeriesTimerInfo()
|
||||
{
|
||||
Days = new List<DayOfWeek>();
|
||||
SkipEpisodesInLibrary = true;
|
||||
KeepUntil = KeepUntil.UntilDeleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class TimerInfo
|
||||
{
|
||||
public TimerInfo()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
KeepUntil = KeepUntil.UntilDeleted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// </summary>
|
||||
|
@ -82,5 +89,30 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// </summary>
|
||||
/// <value>The priority.</value>
|
||||
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; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,10 +91,7 @@
|
|||
<Compile Include="Channels\InternalChannelItemQuery.cs" />
|
||||
<Compile Include="Channels\IRequiresMediaInfoCallback.cs" />
|
||||
<Compile Include="Channels\ISearchableChannel.cs" />
|
||||
<Compile Include="Chapters\ChapterSearchRequest.cs" />
|
||||
<Compile Include="Chapters\IChapterManager.cs" />
|
||||
<Compile Include="Chapters\IChapterProvider.cs" />
|
||||
<Compile Include="Chapters\ChapterResponse.cs" />
|
||||
<Compile Include="Collections\CollectionCreationOptions.cs" />
|
||||
<Compile Include="Collections\CollectionEvents.cs" />
|
||||
<Compile Include="Collections\ICollectionManager.cs" />
|
||||
|
@ -135,7 +132,6 @@
|
|||
<Compile Include="Entities\Game.cs" />
|
||||
<Compile Include="Entities\GameGenre.cs" />
|
||||
<Compile Include="Entities\GameSystem.cs" />
|
||||
<Compile Include="Entities\IArchivable.cs" />
|
||||
<Compile Include="Entities\IByReferenceItem.cs" />
|
||||
<Compile Include="Entities\IHasAspectRatio.cs" />
|
||||
<Compile Include="Entities\IHasBudget.cs" />
|
||||
|
@ -147,15 +143,12 @@
|
|||
<Compile Include="Entities\IHasMediaSources.cs" />
|
||||
<Compile Include="Entities\IHasMetascore.cs" />
|
||||
<Compile Include="Entities\IHasOriginalTitle.cs" />
|
||||
<Compile Include="Entities\IHasProductionLocations.cs" />
|
||||
<Compile Include="Entities\IHasProgramAttributes.cs" />
|
||||
<Compile Include="Entities\IHasScreenshots.cs" />
|
||||
<Compile Include="Entities\IHasSeries.cs" />
|
||||
<Compile Include="Entities\IHasShortOverview.cs" />
|
||||
<Compile Include="Entities\IHasSpecialFeatures.cs" />
|
||||
<Compile Include="Entities\IHasStartDate.cs" />
|
||||
<Compile Include="Entities\IHasTaglines.cs" />
|
||||
<Compile Include="Entities\IHasThemeMedia.cs" />
|
||||
<Compile Include="Entities\IHasTrailers.cs" />
|
||||
<Compile Include="Entities\IHasUserData.cs" />
|
||||
<Compile Include="Entities\IHiddenFromDisplay.cs" />
|
||||
|
@ -201,6 +194,7 @@
|
|||
<Compile Include="Library\UserDataSaveEventArgs.cs" />
|
||||
<Compile Include="LiveTv\IListingsProvider.cs" />
|
||||
<Compile Include="LiveTv\ITunerHost.cs" />
|
||||
<Compile Include="LiveTv\LiveStream.cs" />
|
||||
<Compile Include="LiveTv\RecordingGroup.cs" />
|
||||
<Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" />
|
||||
<Compile Include="LiveTv\ILiveTvRecording.cs" />
|
||||
|
@ -266,7 +260,6 @@
|
|||
<Compile Include="Playlists\IPlaylistManager.cs" />
|
||||
<Compile Include="Playlists\Playlist.cs" />
|
||||
<Compile Include="Plugins\ILocalizablePlugin.cs" />
|
||||
<Compile Include="Power\IPowerManagement.cs" />
|
||||
<Compile Include="Providers\AlbumInfo.cs" />
|
||||
<Compile Include="Providers\ArtistInfo.cs" />
|
||||
<Compile Include="Providers\BookInfo.cs" />
|
||||
|
@ -290,9 +283,7 @@
|
|||
<Compile Include="Providers\IHasItemChangeMonitor.cs" />
|
||||
<Compile Include="Providers\IHasLookupInfo.cs" />
|
||||
<Compile Include="Providers\IHasOrder.cs" />
|
||||
<Compile Include="Providers\IImageFileSaver.cs" />
|
||||
<Compile Include="Providers\IImageProvider.cs" />
|
||||
<Compile Include="Providers\IImageSaver.cs" />
|
||||
<Compile Include="Providers\ILocalImageFileProvider.cs" />
|
||||
<Compile Include="Providers\ILocalMetadataProvider.cs" />
|
||||
<Compile Include="Providers\ImageRefreshMode.cs" />
|
||||
|
@ -319,7 +310,6 @@
|
|||
<Compile Include="Providers\SongInfo.cs" />
|
||||
<Compile Include="Providers\TrailerInfo.cs" />
|
||||
<Compile Include="Providers\VideoContentType.cs" />
|
||||
<Compile Include="RelatedMedia\IRelatedMediaProvider.cs" />
|
||||
<Compile Include="Security\AuthenticationInfo.cs" />
|
||||
<Compile Include="Security\AuthenticationInfoQuery.cs" />
|
||||
<Compile Include="Security\IAuthenticationRepository.cs" />
|
||||
|
|
|
@ -45,9 +45,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
/// <param name="offset">The offset.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <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>
|
||||
/// Extracts the video images on interval.
|
||||
|
@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol);
|
||||
string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input argument.
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
public IIsoMount MountedIso { get; set; }
|
||||
public VideoType VideoType { get; set; }
|
||||
public List<string> PlayableStreamFileNames { get; set; }
|
||||
public int AnalyzeDurationSections { get; set; }
|
||||
|
||||
public MediaInfoRequest()
|
||||
{
|
||||
|
|
|
@ -120,7 +120,7 @@ namespace MediaBrowser.Controller.Net
|
|||
|
||||
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 ?
|
||||
new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) :
|
||||
|
@ -267,7 +267,7 @@ namespace MediaBrowser.Controller.Net
|
|||
/// <param name="connection">The connection.</param>
|
||||
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;
|
||||
|
||||
|
|
|
@ -11,14 +11,6 @@ namespace MediaBrowser.Controller.Net
|
|||
/// </summary>
|
||||
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>
|
||||
/// Gets the result.
|
||||
/// </summary>
|
||||
|
|
|
@ -31,6 +31,15 @@ namespace MediaBrowser.Controller.Playlists
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Equals(MediaType, "Video", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool AlwaysScanInternalMetadataPath
|
||||
{
|
||||
|
@ -198,15 +207,15 @@ namespace MediaBrowser.Controller.Playlists
|
|||
|
||||
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)) ||
|
||||
string.Equals(OwnerUserId, userId, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) ||
|
||||
string.Equals(OwnerUserId, userId, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
return false;
|
||||
public override bool IsVisibleStandalone(User user)
|
||||
{
|
||||
return IsVisible(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue
Block a user