mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-11-16 18:42:52 -07:00
Merge branch 'master' of https://github.com/MediaBrowser/Emby
This commit is contained in:
commit
d9108f69f3
@ -33,7 +33,7 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.8\lib\net45\CommonIO.dll</HintPath>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CommonIO" version="1.0.0.8" targetFramework="net45" />
|
||||
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
|
||||
<package id="ImageMagickSharp" version="1.0.0.18" targetFramework="net45" />
|
||||
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
||||
</packages>
|
@ -63,6 +63,15 @@ namespace MediaBrowser.Api
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
|
||||
Instance = this;
|
||||
_sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress;
|
||||
}
|
||||
|
||||
void _sessionManager_PlaybackProgress(object sender, PlaybackProgressEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
|
||||
{
|
||||
PingTranscodingJob(e.PlaySessionId, e.IsPaused);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -300,26 +309,31 @@ namespace MediaBrowser.Api
|
||||
PingTimer(job, false);
|
||||
}
|
||||
}
|
||||
internal void PingTranscodingJob(string playSessionId)
|
||||
internal void PingTranscodingJob(string playSessionId, bool? isUserPaused)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playSessionId))
|
||||
{
|
||||
throw new ArgumentNullException("playSessionId");
|
||||
}
|
||||
|
||||
//Logger.Debug("PingTranscodingJob PlaySessionId={0}", playSessionId);
|
||||
//Logger.Debug("PingTranscodingJob PlaySessionId={0} isUsedPaused: {1}", playSessionId, isUserPaused);
|
||||
|
||||
var jobs = new List<TranscodingJob>();
|
||||
List<TranscodingJob> jobs;
|
||||
|
||||
lock (_activeTranscodingJobs)
|
||||
{
|
||||
// This is really only needed for HLS.
|
||||
// Progressive streams can stop on their own reliably
|
||||
jobs = jobs.Where(j => string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
jobs = _activeTranscodingJobs.Where(j => string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
}
|
||||
|
||||
foreach (var job in jobs)
|
||||
{
|
||||
if (isUserPaused.HasValue)
|
||||
{
|
||||
//Logger.Debug("Setting job.IsUserPaused to {0}. jobId: {1}", isUserPaused, job.Id);
|
||||
job.IsUserPaused = isUserPaused.Value;
|
||||
}
|
||||
PingTimer(job, true);
|
||||
}
|
||||
}
|
||||
@ -655,6 +669,7 @@ namespace MediaBrowser.Api
|
||||
public object ProcessLock = new object();
|
||||
|
||||
public bool HasExited { get; set; }
|
||||
public bool IsUserPaused { get; set; }
|
||||
|
||||
public string Id { get; set; }
|
||||
|
||||
|
@ -196,9 +196,13 @@ namespace MediaBrowser.Api
|
||||
return name;
|
||||
}
|
||||
|
||||
return libraryManager.RootFolder
|
||||
.GetRecursiveChildren(i => i is IHasArtist)
|
||||
.Cast<IHasArtist>()
|
||||
var items = libraryManager.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicVideo).Name, typeof(MusicAlbum).Name }
|
||||
});
|
||||
|
||||
return items
|
||||
.OfType<IHasArtist>()
|
||||
.SelectMany(i => i.AllArtists)
|
||||
.DistinctNames()
|
||||
.FirstOrDefault(i =>
|
||||
@ -239,8 +243,12 @@ namespace MediaBrowser.Api
|
||||
return name;
|
||||
}
|
||||
|
||||
return libraryManager.RootFolder
|
||||
.GetRecursiveChildren(i => i is Game)
|
||||
var items = libraryManager.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Game).Name }
|
||||
});
|
||||
|
||||
return items
|
||||
.SelectMany(i => i.Genres)
|
||||
.DistinctNames()
|
||||
.FirstOrDefault(i =>
|
||||
|
@ -108,7 +108,7 @@ namespace MediaBrowser.Api
|
||||
IncludeItemTypes = new[] { typeof(GameSystem).Name }
|
||||
};
|
||||
var parentIds = new string[] { } ;
|
||||
var gameSystems = _libraryManager.GetItems(query, parentIds)
|
||||
var gameSystems = _libraryManager.GetItemList(query, parentIds)
|
||||
.Cast<GameSystem>()
|
||||
.ToList();
|
||||
|
||||
@ -129,7 +129,7 @@ namespace MediaBrowser.Api
|
||||
IncludeItemTypes = new[] { typeof(Game).Name }
|
||||
};
|
||||
var parentIds = new string[] { };
|
||||
var games = _libraryManager.GetItems(query, parentIds)
|
||||
var games = _libraryManager.GetItemList(query, parentIds)
|
||||
.Cast<Game>()
|
||||
.ToList();
|
||||
|
||||
@ -192,7 +192,7 @@ namespace MediaBrowser.Api
|
||||
_userDataRepository,
|
||||
_dtoService,
|
||||
Logger,
|
||||
request, item => item is Game,
|
||||
request, new[] { typeof(Game) },
|
||||
SimilarItemsHelper.GetSimiliarityScore);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
|
@ -699,6 +699,7 @@ namespace MediaBrowser.Api.Images
|
||||
|
||||
private ImageFormat[] GetClientSupportedFormats()
|
||||
{
|
||||
//Logger.Debug("Request types: {0}", string.Join(",", Request.AcceptTypes ?? new string[] { }));
|
||||
var supportsWebP = (Request.AcceptTypes ?? new string[] { }).Contains("image/webp", StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var userAgent = Request.UserAgent ?? string.Empty;
|
||||
|
@ -289,7 +289,6 @@ namespace MediaBrowser.Api.Library
|
||||
private readonly IActivityManager _activityManager;
|
||||
private readonly ILocalizationManager _localization;
|
||||
private readonly ILiveTvManager _liveTv;
|
||||
private readonly IChannelManager _channelManager;
|
||||
private readonly ITVSeriesManager _tvManager;
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
@ -298,7 +297,7 @@ namespace MediaBrowser.Api.Library
|
||||
/// Initializes a new instance of the <see cref="LibraryService" /> class.
|
||||
/// </summary>
|
||||
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
|
||||
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, IChannelManager channelManager, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
|
||||
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
|
||||
{
|
||||
_itemRepo = itemRepo;
|
||||
_libraryManager = libraryManager;
|
||||
@ -309,7 +308,6 @@ namespace MediaBrowser.Api.Library
|
||||
_activityManager = activityManager;
|
||||
_localization = localization;
|
||||
_liveTv = liveTv;
|
||||
_channelManager = channelManager;
|
||||
_tvManager = tvManager;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_fileSystem = fileSystem;
|
||||
@ -379,11 +377,10 @@ namespace MediaBrowser.Api.Library
|
||||
}
|
||||
|
||||
var program = item as IHasProgramAttributes;
|
||||
var channelItem = item as ChannelVideoItem;
|
||||
|
||||
if (item is Movie || (program != null && program.IsMovie) || (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Movie) || (channelItem != null && channelItem.ContentType == ChannelMediaContentType.MovieExtra))
|
||||
if (item is Movie || (program != null && program.IsMovie) || item is Trailer)
|
||||
{
|
||||
return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _channelManager)
|
||||
return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService)
|
||||
{
|
||||
AuthorizationContext = AuthorizationContext,
|
||||
Logger = Logger,
|
||||
@ -400,7 +397,7 @@ namespace MediaBrowser.Api.Library
|
||||
});
|
||||
}
|
||||
|
||||
if (item is Series || (program != null && program.IsSeries) || (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Episode))
|
||||
if (item is Series || (program != null && program.IsSeries))
|
||||
{
|
||||
return new TvShowsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _tvManager)
|
||||
{
|
||||
@ -447,13 +444,11 @@ namespace MediaBrowser.Api.Library
|
||||
|
||||
public void Post(PostUpdatedSeries request)
|
||||
{
|
||||
var series = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var series = _libraryManager.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Series).Name }
|
||||
|
||||
}).Items;
|
||||
|
||||
series = series.Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProviders.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||
}).Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProviders.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||
|
||||
if (series.Length > 0)
|
||||
{
|
||||
@ -470,11 +465,11 @@ namespace MediaBrowser.Api.Library
|
||||
|
||||
public void Post(PostUpdatedMovies request)
|
||||
{
|
||||
var movies = _libraryManager.GetItems(new InternalItemsQuery
|
||||
var movies = _libraryManager.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name }
|
||||
|
||||
}).Items;
|
||||
}).ToArray();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.ImdbId))
|
||||
{
|
||||
@ -664,87 +659,38 @@ namespace MediaBrowser.Api.Library
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetItemCounts request)
|
||||
{
|
||||
var filteredItems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i.LocationType != LocationType.Virtual && FilterItem(i, request, request.UserId));
|
||||
var user = string.IsNullOrWhiteSpace(request.UserId) ? null : _userManager.GetUserById(request.UserId);
|
||||
|
||||
var counts = new ItemCounts
|
||||
{
|
||||
AlbumCount = filteredItems.Count(i => i is MusicAlbum),
|
||||
EpisodeCount = filteredItems.Count(i => i is Episode),
|
||||
GameCount = filteredItems.Count(i => i is Game),
|
||||
GameSystemCount = filteredItems.Count(i => i is GameSystem),
|
||||
MovieCount = filteredItems.Count(i => i is Movie),
|
||||
SeriesCount = filteredItems.Count(i => i is Series),
|
||||
SongCount = filteredItems.Count(i => i is Audio),
|
||||
MusicVideoCount = filteredItems.Count(i => i is MusicVideo),
|
||||
BoxSetCount = filteredItems.Count(i => i is BoxSet),
|
||||
BookCount = filteredItems.Count(i => i is Book),
|
||||
|
||||
UniqueTypes = filteredItems.Select(i => i.GetClientTypeName()).Distinct().ToList()
|
||||
AlbumCount = GetCount(typeof(MusicAlbum), user, request),
|
||||
EpisodeCount = GetCount(typeof(Episode), user, request),
|
||||
GameCount = GetCount(typeof(Game), user, request),
|
||||
GameSystemCount = GetCount(typeof(GameSystem), user, request),
|
||||
MovieCount = GetCount(typeof(Movie), user, request),
|
||||
SeriesCount = GetCount(typeof(Series), user, request),
|
||||
SongCount = GetCount(typeof(Audio), user, request),
|
||||
MusicVideoCount = GetCount(typeof(MusicVideo), user, request),
|
||||
BoxSetCount = GetCount(typeof(BoxSet), user, request),
|
||||
BookCount = GetCount(typeof(Book), user, request)
|
||||
};
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(counts);
|
||||
}
|
||||
|
||||
private IList<BaseItem> GetAllLibraryItems(string userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func<BaseItem, bool> filter)
|
||||
private int GetCount(Type type, User user, GetItemCounts request)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(parentId))
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
var folder = (Folder)libraryManager.GetItemById(new Guid(parentId));
|
||||
IncludeItemTypes = new[] { type.Name },
|
||||
Limit = 0,
|
||||
Recursive = true,
|
||||
ExcludeLocationTypes = new[] { LocationType.Virtual },
|
||||
SourceTypes = new[] { SourceType.Library },
|
||||
IsFavorite = request.IsFavorite
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
var user = userManager.GetUserById(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentException("User not found");
|
||||
}
|
||||
|
||||
return folder
|
||||
.GetRecursiveChildren(user, filter)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return folder
|
||||
.GetRecursiveChildren(filter);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
var user = userManager.GetUserById(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentException("User not found");
|
||||
}
|
||||
|
||||
return userManager
|
||||
.GetUserById(userId)
|
||||
.RootFolder
|
||||
.GetRecursiveChildren(user, filter)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return libraryManager
|
||||
.RootFolder
|
||||
.GetRecursiveChildren(filter);
|
||||
}
|
||||
|
||||
private bool FilterItem(BaseItem item, GetItemCounts request, string userId)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
if (request.IsFavorite.HasValue)
|
||||
{
|
||||
var val = request.IsFavorite.Value;
|
||||
|
||||
if (_userDataManager.GetUserData(userId, item.GetUserDataKey()).IsFavorite != val)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return _libraryManager.GetItemsResult(query).TotalRecordCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -985,20 +931,15 @@ namespace MediaBrowser.Api.Library
|
||||
? new string[] { }
|
||||
: request.IncludeItemTypes.Split(',');
|
||||
|
||||
Func<BaseItem, bool> filter = i =>
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
if (includeTypes.Length > 0)
|
||||
{
|
||||
if (!includeTypes.Contains(i.GetType().Name, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
IncludeItemTypes = includeTypes,
|
||||
Recursive = true
|
||||
};
|
||||
|
||||
IEnumerable<BaseItem> items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, filter);
|
||||
var items = _libraryManager.GetItemList(query);
|
||||
|
||||
var lookup = items
|
||||
.ToLookup(i => i.ProductionYear ?? -1)
|
||||
|
@ -201,10 +201,10 @@ namespace MediaBrowser.Api.Library
|
||||
var rootFolderPath = _appPaths.DefaultUserViewsPath;
|
||||
|
||||
var virtualFolderPath = Path.Combine(rootFolderPath, name);
|
||||
|
||||
if (_fileSystem.DirectoryExists(virtualFolderPath))
|
||||
while (_fileSystem.DirectoryExists(virtualFolderPath))
|
||||
{
|
||||
throw new ArgumentException("There is already a media library with the name " + name + ".");
|
||||
name += "1";
|
||||
virtualFolderPath = Path.Combine(rootFolderPath, name);
|
||||
}
|
||||
|
||||
if (request.Paths != null)
|
||||
@ -236,7 +236,7 @@ namespace MediaBrowser.Api.Library
|
||||
{
|
||||
foreach (var path in request.Paths)
|
||||
{
|
||||
LibraryHelpers.AddMediaPath(_fileSystem, request.Name, path, _appPaths);
|
||||
LibraryHelpers.AddMediaPath(_fileSystem, name, path, _appPaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -478,19 +478,30 @@ namespace MediaBrowser.Api.LiveTv
|
||||
public string Feature { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/TunerHosts/Satip/IniMappings", "GET", Summary = "Gets available mappings")]
|
||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
||||
public class GetSatIniMappings : IReturn<List<NameValuePair>>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class LiveTvService : BaseApiService
|
||||
{
|
||||
private readonly ILiveTvManager _liveTvManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
|
||||
public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config, IHttpClient httpClient)
|
||||
public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService)
|
||||
{
|
||||
_liveTvManager = liveTvManager;
|
||||
_userManager = userManager;
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
_libraryManager = libraryManager;
|
||||
_dtoService = dtoService;
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetLiveTvRegistrationInfo request)
|
||||
@ -500,6 +511,11 @@ namespace MediaBrowser.Api.LiveTv
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetSatIniMappings request)
|
||||
{
|
||||
return ToOptimizedResult(_liveTvManager.GetSatIniMappings());
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetSchedulesDirectCountries request)
|
||||
{
|
||||
// https://json.schedulesdirect.org/20141201/available/countries
|
||||
@ -581,7 +597,7 @@ namespace MediaBrowser.Api.LiveTv
|
||||
|
||||
public async Task<object> Get(GetChannels request)
|
||||
{
|
||||
var result = await _liveTvManager.GetChannels(new LiveTvChannelQuery
|
||||
var channelResult = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery
|
||||
{
|
||||
ChannelType = request.Type,
|
||||
UserId = request.UserId,
|
||||
@ -593,16 +609,30 @@ namespace MediaBrowser.Api.LiveTv
|
||||
EnableFavoriteSorting = request.EnableFavoriteSorting,
|
||||
AddCurrentProgram = request.AddCurrentProgram
|
||||
|
||||
}, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
|
||||
|
||||
var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ToArray();
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = returnArray,
|
||||
TotalRecordCount = channelResult.TotalRecordCount
|
||||
};
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetChannel request)
|
||||
public object Get(GetChannel request)
|
||||
{
|
||||
var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
|
||||
var user = string.IsNullOrWhiteSpace(request.UserId) ? null : _userManager.GetUserById(request.UserId);
|
||||
|
||||
var result = await _liveTvManager.GetChannel(request.Id, CancellationToken.None, user).ConfigureAwait(false);
|
||||
var item = _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.8\lib\net45\CommonIO.dll</HintPath>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MoreLinq">
|
||||
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
|
||||
|
@ -91,22 +91,21 @@ namespace MediaBrowser.Api.Movies
|
||||
private readonly IItemRepository _itemRepo;
|
||||
private readonly IDtoService _dtoService;
|
||||
|
||||
private readonly IChannelManager _channelManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MoviesService"/> class.
|
||||
/// Initializes a new instance of the <see cref="MoviesService" /> class.
|
||||
/// </summary>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="userDataRepository">The user data repository.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IChannelManager channelManager)
|
||||
/// <param name="itemRepo">The item repo.</param>
|
||||
/// <param name="dtoService">The dto service.</param>
|
||||
public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_libraryManager = libraryManager;
|
||||
_itemRepo = itemRepo;
|
||||
_dtoService = dtoService;
|
||||
_channelManager = channelManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -138,8 +137,16 @@ namespace MediaBrowser.Api.Movies
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name }
|
||||
};
|
||||
|
||||
if (user.Configuration.IncludeTrailersInSuggestions)
|
||||
{
|
||||
var includeList = query.IncludeItemTypes.ToList();
|
||||
includeList.Add(typeof(Trailer).Name);
|
||||
query.IncludeItemTypes = includeList.ToArray();
|
||||
}
|
||||
|
||||
var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
|
||||
var movies = _libraryManager.GetItems(query, parentIds);
|
||||
var movies = _libraryManager.GetItemList(query, parentIds);
|
||||
movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
|
||||
|
||||
var listEligibleForCategories = new List<BaseItem>();
|
||||
@ -150,19 +157,6 @@ namespace MediaBrowser.Api.Movies
|
||||
listEligibleForCategories.AddRange(list);
|
||||
listEligibleForSuggestion.AddRange(list);
|
||||
|
||||
if (user.Configuration.IncludeTrailersInSuggestions)
|
||||
{
|
||||
var trailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery
|
||||
{
|
||||
ContentTypes = new[] { ChannelMediaContentType.MovieExtra },
|
||||
ExtraTypes = new[] { ExtraType.Trailer },
|
||||
UserId = user.Id.ToString("N")
|
||||
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
listEligibleForSuggestion.AddRange(trailerResult.Items);
|
||||
}
|
||||
|
||||
listEligibleForCategories = listEligibleForCategories
|
||||
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
|
||||
@ -194,36 +188,25 @@ namespace MediaBrowser.Api.Movies
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name }
|
||||
};
|
||||
|
||||
if (user == null || user.Configuration.IncludeTrailersInSuggestions)
|
||||
{
|
||||
var includeList = query.IncludeItemTypes.ToList();
|
||||
includeList.Add(typeof(Trailer).Name);
|
||||
query.IncludeItemTypes = includeList.ToArray();
|
||||
}
|
||||
|
||||
var parentIds = new string[] { };
|
||||
var list = _libraryManager.GetItems(query, parentIds)
|
||||
var list = _libraryManager.GetItemList(query, parentIds)
|
||||
.Where(i =>
|
||||
{
|
||||
// Strip out secondary versions
|
||||
var v = i as Video;
|
||||
return v != null && !v.PrimaryVersionId.HasValue;
|
||||
})
|
||||
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
|
||||
.ToList();
|
||||
|
||||
if (user != null && user.Configuration.IncludeTrailersInSuggestions)
|
||||
{
|
||||
var trailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery
|
||||
{
|
||||
ContentTypes = new[] { ChannelMediaContentType.MovieExtra },
|
||||
ExtraTypes = new[] { ExtraType.Trailer },
|
||||
UserId = user.Id.ToString("N")
|
||||
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
var newTrailers = trailerResult.Items;
|
||||
|
||||
list.AddRange(newTrailers);
|
||||
|
||||
list = list
|
||||
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (item is Video)
|
||||
{
|
||||
var imdbId = item.GetProviderId(MetadataProviders.Imdb);
|
||||
|
@ -12,6 +12,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
using MediaBrowser.Controller.Localization;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Api.Movies
|
||||
{
|
||||
@ -41,87 +44,37 @@ namespace MediaBrowser.Api.Movies
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IChannelManager _channelManager;
|
||||
private readonly ICollectionManager _collectionManager;
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IJsonSerializer _json;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TrailersService"/> class.
|
||||
/// </summary>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="userDataRepository">The user data repository.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, IChannelManager channelManager)
|
||||
public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, ICollectionManager collectionManager, ILocalizationManager localizationManager, IJsonSerializer json)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_libraryManager = libraryManager;
|
||||
_dtoService = dtoService;
|
||||
_channelManager = channelManager;
|
||||
_collectionManager = collectionManager;
|
||||
_localizationManager = localizationManager;
|
||||
_json = json;
|
||||
}
|
||||
|
||||
public async Task<object> Get(Getrailers request)
|
||||
public object Get(Getrailers request)
|
||||
{
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
var result = await GetAllTrailers(user).ConfigureAwait(false);
|
||||
var json = _json.SerializeToString(request);
|
||||
var getItems = _json.DeserializeFromString<GetItems>(json);
|
||||
|
||||
IEnumerable<BaseItem> items = result.Items;
|
||||
getItems.IncludeItemTypes = "Trailer";
|
||||
|
||||
// Apply filters
|
||||
// Run them starting with the ones that are likely to reduce the list the most
|
||||
foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f))
|
||||
return new ItemsService(_userManager, _libraryManager, _userDataRepository, _localizationManager, _dtoService, _collectionManager)
|
||||
{
|
||||
items = ItemsService.ApplyFilter(items, filter, user, _userDataRepository);
|
||||
}
|
||||
AuthorizationContext = AuthorizationContext,
|
||||
Logger = Logger,
|
||||
Request = Request,
|
||||
ResultFactory = ResultFactory,
|
||||
SessionContext = SessionContext
|
||||
|
||||
items = _libraryManager.Sort(items, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending);
|
||||
|
||||
var itemsArray = items.ToList();
|
||||
|
||||
var pagedItems = ApplyPaging(request, itemsArray);
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ToArray();
|
||||
|
||||
return new ItemsResult
|
||||
{
|
||||
TotalRecordCount = itemsArray.Count,
|
||||
Items = returnItems
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<BaseItem> ApplyPaging(Getrailers request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
// Start at
|
||||
if (request.StartIndex.HasValue)
|
||||
{
|
||||
items = items.Skip(request.StartIndex.Value);
|
||||
}
|
||||
|
||||
// Return limit
|
||||
if (request.Limit.HasValue)
|
||||
{
|
||||
items = items.Take(request.Limit.Value);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> GetAllTrailers(User user)
|
||||
{
|
||||
var trailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery
|
||||
{
|
||||
ContentTypes = new[] { ChannelMediaContentType.MovieExtra },
|
||||
ExtraTypes = new[] { ExtraType.Trailer },
|
||||
UserId = user.Id.ToString("N")
|
||||
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
Items = trailerResult.Items,
|
||||
TotalRecordCount = trailerResult.TotalRecordCount
|
||||
};
|
||||
}.Get(getItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,10 +52,15 @@ namespace MediaBrowser.Api.Music
|
||||
|
||||
public object Get(GetSimilarArtists request)
|
||||
{
|
||||
var result = GetSimilarItemsResult(
|
||||
|
||||
request,
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||
_itemRepo,
|
||||
_libraryManager,
|
||||
_userDataRepository,
|
||||
_dtoService,
|
||||
Logger,
|
||||
request, new[] { typeof(MusicArtist) },
|
||||
SimilarItemsHelper.GetSimiliarityScore);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
@ -76,44 +81,11 @@ namespace MediaBrowser.Api.Music
|
||||
_userDataRepository,
|
||||
_dtoService,
|
||||
Logger,
|
||||
request, item => item is MusicAlbum,
|
||||
request, new[] { typeof(MusicAlbum) },
|
||||
GetAlbumSimilarityScore);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
||||
private ItemsResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
|
||||
{
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
|
||||
var item = string.IsNullOrEmpty(request.Id) ?
|
||||
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
|
||||
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var inputItems = _libraryManager.GetArtists(user.RootFolder.GetRecursiveChildren(user, i => i is IHasArtist).OfType<IHasArtist>());
|
||||
|
||||
var list = inputItems.ToList();
|
||||
|
||||
var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList();
|
||||
|
||||
IEnumerable<BaseItem> returnItems = items;
|
||||
|
||||
if (request.Limit.HasValue)
|
||||
{
|
||||
returnItems = returnItems.Take(request.Limit.Value);
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
|
||||
|
||||
TotalRecordCount = items.Count
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album similarity score.
|
||||
|
@ -214,7 +214,7 @@ namespace MediaBrowser.Api.Playback
|
||||
args += " -map -0:a";
|
||||
}
|
||||
|
||||
if (state.SubtitleStream == null)
|
||||
if (state.SubtitleStream == null || state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Hls)
|
||||
{
|
||||
args += " -map -0:s";
|
||||
}
|
||||
@ -477,7 +477,7 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
var pts = string.Empty;
|
||||
|
||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && !state.VideoRequest.CopyTimestamps)
|
||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode && !state.VideoRequest.CopyTimestamps)
|
||||
{
|
||||
var seconds = TimeSpan.FromTicks(state.Request.StartTimeTicks ?? 0).TotalSeconds;
|
||||
|
||||
@ -575,7 +575,7 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
var output = string.Empty;
|
||||
|
||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode)
|
||||
{
|
||||
var subParam = GetTextSubtitleParam(state);
|
||||
|
||||
@ -865,7 +865,7 @@ namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
var arg = string.Format("-i {0}", GetInputPathArgument(state));
|
||||
|
||||
if (state.SubtitleStream != null)
|
||||
if (state.SubtitleStream != null && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode)
|
||||
{
|
||||
if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
|
||||
{
|
||||
@ -1482,6 +1482,17 @@ namespace MediaBrowser.Api.Playback
|
||||
videoRequest.CopyTimestamps = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
else if (i == 25)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(val) && videoRequest != null)
|
||||
{
|
||||
SubtitleDeliveryMethod method;
|
||||
if (Enum.TryParse(val, out method))
|
||||
{
|
||||
videoRequest.SubtitleMethod = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,7 +529,12 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
"subs" :
|
||||
null;
|
||||
|
||||
AppendPlaylist(builder, playlistUrl, totalBitrate, subtitleGroup);
|
||||
if (!string.IsNullOrWhiteSpace(subtitleGroup))
|
||||
{
|
||||
AddSubtitles(state, subtitleStreams, builder);
|
||||
}
|
||||
|
||||
AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup);
|
||||
|
||||
if (EnableAdaptiveBitrateStreaming(state, isLiveStream))
|
||||
{
|
||||
@ -540,17 +545,12 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
|
||||
var newBitrate = totalBitrate - variation;
|
||||
var variantUrl = ReplaceBitrate(playlistUrl, requestedVideoBitrate, (requestedVideoBitrate - variation));
|
||||
AppendPlaylist(builder, variantUrl, newBitrate, subtitleGroup);
|
||||
AppendPlaylist(builder, state, variantUrl, newBitrate, subtitleGroup);
|
||||
|
||||
variation *= 2;
|
||||
newBitrate = totalBitrate - variation;
|
||||
variantUrl = ReplaceBitrate(playlistUrl, requestedVideoBitrate, (requestedVideoBitrate - variation));
|
||||
AppendPlaylist(builder, variantUrl, newBitrate, subtitleGroup);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(subtitleGroup))
|
||||
{
|
||||
AddSubtitles(state, subtitleStreams, builder);
|
||||
AppendPlaylist(builder, state, variantUrl, newBitrate, subtitleGroup);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
@ -566,11 +566,11 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
|
||||
private void AddSubtitles(StreamState state, IEnumerable<MediaStream> subtitles, StringBuilder builder)
|
||||
{
|
||||
var selectedIndex = state.SubtitleStream == null ? (int?)null : state.SubtitleStream.Index;
|
||||
var selectedIndex = state.SubtitleStream == null || state.VideoRequest.SubtitleMethod != SubtitleDeliveryMethod.Hls ? (int?)null : state.SubtitleStream.Index;
|
||||
|
||||
foreach (var stream in subtitles)
|
||||
{
|
||||
const string format = "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"{0}\",DEFAULT={1},FORCED={2},URI=\"{3}\",LANGUAGE=\"{4}\"";
|
||||
const string format = "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"{0}\",DEFAULT={1},FORCED={2},AUTOSELECT=YES,URI=\"{3}\",LANGUAGE=\"{4}\"";
|
||||
|
||||
var name = stream.Language;
|
||||
|
||||
@ -579,10 +579,11 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name)) name = stream.Codec ?? "Unknown";
|
||||
|
||||
var url = string.Format("{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}",
|
||||
var url = string.Format("{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}&api_key={3}",
|
||||
state.Request.MediaSourceId,
|
||||
stream.Index.ToString(UsCulture),
|
||||
30.ToString(UsCulture));
|
||||
30.ToString(UsCulture),
|
||||
AuthorizationContext.GetAuthorizationInfo(Request).Token);
|
||||
|
||||
var line = string.Format(format,
|
||||
name,
|
||||
@ -635,9 +636,15 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
//return state.VideoRequest.VideoBitRate.HasValue;
|
||||
}
|
||||
|
||||
private void AppendPlaylist(StringBuilder builder, string url, int bitrate, string subtitleGroup)
|
||||
private void AppendPlaylist(StringBuilder builder, StreamState state, string url, int bitrate, string subtitleGroup)
|
||||
{
|
||||
var header = "#EXT-X-STREAM-INF:BANDWIDTH=" + bitrate.ToString(UsCulture);
|
||||
var header = "#EXT-X-STREAM-INF:BANDWIDTH=" + bitrate.ToString(UsCulture) + ",AVERAGE-BANDWIDTH=" + bitrate.ToString(UsCulture);
|
||||
|
||||
// tvos wants resolution, codecs, framerate
|
||||
//if (state.TargetFramerate.HasValue)
|
||||
//{
|
||||
// header += string.Format(",FRAME-RATE=\"{0}\"", state.TargetFramerate.Value.ToString(CultureInfo.InvariantCulture));
|
||||
//}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(subtitleGroup))
|
||||
{
|
||||
@ -694,6 +701,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("#EXTM3U");
|
||||
builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
|
||||
builder.AppendLine("#EXT-X-VERSION:3");
|
||||
builder.AppendLine("#EXT-X-TARGETDURATION:" + Math.Ceiling((segmentLengths.Length > 0 ? segmentLengths.Max() : state.SegmentLength)).ToString(UsCulture));
|
||||
builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
|
||||
@ -820,7 +828,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
|
||||
state.SegmentLength.ToString(UsCulture));
|
||||
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
|
||||
|
||||
args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg;
|
||||
|
||||
@ -846,7 +854,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
|
||||
private bool EnableCopyTs(StreamState state)
|
||||
{
|
||||
return state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream;
|
||||
return state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
|
||||
}
|
||||
|
||||
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
|
||||
|
@ -9,6 +9,7 @@ using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Hls
|
||||
{
|
||||
@ -104,7 +105,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
|
||||
state.SegmentLength.ToString(UsCulture));
|
||||
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
|
||||
|
||||
args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg;
|
||||
|
||||
|
@ -73,9 +73,13 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture));
|
||||
}
|
||||
|
||||
if (state.OutputAudioSampleRate.HasValue)
|
||||
// opus will fail on 44100
|
||||
if (!string.Equals(state.OutputAudioCodec, "opus", global::System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture));
|
||||
if (state.OutputAudioSampleRate.HasValue)
|
||||
{
|
||||
audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture));
|
||||
}
|
||||
}
|
||||
|
||||
const string vn = " -vn";
|
||||
|
@ -61,8 +61,9 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
{
|
||||
try
|
||||
{
|
||||
new ProgressiveFileCopier(_fileSystem, _job)
|
||||
.StreamFile(Path, responseStream);
|
||||
var task = new ProgressiveFileCopier(_fileSystem, _job, Logger).StreamFile(Path, responseStream);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
@ -91,19 +92,21 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
{
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly TranscodingJob _job;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
// 256k
|
||||
private const int BufferSize = 262144;
|
||||
|
||||
|
||||
private long _bytesWritten = 0;
|
||||
|
||||
public ProgressiveFileCopier(IFileSystem fileSystem, TranscodingJob job)
|
||||
public ProgressiveFileCopier(IFileSystem fileSystem, TranscodingJob job, ILogger logger)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_job = job;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void StreamFile(string path, Stream outputStream)
|
||||
public async Task StreamFile(string path, Stream outputStream)
|
||||
{
|
||||
var eofCount = 0;
|
||||
long position = 0;
|
||||
@ -126,8 +129,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
{
|
||||
eofCount++;
|
||||
}
|
||||
var task = Task.Delay(100);
|
||||
Task.WaitAll(task);
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -145,6 +147,30 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
int count;
|
||||
while ((count = source.Read(array, 0, array.Length)) != 0)
|
||||
{
|
||||
//if (_job != null)
|
||||
//{
|
||||
// var didPause = false;
|
||||
// var totalPauseTime = 0;
|
||||
|
||||
// if (_job.IsUserPaused)
|
||||
// {
|
||||
// _logger.Debug("Pausing writing to network stream while user has paused playback.");
|
||||
|
||||
// while (_job.IsUserPaused && totalPauseTime < 30000)
|
||||
// {
|
||||
// didPause = true;
|
||||
// var pauseTime = 500;
|
||||
// totalPauseTime += pauseTime;
|
||||
// await Task.Delay(pauseTime).ConfigureAwait(false);
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (didPause)
|
||||
// {
|
||||
// _logger.Debug("Resuming writing to network stream due to user unpausing playback.");
|
||||
// }
|
||||
//}
|
||||
|
||||
destination.Write(array, 0, count);
|
||||
|
||||
_bytesWritten += count;
|
||||
|
@ -13,6 +13,7 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Progressive
|
||||
{
|
||||
@ -161,7 +162,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
|
||||
args += keyFrameArg;
|
||||
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
|
||||
|
||||
var hasCopyTs = false;
|
||||
// Add resolution params, if specified
|
||||
|
@ -213,8 +213,6 @@ namespace MediaBrowser.Api.Reports
|
||||
SortBy = request.GetOrderBy(),
|
||||
SortOrder = request.SortOrder ?? SortOrder.Ascending,
|
||||
|
||||
Filter = i => ApplyAdditionalFilters(request, i, user, _libraryManager),
|
||||
|
||||
IsFavorite = request.IsFavorite,
|
||||
Limit = request.Limit,
|
||||
StartIndex = request.StartIndex,
|
||||
@ -258,7 +256,10 @@ namespace MediaBrowser.Api.Reports
|
||||
MinPlayers = request.MinPlayers,
|
||||
MaxPlayers = request.MaxPlayers,
|
||||
MinCommunityRating = request.MinCommunityRating,
|
||||
MinCriticRating = request.MinCriticRating
|
||||
MinCriticRating = request.MinCriticRating,
|
||||
ParentIndexNumber = request.ParentIndexNumber,
|
||||
AiredDuringSeason = request.AiredDuringSeason,
|
||||
AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Ids))
|
||||
@ -302,6 +303,72 @@ namespace MediaBrowser.Api.Reports
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.MinPremiereDate))
|
||||
{
|
||||
query.MinPremiereDate = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.MaxPremiereDate))
|
||||
{
|
||||
query.MaxPremiereDate = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
||||
}
|
||||
|
||||
// Filter by Series Status
|
||||
if (!string.IsNullOrEmpty(request.SeriesStatus))
|
||||
{
|
||||
query.SeriesStatuses = request.SeriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray();
|
||||
}
|
||||
|
||||
// Filter by Series AirDays
|
||||
if (!string.IsNullOrEmpty(request.AirDays))
|
||||
{
|
||||
query.AirDays = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)).ToArray();
|
||||
}
|
||||
|
||||
// ExcludeLocationTypes
|
||||
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
|
||||
{
|
||||
query.ExcludeLocationTypes = request.ExcludeLocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.LocationTypes))
|
||||
{
|
||||
query.LocationTypes = request.LocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();
|
||||
}
|
||||
|
||||
// Min official rating
|
||||
if (!string.IsNullOrEmpty(request.MinOfficialRating))
|
||||
{
|
||||
query.MinParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
|
||||
}
|
||||
|
||||
// Max official rating
|
||||
if (!string.IsNullOrEmpty(request.MaxOfficialRating))
|
||||
{
|
||||
query.MaxParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
|
||||
}
|
||||
|
||||
// Artists
|
||||
if (!string.IsNullOrEmpty(request.ArtistIds))
|
||||
{
|
||||
var artistIds = request.ArtistIds.Split(new[] { '|', ',' });
|
||||
|
||||
var artistItems = artistIds.Select(_libraryManager.GetItemById).Where(i => i != null).ToList();
|
||||
query.ArtistNames = artistItems.Select(i => i.Name).ToArray();
|
||||
}
|
||||
|
||||
// Artists
|
||||
if (!string.IsNullOrEmpty(request.Artists))
|
||||
{
|
||||
query.ArtistNames = request.Artists.Split('|');
|
||||
}
|
||||
|
||||
// Albums
|
||||
if (!string.IsNullOrEmpty(request.Albums))
|
||||
{
|
||||
query.AlbumNames = request.Albums.Split('|');
|
||||
}
|
||||
|
||||
if (request.HasQueryLimit == false)
|
||||
{
|
||||
query.StartIndex = null;
|
||||
@ -311,278 +378,6 @@ namespace MediaBrowser.Api.Reports
|
||||
return query;
|
||||
}
|
||||
|
||||
private bool ApplyAdditionalFilters(BaseReportRequest request, BaseItem i, User user, ILibraryManager libraryManager)
|
||||
{
|
||||
// Artists
|
||||
if (!string.IsNullOrEmpty(request.ArtistIds))
|
||||
{
|
||||
var artistIds = request.ArtistIds.Split(new[] { '|', ',' });
|
||||
|
||||
var audio = i as IHasArtist;
|
||||
|
||||
if (!(audio != null && artistIds.Any(id =>
|
||||
{
|
||||
var artistItem = libraryManager.GetItemById(id);
|
||||
return artistItem != null && audio.HasAnyArtist(artistItem.Name);
|
||||
})))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Artists
|
||||
if (!string.IsNullOrEmpty(request.Artists))
|
||||
{
|
||||
var artists = request.Artists.Split('|');
|
||||
|
||||
var audio = i as IHasArtist;
|
||||
|
||||
if (!(audio != null && artists.Any(audio.HasAnyArtist)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Albums
|
||||
if (!string.IsNullOrEmpty(request.Albums))
|
||||
{
|
||||
var albums = request.Albums.Split('|');
|
||||
|
||||
var audio = i as Audio;
|
||||
|
||||
if (audio != null)
|
||||
{
|
||||
if (!albums.Any(a => string.Equals(a, audio.Album, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var album = i as MusicAlbum;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
if (!albums.Any(a => string.Equals(a, album.Name, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var musicVideo = i as MusicVideo;
|
||||
|
||||
if (musicVideo != null)
|
||||
{
|
||||
if (!albums.Any(a => string.Equals(a, musicVideo.Album, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Min index number
|
||||
if (request.MinIndexNumber.HasValue)
|
||||
{
|
||||
if (!(i.IndexNumber.HasValue && i.IndexNumber.Value >= request.MinIndexNumber.Value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Min official rating
|
||||
if (!string.IsNullOrEmpty(request.MinOfficialRating))
|
||||
{
|
||||
var level = _localization.GetRatingLevel(request.MinOfficialRating);
|
||||
|
||||
if (level.HasValue)
|
||||
{
|
||||
var rating = i.CustomRating;
|
||||
|
||||
if (string.IsNullOrEmpty(rating))
|
||||
{
|
||||
rating = i.OfficialRating;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(rating))
|
||||
{
|
||||
var itemLevel = _localization.GetRatingLevel(rating);
|
||||
|
||||
if (!(!itemLevel.HasValue || itemLevel.Value >= level.Value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Max official rating
|
||||
if (!string.IsNullOrEmpty(request.MaxOfficialRating))
|
||||
{
|
||||
var level = _localization.GetRatingLevel(request.MaxOfficialRating);
|
||||
|
||||
if (level.HasValue)
|
||||
{
|
||||
var rating = i.CustomRating;
|
||||
|
||||
if (string.IsNullOrEmpty(rating))
|
||||
{
|
||||
rating = i.OfficialRating;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(rating))
|
||||
{
|
||||
var itemLevel = _localization.GetRatingLevel(rating);
|
||||
|
||||
if (!(!itemLevel.HasValue || itemLevel.Value <= level.Value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LocationTypes
|
||||
if (!string.IsNullOrEmpty(request.LocationTypes))
|
||||
{
|
||||
var vals = request.LocationTypes.Split(',');
|
||||
if (!vals.Contains(i.LocationType.ToString(), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ExcludeLocationTypes
|
||||
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
|
||||
{
|
||||
var vals = request.ExcludeLocationTypes.Split(',');
|
||||
if (vals.Contains(i.LocationType.ToString(), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.AlbumArtistStartsWithOrGreater))
|
||||
{
|
||||
var ok = new[] { i }.OfType<IHasAlbumArtist>()
|
||||
.Any(p => string.Compare(request.AlbumArtistStartsWithOrGreater, p.AlbumArtists.FirstOrDefault(), StringComparison.CurrentCultureIgnoreCase) < 1);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by Series Status
|
||||
if (!string.IsNullOrEmpty(request.SeriesStatus))
|
||||
{
|
||||
var vals = request.SeriesStatus.Split(',');
|
||||
|
||||
var ok = new[] { i }.OfType<Series>().Any(p => p.Status.HasValue && vals.Contains(p.Status.Value.ToString(), StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by Series AirDays
|
||||
if (!string.IsNullOrEmpty(request.AirDays))
|
||||
{
|
||||
var days = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true));
|
||||
|
||||
var ok = new[] { i }.OfType<Series>().Any(p => p.AirDays != null && days.Any(d => p.AirDays.Contains(d)));
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (request.ParentIndexNumber.HasValue)
|
||||
{
|
||||
var filterValue = request.ParentIndexNumber.Value;
|
||||
|
||||
var episode = i as Episode;
|
||||
|
||||
if (episode != null)
|
||||
{
|
||||
if (episode.ParentIndexNumber.HasValue && episode.ParentIndexNumber.Value != filterValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var song = i as Audio;
|
||||
|
||||
if (song != null)
|
||||
{
|
||||
if (song.ParentIndexNumber.HasValue && song.ParentIndexNumber.Value != filterValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (request.AiredDuringSeason.HasValue)
|
||||
{
|
||||
var episode = i as Episode;
|
||||
|
||||
if (episode == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Series.FilterEpisodesBySeason(new[] { episode }, request.AiredDuringSeason.Value, true).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.MinPremiereDate))
|
||||
{
|
||||
var date = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
||||
|
||||
if (!(i.PremiereDate.HasValue && i.PremiereDate.Value >= date))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.MaxPremiereDate))
|
||||
{
|
||||
var date = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
||||
|
||||
if (!(i.PremiereDate.HasValue && i.PremiereDate.Value <= date))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary> Applies the paging. </summary>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <returns> IEnumerable{BaseItem}. </returns>
|
||||
private IEnumerable<BaseItem> ApplyPaging(BaseReportRequest request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
// Start at
|
||||
if (request.StartIndex.HasValue)
|
||||
{
|
||||
items = items.Skip(request.StartIndex.Value);
|
||||
}
|
||||
|
||||
// Return limit
|
||||
if (request.Limit.HasValue)
|
||||
{
|
||||
items = items.Take(request.Limit.Value);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/// <summary> Gets query result. </summary>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <returns> The query result. </returns>
|
||||
|
@ -54,21 +54,7 @@ namespace MediaBrowser.Api
|
||||
/// </summary>
|
||||
public static class SimilarItemsHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the similar items.
|
||||
/// </summary>
|
||||
/// <param name="dtoOptions">The dto options.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="itemRepository">The item repository.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="userDataRepository">The user data repository.</param>
|
||||
/// <param name="dtoService">The dto service.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="includeInSearch">The include in search.</param>
|
||||
/// <param name="getSimilarityScore">The get similarity score.</param>
|
||||
/// <returns>ItemsResult.</returns>
|
||||
internal static ItemsResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
|
||||
internal static ItemsResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
|
||||
{
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? userManager.GetUserById(request.UserId) : null;
|
||||
|
||||
@ -76,11 +62,13 @@ namespace MediaBrowser.Api
|
||||
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
|
||||
libraryManager.RootFolder) : libraryManager.GetItemById(request.Id);
|
||||
|
||||
Func<BaseItem, bool> filter = i => i.Id != item.Id && includeInSearch(i);
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(),
|
||||
Recursive = true
|
||||
};
|
||||
|
||||
var inputItems = user == null
|
||||
? libraryManager.RootFolder.GetRecursiveChildren(filter)
|
||||
: user.RootFolder.GetRecursiveChildren(user, filter);
|
||||
var inputItems = libraryManager.GetItemList(query);
|
||||
|
||||
var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore)
|
||||
.ToList();
|
||||
|
@ -68,6 +68,8 @@ namespace MediaBrowser.Api
|
||||
_config.Configuration.EnableLocalizedGuids = true;
|
||||
_config.Configuration.EnableCustomPathSubFolders = true;
|
||||
_config.Configuration.EnableDateLastRefresh = true;
|
||||
_config.Configuration.EnableStandaloneMusicKeys = true;
|
||||
_config.Configuration.EnableCaseSensitiveItemIds = true;
|
||||
_config.SaveConfiguration();
|
||||
}
|
||||
|
||||
|
@ -164,6 +164,8 @@ namespace MediaBrowser.Api.Subtitles
|
||||
long positionTicks = 0;
|
||||
var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks;
|
||||
|
||||
var accessToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
|
||||
|
||||
while (positionTicks < runtime)
|
||||
{
|
||||
var remaining = runtime - positionTicks;
|
||||
@ -173,9 +175,10 @@ namespace MediaBrowser.Api.Subtitles
|
||||
|
||||
var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks);
|
||||
|
||||
var url = string.Format("stream.srt?StartPositionTicks={0}&EndPositionTicks={1}",
|
||||
var url = string.Format("stream.vtt?StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}",
|
||||
positionTicks.ToString(CultureInfo.InvariantCulture),
|
||||
endPositionTicks.ToString(CultureInfo.InvariantCulture));
|
||||
endPositionTicks.ToString(CultureInfo.InvariantCulture),
|
||||
accessToken);
|
||||
|
||||
builder.AppendLine(url);
|
||||
|
||||
|
@ -263,7 +263,7 @@ namespace MediaBrowser.Api
|
||||
_userDataManager,
|
||||
_dtoService,
|
||||
Logger,
|
||||
request, item => item is Series,
|
||||
request, new[] { typeof(Series) },
|
||||
SimilarItemsHelper.GetSimiliarityScore);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
@ -273,11 +273,11 @@ namespace MediaBrowser.Api
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var minPremiereDate = DateTime.Now.Date.AddDays(-1).ToUniversalTime();
|
||||
var minPremiereDate = DateTime.Now.Date.ToUniversalTime();
|
||||
|
||||
var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
|
||||
|
||||
var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
||||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
SortBy = new[] { "PremiereDate", "AirTime", "SortName" },
|
||||
@ -286,15 +286,15 @@ namespace MediaBrowser.Api
|
||||
StartIndex = request.StartIndex,
|
||||
Limit = request.Limit
|
||||
|
||||
}, parentIds);
|
||||
}, parentIds).ToList();
|
||||
|
||||
var options = GetDtoOptions(request);
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, options, user).ToArray();
|
||||
var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user).ToArray();
|
||||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
TotalRecordCount = itemsResult.TotalRecordCount,
|
||||
TotalRecordCount = itemsResult.Count,
|
||||
Items = returnItems
|
||||
};
|
||||
|
||||
|
@ -85,17 +85,16 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
/// <returns>Task{ItemsResult}.</returns>
|
||||
private async Task<ItemsResult> GetItems(GetItems request)
|
||||
{
|
||||
var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId);
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
|
||||
var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false);
|
||||
var result = await GetItemsToSerialize(request, user).ConfigureAwait(false);
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
return new ItemsResult
|
||||
{
|
||||
TotalRecordCount = result.Item1.TotalRecordCount,
|
||||
Items = _dtoService.GetBaseItemDtos(result.Item1.Items, dtoOptions, user).ToArray()
|
||||
TotalRecordCount = result.TotalRecordCount,
|
||||
Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
@ -104,17 +103,16 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="parentItem">The parent item.</param>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
private async Task<Tuple<QueryResult<BaseItem>, bool>> GetItemsToSerialize(GetItems request, User user, BaseItem parentItem)
|
||||
private async Task<QueryResult<BaseItem>> GetItemsToSerialize(GetItems request, User user)
|
||||
{
|
||||
var item = string.IsNullOrEmpty(request.ParentId) ?
|
||||
user == null ? _libraryManager.RootFolder : user.RootFolder :
|
||||
parentItem;
|
||||
_libraryManager.GetItemById(request.ParentId);
|
||||
|
||||
if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item = user == null ? _libraryManager.RootFolder : user.RootFolder;
|
||||
//item = user == null ? _libraryManager.RootFolder : user.RootFolder;
|
||||
}
|
||||
else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@ -137,21 +135,21 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
|
||||
}
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (request.Recursive)
|
||||
{
|
||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
var userRoot = item as UserRootFolder;
|
||||
@ -160,26 +158,24 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
IEnumerable<BaseItem> items = ((Folder)item).GetChildren(user, true);
|
||||
|
||||
var itemsArray = items.ToArray();
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(new QueryResult<BaseItem>
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
Items = itemsArray,
|
||||
TotalRecordCount = itemsArray.Length
|
||||
|
||||
}, false);
|
||||
};
|
||||
}
|
||||
|
||||
private InternalItemsQuery GetItemsQuery(GetItems request, User user)
|
||||
{
|
||||
var query = new InternalItemsQuery
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
User = user,
|
||||
IsPlayed = request.IsPlayed,
|
||||
MediaTypes = request.GetMediaTypes(),
|
||||
IncludeItemTypes = request.GetIncludeItemTypes(),
|
||||
@ -188,8 +184,6 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
SortBy = request.GetOrderBy(),
|
||||
SortOrder = request.SortOrder ?? SortOrder.Ascending,
|
||||
|
||||
Filter = i => ApplyAdditionalFilters(request, i, user, _libraryManager),
|
||||
|
||||
IsFavorite = request.IsFavorite,
|
||||
Limit = request.Limit,
|
||||
StartIndex = request.StartIndex,
|
||||
@ -234,7 +228,11 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
MinPlayers = request.MinPlayers,
|
||||
MaxPlayers = request.MaxPlayers,
|
||||
MinCommunityRating = request.MinCommunityRating,
|
||||
MinCriticRating = request.MinCriticRating
|
||||
MinCriticRating = request.MinCriticRating,
|
||||
ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId),
|
||||
ParentIndexNumber = request.ParentIndexNumber,
|
||||
AiredDuringSeason = request.AiredDuringSeason,
|
||||
AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Ids))
|
||||
@ -278,331 +276,73 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies filtering
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="filter">The filter.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="repository">The repository.</param>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
internal static IEnumerable<BaseItem> ApplyFilter(IEnumerable<BaseItem> items, ItemFilter filter, User user, IUserDataManager repository)
|
||||
{
|
||||
// Avoid implicitly captured closure
|
||||
var currentUser = user;
|
||||
|
||||
switch (filter)
|
||||
if (!string.IsNullOrEmpty(request.MinPremiereDate))
|
||||
{
|
||||
case ItemFilter.IsFavoriteOrLikes:
|
||||
return items.Where(item =>
|
||||
{
|
||||
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
|
||||
|
||||
if (userdata == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var likes = userdata.Likes ?? false;
|
||||
var favorite = userdata.IsFavorite;
|
||||
|
||||
return likes || favorite;
|
||||
});
|
||||
|
||||
case ItemFilter.Likes:
|
||||
return items.Where(item =>
|
||||
{
|
||||
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
|
||||
|
||||
return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
|
||||
});
|
||||
|
||||
case ItemFilter.Dislikes:
|
||||
return items.Where(item =>
|
||||
{
|
||||
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
|
||||
|
||||
return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
|
||||
});
|
||||
|
||||
case ItemFilter.IsFavorite:
|
||||
return items.Where(item =>
|
||||
{
|
||||
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
|
||||
|
||||
return userdata != null && userdata.IsFavorite;
|
||||
});
|
||||
|
||||
case ItemFilter.IsResumable:
|
||||
return items.Where(item =>
|
||||
{
|
||||
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
|
||||
|
||||
return userdata != null && userdata.PlaybackPositionTicks > 0;
|
||||
});
|
||||
|
||||
case ItemFilter.IsPlayed:
|
||||
return items.Where(item => item.IsPlayed(currentUser));
|
||||
|
||||
case ItemFilter.IsUnplayed:
|
||||
return items.Where(item => item.IsUnplayed(currentUser));
|
||||
|
||||
case ItemFilter.IsFolder:
|
||||
return items.Where(item => item.IsFolder);
|
||||
|
||||
case ItemFilter.IsNotFolder:
|
||||
return items.Where(item => !item.IsFolder);
|
||||
|
||||
case ItemFilter.IsRecentlyAdded:
|
||||
return items.Where(item => (DateTime.UtcNow - item.DateCreated).TotalDays <= 10);
|
||||
query.MinPremiereDate = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private bool ApplyAdditionalFilters(GetItems request, BaseItem i, User user, ILibraryManager libraryManager)
|
||||
{
|
||||
// Artists
|
||||
if (!string.IsNullOrEmpty(request.ArtistIds))
|
||||
if (!string.IsNullOrEmpty(request.MaxPremiereDate))
|
||||
{
|
||||
var artistIds = request.ArtistIds.Split(new[] { '|', ',' });
|
||||
|
||||
var audio = i as IHasArtist;
|
||||
|
||||
if (!(audio != null && artistIds.Any(id =>
|
||||
{
|
||||
var artistItem = libraryManager.GetItemById(id);
|
||||
return artistItem != null && audio.HasAnyArtist(artistItem.Name);
|
||||
})))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Artists
|
||||
if (!string.IsNullOrEmpty(request.Artists))
|
||||
{
|
||||
var artists = request.Artists.Split('|');
|
||||
|
||||
var audio = i as IHasArtist;
|
||||
|
||||
if (!(audio != null && artists.Any(audio.HasAnyArtist)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Albums
|
||||
if (!string.IsNullOrEmpty(request.Albums))
|
||||
{
|
||||
var albums = request.Albums.Split('|');
|
||||
|
||||
var audio = i as Audio;
|
||||
|
||||
if (audio != null)
|
||||
{
|
||||
if (!albums.Any(a => string.Equals(a, audio.Album, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var album = i as MusicAlbum;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
if (!albums.Any(a => string.Equals(a, album.Name, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var musicVideo = i as MusicVideo;
|
||||
|
||||
if (musicVideo != null)
|
||||
{
|
||||
if (!albums.Any(a => string.Equals(a, musicVideo.Album, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Min official rating
|
||||
if (!string.IsNullOrEmpty(request.MinOfficialRating))
|
||||
{
|
||||
var level = _localization.GetRatingLevel(request.MinOfficialRating);
|
||||
|
||||
if (level.HasValue)
|
||||
{
|
||||
var rating = i.CustomRating;
|
||||
|
||||
if (string.IsNullOrEmpty(rating))
|
||||
{
|
||||
rating = i.OfficialRating;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(rating))
|
||||
{
|
||||
var itemLevel = _localization.GetRatingLevel(rating);
|
||||
|
||||
if (!(!itemLevel.HasValue || itemLevel.Value >= level.Value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Max official rating
|
||||
if (!string.IsNullOrEmpty(request.MaxOfficialRating))
|
||||
{
|
||||
var level = _localization.GetRatingLevel(request.MaxOfficialRating);
|
||||
|
||||
if (level.HasValue)
|
||||
{
|
||||
var rating = i.CustomRating;
|
||||
|
||||
if (string.IsNullOrEmpty(rating))
|
||||
{
|
||||
rating = i.OfficialRating;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(rating))
|
||||
{
|
||||
var itemLevel = _localization.GetRatingLevel(rating);
|
||||
|
||||
if (!(!itemLevel.HasValue || itemLevel.Value <= level.Value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LocationTypes
|
||||
if (!string.IsNullOrEmpty(request.LocationTypes))
|
||||
{
|
||||
var vals = request.LocationTypes.Split(',');
|
||||
if (!vals.Contains(i.LocationType.ToString(), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ExcludeLocationTypes
|
||||
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
|
||||
{
|
||||
var vals = request.ExcludeLocationTypes.Split(',');
|
||||
if (vals.Contains(i.LocationType.ToString(), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.AlbumArtistStartsWithOrGreater))
|
||||
{
|
||||
var ok = new[] { i }.OfType<IHasAlbumArtist>()
|
||||
.Any(p => string.Compare(request.AlbumArtistStartsWithOrGreater, p.AlbumArtists.FirstOrDefault(), StringComparison.CurrentCultureIgnoreCase) < 1);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
query.MaxPremiereDate = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
||||
}
|
||||
|
||||
// Filter by Series Status
|
||||
if (!string.IsNullOrEmpty(request.SeriesStatus))
|
||||
{
|
||||
var vals = request.SeriesStatus.Split(',');
|
||||
|
||||
var ok = new[] { i }.OfType<Series>().Any(p => p.Status.HasValue && vals.Contains(p.Status.Value.ToString(), StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
query.SeriesStatuses = request.SeriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray();
|
||||
}
|
||||
|
||||
// Filter by Series AirDays
|
||||
if (!string.IsNullOrEmpty(request.AirDays))
|
||||
{
|
||||
var days = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true));
|
||||
|
||||
var ok = new[] { i }.OfType<Series>().Any(p => p.AirDays != null && days.Any(d => p.AirDays.Contains(d)));
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
query.AirDays = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)).ToArray();
|
||||
}
|
||||
|
||||
if (request.ParentIndexNumber.HasValue)
|
||||
// ExcludeLocationTypes
|
||||
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
|
||||
{
|
||||
var filterValue = request.ParentIndexNumber.Value;
|
||||
|
||||
var episode = i as Episode;
|
||||
|
||||
if (episode != null)
|
||||
{
|
||||
if (episode.ParentIndexNumber.HasValue && episode.ParentIndexNumber.Value != filterValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var song = i as Audio;
|
||||
|
||||
if (song != null)
|
||||
{
|
||||
if (song.ParentIndexNumber.HasValue && song.ParentIndexNumber.Value != filterValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
query.ExcludeLocationTypes = request.ExcludeLocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();
|
||||
}
|
||||
|
||||
if (request.AiredDuringSeason.HasValue)
|
||||
if (!string.IsNullOrEmpty(request.LocationTypes))
|
||||
{
|
||||
var episode = i as Episode;
|
||||
|
||||
if (episode == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Series.FilterEpisodesBySeason(new[] { episode }, request.AiredDuringSeason.Value, true).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
query.LocationTypes = request.LocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.MinPremiereDate))
|
||||
|
||||
// Min official rating
|
||||
if (!string.IsNullOrEmpty(request.MinOfficialRating))
|
||||
{
|
||||
var date = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
||||
|
||||
if (!(i.PremiereDate.HasValue && i.PremiereDate.Value >= date))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
query.MinParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.MaxPremiereDate))
|
||||
// Max official rating
|
||||
if (!string.IsNullOrEmpty(request.MaxOfficialRating))
|
||||
{
|
||||
var date = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
||||
|
||||
if (!(i.PremiereDate.HasValue && i.PremiereDate.Value <= date))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
query.MaxParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
|
||||
}
|
||||
|
||||
return true;
|
||||
// Artists
|
||||
if (!string.IsNullOrEmpty(request.ArtistIds))
|
||||
{
|
||||
var artistIds = request.ArtistIds.Split(new[] { '|', ',' });
|
||||
|
||||
var artistItems = artistIds.Select(_libraryManager.GetItemById).Where(i => i != null).ToList();
|
||||
query.ArtistNames = artistItems.Select(i => i.Name).ToArray();
|
||||
}
|
||||
|
||||
// Artists
|
||||
if (!string.IsNullOrEmpty(request.Artists))
|
||||
{
|
||||
query.ArtistNames = request.Artists.Split('|');
|
||||
}
|
||||
|
||||
// Albums
|
||||
if (!string.IsNullOrEmpty(request.Albums))
|
||||
{
|
||||
query.AlbumNames = request.Albums.Split('|');
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,11 +335,6 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
|
||||
public void Post(ReportPlaybackProgress request)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(request.PlaySessionId))
|
||||
{
|
||||
ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId);
|
||||
}
|
||||
|
||||
request.SessionId = GetSession().Result.Id;
|
||||
|
||||
var task = _sessionManager.OnPlaybackProgress(request);
|
||||
@ -349,7 +344,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
|
||||
public void Post(PingPlaybackSession request)
|
||||
{
|
||||
ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId);
|
||||
ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CommonIO" version="1.0.0.8" targetFramework="net45" />
|
||||
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
|
||||
<package id="morelinq" version="1.4.0" targetFramework="net45" />
|
||||
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
||||
</packages>
|
@ -126,6 +126,23 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
||||
}
|
||||
}
|
||||
|
||||
private void AddIpv4Option(HttpWebRequest request, HttpRequestOptions options)
|
||||
{
|
||||
if (!options.PreferIpv4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
request.ServicePoint.BindIPEndPointDelegate = (servicePount, remoteEndPoint, retryCount) =>
|
||||
{
|
||||
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
return new IPEndPoint(IPAddress.Any, 0);
|
||||
}
|
||||
throw new InvalidOperationException("no IPv4 address");
|
||||
};
|
||||
}
|
||||
|
||||
private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
|
||||
{
|
||||
var request = CreateWebRequest(options.Url);
|
||||
@ -133,6 +150,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
||||
|
||||
if (httpWebRequest != null)
|
||||
{
|
||||
AddIpv4Option(httpWebRequest, options);
|
||||
|
||||
AddRequestHeaders(httpWebRequest, options);
|
||||
|
||||
httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
|
||||
|
@ -49,7 +49,7 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.8\lib\net45\CommonIO.dll</HintPath>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MoreLinq">
|
||||
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
|
||||
|
@ -170,6 +170,17 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
||||
QueueScheduledTask<T>(new TaskExecutionOptions());
|
||||
}
|
||||
|
||||
public void QueueIfNotRunning<T>()
|
||||
where T : IScheduledTask
|
||||
{
|
||||
var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
|
||||
|
||||
if (task.State != TaskState.Running)
|
||||
{
|
||||
QueueScheduledTask<T>(new TaskExecutionOptions());
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute<T>()
|
||||
where T : IScheduledTask
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CommonIO" version="1.0.0.8" targetFramework="net45" />
|
||||
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
|
||||
<package id="morelinq" version="1.4.0" targetFramework="net45" />
|
||||
<package id="NLog" version="4.2.3" targetFramework="net45" />
|
||||
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
||||
|
@ -96,6 +96,7 @@ namespace MediaBrowser.Common.Net
|
||||
public TimeSpan CacheLength { get; set; }
|
||||
|
||||
public int TimeoutMs { get; set; }
|
||||
public bool PreferIpv4 { get; set; }
|
||||
|
||||
private string GetHeaderValue(string name)
|
||||
{
|
||||
|
@ -50,6 +50,9 @@ namespace MediaBrowser.Common.ScheduledTasks
|
||||
void QueueScheduledTask<T>()
|
||||
where T : IScheduledTask;
|
||||
|
||||
void QueueIfNotRunning<T>()
|
||||
where T : IScheduledTask;
|
||||
|
||||
/// <summary>
|
||||
/// Queues the scheduled task.
|
||||
/// </summary>
|
||||
|
@ -3,6 +3,7 @@ using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -30,6 +31,13 @@ namespace MediaBrowser.Controller.Channels
|
||||
return base.IsVisible(user);
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override SourceType SourceType
|
||||
{
|
||||
get { return SourceType.Channel; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
|
||||
{
|
||||
try
|
||||
@ -75,5 +83,12 @@ namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsChannelVisible(BaseItem channelItem, User user)
|
||||
{
|
||||
var channel = ChannelManager.GetChannel(channelItem.ChannelId);
|
||||
|
||||
return channel.IsVisible(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public class ChannelAudioItem : Audio, IChannelMediaItem
|
||||
public class ChannelAudioItem : Audio
|
||||
{
|
||||
public ChannelMediaContentType ContentType { get; set; }
|
||||
|
||||
|
@ -11,7 +11,7 @@ using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public class ChannelFolderItem : Folder, IChannelItem
|
||||
public class ChannelFolderItem : Folder
|
||||
{
|
||||
public ChannelFolderType ChannelFolderType { get; set; }
|
||||
|
||||
|
@ -13,7 +13,7 @@ using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public class ChannelVideoItem : Video, IChannelMediaItem, IHasLookupInfo<ChannelItemLookupInfo>
|
||||
public class ChannelVideoItem : Video
|
||||
{
|
||||
public ChannelMediaContentType ContentType { get; set; }
|
||||
|
||||
@ -103,20 +103,6 @@ namespace MediaBrowser.Controller.Channels
|
||||
return list;
|
||||
}
|
||||
|
||||
public ChannelItemLookupInfo GetLookupInfo()
|
||||
{
|
||||
var info = GetItemLookupInfo<ChannelItemLookupInfo>();
|
||||
|
||||
info.ContentType = ContentType;
|
||||
|
||||
if (ExtraType.HasValue)
|
||||
{
|
||||
info.ExtraType = ExtraType.Value;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
protected override string GetInternalMetadataPath(string basePath)
|
||||
{
|
||||
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N"));
|
||||
@ -132,7 +118,7 @@ namespace MediaBrowser.Controller.Channels
|
||||
return IsVisibleStandaloneInternal(user, false) && IsChannelVisible(this, user);
|
||||
}
|
||||
|
||||
internal static bool IsChannelVisible(IChannelItem item, User user)
|
||||
internal static bool IsChannelVisible(BaseItem item, User user)
|
||||
{
|
||||
var channel = ChannelManager.GetChannel(item.ChannelId);
|
||||
|
||||
|
@ -116,7 +116,7 @@ namespace MediaBrowser.Controller.Channels
|
||||
/// <param name="includeCachedVersions">if set to <c>true</c> [include cached versions].</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{IEnumerable{MediaSourceInfo}}.</returns>
|
||||
Task<IEnumerable<MediaSourceInfo>> GetStaticMediaSources(IChannelMediaItem item, bool includeCachedVersions, CancellationToken cancellationToken);
|
||||
Task<IEnumerable<MediaSourceInfo>> GetStaticMediaSources(BaseItem item, bool includeCachedVersions, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel folder.
|
||||
@ -141,6 +141,6 @@ namespace MediaBrowser.Controller.Channels
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task DownloadChannelItem(IChannelMediaItem item, string destinationPath, IProgress<double> progress, CancellationToken cancellationToken);
|
||||
Task DownloadChannelItem(BaseItem item, string destinationPath, IProgress<double> progress, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Dto
|
||||
public List<ImageType> ImageTypes { get; set; }
|
||||
public int ImageTypeLimit { get; set; }
|
||||
public bool EnableImages { get; set; }
|
||||
public bool AddProgramRecordingInfo { get; set; }
|
||||
public string DeviceId { get; set; }
|
||||
|
||||
public DtoOptions()
|
||||
|
@ -8,6 +8,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
@ -24,6 +26,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
IThemeMedia,
|
||||
IArchivable
|
||||
{
|
||||
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||
|
||||
public long? Size { get; set; }
|
||||
public string Container { get; set; }
|
||||
public int? TotalBitrate { get; set; }
|
||||
@ -153,6 +157,31 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// <returns>System.String.</returns>
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
if (ConfigurationManager.Configuration.EnableStandaloneMusicKeys)
|
||||
{
|
||||
var songKey = IndexNumber.HasValue ? IndexNumber.Value.ToString("0000") : string.Empty;
|
||||
|
||||
|
||||
if (ParentIndexNumber.HasValue)
|
||||
{
|
||||
songKey = ParentIndexNumber.Value.ToString("0000") + "-" + songKey;
|
||||
}
|
||||
songKey+= Name;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Album))
|
||||
{
|
||||
songKey = Album + "-" + songKey;
|
||||
}
|
||||
|
||||
var albumArtist = AlbumArtists.FirstOrDefault();
|
||||
if (!string.IsNullOrWhiteSpace(albumArtist))
|
||||
{
|
||||
songKey = albumArtist + "-" + songKey;
|
||||
}
|
||||
|
||||
return songKey;
|
||||
}
|
||||
|
||||
var parent = AlbumEntity;
|
||||
|
||||
if (parent != null)
|
||||
@ -173,7 +202,11 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.Music;
|
||||
if (SourceType == SourceType.Library)
|
||||
{
|
||||
return UnratedItem.Music;
|
||||
}
|
||||
return base.GetBlockUnratedType();
|
||||
}
|
||||
|
||||
public SongInfo GetLookupInfo()
|
||||
@ -189,6 +222,32 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
|
||||
public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
var sources = ChannelManager.GetStaticMediaSources(this, false, CancellationToken.None)
|
||||
.Result.ToList();
|
||||
|
||||
if (sources.Count > 0)
|
||||
{
|
||||
return sources;
|
||||
}
|
||||
|
||||
var list = new List<MediaSourceInfo>
|
||||
{
|
||||
GetVersionInfo(this, enablePathSubstitution)
|
||||
};
|
||||
|
||||
foreach (var mediaSource in list)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(mediaSource.Path))
|
||||
{
|
||||
mediaSource.Type = MediaSourceType.Placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
var result = new List<MediaSourceInfo>
|
||||
{
|
||||
GetVersionInfo(this, enablePathSubstitution)
|
||||
|
12
MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs
Normal file
12
MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
public class AudioPodcast : Audio
|
||||
{
|
||||
}
|
||||
}
|
@ -34,7 +34,17 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetParents().OfType<MusicArtist>().FirstOrDefault();
|
||||
var artist = GetParents().OfType<MusicArtist>().FirstOrDefault();
|
||||
|
||||
if (artist == null)
|
||||
{
|
||||
var name = AlbumArtist;
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
artist = LibraryManager.GetArtist(name);
|
||||
}
|
||||
}
|
||||
return artist;
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,6 +116,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return "MusicAlbum-Musicbrainz-" + id;
|
||||
}
|
||||
|
||||
if (ConfigurationManager.Configuration.EnableStandaloneMusicKeys)
|
||||
{
|
||||
var albumArtist = AlbumArtist;
|
||||
if (!string.IsNullOrWhiteSpace(albumArtist))
|
||||
{
|
||||
return albumArtist + "-" + Name;
|
||||
}
|
||||
}
|
||||
|
||||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
@ -125,7 +144,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
|
||||
id.AlbumArtists = AlbumArtists;
|
||||
|
||||
var artist = GetParents().OfType<MusicArtist>().FirstOrDefault();
|
||||
var artist = MusicArtist;
|
||||
|
||||
if (artist != null)
|
||||
{
|
||||
|
@ -20,9 +20,11 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
@ -57,7 +59,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
public static string ThemeSongFilename = "theme";
|
||||
public static string ThemeVideosFolderName = "backdrops";
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string PreferredMetadataCountryCode { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public string PreferredMetadataLanguage { get; set; }
|
||||
|
||||
public List<ItemImageInfo> ImageInfos { get; set; }
|
||||
@ -88,6 +92,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// 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>
|
||||
[IgnoreDataMember]
|
||||
public bool IsInMixedFolder { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
@ -166,6 +171,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
[IgnoreDataMember]
|
||||
public bool IsOffline { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual SourceType SourceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself
|
||||
@ -184,6 +192,13 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
[IgnoreDataMember]
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If this content came from an external service, the id of the content on that service
|
||||
/// </summary>
|
||||
@ -252,6 +267,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var locationType = LocationType;
|
||||
|
||||
return locationType != LocationType.Remote && locationType != LocationType.Virtual;
|
||||
@ -281,6 +301,40 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
private List<Tuple<StringBuilder,bool>> GetSortChunks(string s1)
|
||||
{
|
||||
var list = new List<Tuple<StringBuilder, bool>>();
|
||||
|
||||
int thisMarker = 0, thisNumericChunk = 0;
|
||||
|
||||
while ((thisMarker < s1.Length))
|
||||
{
|
||||
if (thisMarker >= s1.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
char thisCh = s1[thisMarker];
|
||||
|
||||
StringBuilder thisChunk = new StringBuilder();
|
||||
|
||||
while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || SortHelper.InChunk(thisCh, thisChunk[0])))
|
||||
{
|
||||
thisChunk.Append(thisCh);
|
||||
thisMarker++;
|
||||
|
||||
if (thisMarker < s1.Length)
|
||||
{
|
||||
thisCh = s1[thisMarker];
|
||||
}
|
||||
}
|
||||
|
||||
var isNumeric = thisChunk.Length > 0 && char.IsDigit(thisChunk[0]);
|
||||
list.Add(new Tuple<StringBuilder, bool>(thisChunk, isNumeric));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is just a helper for convenience
|
||||
/// </summary>
|
||||
@ -298,6 +352,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public virtual bool CanDelete()
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var locationType = LocationType;
|
||||
return locationType != LocationType.Remote &&
|
||||
locationType != LocationType.Virtual;
|
||||
@ -342,6 +401,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
[IgnoreDataMember]
|
||||
public DateTime DateModified { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public DateTime DateLastSaved { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
@ -380,6 +440,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Gets or sets the locked fields.
|
||||
/// </summary>
|
||||
/// <value>The locked fields.</value>
|
||||
[IgnoreDataMember]
|
||||
public List<MetadataFields> LockedFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -433,11 +494,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(ForcedSortName))
|
||||
{
|
||||
return ForcedSortName;
|
||||
}
|
||||
|
||||
return _sortName ?? (_sortName = CreateSortName());
|
||||
}
|
||||
set
|
||||
@ -455,6 +511,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
protected virtual string GetInternalMetadataPath(string basePath)
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N"));
|
||||
}
|
||||
|
||||
var idString = Id.ToString("N");
|
||||
|
||||
basePath = System.IO.Path.Combine(basePath, "library");
|
||||
@ -468,6 +529,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <returns>System.String.</returns>
|
||||
protected virtual string CreateSortName()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(ForcedSortName))
|
||||
{
|
||||
return ModifySortChunks(ForcedSortName).ToLower();
|
||||
}
|
||||
|
||||
if (Name == null) return null; //some items may not have name filled in properly
|
||||
|
||||
if (!EnableAlphaNumericSorting)
|
||||
@ -497,7 +563,32 @@ namespace MediaBrowser.Controller.Entities
|
||||
sortable = sortable.Remove(sortable.Length - (searchLower.Length + 1));
|
||||
}
|
||||
}
|
||||
return sortable;
|
||||
return ModifySortChunks(sortable);
|
||||
}
|
||||
|
||||
private string ModifySortChunks(string name)
|
||||
{
|
||||
var chunks = GetSortChunks(name);
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
foreach (var chunk in chunks)
|
||||
{
|
||||
var chunkBuilder = chunk.Item1;
|
||||
|
||||
// This chunk is numeric
|
||||
if (chunk.Item2)
|
||||
{
|
||||
while (chunkBuilder.Length < 10)
|
||||
{
|
||||
chunkBuilder.Insert(0, '0');
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append(chunkBuilder);
|
||||
}
|
||||
//Logger.Debug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString());
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
@ -595,6 +686,18 @@ namespace MediaBrowser.Controller.Entities
|
||||
[IgnoreDataMember]
|
||||
public string OfficialRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating.
|
||||
/// </summary>
|
||||
/// <value>The critic rating.</value>
|
||||
public float? CriticRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating summary.
|
||||
/// </summary>
|
||||
/// <value>The critic rating summary.</value>
|
||||
public string CriticRatingSummary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the official rating description.
|
||||
/// </summary>
|
||||
@ -620,6 +723,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Gets or sets the studios.
|
||||
/// </summary>
|
||||
/// <value>The studios.</value>
|
||||
[IgnoreDataMember]
|
||||
public List<string> Studios { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -633,6 +737,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Gets or sets the tags.
|
||||
/// </summary>
|
||||
/// <value>The tags.</value>
|
||||
[IgnoreDataMember]
|
||||
public List<string> Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -1025,6 +1130,13 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
protected virtual string CreateUserDataKey()
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(ExternalId))
|
||||
{
|
||||
return ExternalId;
|
||||
}
|
||||
}
|
||||
return Id.ToString();
|
||||
}
|
||||
|
||||
@ -1103,6 +1215,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public virtual bool IsSaveLocalMetadataEnabled()
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ConfigurationManager.Configuration.SaveLocalMeta;
|
||||
}
|
||||
|
||||
@ -1218,6 +1335,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public virtual UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return UnratedItem.ChannelContent;
|
||||
}
|
||||
|
||||
return UnratedItem.Other;
|
||||
}
|
||||
|
||||
@ -1261,6 +1383,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public virtual bool IsVisibleStandalone(User user)
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return IsVisibleStandaloneInternal(user, false) && Channel.IsChannelVisible(this, user);
|
||||
}
|
||||
|
||||
return IsVisibleStandaloneInternal(user, true);
|
||||
}
|
||||
|
||||
@ -1312,6 +1439,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public virtual string GetClientTypeName()
|
||||
{
|
||||
if (IsFolder && SourceType == SourceType.Channel)
|
||||
{
|
||||
return "ChannelFolderItem";
|
||||
}
|
||||
|
||||
return GetType().Name;
|
||||
}
|
||||
|
||||
@ -1835,8 +1967,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
ProviderIds = ProviderIds,
|
||||
IndexNumber = IndexNumber,
|
||||
ParentIndexNumber = ParentIndexNumber,
|
||||
Year = ProductionYear,
|
||||
PremiereDate = PremiereDate
|
||||
Year = ProductionYear,
|
||||
PremiereDate = PremiereDate
|
||||
};
|
||||
}
|
||||
|
||||
@ -1985,5 +2117,14 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
return LibraryManager.DeleteItem(this, options);
|
||||
}
|
||||
|
||||
public virtual Task OnFileDeleted()
|
||||
{
|
||||
// Remove from database
|
||||
return Delete(new DeleteOptions
|
||||
{
|
||||
DeleteFileLocation = false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
@ -9,6 +10,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class Book : BaseItem, IHasTags, IHasLookupInfo<BookInfo>, IHasSeries
|
||||
{
|
||||
[IgnoreDataMember]
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
|
@ -15,6 +15,9 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Model.Channels;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
@ -145,60 +148,38 @@ namespace MediaBrowser.Controller.Entities
|
||||
item.DateModified = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
AddChildInternal(item);
|
||||
AddChildInternal(item.Id);
|
||||
|
||||
await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!EnableNewFolderQuerying())
|
||||
{
|
||||
await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool EnableNewFolderQuerying()
|
||||
protected void AddChildrenInternal(List<Guid> children)
|
||||
{
|
||||
return ConfigurationManager.Configuration.MigrationVersion >= 1;
|
||||
}
|
||||
|
||||
protected void AddChildrenInternal(IEnumerable<BaseItem> children)
|
||||
{
|
||||
var actualChildren = ActualChildren;
|
||||
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
var newChildren = actualChildren.ToList();
|
||||
var newChildren = ChildIds.ToList();
|
||||
newChildren.AddRange(children);
|
||||
_children = newChildren;
|
||||
_children = newChildren.ToList();
|
||||
}
|
||||
}
|
||||
protected void AddChildInternal(BaseItem child)
|
||||
{
|
||||
var actualChildren = ActualChildren;
|
||||
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
var newChildren = actualChildren.ToList();
|
||||
newChildren.Add(child);
|
||||
_children = newChildren;
|
||||
}
|
||||
}
|
||||
|
||||
protected void RemoveChildrenInternal(IEnumerable<BaseItem> children)
|
||||
{
|
||||
var ids = children.Select(i => i.Id).ToList();
|
||||
var actualChildren = ActualChildren;
|
||||
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
_children = actualChildren.Where(i => !ids.Contains(i.Id)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
protected void ClearChildrenInternal()
|
||||
protected void AddChildInternal(Guid child)
|
||||
{
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
_children = new List<BaseItem>();
|
||||
var childIds = ChildIds.ToList();
|
||||
if (!childIds.Contains(child))
|
||||
{
|
||||
childIds.Add(child);
|
||||
_children = childIds.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void RemoveChildrenInternal(List<Guid> children)
|
||||
{
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
_children = ChildIds.Except(children).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,40 +187,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Removes the child.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.InvalidOperationException">Unable to remove + item.Name</exception>
|
||||
public Task RemoveChild(BaseItem item, CancellationToken cancellationToken)
|
||||
public void RemoveChild(BaseItem item)
|
||||
{
|
||||
RemoveChildrenInternal(new[] { item });
|
||||
RemoveChildrenInternal(new[] { item.Id }.ToList());
|
||||
|
||||
item.SetParent(null);
|
||||
|
||||
if (!EnableNewFolderQuerying())
|
||||
{
|
||||
return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken);
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the children.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task ClearChildren(CancellationToken cancellationToken)
|
||||
{
|
||||
var items = ActualChildren.ToList();
|
||||
|
||||
ClearChildrenInternal();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
LibraryManager.ReportItemRemoved(item);
|
||||
}
|
||||
|
||||
return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken);
|
||||
}
|
||||
|
||||
#region Indexing
|
||||
@ -276,7 +228,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// The children
|
||||
/// </summary>
|
||||
private IReadOnlyList<BaseItem> _children;
|
||||
private IReadOnlyList<Guid> _children;
|
||||
/// <summary>
|
||||
/// The _children sync lock
|
||||
/// </summary>
|
||||
@ -285,21 +237,30 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Gets or sets the actual children.
|
||||
/// </summary>
|
||||
/// <value>The actual children.</value>
|
||||
protected virtual IEnumerable<Guid> ChildIds
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
if (_children == null)
|
||||
{
|
||||
_children = LoadChildren().ToList();
|
||||
}
|
||||
return _children.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actual children.
|
||||
/// </summary>
|
||||
/// <value>The actual children.</value>
|
||||
protected virtual IEnumerable<BaseItem> ActualChildren
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_children == null)
|
||||
{
|
||||
lock (_childrenSyncLock)
|
||||
{
|
||||
if (_children == null)
|
||||
{
|
||||
_children = LoadChildren().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
return _children;
|
||||
return ChildIds.Select(LibraryManager.GetItemById).Where(i => i != null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -353,7 +314,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Loads our children. Validation will occur externally.
|
||||
/// We want this sychronous.
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<BaseItem> LoadChildren()
|
||||
protected virtual IEnumerable<Guid> LoadChildren()
|
||||
{
|
||||
//just load our children from the repo - the library will be validated and maintained in other processes
|
||||
return GetCachedChildren();
|
||||
@ -503,7 +464,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
if (actualRemovals.Count > 0)
|
||||
{
|
||||
RemoveChildrenInternal(actualRemovals);
|
||||
RemoveChildrenInternal(actualRemovals.Select(i => i.Id).ToList());
|
||||
|
||||
foreach (var item in actualRemovals)
|
||||
{
|
||||
@ -518,12 +479,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
AddChildrenInternal(newItems);
|
||||
|
||||
if (!EnableNewFolderQuerying())
|
||||
{
|
||||
await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
AddChildrenInternal(newItems.Select(i => i.Id).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
@ -751,51 +707,459 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Get our children from the repo - stubbed for now
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
protected IEnumerable<BaseItem> GetCachedChildren()
|
||||
protected IEnumerable<Guid> GetCachedChildren()
|
||||
{
|
||||
if (EnableNewFolderQuerying())
|
||||
return ItemRepository.GetItemIdsList(new InternalItemsQuery
|
||||
{
|
||||
return ItemRepository.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
ParentId = Id
|
||||
ParentId = Id
|
||||
|
||||
}).Select(RetrieveChild).Where(i => i != null);
|
||||
}
|
||||
|
||||
return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
|
||||
});
|
||||
}
|
||||
|
||||
private BaseItem RetrieveChild(BaseItem child)
|
||||
public QueryResult<BaseItem> QueryRecursive(InternalItemsQuery query)
|
||||
{
|
||||
if (child == null || child.Id == Guid.Empty)
|
||||
{
|
||||
Logger.Error("Item found with empty Id: " + (child.Path ?? child.Name));
|
||||
return null;
|
||||
}
|
||||
var user = query.User;
|
||||
|
||||
var item = LibraryManager.GetMemoryItemById(child.Id);
|
||||
|
||||
if (item != null)
|
||||
if (RequiresPostFiltering(query))
|
||||
{
|
||||
if (item is IByReferenceItem)
|
||||
IEnumerable<BaseItem> items;
|
||||
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
|
||||
|
||||
if (query.User == null)
|
||||
{
|
||||
return LibraryManager.GetOrAddByReferenceItem(item);
|
||||
items = GetRecursiveChildren(filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
items = GetRecursiveChildren(user, filter);
|
||||
}
|
||||
|
||||
item.SetParent(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
child.SetParent(this);
|
||||
LibraryManager.RegisterItem(child);
|
||||
item = child;
|
||||
return PostFilterAndSort(items, query);
|
||||
}
|
||||
|
||||
return item;
|
||||
if (!(this is UserRootFolder) && !(this is AggregateFolder))
|
||||
{
|
||||
query.ParentId = query.ParentId ?? Id;
|
||||
}
|
||||
|
||||
return LibraryManager.GetItemsResult(query);
|
||||
}
|
||||
|
||||
public virtual Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
|
||||
private bool RequiresPostFiltering(InternalItemsQuery query)
|
||||
{
|
||||
if (LinkedChildren.Count > 0)
|
||||
{
|
||||
if (!(this is ICollectionFolder))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to LinkedChildren");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.SortBy != null && query.SortBy.Length > 0)
|
||||
{
|
||||
if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.DatePlayed");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.IsPlayed");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.IsUnplayed");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.AiredEpisodeOrder, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.Album, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.Album");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.Artist, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.Artist");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.Budget, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.Budget");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.DateLastContentAdded, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.DateLastContentAdded");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.GameSystem, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.GameSystem");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.Metascore, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.Metascore");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.OfficialRating, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.OfficialRating");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.PlayCount");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.Players, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.Players");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.Revenue, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.Revenue");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.SeriesSortName, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.SeriesSortName");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.StartDate, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.StartDate");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.Studio, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.Studio");
|
||||
return true;
|
||||
}
|
||||
if (query.SortBy.Contains(ItemSortBy.VideoBitRate, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemSortBy.VideoBitRate");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.ItemIds.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemIds");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.PersonIds.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to PersonIds");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsLiked.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsLiked");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsFavoriteOrLiked.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsFavoriteOrLiked");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsFavorite.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsFavorite");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsResumable.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsResumable");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsPlayed.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsPlayed");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsInBoxSet.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsInBoxSet");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Filter by Video3DFormat
|
||||
if (query.Is3D.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to Is3D");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.HasImdbId.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to HasImdbId");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.HasTmdbId.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to HasTmdbId");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.HasTvdbId.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to HasTvdbId");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsYearMismatched.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsYearMismatched");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.HasOfficialRating.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to HasOfficialRating");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsPlaceHolder.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsPlaceHolder");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.HasSpecialFeature.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to HasSpecialFeature");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.HasSubtitles.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to HasSubtitles");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.HasTrailer.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to HasTrailer");
|
||||
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)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to VideoTypes");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.ImageTypes.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ImageTypes");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Apply studio filter
|
||||
if (query.StudioIds.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to StudioIds");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Apply genre filter
|
||||
if (query.GenreIds.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to GenreIds");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Apply person filter
|
||||
if (query.ItemIdsFromPersonFilters != null)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ItemIdsFromPersonFilters");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.MinPlayers.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to MinPlayers");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.MaxPlayers.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to MaxPlayers");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.OfficialRatings.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to OfficialRatings");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsMissing.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsMissing");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsUnaired.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsUnaired");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.IsVirtualUnaired.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to IsVirtualUnaired");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to CollapseBoxSetItems");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.AdjacentTo))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to AdjacentTo");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.NameContains))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to NameContains");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.NameLessThan))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to NameLessThan");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.NameStartsWith))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to NameStartsWith");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.NameStartsWithOrGreater))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to NameStartsWithOrGreater");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.AirDays.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to AirDays");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.SeriesStatuses.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to SeriesStatuses");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.AiredDuringSeason.HasValue)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to AiredDuringSeason");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.AlbumArtistStartsWithOrGreater))
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to AlbumArtistStartsWithOrGreater");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.AlbumNames.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to AlbumNames");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (query.ArtistNames.Length > 0)
|
||||
{
|
||||
Logger.Debug("Query requires post-filtering due to ArtistNames");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Don't blow up here because it could cause parent screens with other content to fail
|
||||
return await ChannelManager.GetChannelItemsInternal(new ChannelItemQuery
|
||||
{
|
||||
ChannelId = ChannelId,
|
||||
FolderId = Id.ToString("N"),
|
||||
Limit = query.Limit,
|
||||
StartIndex = query.StartIndex,
|
||||
UserId = query.User.Id.ToString("N"),
|
||||
SortBy = query.SortBy,
|
||||
SortOrder = query.SortOrder
|
||||
|
||||
}, new Progress<double>(), CancellationToken.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Already logged at lower levels
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (query.Recursive)
|
||||
{
|
||||
return QueryRecursive(query);
|
||||
}
|
||||
|
||||
var user = query.User;
|
||||
|
||||
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
|
||||
@ -817,7 +1181,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
var result = PostFilterAndSort(items, query);
|
||||
|
||||
return Task.FromResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query)
|
||||
|
@ -83,6 +83,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
public string[] OfficialRatings { get; set; }
|
||||
|
||||
public DateTime? MinPremiereDate { get; set; }
|
||||
public DateTime? MaxPremiereDate { get; set; }
|
||||
public DateTime? MinStartDate { get; set; }
|
||||
public DateTime? MaxStartDate { get; set; }
|
||||
public DateTime? MinEndDate { get; set; }
|
||||
@ -96,28 +97,45 @@ namespace MediaBrowser.Controller.Entities
|
||||
public int? MinPlayers { get; set; }
|
||||
public int? MaxPlayers { get; set; }
|
||||
public int? MinIndexNumber { get; set; }
|
||||
public int? AiredDuringSeason { get; set; }
|
||||
public double? MinCriticRating { get; set; }
|
||||
public double? MinCommunityRating { get; set; }
|
||||
|
||||
public string[] ChannelIds { get; set; }
|
||||
|
||||
internal List<Guid> ItemIdsFromPersonFilters { get; set; }
|
||||
public int? ParentIndexNumber { get; set; }
|
||||
public int? MinParentalRating { get; set; }
|
||||
public int? MaxParentalRating { get; set; }
|
||||
|
||||
public bool? IsCurrentSchema { get; set; }
|
||||
public bool? HasDeadParentId { get; set; }
|
||||
public bool? IsOffline { get; set; }
|
||||
public LocationType? LocationType { get; set; }
|
||||
|
||||
public Guid? ParentId { get; set; }
|
||||
public string[] AncestorIds { get; set; }
|
||||
public string[] TopParentIds { get; set; }
|
||||
|
||||
public LocationType[] LocationTypes { get; set; }
|
||||
public LocationType[] ExcludeLocationTypes { get; set; }
|
||||
public string[] PresetViews { get; set; }
|
||||
public SourceType[] SourceTypes { get; set; }
|
||||
public SourceType[] ExcludeSourceTypes { get; set; }
|
||||
public TrailerType[] TrailerTypes { get; set; }
|
||||
public TrailerType[] ExcludeTrailerTypes { get; set; }
|
||||
|
||||
public DayOfWeek[] AirDays { get; set; }
|
||||
public SeriesStatus[] SeriesStatuses { get; set; }
|
||||
public string AlbumArtistStartsWithOrGreater { get; set; }
|
||||
|
||||
public string[] AlbumNames { get; set; }
|
||||
public string[] ArtistNames { get; set; }
|
||||
|
||||
public InternalItemsQuery()
|
||||
{
|
||||
AlbumNames = new string[] { };
|
||||
ArtistNames = new string[] { };
|
||||
|
||||
BlockUnratedItems = new UnratedItem[] { };
|
||||
Tags = new string[] { };
|
||||
OfficialRatings = new string[] { };
|
||||
@ -139,8 +157,15 @@ namespace MediaBrowser.Controller.Entities
|
||||
AncestorIds = new string[] { };
|
||||
TopParentIds = new string[] { };
|
||||
ExcludeTags = new string[] { };
|
||||
LocationTypes = new LocationType[] { };
|
||||
ExcludeLocationTypes = new LocationType[] { };
|
||||
PresetViews = new string[] { };
|
||||
SourceTypes = new SourceType[] { };
|
||||
ExcludeSourceTypes = new SourceType[] { };
|
||||
TrailerTypes = new TrailerType[] { };
|
||||
ExcludeTrailerTypes = new TrailerType[] { };
|
||||
AirDays = new DayOfWeek[] { };
|
||||
SeriesStatuses = new SeriesStatus[] { };
|
||||
}
|
||||
|
||||
public InternalItemsQuery(User user)
|
||||
|
@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
@ -67,24 +68,19 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
/// <value>The revenue.</value>
|
||||
public double? Revenue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating.
|
||||
/// </summary>
|
||||
/// <value>The critic rating.</value>
|
||||
public float? CriticRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating summary.
|
||||
/// </summary>
|
||||
/// <value>The critic rating summary.</value>
|
||||
public string CriticRatingSummary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the TMDB collection.
|
||||
/// </summary>
|
||||
/// <value>The name of the TMDB collection.</value>
|
||||
public string TmdbCollectionName { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string CollectionName
|
||||
{
|
||||
get { return TmdbCollectionName; }
|
||||
set { TmdbCollectionName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the trailer ids.
|
||||
/// </summary>
|
||||
|
10
MediaBrowser.Controller/Entities/SourceType.cs
Normal file
10
MediaBrowser.Controller/Entities/SourceType.cs
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public enum SourceType
|
||||
{
|
||||
Library = 0,
|
||||
Channel = 1,
|
||||
LiveTV = 2
|
||||
}
|
||||
}
|
@ -14,7 +14,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// Class Trailer
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasLookupInfo<TrailerInfo>
|
||||
{
|
||||
public List<string> ProductionLocations { get; set; }
|
||||
@ -25,14 +24,23 @@ namespace MediaBrowser.Controller.Entities
|
||||
Taglines = new List<string>();
|
||||
Keywords = new List<string>();
|
||||
ProductionLocations = new List<string>();
|
||||
TrailerTypes = new List<TrailerType>();
|
||||
}
|
||||
|
||||
public List<TrailerType> TrailerTypes { get; set; }
|
||||
|
||||
public float? Metascore { get; set; }
|
||||
|
||||
public List<MediaUrl> RemoteTrailers { get; set; }
|
||||
|
||||
public List<string> Keywords { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool IsLocalTrailer
|
||||
{
|
||||
get { return TrailerTypes.Contains(TrailerType.LocalTrailer); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the taglines.
|
||||
/// </summary>
|
||||
@ -51,32 +59,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <value>The revenue.</value>
|
||||
public double? Revenue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating.
|
||||
/// </summary>
|
||||
/// <value>The critic rating.</value>
|
||||
public float? CriticRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the critic rating summary.
|
||||
/// </summary>
|
||||
/// <value>The critic rating summary.</value>
|
||||
public string CriticRatingSummary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is local trailer.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is local trailer; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public bool IsLocalTrailer
|
||||
{
|
||||
get
|
||||
{
|
||||
// Local trailers are not part of children
|
||||
return GetParent() == null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
var key = Movie.GetMovieUserDataKey(this);
|
||||
@ -106,9 +88,50 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var info = GetItemLookupInfo<TrailerInfo>();
|
||||
|
||||
info.IsLocalTrailer = IsLocalTrailer;
|
||||
info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
|
||||
|
||||
if (!IsInMixedFolder)
|
||||
{
|
||||
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public override bool BeforeMetadataRefresh()
|
||||
{
|
||||
var hasChanges = base.BeforeMetadataRefresh();
|
||||
|
||||
if (!ProductionYear.HasValue)
|
||||
{
|
||||
var info = LibraryManager.ParseName(Name);
|
||||
|
||||
var yearInName = info.Year;
|
||||
|
||||
if (yearInName.HasValue)
|
||||
{
|
||||
ProductionYear = yearInName;
|
||||
hasChanges = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to get the year from the folder name
|
||||
if (!IsInMixedFolder)
|
||||
{
|
||||
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
|
||||
|
||||
yearInName = info.Year;
|
||||
|
||||
if (yearInName.HasValue)
|
||||
{
|
||||
ProductionYear = yearInName;
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
|
||||
{
|
||||
var user = query.User;
|
||||
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
|
||||
|
||||
if (query.Recursive)
|
||||
{
|
||||
var items = query.User.RootFolder.GetRecursiveChildren(query.User, filter);
|
||||
return PostFilterAndSort(items, query);
|
||||
return QueryRecursive(query);
|
||||
}
|
||||
|
||||
var result = await UserViewManager.GetUserViews(new UserViewQuery
|
||||
@ -35,6 +31,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
var user = query.User;
|
||||
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
|
||||
|
||||
return PostFilterAndSort(result.Where(filter), query);
|
||||
}
|
||||
|
||||
|
@ -50,15 +50,15 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var user = query.User;
|
||||
|
||||
if (query.IncludeItemTypes != null &&
|
||||
query.IncludeItemTypes.Length == 1 &&
|
||||
string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
//if (query.IncludeItemTypes != null &&
|
||||
// query.IncludeItemTypes.Length == 1 &&
|
||||
// string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
|
||||
// }
|
||||
//}
|
||||
|
||||
switch (viewType)
|
||||
{
|
||||
@ -766,7 +766,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
return items;
|
||||
}
|
||||
|
||||
private static bool CollapseBoxSetItems(InternalItemsQuery query,
|
||||
public static bool CollapseBoxSetItems(InternalItemsQuery query,
|
||||
BaseItem queryParent,
|
||||
User user)
|
||||
{
|
||||
@ -1199,6 +1199,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.ExcludeLocationTypes.Length > 0 && query.ExcludeLocationTypes.Contains(item.LocationType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
|
||||
{
|
||||
return false;
|
||||
@ -1689,6 +1694,127 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
if (query.MinPremiereDate.HasValue)
|
||||
{
|
||||
var val = query.MinPremiereDate.Value;
|
||||
|
||||
if (!(item.PremiereDate.HasValue && item.PremiereDate.Value >= val))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.MaxPremiereDate.HasValue)
|
||||
{
|
||||
var val = query.MaxPremiereDate.Value;
|
||||
|
||||
if (!(item.PremiereDate.HasValue && item.PremiereDate.Value <= val))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.ParentIndexNumber.HasValue)
|
||||
{
|
||||
var filterValue = query.ParentIndexNumber.Value;
|
||||
|
||||
if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value != filterValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.AirDays.Length > 0)
|
||||
{
|
||||
var ok = new[] { item }.OfType<Series>().Any(p => p.AirDays != null && query.AirDays.Any(d => p.AirDays.Contains(d)));
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.SeriesStatuses.Length > 0)
|
||||
{
|
||||
var ok = new[] { item }.OfType<Series>().Any(p => p.Status.HasValue && query.SeriesStatuses.Contains(p.Status.Value));
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (query.AiredDuringSeason.HasValue)
|
||||
{
|
||||
var episode = item as Episode;
|
||||
|
||||
if (episode == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Series.FilterEpisodesBySeason(new[] { episode }, query.AiredDuringSeason.Value, true).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(query.AlbumArtistStartsWithOrGreater))
|
||||
{
|
||||
var ok = new[] { item }.OfType<IHasAlbumArtist>()
|
||||
.Any(p => string.Compare(query.AlbumArtistStartsWithOrGreater, p.AlbumArtists.FirstOrDefault(), StringComparison.CurrentCultureIgnoreCase) < 1);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Artists
|
||||
if (query.ArtistNames.Length > 0)
|
||||
{
|
||||
var audio = item as IHasArtist;
|
||||
|
||||
if (!(audio != null && query.ArtistNames.Any(audio.HasAnyArtist)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Albums
|
||||
if (query.AlbumNames.Length > 0)
|
||||
{
|
||||
var audio = item as Audio.Audio;
|
||||
|
||||
if (audio != null)
|
||||
{
|
||||
if (!query.AlbumNames.Any(a => string.Equals(a, audio.Album, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var album = item as MusicAlbum;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
if (!query.AlbumNames.Any(a => string.Equals(a, album.Name, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var musicVideo = item as MusicVideo;
|
||||
|
||||
if (musicVideo != null)
|
||||
{
|
||||
if (!query.AlbumNames.Any(a => string.Equals(a, musicVideo.Album, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6,13 +6,16 @@ using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Mime;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
@ -33,6 +36,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
public List<string> AdditionalParts { get; set; }
|
||||
public List<string> LocalAlternateVersions { get; set; }
|
||||
public List<LinkedChild> LinkedAlternateVersions { get; set; }
|
||||
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public bool IsThemeMedia
|
||||
@ -78,6 +82,23 @@ namespace MediaBrowser.Controller.Entities
|
||||
locationType != LocationType.Virtual;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override LocationType LocationType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Path))
|
||||
{
|
||||
return LocationType.Remote;
|
||||
}
|
||||
}
|
||||
|
||||
return base.LocationType;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
@ -130,6 +151,29 @@ namespace MediaBrowser.Controller.Entities
|
||||
return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
|
||||
}
|
||||
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
if (ExtraType.HasValue)
|
||||
{
|
||||
var key = this.GetProviderId(MetadataProviders.Imdb) ?? this.GetProviderId(MetadataProviders.Tmdb);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
key = key + "-" + ExtraType.ToString().ToLower();
|
||||
|
||||
// Make sure different trailers have their own data.
|
||||
if (RunTimeTicks.HasValue)
|
||||
{
|
||||
key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the linked children.
|
||||
/// </summary>
|
||||
@ -441,6 +485,22 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
var sources = ChannelManager.GetStaticMediaSources(this, false, CancellationToken.None)
|
||||
.Result.ToList();
|
||||
|
||||
if (sources.Count > 0)
|
||||
{
|
||||
return sources;
|
||||
}
|
||||
|
||||
return new List<MediaSourceInfo>
|
||||
{
|
||||
GetVersionInfo(enablePathSubstitution, this, MediaSourceType.Placeholder)
|
||||
};
|
||||
}
|
||||
|
||||
var item = this;
|
||||
|
||||
var result = item.GetAlternateVersions()
|
||||
|
@ -79,5 +79,12 @@ namespace MediaBrowser.Controller
|
||||
/// <param name="host">The host.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetLocalApiUrl(string host);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local API URL.
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">The ip address.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetLocalApiUrl(IPAddress ipAddress);
|
||||
}
|
||||
}
|
||||
|
@ -152,13 +152,6 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns>BaseItem.</returns>
|
||||
BaseItem GetItemById(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>QueryResult<BaseItem>.</returns>
|
||||
QueryResult<BaseItem> GetItems(InternalItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the memory item by identifier.
|
||||
/// </summary>
|
||||
@ -547,22 +540,28 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns>Task.</returns>
|
||||
Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>QueryResult<BaseItem>.</returns>
|
||||
IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="parentIds">The parent ids.</param>
|
||||
/// <returns>List<BaseItem>.</returns>
|
||||
IEnumerable<BaseItem> GetItems(InternalItemsQuery query, IEnumerable<string> parentIds);
|
||||
IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items result.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="parentIds">The parent ids.</param>
|
||||
/// <returns>QueryResult<BaseItem>.</returns>
|
||||
QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, IEnumerable<string> parentIds);
|
||||
|
||||
QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Ignores the file.
|
||||
/// </summary>
|
||||
|
@ -15,11 +15,14 @@ namespace MediaBrowser.Controller.Library
|
||||
public BaseItem Item { get; set; }
|
||||
public BaseItemInfo MediaInfo { get; set; }
|
||||
public string MediaSourceId { get; set; }
|
||||
public bool IsPaused { get; set; }
|
||||
|
||||
public string DeviceId { get; set; }
|
||||
public string DeviceName { get; set; }
|
||||
public string ClientName { get; set; }
|
||||
|
||||
public string PlaySessionId { get; set; }
|
||||
|
||||
public PlaybackProgressEventArgs()
|
||||
{
|
||||
Users = new List<User>();
|
||||
|
@ -1,10 +0,0 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public interface ILiveTvItem : IHasId
|
||||
{
|
||||
string ServiceName { get; set; }
|
||||
string ExternalId { get; set; }
|
||||
}
|
||||
}
|
@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// </summary>
|
||||
/// <param name="recording">The recording.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task DeleteRecording(ILiveTvRecording recording);
|
||||
Task DeleteRecording(BaseItem recording);
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the timer.
|
||||
@ -74,15 +74,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <param name="listingProviders">The listing providers.</param>
|
||||
void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channels.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>IEnumerable{Channel}.</returns>
|
||||
Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recording.
|
||||
/// </summary>
|
||||
@ -92,15 +83,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>Task{RecordingInfoDto}.</returns>
|
||||
Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>Task{RecordingInfoDto}.</returns>
|
||||
Task<ChannelInfoDto> GetChannel(string id, CancellationToken cancellationToken, User user = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timer.
|
||||
@ -156,7 +138,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>LiveTvRecording.</returns>
|
||||
Task<ILiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken);
|
||||
Task<BaseItem> GetInternalRecording(string id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recording stream.
|
||||
@ -385,10 +367,22 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <summary>
|
||||
/// Adds the channel information.
|
||||
/// </summary>
|
||||
/// <param name="dto">The dto.</param>
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
void AddChannelInfo(BaseItemDto dto, LiveTvChannel channel, DtoOptions options, User user);
|
||||
void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user);
|
||||
|
||||
/// <summary>
|
||||
/// Called when [recording file deleted].
|
||||
/// </summary>
|
||||
/// <param name="recording">The recording.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task OnRecordingFileDeleted(BaseItem recording);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sat ini mappings.
|
||||
/// </summary>
|
||||
/// <returns>List<NameValuePair>.</returns>
|
||||
List<NameValuePair> GetSatIniMappings();
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,10 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData, ILiveTvItem, IHasStartDate, IHasProgramAttributes
|
||||
public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData, IHasStartDate, IHasProgramAttributes
|
||||
{
|
||||
string ServiceName { get; set; }
|
||||
string ExternalId { get; set; }
|
||||
string ChannelId { get; }
|
||||
string MediaType { get; }
|
||||
|
||||
|
@ -39,6 +39,13 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
[IgnoreDataMember]
|
||||
public bool IsPremiere { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override SourceType SourceType
|
||||
{
|
||||
get { return SourceType.LiveTV; }
|
||||
set { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
@ -50,8 +57,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
return name + "-" + Name + (EpisodeTitle ?? string.Empty);
|
||||
}
|
||||
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is owned item.
|
||||
/// </summary>
|
||||
@ -151,5 +156,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
return LiveTvManager.DeleteRecording(this);
|
||||
}
|
||||
|
||||
public override Task OnFileDeleted()
|
||||
{
|
||||
return LiveTvManager.OnRecordingFileDeleted(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvChannel : BaseItem, IHasMediaSources, ILiveTvItem
|
||||
public class LiveTvChannel : BaseItem, IHasMediaSources
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
@ -40,6 +40,13 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override SourceType SourceType
|
||||
{
|
||||
get { return SourceType.LiveTV; }
|
||||
set { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number.
|
||||
/// </summary>
|
||||
@ -52,12 +59,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <value>The type of the channel.</value>
|
||||
public ChannelType ChannelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override LocationType LocationType
|
||||
{
|
||||
|
@ -11,7 +11,7 @@ using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvProgram : BaseItem, ILiveTvItem, IHasLookupInfo<LiveTvProgramLookupInfo>, IHasStartDate, IHasProgramAttributes
|
||||
public class LiveTvProgram : BaseItem, IHasLookupInfo<LiveTvProgramLookupInfo>, IHasStartDate, IHasProgramAttributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
@ -39,12 +39,12 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[IgnoreDataMember]
|
||||
public string ServiceName { get; set; }
|
||||
public override SourceType SourceType
|
||||
{
|
||||
get { return SourceType.LiveTV; }
|
||||
set { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the program, in UTC.
|
||||
|
@ -39,6 +39,13 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
[IgnoreDataMember]
|
||||
public bool IsPremiere { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override SourceType SourceType
|
||||
{
|
||||
get { return SourceType.LiveTV; }
|
||||
set { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
@ -65,8 +72,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override string MediaType
|
||||
{
|
||||
@ -166,5 +171,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
return LiveTvManager.DeleteRecording(this);
|
||||
}
|
||||
|
||||
public override Task OnFileDeleted()
|
||||
{
|
||||
return LiveTvManager.OnRecordingFileDeleted(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
@ -24,5 +25,12 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override SourceType SourceType
|
||||
{
|
||||
get { return SourceType.LiveTV; }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.8\lib\net45\CommonIO.dll</HintPath>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Interfaces.IO">
|
||||
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
|
||||
@ -75,6 +75,7 @@
|
||||
</Compile>
|
||||
<Compile Include="Activity\IActivityManager.cs" />
|
||||
<Compile Include="Activity\IActivityRepository.cs" />
|
||||
<Compile Include="Channels\ChannelAudioItem.cs" />
|
||||
<Compile Include="Channels\ChannelFolderItem.cs" />
|
||||
<Compile Include="Channels\ChannelItemInfo.cs" />
|
||||
<Compile Include="Channels\ChannelItemResult.cs" />
|
||||
@ -82,11 +83,10 @@
|
||||
<Compile Include="Channels\ChannelMediaInfo.cs" />
|
||||
<Compile Include="Channels\ChannelParentalRating.cs" />
|
||||
<Compile Include="Channels\ChannelSearchInfo.cs" />
|
||||
<Compile Include="Channels\IChannel.cs" />
|
||||
<Compile Include="Channels\IChannelManager.cs" />
|
||||
<Compile Include="Channels\IChannelItem.cs" />
|
||||
<Compile Include="Channels\ChannelAudioItem.cs" />
|
||||
<Compile Include="Channels\ChannelVideoItem.cs" />
|
||||
<Compile Include="Channels\IChannel.cs" />
|
||||
<Compile Include="Channels\IChannelItem.cs" />
|
||||
<Compile Include="Channels\IChannelManager.cs" />
|
||||
<Compile Include="Channels\Channel.cs" />
|
||||
<Compile Include="Channels\IChannelMediaItem.cs" />
|
||||
<Compile Include="Channels\IHasCacheKey.cs" />
|
||||
@ -128,6 +128,7 @@
|
||||
<Compile Include="Drawing\ImageStream.cs" />
|
||||
<Compile Include="Dto\DtoOptions.cs" />
|
||||
<Compile Include="Dto\IDtoService.cs" />
|
||||
<Compile Include="Entities\Audio\AudioPodcast.cs" />
|
||||
<Compile Include="Entities\Audio\IHasAlbumArtist.cs" />
|
||||
<Compile Include="Entities\Audio\IHasMusicGenres.cs" />
|
||||
<Compile Include="Entities\Book.cs" />
|
||||
@ -180,6 +181,7 @@
|
||||
<Compile Include="Entities\Photo.cs" />
|
||||
<Compile Include="Entities\PhotoAlbum.cs" />
|
||||
<Compile Include="Entities\Share.cs" />
|
||||
<Compile Include="Entities\SourceType.cs" />
|
||||
<Compile Include="Entities\UserView.cs" />
|
||||
<Compile Include="Entities\UserViewBuilder.cs" />
|
||||
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
|
||||
@ -202,7 +204,6 @@
|
||||
<Compile Include="Library\UserDataSaveEventArgs.cs" />
|
||||
<Compile Include="LiveTv\IHasRegistrationInfo.cs" />
|
||||
<Compile Include="LiveTv\IListingsProvider.cs" />
|
||||
<Compile Include="LiveTv\ILiveTvItem.cs" />
|
||||
<Compile Include="LiveTv\ITunerHost.cs" />
|
||||
<Compile Include="LiveTv\RecordingGroup.cs" />
|
||||
<Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" />
|
||||
@ -271,7 +272,6 @@
|
||||
<Compile Include="Providers\ArtistInfo.cs" />
|
||||
<Compile Include="Providers\BookInfo.cs" />
|
||||
<Compile Include="Providers\BoxSetInfo.cs" />
|
||||
<Compile Include="Providers\ChannelItemLookupInfo.cs" />
|
||||
<Compile Include="Providers\DirectoryService.cs" />
|
||||
<Compile Include="Providers\DynamicImageInfo.cs" />
|
||||
<Compile Include="Providers\DynamicImageResponse.cs" />
|
||||
@ -331,6 +331,7 @@
|
||||
<Compile Include="Security\IEncryptionManager.cs" />
|
||||
<Compile Include="Session\AuthenticationRequest.cs" />
|
||||
<Compile Include="Social\ISharingManager.cs" />
|
||||
<Compile Include="Sorting\SortHelper.cs" />
|
||||
<Compile Include="Subtitles\ISubtitleManager.cs" />
|
||||
<Compile Include="Subtitles\ISubtitleProvider.cs" />
|
||||
<Compile Include="Providers\ItemIdentifier.cs" />
|
||||
|
@ -90,8 +90,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
Cabac = info.Cabac;
|
||||
Context = info.Context;
|
||||
|
||||
if (info.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode ||
|
||||
info.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Embed)
|
||||
if (info.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External)
|
||||
{
|
||||
SubtitleStreamIndex = info.SubtitleStreamIndex;
|
||||
}
|
||||
|
@ -42,13 +42,6 @@ namespace MediaBrowser.Controller.Persistence
|
||||
/// <returns>Task{IEnumerable{ItemReview}}.</returns>
|
||||
IEnumerable<ItemReview> GetCriticReviews(Guid itemId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children items.
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent identifier.</param>
|
||||
/// <returns>IEnumerable<BaseItem>.</returns>
|
||||
IEnumerable<BaseItem> GetChildrenItems(Guid parentId);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the critic reviews.
|
||||
/// </summary>
|
||||
@ -96,22 +89,6 @@ namespace MediaBrowser.Controller.Persistence
|
||||
/// <returns>Task.</returns>
|
||||
Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children.
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent id.</param>
|
||||
/// <returns>IEnumerable{ChildDefinition}.</returns>
|
||||
IEnumerable<Guid> GetChildren(Guid parentId);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the children.
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent id.</param>
|
||||
/// <param name="children">The children.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SaveChildren(Guid parentId, IEnumerable<Guid> children, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media streams.
|
||||
/// </summary>
|
||||
|
@ -1,11 +0,0 @@
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public class ChannelItemLookupInfo : ItemLookupInfo
|
||||
{
|
||||
public ChannelMediaContentType ContentType { get; set; }
|
||||
public ExtraType ExtraType { get; set; }
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public class TrailerInfo : ItemLookupInfo
|
||||
|
31
MediaBrowser.Controller/Sorting/SortHelper.cs
Normal file
31
MediaBrowser.Controller/Sorting/SortHelper.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Sorting
|
||||
{
|
||||
public static class SortHelper
|
||||
{
|
||||
private enum ChunkType { Alphanumeric, Numeric };
|
||||
|
||||
public static bool InChunk(char ch, char otherCh)
|
||||
{
|
||||
var type = ChunkType.Alphanumeric;
|
||||
|
||||
if (char.IsDigit(otherCh))
|
||||
{
|
||||
type = ChunkType.Numeric;
|
||||
}
|
||||
|
||||
if ((type == ChunkType.Alphanumeric && char.IsDigit(ch))
|
||||
|| (type == ChunkType.Numeric && !char.IsDigit(ch)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CommonIO" version="1.0.0.8" targetFramework="net45" />
|
||||
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
|
||||
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
|
||||
<package id="morelinq" version="1.4.0" targetFramework="net45" />
|
||||
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
||||
|
@ -488,12 +488,12 @@ namespace MediaBrowser.Dlna.ContentDirectory
|
||||
var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
||||
{
|
||||
Person = person.Name,
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name, typeof(ChannelVideoItem).Name },
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name, typeof(Trailer).Name },
|
||||
SortBy = new[] { ItemSortBy.SortName },
|
||||
Limit = limit,
|
||||
StartIndex = startIndex
|
||||
|
||||
}, new string[] { });
|
||||
});
|
||||
|
||||
var serverItems = itemsResult.Items.Select(i => new ServerItem
|
||||
{
|
||||
|
@ -188,15 +188,15 @@ namespace MediaBrowser.Dlna.Didl
|
||||
{
|
||||
var subtitleAdded = AddSubtitleElement(container, subtitle);
|
||||
|
||||
if (subtitleAdded && _profile.EnableSingleSubtitleLimit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (subtitleAdded && _profile.EnableSingleSubtitleLimit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool AddSubtitleElement(XmlElement container, SubtitleStreamInfo info)
|
||||
private bool AddSubtitleElement(XmlElement container, SubtitleStreamInfo info)
|
||||
{
|
||||
var subtitleProfile = _profile.SubtitleProfiles
|
||||
.FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase) && i.Method == SubtitleDeliveryMethod.External);
|
||||
@ -213,13 +213,13 @@ namespace MediaBrowser.Dlna.Didl
|
||||
// <sec:CaptionInfoEx sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfoEx>
|
||||
// <sec:CaptionInfo sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfo>
|
||||
|
||||
//var res = container.OwnerDocument.CreateElement("SEC", "CaptionInfoEx");
|
||||
var res = container.OwnerDocument.CreateElement("CaptionInfoEx", "sec");
|
||||
|
||||
//res.InnerText = info.Url;
|
||||
res.InnerText = info.Url;
|
||||
|
||||
//// TODO: attribute needs SEC:
|
||||
//res.SetAttribute("type", info.Format.ToLower());
|
||||
//container.AppendChild(res);
|
||||
res.SetAttribute("type", "sec", info.Format.ToLower());
|
||||
container.AppendChild(res);
|
||||
}
|
||||
else if (string.Equals(subtitleMode, "smi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@ -243,7 +243,7 @@ namespace MediaBrowser.Dlna.Didl
|
||||
container.AppendChild(res);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AddVideoResource(XmlElement container, IHasMediaSources video, string deviceId, Filter filter, string contentFeatures, StreamInfo streamInfo)
|
||||
|
@ -161,7 +161,7 @@ namespace MediaBrowser.Dlna.Main
|
||||
|
||||
var descriptorURI = "/dlna/" + udn + "/description.xml";
|
||||
|
||||
var uri = new Uri(_appHost.GetLocalApiUrl(addressString) + descriptorURI);
|
||||
var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorURI);
|
||||
|
||||
var services = new List<string>
|
||||
{
|
||||
|
@ -42,7 +42,7 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.8\lib\net45\CommonIO.dll</HintPath>
|
||||
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MoreLinq">
|
||||
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
|
||||
|
@ -171,7 +171,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
private string GetServerAddress(IPAddress localIp)
|
||||
{
|
||||
return _appHost.GetLocalApiUrl(localIp.ToString());
|
||||
return _appHost.GetLocalApiUrl(localIp);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -31,10 +31,10 @@ namespace MediaBrowser.Dlna.Profiles
|
||||
MaxIconWidth = 48;
|
||||
MaxIconHeight = 48;
|
||||
|
||||
MaxStreamingBitrate = 12000000;
|
||||
MaxStaticBitrate = 12000000;
|
||||
MusicStreamingTranscodingBitrate = 128000;
|
||||
MusicSyncBitrate = 128000;
|
||||
MaxStreamingBitrate = 15000000;
|
||||
MaxStaticBitrate = 15000000;
|
||||
MusicStreamingTranscodingBitrate = 192000;
|
||||
MusicSyncBitrate = 192000;
|
||||
|
||||
EnableAlbumArtInDidl = false;
|
||||
|
||||
|
@ -99,6 +99,48 @@ namespace MediaBrowser.Dlna.Profiles
|
||||
DidlMode = "",
|
||||
},
|
||||
|
||||
new SubtitleProfile
|
||||
{
|
||||
Format = "ass",
|
||||
Method = SubtitleDeliveryMethod.Embed,
|
||||
DidlMode = "",
|
||||
},
|
||||
|
||||
new SubtitleProfile
|
||||
{
|
||||
Format = "ssa",
|
||||
Method = SubtitleDeliveryMethod.Embed,
|
||||
DidlMode = "",
|
||||
},
|
||||
|
||||
new SubtitleProfile
|
||||
{
|
||||
Format = "smi",
|
||||
Method = SubtitleDeliveryMethod.Embed,
|
||||
DidlMode = "",
|
||||
},
|
||||
|
||||
new SubtitleProfile
|
||||
{
|
||||
Format = "dvdsub",
|
||||
Method = SubtitleDeliveryMethod.Embed,
|
||||
DidlMode = "",
|
||||
},
|
||||
|
||||
new SubtitleProfile
|
||||
{
|
||||
Format = "pgs",
|
||||
Method = SubtitleDeliveryMethod.Embed,
|
||||
DidlMode = "",
|
||||
},
|
||||
|
||||
new SubtitleProfile
|
||||
{
|
||||
Format = "pgssub",
|
||||
Method = SubtitleDeliveryMethod.Embed,
|
||||
DidlMode = "",
|
||||
},
|
||||
|
||||
new SubtitleProfile
|
||||
{
|
||||
Format = "sub",
|
||||
|
@ -54,21 +54,21 @@ namespace MediaBrowser.Dlna.Profiles
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
VideoCodec = "h264",
|
||||
VideoCodec = "h264,hevc",
|
||||
AudioCodec = "aac,ac3,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "mkv",
|
||||
VideoCodec = "h264",
|
||||
VideoCodec = "h264,hevc",
|
||||
AudioCodec = "aac,ac3,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "mp4",
|
||||
VideoCodec = "h264,mpeg4",
|
||||
VideoCodec = "h264,mpeg4,hevc",
|
||||
AudioCodec = "aac,ac3,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -24,10 +24,10 @@
|
||||
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
|
||||
<MaxIconWidth>48</MaxIconWidth>
|
||||
<MaxIconHeight>48</MaxIconHeight>
|
||||
<MaxStreamingBitrate>12000000</MaxStreamingBitrate>
|
||||
<MaxStaticBitrate>12000000</MaxStaticBitrate>
|
||||
<MusicStreamingTranscodingBitrate>128000</MusicStreamingTranscodingBitrate>
|
||||
<MusicSyncBitrate>128000</MusicSyncBitrate>
|
||||
<MaxStreamingBitrate>15000000</MaxStreamingBitrate>
|
||||
<MaxStaticBitrate>15000000</MaxStaticBitrate>
|
||||
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
|
||||
<MusicSyncBitrate>192000</MusicSyncBitrate>
|
||||
<XDlnaDoc>DMS-1.50</XDlnaDoc>
|
||||
<ProtocolInfo>http-get:*:video/mp2t:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*</ProtocolInfo>
|
||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||
|
@ -52,6 +52,12 @@
|
||||
<SubtitleProfile format="srt" method="External" />
|
||||
<SubtitleProfile format="sub" method="External" />
|
||||
<SubtitleProfile format="srt" method="Embed" didlMode="" />
|
||||
<SubtitleProfile format="ass" method="Embed" didlMode="" />
|
||||
<SubtitleProfile format="ssa" method="Embed" didlMode="" />
|
||||
<SubtitleProfile format="smi" method="Embed" didlMode="" />
|
||||
<SubtitleProfile format="dvdsub" method="Embed" didlMode="" />
|
||||
<SubtitleProfile format="pgs" method="Embed" didlMode="" />
|
||||
<SubtitleProfile format="pgssub" method="Embed" didlMode="" />
|
||||
<SubtitleProfile format="sub" method="Embed" didlMode="" />
|
||||
</SubtitleProfiles>
|
||||
</Profile>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -24,10 +24,10 @@
|
||||
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
|
||||
<MaxIconWidth>48</MaxIconWidth>
|
||||
<MaxIconHeight>48</MaxIconHeight>
|
||||
<MaxStreamingBitrate>12000000</MaxStreamingBitrate>
|
||||
<MaxStaticBitrate>12000000</MaxStaticBitrate>
|
||||
<MusicStreamingTranscodingBitrate>128000</MusicStreamingTranscodingBitrate>
|
||||
<MusicSyncBitrate>128000</MusicSyncBitrate>
|
||||
<MaxStreamingBitrate>15000000</MaxStreamingBitrate>
|
||||
<MaxStaticBitrate>15000000</MaxStaticBitrate>
|
||||
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
|
||||
<MusicSyncBitrate>192000</MusicSyncBitrate>
|
||||
<XDlnaDoc>DMS-1.50</XDlnaDoc>
|
||||
<SonyAggregationFlags>10</SonyAggregationFlags>
|
||||
<ProtocolInfo>http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000</ProtocolInfo>
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user