This commit is contained in:
Luke Pulverenti 2016-03-25 13:52:36 -04:00
commit d9108f69f3
424 changed files with 14381 additions and 3462 deletions

View File

@ -33,7 +33,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <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>
<Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <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="ImageMagickSharp" version="1.0.0.18" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" /> <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
</packages> </packages>

View File

@ -63,6 +63,15 @@ namespace MediaBrowser.Api
_mediaSourceManager = mediaSourceManager; _mediaSourceManager = mediaSourceManager;
Instance = this; Instance = this;
_sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress;
}
void _sessionManager_PlaybackProgress(object sender, PlaybackProgressEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
{
PingTranscodingJob(e.PlaySessionId, e.IsPaused);
}
} }
/// <summary> /// <summary>
@ -300,26 +309,31 @@ namespace MediaBrowser.Api
PingTimer(job, false); PingTimer(job, false);
} }
} }
internal void PingTranscodingJob(string playSessionId) internal void PingTranscodingJob(string playSessionId, bool? isUserPaused)
{ {
if (string.IsNullOrEmpty(playSessionId)) if (string.IsNullOrEmpty(playSessionId))
{ {
throw new ArgumentNullException("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) lock (_activeTranscodingJobs)
{ {
// This is really only needed for HLS. // This is really only needed for HLS.
// Progressive streams can stop on their own reliably // 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) 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); PingTimer(job, true);
} }
} }
@ -655,6 +669,7 @@ namespace MediaBrowser.Api
public object ProcessLock = new object(); public object ProcessLock = new object();
public bool HasExited { get; set; } public bool HasExited { get; set; }
public bool IsUserPaused { get; set; }
public string Id { get; set; } public string Id { get; set; }

View File

@ -196,9 +196,13 @@ namespace MediaBrowser.Api
return name; return name;
} }
return libraryManager.RootFolder var items = libraryManager.GetItemList(new InternalItemsQuery
.GetRecursiveChildren(i => i is IHasArtist) {
.Cast<IHasArtist>() IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicVideo).Name, typeof(MusicAlbum).Name }
});
return items
.OfType<IHasArtist>()
.SelectMany(i => i.AllArtists) .SelectMany(i => i.AllArtists)
.DistinctNames() .DistinctNames()
.FirstOrDefault(i => .FirstOrDefault(i =>
@ -239,8 +243,12 @@ namespace MediaBrowser.Api
return name; return name;
} }
return libraryManager.RootFolder var items = libraryManager.GetItemList(new InternalItemsQuery
.GetRecursiveChildren(i => i is Game) {
IncludeItemTypes = new[] { typeof(Game).Name }
});
return items
.SelectMany(i => i.Genres) .SelectMany(i => i.Genres)
.DistinctNames() .DistinctNames()
.FirstOrDefault(i => .FirstOrDefault(i =>

View File

@ -108,7 +108,7 @@ namespace MediaBrowser.Api
IncludeItemTypes = new[] { typeof(GameSystem).Name } IncludeItemTypes = new[] { typeof(GameSystem).Name }
}; };
var parentIds = new string[] { } ; var parentIds = new string[] { } ;
var gameSystems = _libraryManager.GetItems(query, parentIds) var gameSystems = _libraryManager.GetItemList(query, parentIds)
.Cast<GameSystem>() .Cast<GameSystem>()
.ToList(); .ToList();
@ -129,7 +129,7 @@ namespace MediaBrowser.Api
IncludeItemTypes = new[] { typeof(Game).Name } IncludeItemTypes = new[] { typeof(Game).Name }
}; };
var parentIds = new string[] { }; var parentIds = new string[] { };
var games = _libraryManager.GetItems(query, parentIds) var games = _libraryManager.GetItemList(query, parentIds)
.Cast<Game>() .Cast<Game>()
.ToList(); .ToList();
@ -192,7 +192,7 @@ namespace MediaBrowser.Api
_userDataRepository, _userDataRepository,
_dtoService, _dtoService,
Logger, Logger,
request, item => item is Game, request, new[] { typeof(Game) },
SimilarItemsHelper.GetSimiliarityScore); SimilarItemsHelper.GetSimiliarityScore);
return ToOptimizedSerializedResultUsingCache(result); return ToOptimizedSerializedResultUsingCache(result);

View File

@ -699,6 +699,7 @@ namespace MediaBrowser.Api.Images
private ImageFormat[] GetClientSupportedFormats() 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 supportsWebP = (Request.AcceptTypes ?? new string[] { }).Contains("image/webp", StringComparer.OrdinalIgnoreCase);
var userAgent = Request.UserAgent ?? string.Empty; var userAgent = Request.UserAgent ?? string.Empty;

View File

@ -289,7 +289,6 @@ namespace MediaBrowser.Api.Library
private readonly IActivityManager _activityManager; private readonly IActivityManager _activityManager;
private readonly ILocalizationManager _localization; private readonly ILocalizationManager _localization;
private readonly ILiveTvManager _liveTv; private readonly ILiveTvManager _liveTv;
private readonly IChannelManager _channelManager;
private readonly ITVSeriesManager _tvManager; private readonly ITVSeriesManager _tvManager;
private readonly ILibraryMonitor _libraryMonitor; private readonly ILibraryMonitor _libraryMonitor;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
@ -298,7 +297,7 @@ namespace MediaBrowser.Api.Library
/// Initializes a new instance of the <see cref="LibraryService" /> class. /// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary> /// </summary>
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, 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; _itemRepo = itemRepo;
_libraryManager = libraryManager; _libraryManager = libraryManager;
@ -309,7 +308,6 @@ namespace MediaBrowser.Api.Library
_activityManager = activityManager; _activityManager = activityManager;
_localization = localization; _localization = localization;
_liveTv = liveTv; _liveTv = liveTv;
_channelManager = channelManager;
_tvManager = tvManager; _tvManager = tvManager;
_libraryMonitor = libraryMonitor; _libraryMonitor = libraryMonitor;
_fileSystem = fileSystem; _fileSystem = fileSystem;
@ -379,11 +377,10 @@ namespace MediaBrowser.Api.Library
} }
var program = item as IHasProgramAttributes; 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, AuthorizationContext = AuthorizationContext,
Logger = Logger, 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) return new TvShowsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _tvManager)
{ {
@ -447,13 +444,11 @@ namespace MediaBrowser.Api.Library
public void Post(PostUpdatedSeries request) public void Post(PostUpdatedSeries request)
{ {
var series = _libraryManager.GetItems(new InternalItemsQuery var series = _libraryManager.GetItemList(new InternalItemsQuery
{ {
IncludeItemTypes = new[] { typeof(Series).Name } IncludeItemTypes = new[] { typeof(Series).Name }
}).Items; }).Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProviders.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray();
series = series.Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProviders.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray();
if (series.Length > 0) if (series.Length > 0)
{ {
@ -470,11 +465,11 @@ namespace MediaBrowser.Api.Library
public void Post(PostUpdatedMovies request) public void Post(PostUpdatedMovies request)
{ {
var movies = _libraryManager.GetItems(new InternalItemsQuery var movies = _libraryManager.GetItemList(new InternalItemsQuery
{ {
IncludeItemTypes = new[] { typeof(Movie).Name } IncludeItemTypes = new[] { typeof(Movie).Name }
}).Items; }).ToArray();
if (!string.IsNullOrWhiteSpace(request.ImdbId)) if (!string.IsNullOrWhiteSpace(request.ImdbId))
{ {
@ -664,87 +659,38 @@ namespace MediaBrowser.Api.Library
/// <returns>System.Object.</returns> /// <returns>System.Object.</returns>
public object Get(GetItemCounts request) 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 var counts = new ItemCounts
{ {
AlbumCount = filteredItems.Count(i => i is MusicAlbum), AlbumCount = GetCount(typeof(MusicAlbum), user, request),
EpisodeCount = filteredItems.Count(i => i is Episode), EpisodeCount = GetCount(typeof(Episode), user, request),
GameCount = filteredItems.Count(i => i is Game), GameCount = GetCount(typeof(Game), user, request),
GameSystemCount = filteredItems.Count(i => i is GameSystem), GameSystemCount = GetCount(typeof(GameSystem), user, request),
MovieCount = filteredItems.Count(i => i is Movie), MovieCount = GetCount(typeof(Movie), user, request),
SeriesCount = filteredItems.Count(i => i is Series), SeriesCount = GetCount(typeof(Series), user, request),
SongCount = filteredItems.Count(i => i is Audio), SongCount = GetCount(typeof(Audio), user, request),
MusicVideoCount = filteredItems.Count(i => i is MusicVideo), MusicVideoCount = GetCount(typeof(MusicVideo), user, request),
BoxSetCount = filteredItems.Count(i => i is BoxSet), BoxSetCount = GetCount(typeof(BoxSet), user, request),
BookCount = filteredItems.Count(i => i is Book), BookCount = GetCount(typeof(Book), user, request)
UniqueTypes = filteredItems.Select(i => i.GetClientTypeName()).Distinct().ToList()
}; };
return ToOptimizedSerializedResultUsingCache(counts); 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)) return _libraryManager.GetItemsResult(query).TotalRecordCount;
{
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;
} }
/// <summary> /// <summary>
@ -985,20 +931,15 @@ namespace MediaBrowser.Api.Library
? new string[] { } ? new string[] { }
: request.IncludeItemTypes.Split(','); : 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) IncludeItemTypes = includeTypes,
{ Recursive = true
if (!includeTypes.Contains(i.GetType().Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
}
return true;
}; };
IEnumerable<BaseItem> items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, filter); var items = _libraryManager.GetItemList(query);
var lookup = items var lookup = items
.ToLookup(i => i.ProductionYear ?? -1) .ToLookup(i => i.ProductionYear ?? -1)

View File

@ -201,10 +201,10 @@ namespace MediaBrowser.Api.Library
var rootFolderPath = _appPaths.DefaultUserViewsPath; var rootFolderPath = _appPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, name); var virtualFolderPath = Path.Combine(rootFolderPath, name);
while (_fileSystem.DirectoryExists(virtualFolderPath))
if (_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) if (request.Paths != null)
@ -236,7 +236,7 @@ namespace MediaBrowser.Api.Library
{ {
foreach (var path in request.Paths) foreach (var path in request.Paths)
{ {
LibraryHelpers.AddMediaPath(_fileSystem, request.Name, path, _appPaths); LibraryHelpers.AddMediaPath(_fileSystem, name, path, _appPaths);
} }
} }
} }

View File

@ -478,19 +478,30 @@ namespace MediaBrowser.Api.LiveTv
public string Feature { get; set; } 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 public class LiveTvService : BaseApiService
{ {
private readonly ILiveTvManager _liveTvManager; private readonly ILiveTvManager _liveTvManager;
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IConfigurationManager _config; private readonly IConfigurationManager _config;
private readonly IHttpClient _httpClient; 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; _liveTvManager = liveTvManager;
_userManager = userManager; _userManager = userManager;
_config = config; _config = config;
_httpClient = httpClient; _httpClient = httpClient;
_libraryManager = libraryManager;
_dtoService = dtoService;
} }
public async Task<object> Get(GetLiveTvRegistrationInfo request) public async Task<object> Get(GetLiveTvRegistrationInfo request)
@ -500,6 +511,11 @@ namespace MediaBrowser.Api.LiveTv
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
public object Get(GetSatIniMappings request)
{
return ToOptimizedResult(_liveTvManager.GetSatIniMappings());
}
public async Task<object> Get(GetSchedulesDirectCountries request) public async Task<object> Get(GetSchedulesDirectCountries request)
{ {
// https://json.schedulesdirect.org/20141201/available/countries // https://json.schedulesdirect.org/20141201/available/countries
@ -581,7 +597,7 @@ namespace MediaBrowser.Api.LiveTv
public async Task<object> Get(GetChannels request) public async Task<object> Get(GetChannels request)
{ {
var result = await _liveTvManager.GetChannels(new LiveTvChannelQuery var channelResult = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery
{ {
ChannelType = request.Type, ChannelType = request.Type,
UserId = request.UserId, UserId = request.UserId,
@ -593,16 +609,30 @@ namespace MediaBrowser.Api.LiveTv
EnableFavoriteSorting = request.EnableFavoriteSorting, EnableFavoriteSorting = request.EnableFavoriteSorting,
AddCurrentProgram = request.AddCurrentProgram 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); 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); return ToOptimizedSerializedResultUsingCache(result);
} }

View File

@ -47,7 +47,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <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>
<Reference Include="MoreLinq"> <Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath> <HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>

View File

@ -91,22 +91,21 @@ namespace MediaBrowser.Api.Movies
private readonly IItemRepository _itemRepo; private readonly IItemRepository _itemRepo;
private readonly IDtoService _dtoService; private readonly IDtoService _dtoService;
private readonly IChannelManager _channelManager;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MoviesService"/> class. /// Initializes a new instance of the <see cref="MoviesService" /> class.
/// </summary> /// </summary>
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
/// <param name="userDataRepository">The user data repository.</param> /// <param name="userDataRepository">The user data repository.</param>
/// <param name="libraryManager">The library manager.</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; _userManager = userManager;
_userDataRepository = userDataRepository; _userDataRepository = userDataRepository;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_itemRepo = itemRepo; _itemRepo = itemRepo;
_dtoService = dtoService; _dtoService = dtoService;
_channelManager = channelManager;
} }
/// <summary> /// <summary>
@ -138,8 +137,16 @@ namespace MediaBrowser.Api.Movies
{ {
IncludeItemTypes = new[] { typeof(Movie).Name } 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 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); movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
var listEligibleForCategories = new List<BaseItem>(); var listEligibleForCategories = new List<BaseItem>();
@ -150,19 +157,6 @@ namespace MediaBrowser.Api.Movies
listEligibleForCategories.AddRange(list); listEligibleForCategories.AddRange(list);
listEligibleForSuggestion.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 listEligibleForCategories = listEligibleForCategories
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), 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 } 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 parentIds = new string[] { };
var list = _libraryManager.GetItems(query, parentIds) var list = _libraryManager.GetItemList(query, parentIds)
.Where(i => .Where(i =>
{ {
// Strip out secondary versions // Strip out secondary versions
var v = i as Video; var v = i as Video;
return v != null && !v.PrimaryVersionId.HasValue; return v != null && !v.PrimaryVersionId.HasValue;
}) })
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
.ToList(); .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) if (item is Video)
{ {
var imdbId = item.GetProviderId(MetadataProviders.Imdb); var imdbId = item.GetProviderId(MetadataProviders.Imdb);

View File

@ -12,6 +12,9 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Api.Movies namespace MediaBrowser.Api.Movies
{ {
@ -41,87 +44,37 @@ namespace MediaBrowser.Api.Movies
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly IDtoService _dtoService; private readonly IDtoService _dtoService;
private readonly IChannelManager _channelManager; private readonly ICollectionManager _collectionManager;
private readonly ILocalizationManager _localizationManager;
private readonly IJsonSerializer _json;
/// <summary> public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, ICollectionManager collectionManager, ILocalizationManager localizationManager, IJsonSerializer json)
/// 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)
{ {
_userManager = userManager; _userManager = userManager;
_userDataRepository = userDataRepository; _userDataRepository = userDataRepository;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_dtoService = dtoService; _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 json = _json.SerializeToString(request);
var result = await GetAllTrailers(user).ConfigureAwait(false); var getItems = _json.DeserializeFromString<GetItems>(json);
IEnumerable<BaseItem> items = result.Items; getItems.IncludeItemTypes = "Trailer";
// Apply filters return new ItemsService(_userManager, _libraryManager, _userDataRepository, _localizationManager, _dtoService, _collectionManager)
// 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))
{ {
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); }.Get(getItems);
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
};
} }
} }
} }

View File

@ -52,10 +52,15 @@ namespace MediaBrowser.Api.Music
public object Get(GetSimilarArtists request) public object Get(GetSimilarArtists request)
{ {
var result = GetSimilarItemsResult( var dtoOptions = GetDtoOptions(request);
request,
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataRepository,
_dtoService,
Logger,
request, new[] { typeof(MusicArtist) },
SimilarItemsHelper.GetSimiliarityScore); SimilarItemsHelper.GetSimiliarityScore);
return ToOptimizedSerializedResultUsingCache(result); return ToOptimizedSerializedResultUsingCache(result);
@ -76,44 +81,11 @@ namespace MediaBrowser.Api.Music
_userDataRepository, _userDataRepository,
_dtoService, _dtoService,
Logger, Logger,
request, item => item is MusicAlbum, request, new[] { typeof(MusicAlbum) },
GetAlbumSimilarityScore); GetAlbumSimilarityScore);
return ToOptimizedSerializedResultUsingCache(result); 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> /// <summary>
/// Gets the album similarity score. /// Gets the album similarity score.

View File

@ -214,7 +214,7 @@ namespace MediaBrowser.Api.Playback
args += " -map -0:a"; args += " -map -0:a";
} }
if (state.SubtitleStream == null) if (state.SubtitleStream == null || state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Hls)
{ {
args += " -map -0:s"; args += " -map -0:s";
} }
@ -477,7 +477,7 @@ namespace MediaBrowser.Api.Playback
var pts = string.Empty; 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; var seconds = TimeSpan.FromTicks(state.Request.StartTimeTicks ?? 0).TotalSeconds;
@ -575,7 +575,7 @@ namespace MediaBrowser.Api.Playback
var output = string.Empty; 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); var subParam = GetTextSubtitleParam(state);
@ -865,7 +865,7 @@ namespace MediaBrowser.Api.Playback
{ {
var arg = string.Format("-i {0}", GetInputPathArgument(state)); 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) if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
{ {
@ -1482,6 +1482,17 @@ namespace MediaBrowser.Api.Playback
videoRequest.CopyTimestamps = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); 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;
}
}
}
} }
} }

View File

@ -529,7 +529,12 @@ namespace MediaBrowser.Api.Playback.Hls
"subs" : "subs" :
null; null;
AppendPlaylist(builder, playlistUrl, totalBitrate, subtitleGroup); if (!string.IsNullOrWhiteSpace(subtitleGroup))
{
AddSubtitles(state, subtitleStreams, builder);
}
AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup);
if (EnableAdaptiveBitrateStreaming(state, isLiveStream)) if (EnableAdaptiveBitrateStreaming(state, isLiveStream))
{ {
@ -540,17 +545,12 @@ namespace MediaBrowser.Api.Playback.Hls
var newBitrate = totalBitrate - variation; var newBitrate = totalBitrate - variation;
var variantUrl = ReplaceBitrate(playlistUrl, requestedVideoBitrate, (requestedVideoBitrate - variation)); var variantUrl = ReplaceBitrate(playlistUrl, requestedVideoBitrate, (requestedVideoBitrate - variation));
AppendPlaylist(builder, variantUrl, newBitrate, subtitleGroup); AppendPlaylist(builder, state, variantUrl, newBitrate, subtitleGroup);
variation *= 2; variation *= 2;
newBitrate = totalBitrate - variation; newBitrate = totalBitrate - variation;
variantUrl = ReplaceBitrate(playlistUrl, requestedVideoBitrate, (requestedVideoBitrate - variation)); variantUrl = ReplaceBitrate(playlistUrl, requestedVideoBitrate, (requestedVideoBitrate - variation));
AppendPlaylist(builder, variantUrl, newBitrate, subtitleGroup); AppendPlaylist(builder, state, variantUrl, newBitrate, subtitleGroup);
}
if (!string.IsNullOrWhiteSpace(subtitleGroup))
{
AddSubtitles(state, subtitleStreams, builder);
} }
return builder.ToString(); return builder.ToString();
@ -566,11 +566,11 @@ namespace MediaBrowser.Api.Playback.Hls
private void AddSubtitles(StreamState state, IEnumerable<MediaStream> subtitles, StringBuilder builder) 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) 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; var name = stream.Language;
@ -579,10 +579,11 @@ namespace MediaBrowser.Api.Playback.Hls
if (string.IsNullOrWhiteSpace(name)) name = stream.Codec ?? "Unknown"; 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, state.Request.MediaSourceId,
stream.Index.ToString(UsCulture), stream.Index.ToString(UsCulture),
30.ToString(UsCulture)); 30.ToString(UsCulture),
AuthorizationContext.GetAuthorizationInfo(Request).Token);
var line = string.Format(format, var line = string.Format(format,
name, name,
@ -635,9 +636,15 @@ namespace MediaBrowser.Api.Playback.Hls
//return state.VideoRequest.VideoBitRate.HasValue; //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)) if (!string.IsNullOrWhiteSpace(subtitleGroup))
{ {
@ -694,6 +701,7 @@ namespace MediaBrowser.Api.Playback.Hls
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("#EXTM3U"); builder.AppendLine("#EXTM3U");
builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
builder.AppendLine("#EXT-X-VERSION:3"); 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-TARGETDURATION:" + Math.Ceiling((segmentLengths.Length > 0 ? segmentLengths.Max() : state.SegmentLength)).ToString(UsCulture));
builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0"); 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})\"", var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
state.SegmentLength.ToString(UsCulture)); 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; args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg;
@ -846,7 +854,7 @@ namespace MediaBrowser.Api.Playback.Hls
private bool EnableCopyTs(StreamState state) 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) protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)

View File

@ -9,6 +9,7 @@ using MediaBrowser.Model.Serialization;
using ServiceStack; using ServiceStack;
using System; using System;
using CommonIO; using CommonIO;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Api.Playback.Hls 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})\"", var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
state.SegmentLength.ToString(UsCulture)); 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; args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg;

View File

@ -73,9 +73,13 @@ namespace MediaBrowser.Api.Playback.Progressive
audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture)); 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"; const string vn = " -vn";

View File

@ -61,8 +61,9 @@ namespace MediaBrowser.Api.Playback.Progressive
{ {
try try
{ {
new ProgressiveFileCopier(_fileSystem, _job) var task = new ProgressiveFileCopier(_fileSystem, _job, Logger).StreamFile(Path, responseStream);
.StreamFile(Path, responseStream);
Task.WaitAll(task);
} }
catch (IOException) catch (IOException)
{ {
@ -91,19 +92,21 @@ namespace MediaBrowser.Api.Playback.Progressive
{ {
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly TranscodingJob _job; private readonly TranscodingJob _job;
private readonly ILogger _logger;
// 256k // 256k
private const int BufferSize = 262144; private const int BufferSize = 262144;
private long _bytesWritten = 0; private long _bytesWritten = 0;
public ProgressiveFileCopier(IFileSystem fileSystem, TranscodingJob job) public ProgressiveFileCopier(IFileSystem fileSystem, TranscodingJob job, ILogger logger)
{ {
_fileSystem = fileSystem; _fileSystem = fileSystem;
_job = job; _job = job;
_logger = logger;
} }
public void StreamFile(string path, Stream outputStream) public async Task StreamFile(string path, Stream outputStream)
{ {
var eofCount = 0; var eofCount = 0;
long position = 0; long position = 0;
@ -126,8 +129,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{ {
eofCount++; eofCount++;
} }
var task = Task.Delay(100); await Task.Delay(100).ConfigureAwait(false);
Task.WaitAll(task);
} }
else else
{ {
@ -145,6 +147,30 @@ namespace MediaBrowser.Api.Playback.Progressive
int count; int count;
while ((count = source.Read(array, 0, array.Length)) != 0) 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); destination.Write(array, 0, count);
_bytesWritten += count; _bytesWritten += count;

View File

@ -13,6 +13,7 @@ using System;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using CommonIO; using CommonIO;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Api.Playback.Progressive namespace MediaBrowser.Api.Playback.Progressive
{ {
@ -161,7 +162,7 @@ namespace MediaBrowser.Api.Playback.Progressive
args += keyFrameArg; 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; var hasCopyTs = false;
// Add resolution params, if specified // Add resolution params, if specified

View File

@ -213,8 +213,6 @@ namespace MediaBrowser.Api.Reports
SortBy = request.GetOrderBy(), SortBy = request.GetOrderBy(),
SortOrder = request.SortOrder ?? SortOrder.Ascending, SortOrder = request.SortOrder ?? SortOrder.Ascending,
Filter = i => ApplyAdditionalFilters(request, i, user, _libraryManager),
IsFavorite = request.IsFavorite, IsFavorite = request.IsFavorite,
Limit = request.Limit, Limit = request.Limit,
StartIndex = request.StartIndex, StartIndex = request.StartIndex,
@ -258,7 +256,10 @@ namespace MediaBrowser.Api.Reports
MinPlayers = request.MinPlayers, MinPlayers = request.MinPlayers,
MaxPlayers = request.MaxPlayers, MaxPlayers = request.MaxPlayers,
MinCommunityRating = request.MinCommunityRating, MinCommunityRating = request.MinCommunityRating,
MinCriticRating = request.MinCriticRating MinCriticRating = request.MinCriticRating,
ParentIndexNumber = request.ParentIndexNumber,
AiredDuringSeason = request.AiredDuringSeason,
AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater
}; };
if (!string.IsNullOrWhiteSpace(request.Ids)) 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) if (request.HasQueryLimit == false)
{ {
query.StartIndex = null; query.StartIndex = null;
@ -311,278 +378,6 @@ namespace MediaBrowser.Api.Reports
return query; 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> /// <summary> Gets query result. </summary>
/// <param name="request"> The request. </param> /// <param name="request"> The request. </param>
/// <returns> The query result. </returns> /// <returns> The query result. </returns>

View File

@ -54,21 +54,7 @@ namespace MediaBrowser.Api
/// </summary> /// </summary>
public static class SimilarItemsHelper public static class SimilarItemsHelper
{ {
/// <summary> 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)
/// 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)
{ {
var user = !string.IsNullOrWhiteSpace(request.UserId) ? userManager.GetUserById(request.UserId) : null; var user = !string.IsNullOrWhiteSpace(request.UserId) ? userManager.GetUserById(request.UserId) : null;
@ -76,11 +62,13 @@ namespace MediaBrowser.Api
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
libraryManager.RootFolder) : libraryManager.GetItemById(request.Id); libraryManager.RootFolder) : libraryManager.GetItemById(request.Id);
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 var inputItems = libraryManager.GetItemList(query);
? libraryManager.RootFolder.GetRecursiveChildren(filter)
: user.RootFolder.GetRecursiveChildren(user, filter);
var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore) var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore)
.ToList(); .ToList();

View File

@ -68,6 +68,8 @@ namespace MediaBrowser.Api
_config.Configuration.EnableLocalizedGuids = true; _config.Configuration.EnableLocalizedGuids = true;
_config.Configuration.EnableCustomPathSubFolders = true; _config.Configuration.EnableCustomPathSubFolders = true;
_config.Configuration.EnableDateLastRefresh = true; _config.Configuration.EnableDateLastRefresh = true;
_config.Configuration.EnableStandaloneMusicKeys = true;
_config.Configuration.EnableCaseSensitiveItemIds = true;
_config.SaveConfiguration(); _config.SaveConfiguration();
} }

View File

@ -164,6 +164,8 @@ namespace MediaBrowser.Api.Subtitles
long positionTicks = 0; long positionTicks = 0;
var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks; var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks;
var accessToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
while (positionTicks < runtime) while (positionTicks < runtime)
{ {
var remaining = runtime - positionTicks; var remaining = runtime - positionTicks;
@ -173,9 +175,10 @@ namespace MediaBrowser.Api.Subtitles
var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks); 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), positionTicks.ToString(CultureInfo.InvariantCulture),
endPositionTicks.ToString(CultureInfo.InvariantCulture)); endPositionTicks.ToString(CultureInfo.InvariantCulture),
accessToken);
builder.AppendLine(url); builder.AppendLine(url);

View File

@ -263,7 +263,7 @@ namespace MediaBrowser.Api
_userDataManager, _userDataManager,
_dtoService, _dtoService,
Logger, Logger,
request, item => item is Series, request, new[] { typeof(Series) },
SimilarItemsHelper.GetSimiliarityScore); SimilarItemsHelper.GetSimiliarityScore);
return ToOptimizedSerializedResultUsingCache(result); return ToOptimizedSerializedResultUsingCache(result);
@ -273,11 +273,11 @@ namespace MediaBrowser.Api
{ {
var user = _userManager.GetUserById(request.UserId); 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 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 }, IncludeItemTypes = new[] { typeof(Episode).Name },
SortBy = new[] { "PremiereDate", "AirTime", "SortName" }, SortBy = new[] { "PremiereDate", "AirTime", "SortName" },
@ -286,15 +286,15 @@ namespace MediaBrowser.Api
StartIndex = request.StartIndex, StartIndex = request.StartIndex,
Limit = request.Limit Limit = request.Limit
}, parentIds); }, parentIds).ToList();
var options = GetDtoOptions(request); 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 var result = new ItemsResult
{ {
TotalRecordCount = itemsResult.TotalRecordCount, TotalRecordCount = itemsResult.Count,
Items = returnItems Items = returnItems
}; };

View File

@ -85,17 +85,16 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{ItemsResult}.</returns> /// <returns>Task{ItemsResult}.</returns>
private async Task<ItemsResult> GetItems(GetItems request) 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 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); var dtoOptions = GetDtoOptions(request);
return new ItemsResult return new ItemsResult
{ {
TotalRecordCount = result.Item1.TotalRecordCount, TotalRecordCount = result.TotalRecordCount,
Items = _dtoService.GetBaseItemDtos(result.Item1.Items, dtoOptions, user).ToArray() Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ToArray()
}; };
} }
@ -104,17 +103,16 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary> /// </summary>
/// <param name="request">The request.</param> /// <param name="request">The request.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <param name="parentItem">The parent item.</param>
/// <returns>IEnumerable{BaseItem}.</returns> /// <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) ? var item = string.IsNullOrEmpty(request.ParentId) ?
user == null ? _libraryManager.RootFolder : user.RootFolder : user == null ? _libraryManager.RootFolder : user.RootFolder :
parentItem; _libraryManager.GetItemById(request.ParentId);
if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase)) if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase))
{ {
item = user == null ? _libraryManager.RootFolder : user.RootFolder; //item = user == null ? _libraryManager.RootFolder : user.RootFolder;
} }
else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase)) 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(); 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) if (request.Recursive)
{ {
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
return new Tuple<QueryResult<BaseItem>, bool>(result, true); return result;
} }
if (user == null) if (user == null)
{ {
var result = await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false); 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; var userRoot = item as UserRootFolder;
@ -160,26 +158,24 @@ namespace MediaBrowser.Api.UserLibrary
{ {
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); 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); IEnumerable<BaseItem> items = ((Folder)item).GetChildren(user, true);
var itemsArray = items.ToArray(); var itemsArray = items.ToArray();
return new Tuple<QueryResult<BaseItem>, bool>(new QueryResult<BaseItem> return new QueryResult<BaseItem>
{ {
Items = itemsArray, Items = itemsArray,
TotalRecordCount = itemsArray.Length TotalRecordCount = itemsArray.Length
};
}, false);
} }
private InternalItemsQuery GetItemsQuery(GetItems request, User user) private InternalItemsQuery GetItemsQuery(GetItems request, User user)
{ {
var query = new InternalItemsQuery var query = new InternalItemsQuery(user)
{ {
User = user,
IsPlayed = request.IsPlayed, IsPlayed = request.IsPlayed,
MediaTypes = request.GetMediaTypes(), MediaTypes = request.GetMediaTypes(),
IncludeItemTypes = request.GetIncludeItemTypes(), IncludeItemTypes = request.GetIncludeItemTypes(),
@ -188,8 +184,6 @@ namespace MediaBrowser.Api.UserLibrary
SortBy = request.GetOrderBy(), SortBy = request.GetOrderBy(),
SortOrder = request.SortOrder ?? SortOrder.Ascending, SortOrder = request.SortOrder ?? SortOrder.Ascending,
Filter = i => ApplyAdditionalFilters(request, i, user, _libraryManager),
IsFavorite = request.IsFavorite, IsFavorite = request.IsFavorite,
Limit = request.Limit, Limit = request.Limit,
StartIndex = request.StartIndex, StartIndex = request.StartIndex,
@ -234,7 +228,11 @@ namespace MediaBrowser.Api.UserLibrary
MinPlayers = request.MinPlayers, MinPlayers = request.MinPlayers,
MaxPlayers = request.MaxPlayers, MaxPlayers = request.MaxPlayers,
MinCommunityRating = request.MinCommunityRating, 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)) if (!string.IsNullOrWhiteSpace(request.Ids))
@ -278,331 +276,73 @@ namespace MediaBrowser.Api.UserLibrary
} }
} }
return query; if (!string.IsNullOrEmpty(request.MinPremiereDate))
}
/// <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)
{ {
case ItemFilter.IsFavoriteOrLikes: query.MinPremiereDate = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
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);
} }
return items; if (!string.IsNullOrEmpty(request.MaxPremiereDate))
}
private bool ApplyAdditionalFilters(GetItems request, BaseItem i, User user, ILibraryManager libraryManager)
{
// Artists
if (!string.IsNullOrEmpty(request.ArtistIds))
{ {
var artistIds = request.ArtistIds.Split(new[] { '|', ',' }); query.MaxPremiereDate = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
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;
}
} }
// Filter by Series Status // Filter by Series Status
if (!string.IsNullOrEmpty(request.SeriesStatus)) if (!string.IsNullOrEmpty(request.SeriesStatus))
{ {
var vals = request.SeriesStatus.Split(','); query.SeriesStatuses = request.SeriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray();
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 // Filter by Series AirDays
if (!string.IsNullOrEmpty(request.AirDays)) if (!string.IsNullOrEmpty(request.AirDays))
{ {
var days = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)); query.AirDays = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)).ToArray();
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) // ExcludeLocationTypes
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
{ {
var filterValue = request.ParentIndexNumber.Value; query.ExcludeLocationTypes = request.ExcludeLocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();
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) if (!string.IsNullOrEmpty(request.LocationTypes))
{ {
var episode = i as Episode; query.LocationTypes = request.LocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();
if (episode == null)
{
return false;
}
if (!Series.FilterEpisodesBySeason(new[] { episode }, request.AiredDuringSeason.Value, true).Any())
{
return false;
}
} }
if (!string.IsNullOrEmpty(request.MinPremiereDate)) // Min official rating
if (!string.IsNullOrEmpty(request.MinOfficialRating))
{ {
var date = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); query.MinParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
if (!(i.PremiereDate.HasValue && i.PremiereDate.Value >= date))
{
return false;
}
} }
if (!string.IsNullOrEmpty(request.MaxPremiereDate)) // Max official rating
if (!string.IsNullOrEmpty(request.MaxOfficialRating))
{ {
var date = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); query.MaxParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
if (!(i.PremiereDate.HasValue && i.PremiereDate.Value <= date))
{
return false;
}
} }
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;
} }
} }

View File

@ -335,11 +335,6 @@ namespace MediaBrowser.Api.UserLibrary
public void Post(ReportPlaybackProgress request) public void Post(ReportPlaybackProgress request)
{ {
if (!string.IsNullOrWhiteSpace(request.PlaySessionId))
{
ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId);
}
request.SessionId = GetSession().Result.Id; request.SessionId = GetSession().Result.Id;
var task = _sessionManager.OnPlaybackProgress(request); var task = _sessionManager.OnPlaybackProgress(request);
@ -349,7 +344,7 @@ namespace MediaBrowser.Api.UserLibrary
public void Post(PingPlaybackSession request) public void Post(PingPlaybackSession request)
{ {
ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId); ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId, null);
} }
/// <summary> /// <summary>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <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="morelinq" version="1.4.0" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" /> <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
</packages> </packages>

View File

@ -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) private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
{ {
var request = CreateWebRequest(options.Url); var request = CreateWebRequest(options.Url);
@ -133,6 +150,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
if (httpWebRequest != null) if (httpWebRequest != null)
{ {
AddIpv4Option(httpWebRequest, options);
AddRequestHeaders(httpWebRequest, options); AddRequestHeaders(httpWebRequest, options);
httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None; httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;

View File

@ -49,7 +49,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <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>
<Reference Include="MoreLinq"> <Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath> <HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>

View File

@ -170,6 +170,17 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
QueueScheduledTask<T>(new TaskExecutionOptions()); 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>() public void Execute<T>()
where T : IScheduledTask where T : IScheduledTask
{ {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <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="morelinq" version="1.4.0" targetFramework="net45" />
<package id="NLog" version="4.2.3" targetFramework="net45" /> <package id="NLog" version="4.2.3" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" /> <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />

View File

@ -96,6 +96,7 @@ namespace MediaBrowser.Common.Net
public TimeSpan CacheLength { get; set; } public TimeSpan CacheLength { get; set; }
public int TimeoutMs { get; set; } public int TimeoutMs { get; set; }
public bool PreferIpv4 { get; set; }
private string GetHeaderValue(string name) private string GetHeaderValue(string name)
{ {

View File

@ -50,6 +50,9 @@ namespace MediaBrowser.Common.ScheduledTasks
void QueueScheduledTask<T>() void QueueScheduledTask<T>()
where T : IScheduledTask; where T : IScheduledTask;
void QueueIfNotRunning<T>()
where T : IScheduledTask;
/// <summary> /// <summary>
/// Queues the scheduled task. /// Queues the scheduled task.
/// </summary> /// </summary>

View File

@ -3,6 +3,7 @@ using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.Serialization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -30,6 +31,13 @@ namespace MediaBrowser.Controller.Channels
return base.IsVisible(user); return base.IsVisible(user);
} }
[IgnoreDataMember]
public override SourceType SourceType
{
get { return SourceType.Channel; }
set { }
}
public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query) public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
{ {
try try
@ -75,5 +83,12 @@ namespace MediaBrowser.Controller.Channels
{ {
return false; return false;
} }
internal static bool IsChannelVisible(BaseItem channelItem, User user)
{
var channel = ChannelManager.GetChannel(channelItem.ChannelId);
return channel.IsVisible(user);
}
} }
} }

View File

@ -12,7 +12,7 @@ using System.Threading;
namespace MediaBrowser.Controller.Channels namespace MediaBrowser.Controller.Channels
{ {
public class ChannelAudioItem : Audio, IChannelMediaItem public class ChannelAudioItem : Audio
{ {
public ChannelMediaContentType ContentType { get; set; } public ChannelMediaContentType ContentType { get; set; }

View File

@ -11,7 +11,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Channels namespace MediaBrowser.Controller.Channels
{ {
public class ChannelFolderItem : Folder, IChannelItem public class ChannelFolderItem : Folder
{ {
public ChannelFolderType ChannelFolderType { get; set; } public ChannelFolderType ChannelFolderType { get; set; }

View File

@ -13,7 +13,7 @@ using System.Threading;
namespace MediaBrowser.Controller.Channels namespace MediaBrowser.Controller.Channels
{ {
public class ChannelVideoItem : Video, IChannelMediaItem, IHasLookupInfo<ChannelItemLookupInfo> public class ChannelVideoItem : Video
{ {
public ChannelMediaContentType ContentType { get; set; } public ChannelMediaContentType ContentType { get; set; }
@ -103,20 +103,6 @@ namespace MediaBrowser.Controller.Channels
return list; 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) protected override string GetInternalMetadataPath(string basePath)
{ {
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N")); 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); 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); var channel = ChannelManager.GetChannel(item.ChannelId);

View File

@ -116,7 +116,7 @@ namespace MediaBrowser.Controller.Channels
/// <param name="includeCachedVersions">if set to <c>true</c> [include cached versions].</param> /// <param name="includeCachedVersions">if set to <c>true</c> [include cached versions].</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{MediaSourceInfo}}.</returns> /// <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> /// <summary>
/// Gets the channel folder. /// Gets the channel folder.
@ -141,6 +141,6 @@ namespace MediaBrowser.Controller.Channels
/// <param name="progress">The progress.</param> /// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <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);
} }
} }

View File

@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Dto
public List<ImageType> ImageTypes { get; set; } public List<ImageType> ImageTypes { get; set; }
public int ImageTypeLimit { get; set; } public int ImageTypeLimit { get; set; }
public bool EnableImages { get; set; } public bool EnableImages { get; set; }
public bool AddProgramRecordingInfo { get; set; }
public string DeviceId { get; set; } public string DeviceId { get; set; }
public DtoOptions() public DtoOptions()

View File

@ -8,6 +8,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Threading;
using MediaBrowser.Controller.Channels;
namespace MediaBrowser.Controller.Entities.Audio namespace MediaBrowser.Controller.Entities.Audio
{ {
@ -24,6 +26,8 @@ namespace MediaBrowser.Controller.Entities.Audio
IThemeMedia, IThemeMedia,
IArchivable IArchivable
{ {
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
public long? Size { get; set; } public long? Size { get; set; }
public string Container { get; set; } public string Container { get; set; }
public int? TotalBitrate { get; set; } public int? TotalBitrate { get; set; }
@ -153,6 +157,31 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
protected override string CreateUserDataKey() 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; var parent = AlbumEntity;
if (parent != null) if (parent != null)
@ -173,7 +202,11 @@ namespace MediaBrowser.Controller.Entities.Audio
public override UnratedItem GetBlockUnratedType() public override UnratedItem GetBlockUnratedType()
{ {
return UnratedItem.Music; if (SourceType == SourceType.Library)
{
return UnratedItem.Music;
}
return base.GetBlockUnratedType();
} }
public SongInfo GetLookupInfo() public SongInfo GetLookupInfo()
@ -189,6 +222,32 @@ namespace MediaBrowser.Controller.Entities.Audio
public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution) 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> var result = new List<MediaSourceInfo>
{ {
GetVersionInfo(this, enablePathSubstitution) GetVersionInfo(this, enablePathSubstitution)

View 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
{
}
}

View File

@ -34,7 +34,17 @@ namespace MediaBrowser.Controller.Entities.Audio
{ {
get 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; return "MusicAlbum-Musicbrainz-" + id;
} }
if (ConfigurationManager.Configuration.EnableStandaloneMusicKeys)
{
var albumArtist = AlbumArtist;
if (!string.IsNullOrWhiteSpace(albumArtist))
{
return albumArtist + "-" + Name;
}
}
return base.CreateUserDataKey(); return base.CreateUserDataKey();
} }
@ -125,7 +144,7 @@ namespace MediaBrowser.Controller.Entities.Audio
id.AlbumArtists = AlbumArtists; id.AlbumArtists = AlbumArtists;
var artist = GetParents().OfType<MusicArtist>().FirstOrDefault(); var artist = MusicArtist;
if (artist != null) if (artist != null)
{ {

View File

@ -20,9 +20,11 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
@ -57,7 +59,9 @@ namespace MediaBrowser.Controller.Entities
public static string ThemeSongFilename = "theme"; public static string ThemeSongFilename = "theme";
public static string ThemeVideosFolderName = "backdrops"; public static string ThemeVideosFolderName = "backdrops";
[IgnoreDataMember]
public string PreferredMetadataCountryCode { get; set; } public string PreferredMetadataCountryCode { get; set; }
[IgnoreDataMember]
public string PreferredMetadataLanguage { get; set; } public string PreferredMetadataLanguage { get; set; }
public List<ItemImageInfo> ImageInfos { 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. /// Gets a value indicating whether this instance is in mixed folder.
/// </summary> /// </summary>
/// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value> /// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value>
[IgnoreDataMember]
public bool IsInMixedFolder { get; set; } public bool IsInMixedFolder { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
@ -166,6 +171,9 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember] [IgnoreDataMember]
public bool IsOffline { get; set; } public bool IsOffline { get; set; }
[IgnoreDataMember]
public virtual SourceType SourceType { get; set; }
/// <summary> /// <summary>
/// Returns the folder containing the item. /// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself /// 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> /// <summary>
/// If this content came from an external service, the id of the content on that service /// If this content came from an external service, the id of the content on that service
/// </summary> /// </summary>
@ -252,6 +267,11 @@ namespace MediaBrowser.Controller.Entities
{ {
get get
{ {
if (SourceType == SourceType.Channel)
{
return false;
}
var locationType = LocationType; var locationType = LocationType;
return locationType != LocationType.Remote && locationType != LocationType.Virtual; 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> /// <summary>
/// This is just a helper for convenience /// This is just a helper for convenience
/// </summary> /// </summary>
@ -298,6 +352,11 @@ namespace MediaBrowser.Controller.Entities
public virtual bool CanDelete() public virtual bool CanDelete()
{ {
if (SourceType == SourceType.Channel)
{
return false;
}
var locationType = LocationType; var locationType = LocationType;
return locationType != LocationType.Remote && return locationType != LocationType.Remote &&
locationType != LocationType.Virtual; locationType != LocationType.Virtual;
@ -342,6 +401,7 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember] [IgnoreDataMember]
public DateTime DateModified { get; set; } public DateTime DateModified { get; set; }
[IgnoreDataMember]
public DateTime DateLastSaved { get; set; } public DateTime DateLastSaved { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
@ -380,6 +440,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the locked fields. /// Gets or sets the locked fields.
/// </summary> /// </summary>
/// <value>The locked fields.</value> /// <value>The locked fields.</value>
[IgnoreDataMember]
public List<MetadataFields> LockedFields { get; set; } public List<MetadataFields> LockedFields { get; set; }
/// <summary> /// <summary>
@ -433,11 +494,6 @@ namespace MediaBrowser.Controller.Entities
{ {
get get
{ {
if (!string.IsNullOrWhiteSpace(ForcedSortName))
{
return ForcedSortName;
}
return _sortName ?? (_sortName = CreateSortName()); return _sortName ?? (_sortName = CreateSortName());
} }
set set
@ -455,6 +511,11 @@ namespace MediaBrowser.Controller.Entities
protected virtual string GetInternalMetadataPath(string basePath) 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"); var idString = Id.ToString("N");
basePath = System.IO.Path.Combine(basePath, "library"); basePath = System.IO.Path.Combine(basePath, "library");
@ -468,6 +529,11 @@ namespace MediaBrowser.Controller.Entities
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
protected virtual string CreateSortName() 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 (Name == null) return null; //some items may not have name filled in properly
if (!EnableAlphaNumericSorting) if (!EnableAlphaNumericSorting)
@ -497,7 +563,32 @@ namespace MediaBrowser.Controller.Entities
sortable = sortable.Remove(sortable.Length - (searchLower.Length + 1)); 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] [IgnoreDataMember]
@ -595,6 +686,18 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember] [IgnoreDataMember]
public string OfficialRating { get; set; } 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> /// <summary>
/// Gets or sets the official rating description. /// Gets or sets the official rating description.
/// </summary> /// </summary>
@ -620,6 +723,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the studios. /// Gets or sets the studios.
/// </summary> /// </summary>
/// <value>The studios.</value> /// <value>The studios.</value>
[IgnoreDataMember]
public List<string> Studios { get; set; } public List<string> Studios { get; set; }
/// <summary> /// <summary>
@ -633,6 +737,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the tags. /// Gets or sets the tags.
/// </summary> /// </summary>
/// <value>The tags.</value> /// <value>The tags.</value>
[IgnoreDataMember]
public List<string> Tags { get; set; } public List<string> Tags { get; set; }
/// <summary> /// <summary>
@ -1025,6 +1130,13 @@ namespace MediaBrowser.Controller.Entities
protected virtual string CreateUserDataKey() protected virtual string CreateUserDataKey()
{ {
if (SourceType == SourceType.Channel)
{
if (!string.IsNullOrWhiteSpace(ExternalId))
{
return ExternalId;
}
}
return Id.ToString(); return Id.ToString();
} }
@ -1103,6 +1215,11 @@ namespace MediaBrowser.Controller.Entities
public virtual bool IsSaveLocalMetadataEnabled() public virtual bool IsSaveLocalMetadataEnabled()
{ {
if (SourceType == SourceType.Channel)
{
return false;
}
return ConfigurationManager.Configuration.SaveLocalMeta; return ConfigurationManager.Configuration.SaveLocalMeta;
} }
@ -1218,6 +1335,11 @@ namespace MediaBrowser.Controller.Entities
public virtual UnratedItem GetBlockUnratedType() public virtual UnratedItem GetBlockUnratedType()
{ {
if (SourceType == SourceType.Channel)
{
return UnratedItem.ChannelContent;
}
return UnratedItem.Other; return UnratedItem.Other;
} }
@ -1261,6 +1383,11 @@ namespace MediaBrowser.Controller.Entities
public virtual bool IsVisibleStandalone(User user) public virtual bool IsVisibleStandalone(User user)
{ {
if (SourceType == SourceType.Channel)
{
return IsVisibleStandaloneInternal(user, false) && Channel.IsChannelVisible(this, user);
}
return IsVisibleStandaloneInternal(user, true); return IsVisibleStandaloneInternal(user, true);
} }
@ -1312,6 +1439,11 @@ namespace MediaBrowser.Controller.Entities
public virtual string GetClientTypeName() public virtual string GetClientTypeName()
{ {
if (IsFolder && SourceType == SourceType.Channel)
{
return "ChannelFolderItem";
}
return GetType().Name; return GetType().Name;
} }
@ -1835,8 +1967,8 @@ namespace MediaBrowser.Controller.Entities
ProviderIds = ProviderIds, ProviderIds = ProviderIds,
IndexNumber = IndexNumber, IndexNumber = IndexNumber,
ParentIndexNumber = ParentIndexNumber, ParentIndexNumber = ParentIndexNumber,
Year = ProductionYear, Year = ProductionYear,
PremiereDate = PremiereDate PremiereDate = PremiereDate
}; };
} }
@ -1985,5 +2117,14 @@ namespace MediaBrowser.Controller.Entities
{ {
return LibraryManager.DeleteItem(this, options); return LibraryManager.DeleteItem(this, options);
} }
public virtual Task OnFileDeleted()
{
// Remove from database
return Delete(new DeleteOptions
{
DeleteFileLocation = false
});
}
} }
} }

View File

@ -2,6 +2,7 @@
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users; using MediaBrowser.Model.Users;
@ -9,6 +10,7 @@ namespace MediaBrowser.Controller.Entities
{ {
public class Book : BaseItem, IHasTags, IHasLookupInfo<BookInfo>, IHasSeries public class Book : BaseItem, IHasTags, IHasLookupInfo<BookInfo>, IHasSeries
{ {
[IgnoreDataMember]
public override string MediaType public override string MediaType
{ {
get get

View File

@ -15,6 +15,9 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Channels;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
@ -145,60 +148,38 @@ namespace MediaBrowser.Controller.Entities
item.DateModified = DateTime.UtcNow; item.DateModified = DateTime.UtcNow;
} }
AddChildInternal(item); AddChildInternal(item.Id);
await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); 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) lock (_childrenSyncLock)
{ {
var newChildren = actualChildren.ToList(); var newChildren = ChildIds.ToList();
newChildren.AddRange(children); newChildren.AddRange(children);
_children = newChildren; _children = newChildren.ToList();
} }
} }
protected void AddChildInternal(BaseItem child) protected void AddChildInternal(Guid 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()
{ {
lock (_childrenSyncLock) 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. /// Removes the child.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param> public void RemoveChild(BaseItem item)
/// <returns>Task.</returns>
/// <exception cref="System.InvalidOperationException">Unable to remove + item.Name</exception>
public Task RemoveChild(BaseItem item, CancellationToken cancellationToken)
{ {
RemoveChildrenInternal(new[] { item }); RemoveChildrenInternal(new[] { item.Id }.ToList());
item.SetParent(null); 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 #region Indexing
@ -276,7 +228,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// The children /// The children
/// </summary> /// </summary>
private IReadOnlyList<BaseItem> _children; private IReadOnlyList<Guid> _children;
/// <summary> /// <summary>
/// The _children sync lock /// The _children sync lock
/// </summary> /// </summary>
@ -285,21 +237,30 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the actual children. /// Gets or sets the actual children.
/// </summary> /// </summary>
/// <value>The actual children.</value> /// <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 protected virtual IEnumerable<BaseItem> ActualChildren
{ {
get get
{ {
if (_children == null) return ChildIds.Select(LibraryManager.GetItemById).Where(i => i != null);
{
lock (_childrenSyncLock)
{
if (_children == null)
{
_children = LoadChildren().ToList();
}
}
}
return _children;
} }
} }
@ -353,7 +314,7 @@ namespace MediaBrowser.Controller.Entities
/// Loads our children. Validation will occur externally. /// Loads our children. Validation will occur externally.
/// We want this sychronous. /// We want this sychronous.
/// </summary> /// </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 //just load our children from the repo - the library will be validated and maintained in other processes
return GetCachedChildren(); return GetCachedChildren();
@ -503,7 +464,7 @@ namespace MediaBrowser.Controller.Entities
if (actualRemovals.Count > 0) if (actualRemovals.Count > 0)
{ {
RemoveChildrenInternal(actualRemovals); RemoveChildrenInternal(actualRemovals.Select(i => i.Id).ToList());
foreach (var item in actualRemovals) foreach (var item in actualRemovals)
{ {
@ -518,12 +479,7 @@ namespace MediaBrowser.Controller.Entities
await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false); await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);
AddChildrenInternal(newItems); AddChildrenInternal(newItems.Select(i => i.Id).ToList());
if (!EnableNewFolderQuerying())
{
await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
}
} }
} }
@ -751,51 +707,459 @@ namespace MediaBrowser.Controller.Entities
/// Get our children from the repo - stubbed for now /// Get our children from the repo - stubbed for now
/// </summary> /// </summary>
/// <returns>IEnumerable{BaseItem}.</returns> /// <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) var user = query.User;
{
Logger.Error("Item found with empty Id: " + (child.Path ?? child.Name));
return null;
}
var item = LibraryManager.GetMemoryItemById(child.Id); if (RequiresPostFiltering(query))
if (item != null)
{ {
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); return PostFilterAndSort(items, query);
}
else
{
child.SetParent(this);
LibraryManager.RegisterItem(child);
item = child;
} }
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; var user = query.User;
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); 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); var result = PostFilterAndSort(items, query);
return Task.FromResult(result); return result;
} }
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query) protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query)

View File

@ -83,6 +83,7 @@ namespace MediaBrowser.Controller.Entities
public string[] OfficialRatings { get; set; } public string[] OfficialRatings { get; set; }
public DateTime? MinPremiereDate { get; set; } public DateTime? MinPremiereDate { get; set; }
public DateTime? MaxPremiereDate { get; set; }
public DateTime? MinStartDate { get; set; } public DateTime? MinStartDate { get; set; }
public DateTime? MaxStartDate { get; set; } public DateTime? MaxStartDate { get; set; }
public DateTime? MinEndDate { get; set; } public DateTime? MinEndDate { get; set; }
@ -96,28 +97,45 @@ namespace MediaBrowser.Controller.Entities
public int? MinPlayers { get; set; } public int? MinPlayers { get; set; }
public int? MaxPlayers { get; set; } public int? MaxPlayers { get; set; }
public int? MinIndexNumber { get; set; } public int? MinIndexNumber { get; set; }
public int? AiredDuringSeason { get; set; }
public double? MinCriticRating { get; set; } public double? MinCriticRating { get; set; }
public double? MinCommunityRating { get; set; } public double? MinCommunityRating { get; set; }
public string[] ChannelIds { get; set; } public string[] ChannelIds { get; set; }
internal List<Guid> ItemIdsFromPersonFilters { get; set; } internal List<Guid> ItemIdsFromPersonFilters { get; set; }
public int? ParentIndexNumber { get; set; }
public int? MinParentalRating { get; set; }
public int? MaxParentalRating { get; set; } public int? MaxParentalRating { get; set; }
public bool? IsCurrentSchema { get; set; } public bool? IsCurrentSchema { get; set; }
public bool? HasDeadParentId { get; set; } public bool? HasDeadParentId { get; set; }
public bool? IsOffline { get; set; } public bool? IsOffline { get; set; }
public LocationType? LocationType { get; set; }
public Guid? ParentId { get; set; } public Guid? ParentId { get; set; }
public string[] AncestorIds { get; set; } public string[] AncestorIds { get; set; }
public string[] TopParentIds { get; set; } public string[] TopParentIds { get; set; }
public LocationType[] LocationTypes { get; set; }
public LocationType[] ExcludeLocationTypes { get; set; } public LocationType[] ExcludeLocationTypes { get; set; }
public string[] PresetViews { 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() public InternalItemsQuery()
{ {
AlbumNames = new string[] { };
ArtistNames = new string[] { };
BlockUnratedItems = new UnratedItem[] { }; BlockUnratedItems = new UnratedItem[] { };
Tags = new string[] { }; Tags = new string[] { };
OfficialRatings = new string[] { }; OfficialRatings = new string[] { };
@ -139,8 +157,15 @@ namespace MediaBrowser.Controller.Entities
AncestorIds = new string[] { }; AncestorIds = new string[] { };
TopParentIds = new string[] { }; TopParentIds = new string[] { };
ExcludeTags = new string[] { }; ExcludeTags = new string[] { };
LocationTypes = new LocationType[] { };
ExcludeLocationTypes = new LocationType[] { }; ExcludeLocationTypes = new LocationType[] { };
PresetViews = new string[] { }; 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) public InternalItemsQuery(User user)

View File

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.Serialization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
@ -67,24 +68,19 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <value>The revenue.</value> /// <value>The revenue.</value>
public double? Revenue { get; set; } 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> /// <summary>
/// Gets or sets the name of the TMDB collection. /// Gets or sets the name of the TMDB collection.
/// </summary> /// </summary>
/// <value>The name of the TMDB collection.</value> /// <value>The name of the TMDB collection.</value>
public string TmdbCollectionName { get; set; } public string TmdbCollectionName { get; set; }
[IgnoreDataMember]
public string CollectionName
{
get { return TmdbCollectionName; }
set { TmdbCollectionName = value; }
}
/// <summary> /// <summary>
/// Gets the trailer ids. /// Gets the trailer ids.
/// </summary> /// </summary>

View File

@ -0,0 +1,10 @@

namespace MediaBrowser.Controller.Entities
{
public enum SourceType
{
Library = 0,
Channel = 1,
LiveTV = 2
}
}

View File

@ -14,7 +14,6 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// Class Trailer /// Class Trailer
/// </summary> /// </summary>
[Obsolete]
public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasLookupInfo<TrailerInfo> public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasLookupInfo<TrailerInfo>
{ {
public List<string> ProductionLocations { get; set; } public List<string> ProductionLocations { get; set; }
@ -25,14 +24,23 @@ namespace MediaBrowser.Controller.Entities
Taglines = new List<string>(); Taglines = new List<string>();
Keywords = new List<string>(); Keywords = new List<string>();
ProductionLocations = new List<string>(); ProductionLocations = new List<string>();
TrailerTypes = new List<TrailerType>();
} }
public List<TrailerType> TrailerTypes { get; set; }
public float? Metascore { get; set; } public float? Metascore { get; set; }
public List<MediaUrl> RemoteTrailers { get; set; } public List<MediaUrl> RemoteTrailers { get; set; }
public List<string> Keywords { get; set; } public List<string> Keywords { get; set; }
[IgnoreDataMember]
public bool IsLocalTrailer
{
get { return TrailerTypes.Contains(TrailerType.LocalTrailer); }
}
/// <summary> /// <summary>
/// Gets or sets the taglines. /// Gets or sets the taglines.
/// </summary> /// </summary>
@ -51,32 +59,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The revenue.</value> /// <value>The revenue.</value>
public double? Revenue { get; set; } 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() protected override string CreateUserDataKey()
{ {
var key = Movie.GetMovieUserDataKey(this); var key = Movie.GetMovieUserDataKey(this);
@ -106,9 +88,50 @@ namespace MediaBrowser.Controller.Entities
{ {
var info = GetItemLookupInfo<TrailerInfo>(); var info = GetItemLookupInfo<TrailerInfo>();
info.IsLocalTrailer = IsLocalTrailer; info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
if (!IsInMixedFolder)
{
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
}
return info; 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;
}
} }
} }

View File

@ -19,13 +19,9 @@ namespace MediaBrowser.Controller.Entities
{ {
public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query) 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) if (query.Recursive)
{ {
var items = query.User.RootFolder.GetRecursiveChildren(query.User, filter); return QueryRecursive(query);
return PostFilterAndSort(items, query);
} }
var result = await UserViewManager.GetUserViews(new UserViewQuery var result = await UserViewManager.GetUserViews(new UserViewQuery
@ -35,6 +31,9 @@ namespace MediaBrowser.Controller.Entities
}, CancellationToken.None).ConfigureAwait(false); }, 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); return PostFilterAndSort(result.Where(filter), query);
} }

View File

@ -50,15 +50,15 @@ namespace MediaBrowser.Controller.Entities
{ {
var user = query.User; var user = query.User;
if (query.IncludeItemTypes != null && //if (query.IncludeItemTypes != null &&
query.IncludeItemTypes.Length == 1 && // query.IncludeItemTypes.Length == 1 &&
string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase)) // string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
{ //{
if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) // if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
{ // {
return await FindPlaylists(queryParent, user, query).ConfigureAwait(false); // return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
} // }
} //}
switch (viewType) switch (viewType)
{ {
@ -766,7 +766,7 @@ namespace MediaBrowser.Controller.Entities
return items; return items;
} }
private static bool CollapseBoxSetItems(InternalItemsQuery query, public static bool CollapseBoxSetItems(InternalItemsQuery query,
BaseItem queryParent, BaseItem queryParent,
User user) User user)
{ {
@ -1199,6 +1199,11 @@ namespace MediaBrowser.Controller.Entities
return false; return false;
} }
if (query.ExcludeLocationTypes.Length > 0 && query.ExcludeLocationTypes.Contains(item.LocationType))
{
return false;
}
if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder) if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
{ {
return false; 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; return true;
} }

View File

@ -6,13 +6,16 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Mime;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Channels;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
@ -33,6 +36,7 @@ namespace MediaBrowser.Controller.Entities
public List<string> AdditionalParts { get; set; } public List<string> AdditionalParts { get; set; }
public List<string> LocalAlternateVersions { get; set; } public List<string> LocalAlternateVersions { get; set; }
public List<LinkedChild> LinkedAlternateVersions { get; set; } public List<LinkedChild> LinkedAlternateVersions { get; set; }
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
public bool IsThemeMedia public bool IsThemeMedia
@ -78,6 +82,23 @@ namespace MediaBrowser.Controller.Entities
locationType != LocationType.Virtual; locationType != LocationType.Virtual;
} }
[IgnoreDataMember]
public override LocationType LocationType
{
get
{
if (SourceType == SourceType.Channel)
{
if (string.IsNullOrEmpty(Path))
{
return LocationType.Remote;
}
}
return base.LocationType;
}
}
[IgnoreDataMember] [IgnoreDataMember]
public override bool SupportsAddingToPlaylist public override bool SupportsAddingToPlaylist
{ {
@ -130,6 +151,29 @@ namespace MediaBrowser.Controller.Entities
return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video))); 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> /// <summary>
/// Gets the linked children. /// Gets the linked children.
/// </summary> /// </summary>
@ -441,6 +485,22 @@ namespace MediaBrowser.Controller.Entities
public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution) 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 item = this;
var result = item.GetAlternateVersions() var result = item.GetAlternateVersions()

View File

@ -79,5 +79,12 @@ namespace MediaBrowser.Controller
/// <param name="host">The host.</param> /// <param name="host">The host.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
string GetLocalApiUrl(string host); 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);
} }
} }

View File

@ -152,13 +152,6 @@ namespace MediaBrowser.Controller.Library
/// <returns>BaseItem.</returns> /// <returns>BaseItem.</returns>
BaseItem GetItemById(Guid id); BaseItem GetItemById(Guid id);
/// <summary>
/// Gets the items.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>QueryResult&lt;BaseItem&gt;.</returns>
QueryResult<BaseItem> GetItems(InternalItemsQuery query);
/// <summary> /// <summary>
/// Gets the memory item by identifier. /// Gets the memory item by identifier.
/// </summary> /// </summary>
@ -547,22 +540,28 @@ namespace MediaBrowser.Controller.Library
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex); Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex);
/// <summary>
/// Gets the items.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>QueryResult&lt;BaseItem&gt;.</returns>
IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
/// <summary> /// <summary>
/// Gets the items. /// Gets the items.
/// </summary> /// </summary>
/// <param name="query">The query.</param> /// <param name="query">The query.</param>
/// <param name="parentIds">The parent ids.</param> /// <param name="parentIds">The parent ids.</param>
/// <returns>List&lt;BaseItem&gt;.</returns> /// <returns>List&lt;BaseItem&gt;.</returns>
IEnumerable<BaseItem> GetItems(InternalItemsQuery query, IEnumerable<string> parentIds); IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds);
/// <summary> /// <summary>
/// Gets the items result. /// Gets the items result.
/// </summary> /// </summary>
/// <param name="query">The query.</param> /// <param name="query">The query.</param>
/// <param name="parentIds">The parent ids.</param>
/// <returns>QueryResult&lt;BaseItem&gt;.</returns> /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, IEnumerable<string> parentIds); QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query);
/// <summary> /// <summary>
/// Ignores the file. /// Ignores the file.
/// </summary> /// </summary>

View File

@ -15,11 +15,14 @@ namespace MediaBrowser.Controller.Library
public BaseItem Item { get; set; } public BaseItem Item { get; set; }
public BaseItemInfo MediaInfo { get; set; } public BaseItemInfo MediaInfo { get; set; }
public string MediaSourceId { get; set; } public string MediaSourceId { get; set; }
public bool IsPaused { get; set; }
public string DeviceId { get; set; } public string DeviceId { get; set; }
public string DeviceName { get; set; } public string DeviceName { get; set; }
public string ClientName { get; set; } public string ClientName { get; set; }
public string PlaySessionId { get; set; }
public PlaybackProgressEventArgs() public PlaybackProgressEventArgs()
{ {
Users = new List<User>(); Users = new List<User>();

View File

@ -1,10 +0,0 @@
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.LiveTv
{
public interface ILiveTvItem : IHasId
{
string ServiceName { get; set; }
string ExternalId { get; set; }
}
}

View File

@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary> /// </summary>
/// <param name="recording">The recording.</param> /// <param name="recording">The recording.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task DeleteRecording(ILiveTvRecording recording); Task DeleteRecording(BaseItem recording);
/// <summary> /// <summary>
/// Cancels the timer. /// Cancels the timer.
@ -74,15 +74,6 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="listingProviders">The listing providers.</param> /// <param name="listingProviders">The listing providers.</param>
void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders); 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> /// <summary>
/// Gets the recording. /// Gets the recording.
/// </summary> /// </summary>
@ -92,15 +83,6 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <returns>Task{RecordingInfoDto}.</returns> /// <returns>Task{RecordingInfoDto}.</returns>
Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null); Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null);
/// <summary>
/// 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> /// <summary>
/// Gets the timer. /// Gets the timer.
@ -156,7 +138,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="id">The identifier.</param> /// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>LiveTvRecording.</returns> /// <returns>LiveTvRecording.</returns>
Task<ILiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken); Task<BaseItem> GetInternalRecording(string id, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the recording stream. /// Gets the recording stream.
@ -385,10 +367,22 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary> /// <summary>
/// Adds the channel information. /// Adds the channel information.
/// </summary> /// </summary>
/// <param name="dto">The dto.</param> /// <param name="items">The items.</param>
/// <param name="channel">The channel.</param>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
/// <param name="user">The user.</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&lt;NameValuePair&gt;.</returns>
List<NameValuePair> GetSatIniMappings();
} }
} }

View File

@ -9,8 +9,10 @@ using System.Threading.Tasks;
namespace MediaBrowser.Controller.LiveTv 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 ChannelId { get; }
string MediaType { get; } string MediaType { get; }

View File

@ -39,6 +39,13 @@ namespace MediaBrowser.Controller.LiveTv
[IgnoreDataMember] [IgnoreDataMember]
public bool IsPremiere { get; set; } public bool IsPremiere { get; set; }
[IgnoreDataMember]
public override SourceType SourceType
{
get { return SourceType.LiveTV; }
set { }
}
/// <summary> /// <summary>
/// Gets the user data key. /// Gets the user data key.
/// </summary> /// </summary>
@ -50,8 +57,6 @@ namespace MediaBrowser.Controller.LiveTv
return name + "-" + Name + (EpisodeTitle ?? string.Empty); return name + "-" + Name + (EpisodeTitle ?? string.Empty);
} }
public string ServiceName { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is owned item. /// Gets a value indicating whether this instance is owned item.
/// </summary> /// </summary>
@ -151,5 +156,10 @@ namespace MediaBrowser.Controller.LiveTv
{ {
return LiveTvManager.DeleteRecording(this); return LiveTvManager.DeleteRecording(this);
} }
public override Task OnFileDeleted()
{
return LiveTvManager.OnRecordingFileDeleted(this);
}
} }
} }

View File

@ -11,7 +11,7 @@ using System.Runtime.Serialization;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
public class LiveTvChannel : BaseItem, IHasMediaSources, ILiveTvItem public class LiveTvChannel : BaseItem, IHasMediaSources
{ {
/// <summary> /// <summary>
/// Gets the user data key. /// Gets the user data key.
@ -40,6 +40,13 @@ namespace MediaBrowser.Controller.LiveTv
} }
} }
[IgnoreDataMember]
public override SourceType SourceType
{
get { return SourceType.LiveTV; }
set { }
}
/// <summary> /// <summary>
/// Gets or sets the number. /// Gets or sets the number.
/// </summary> /// </summary>
@ -52,12 +59,6 @@ namespace MediaBrowser.Controller.LiveTv
/// <value>The type of the channel.</value> /// <value>The type of the channel.</value>
public ChannelType ChannelType { get; set; } 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] [IgnoreDataMember]
public override LocationType LocationType public override LocationType LocationType
{ {

View File

@ -11,7 +11,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
public class LiveTvProgram : BaseItem, ILiveTvItem, IHasLookupInfo<LiveTvProgramLookupInfo>, IHasStartDate, IHasProgramAttributes public class LiveTvProgram : BaseItem, IHasLookupInfo<LiveTvProgramLookupInfo>, IHasStartDate, IHasProgramAttributes
{ {
/// <summary> /// <summary>
/// Gets the user data key. /// Gets the user data key.
@ -39,12 +39,12 @@ namespace MediaBrowser.Controller.LiveTv
return base.CreateUserDataKey(); return base.CreateUserDataKey();
} }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
[IgnoreDataMember] [IgnoreDataMember]
public string ServiceName { get; set; } public override SourceType SourceType
{
get { return SourceType.LiveTV; }
set { }
}
/// <summary> /// <summary>
/// The start date of the program, in UTC. /// The start date of the program, in UTC.

View File

@ -39,6 +39,13 @@ namespace MediaBrowser.Controller.LiveTv
[IgnoreDataMember] [IgnoreDataMember]
public bool IsPremiere { get; set; } public bool IsPremiere { get; set; }
[IgnoreDataMember]
public override SourceType SourceType
{
get { return SourceType.LiveTV; }
set { }
}
/// <summary> /// <summary>
/// Gets the user data key. /// Gets the user data key.
/// </summary> /// </summary>
@ -65,8 +72,6 @@ namespace MediaBrowser.Controller.LiveTv
return base.CreateUserDataKey(); return base.CreateUserDataKey();
} }
public string ServiceName { get; set; }
[IgnoreDataMember] [IgnoreDataMember]
public override string MediaType public override string MediaType
{ {
@ -166,5 +171,10 @@ namespace MediaBrowser.Controller.LiveTv
{ {
return LiveTvManager.DeleteRecording(this); return LiveTvManager.DeleteRecording(this);
} }
public override Task OnFileDeleted()
{
return LiveTvManager.OnRecordingFileDeleted(this);
}
} }
} }

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Entities; using System.Runtime.Serialization;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Users; using MediaBrowser.Model.Users;
@ -24,5 +25,12 @@ namespace MediaBrowser.Controller.LiveTv
return false; return false;
} }
} }
[IgnoreDataMember]
public override SourceType SourceType
{
get { return SourceType.LiveTV; }
set { }
}
} }
} }

View File

@ -46,7 +46,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <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>
<Reference Include="Interfaces.IO"> <Reference Include="Interfaces.IO">
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath> <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>
<Compile Include="Activity\IActivityManager.cs" /> <Compile Include="Activity\IActivityManager.cs" />
<Compile Include="Activity\IActivityRepository.cs" /> <Compile Include="Activity\IActivityRepository.cs" />
<Compile Include="Channels\ChannelAudioItem.cs" />
<Compile Include="Channels\ChannelFolderItem.cs" /> <Compile Include="Channels\ChannelFolderItem.cs" />
<Compile Include="Channels\ChannelItemInfo.cs" /> <Compile Include="Channels\ChannelItemInfo.cs" />
<Compile Include="Channels\ChannelItemResult.cs" /> <Compile Include="Channels\ChannelItemResult.cs" />
@ -82,11 +83,10 @@
<Compile Include="Channels\ChannelMediaInfo.cs" /> <Compile Include="Channels\ChannelMediaInfo.cs" />
<Compile Include="Channels\ChannelParentalRating.cs" /> <Compile Include="Channels\ChannelParentalRating.cs" />
<Compile Include="Channels\ChannelSearchInfo.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\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\Channel.cs" />
<Compile Include="Channels\IChannelMediaItem.cs" /> <Compile Include="Channels\IChannelMediaItem.cs" />
<Compile Include="Channels\IHasCacheKey.cs" /> <Compile Include="Channels\IHasCacheKey.cs" />
@ -128,6 +128,7 @@
<Compile Include="Drawing\ImageStream.cs" /> <Compile Include="Drawing\ImageStream.cs" />
<Compile Include="Dto\DtoOptions.cs" /> <Compile Include="Dto\DtoOptions.cs" />
<Compile Include="Dto\IDtoService.cs" /> <Compile Include="Dto\IDtoService.cs" />
<Compile Include="Entities\Audio\AudioPodcast.cs" />
<Compile Include="Entities\Audio\IHasAlbumArtist.cs" /> <Compile Include="Entities\Audio\IHasAlbumArtist.cs" />
<Compile Include="Entities\Audio\IHasMusicGenres.cs" /> <Compile Include="Entities\Audio\IHasMusicGenres.cs" />
<Compile Include="Entities\Book.cs" /> <Compile Include="Entities\Book.cs" />
@ -180,6 +181,7 @@
<Compile Include="Entities\Photo.cs" /> <Compile Include="Entities\Photo.cs" />
<Compile Include="Entities\PhotoAlbum.cs" /> <Compile Include="Entities\PhotoAlbum.cs" />
<Compile Include="Entities\Share.cs" /> <Compile Include="Entities\Share.cs" />
<Compile Include="Entities\SourceType.cs" />
<Compile Include="Entities\UserView.cs" /> <Compile Include="Entities\UserView.cs" />
<Compile Include="Entities\UserViewBuilder.cs" /> <Compile Include="Entities\UserViewBuilder.cs" />
<Compile Include="FileOrganization\IFileOrganizationService.cs" /> <Compile Include="FileOrganization\IFileOrganizationService.cs" />
@ -202,7 +204,6 @@
<Compile Include="Library\UserDataSaveEventArgs.cs" /> <Compile Include="Library\UserDataSaveEventArgs.cs" />
<Compile Include="LiveTv\IHasRegistrationInfo.cs" /> <Compile Include="LiveTv\IHasRegistrationInfo.cs" />
<Compile Include="LiveTv\IListingsProvider.cs" /> <Compile Include="LiveTv\IListingsProvider.cs" />
<Compile Include="LiveTv\ILiveTvItem.cs" />
<Compile Include="LiveTv\ITunerHost.cs" /> <Compile Include="LiveTv\ITunerHost.cs" />
<Compile Include="LiveTv\RecordingGroup.cs" /> <Compile Include="LiveTv\RecordingGroup.cs" />
<Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" /> <Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" />
@ -271,7 +272,6 @@
<Compile Include="Providers\ArtistInfo.cs" /> <Compile Include="Providers\ArtistInfo.cs" />
<Compile Include="Providers\BookInfo.cs" /> <Compile Include="Providers\BookInfo.cs" />
<Compile Include="Providers\BoxSetInfo.cs" /> <Compile Include="Providers\BoxSetInfo.cs" />
<Compile Include="Providers\ChannelItemLookupInfo.cs" />
<Compile Include="Providers\DirectoryService.cs" /> <Compile Include="Providers\DirectoryService.cs" />
<Compile Include="Providers\DynamicImageInfo.cs" /> <Compile Include="Providers\DynamicImageInfo.cs" />
<Compile Include="Providers\DynamicImageResponse.cs" /> <Compile Include="Providers\DynamicImageResponse.cs" />
@ -331,6 +331,7 @@
<Compile Include="Security\IEncryptionManager.cs" /> <Compile Include="Security\IEncryptionManager.cs" />
<Compile Include="Session\AuthenticationRequest.cs" /> <Compile Include="Session\AuthenticationRequest.cs" />
<Compile Include="Social\ISharingManager.cs" /> <Compile Include="Social\ISharingManager.cs" />
<Compile Include="Sorting\SortHelper.cs" />
<Compile Include="Subtitles\ISubtitleManager.cs" /> <Compile Include="Subtitles\ISubtitleManager.cs" />
<Compile Include="Subtitles\ISubtitleProvider.cs" /> <Compile Include="Subtitles\ISubtitleProvider.cs" />
<Compile Include="Providers\ItemIdentifier.cs" /> <Compile Include="Providers\ItemIdentifier.cs" />

View File

@ -90,8 +90,7 @@ namespace MediaBrowser.Controller.MediaEncoding
Cabac = info.Cabac; Cabac = info.Cabac;
Context = info.Context; Context = info.Context;
if (info.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode || if (info.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External)
info.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Embed)
{ {
SubtitleStreamIndex = info.SubtitleStreamIndex; SubtitleStreamIndex = info.SubtitleStreamIndex;
} }

View File

@ -42,13 +42,6 @@ namespace MediaBrowser.Controller.Persistence
/// <returns>Task{IEnumerable{ItemReview}}.</returns> /// <returns>Task{IEnumerable{ItemReview}}.</returns>
IEnumerable<ItemReview> GetCriticReviews(Guid itemId); IEnumerable<ItemReview> GetCriticReviews(Guid itemId);
/// <summary>
/// Gets the children items.
/// </summary>
/// <param name="parentId">The parent identifier.</param>
/// <returns>IEnumerable&lt;BaseItem&gt;.</returns>
IEnumerable<BaseItem> GetChildrenItems(Guid parentId);
/// <summary> /// <summary>
/// Saves the critic reviews. /// Saves the critic reviews.
/// </summary> /// </summary>
@ -96,22 +89,6 @@ namespace MediaBrowser.Controller.Persistence
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken); 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> /// <summary>
/// Gets the media streams. /// Gets the media streams.
/// </summary> /// </summary>

View File

@ -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; }
}
}

View File

@ -1,3 +1,5 @@
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Providers namespace MediaBrowser.Controller.Providers
{ {
public class TrailerInfo : ItemLookupInfo public class TrailerInfo : ItemLookupInfo

View 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;
}
}
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <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="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" /> <package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" /> <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />

View File

@ -488,12 +488,12 @@ namespace MediaBrowser.Dlna.ContentDirectory
var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user) var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{ {
Person = person.Name, 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 }, SortBy = new[] { ItemSortBy.SortName },
Limit = limit, Limit = limit,
StartIndex = startIndex StartIndex = startIndex
}, new string[] { }); });
var serverItems = itemsResult.Items.Select(i => new ServerItem var serverItems = itemsResult.Items.Select(i => new ServerItem
{ {

View File

@ -188,15 +188,15 @@ namespace MediaBrowser.Dlna.Didl
{ {
var subtitleAdded = AddSubtitleElement(container, subtitle); var subtitleAdded = AddSubtitleElement(container, subtitle);
if (subtitleAdded && _profile.EnableSingleSubtitleLimit) if (subtitleAdded && _profile.EnableSingleSubtitleLimit)
{ {
break; break;
} }
} }
} }
} }
private bool AddSubtitleElement(XmlElement container, SubtitleStreamInfo info) private bool AddSubtitleElement(XmlElement container, SubtitleStreamInfo info)
{ {
var subtitleProfile = _profile.SubtitleProfiles var subtitleProfile = _profile.SubtitleProfiles
.FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase) && i.Method == SubtitleDeliveryMethod.External); .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: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> // <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: //// TODO: attribute needs SEC:
//res.SetAttribute("type", info.Format.ToLower()); res.SetAttribute("type", "sec", info.Format.ToLower());
//container.AppendChild(res); container.AppendChild(res);
} }
else if (string.Equals(subtitleMode, "smi", StringComparison.OrdinalIgnoreCase)) else if (string.Equals(subtitleMode, "smi", StringComparison.OrdinalIgnoreCase))
{ {
@ -243,7 +243,7 @@ namespace MediaBrowser.Dlna.Didl
container.AppendChild(res); container.AppendChild(res);
} }
return true; return true;
} }
private void AddVideoResource(XmlElement container, IHasMediaSources video, string deviceId, Filter filter, string contentFeatures, StreamInfo streamInfo) private void AddVideoResource(XmlElement container, IHasMediaSources video, string deviceId, Filter filter, string contentFeatures, StreamInfo streamInfo)

View File

@ -161,7 +161,7 @@ namespace MediaBrowser.Dlna.Main
var descriptorURI = "/dlna/" + udn + "/description.xml"; 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> var services = new List<string>
{ {

View File

@ -42,7 +42,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <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>
<Reference Include="MoreLinq"> <Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath> <HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>

View File

@ -171,7 +171,7 @@ namespace MediaBrowser.Dlna.PlayTo
private string GetServerAddress(IPAddress localIp) private string GetServerAddress(IPAddress localIp)
{ {
return _appHost.GetLocalApiUrl(localIp.ToString()); return _appHost.GetLocalApiUrl(localIp);
} }
public void Dispose() public void Dispose()

View File

@ -31,10 +31,10 @@ namespace MediaBrowser.Dlna.Profiles
MaxIconWidth = 48; MaxIconWidth = 48;
MaxIconHeight = 48; MaxIconHeight = 48;
MaxStreamingBitrate = 12000000; MaxStreamingBitrate = 15000000;
MaxStaticBitrate = 12000000; MaxStaticBitrate = 15000000;
MusicStreamingTranscodingBitrate = 128000; MusicStreamingTranscodingBitrate = 192000;
MusicSyncBitrate = 128000; MusicSyncBitrate = 192000;
EnableAlbumArtInDidl = false; EnableAlbumArtInDidl = false;

View File

@ -99,6 +99,48 @@ namespace MediaBrowser.Dlna.Profiles
DidlMode = "", 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 new SubtitleProfile
{ {
Format = "sub", Format = "sub",

View File

@ -54,21 +54,21 @@ namespace MediaBrowser.Dlna.Profiles
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "ts", Container = "ts",
VideoCodec = "h264", VideoCodec = "h264,hevc",
AudioCodec = "aac,ac3,mp3", AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mkv", Container = "mkv",
VideoCodec = "h264", VideoCodec = "h264,hevc",
AudioCodec = "aac,ac3,mp3", AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mp4", Container = "mp4",
VideoCodec = "h264,mpeg4", VideoCodec = "h264,mpeg4,hevc",
AudioCodec = "aac,ac3,mp3", AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video 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

View File

@ -24,10 +24,10 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight> <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth> <MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight> <MaxIconHeight>48</MaxIconHeight>
<MaxStreamingBitrate>12000000</MaxStreamingBitrate> <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
<MaxStaticBitrate>12000000</MaxStaticBitrate> <MaxStaticBitrate>15000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>128000</MusicStreamingTranscodingBitrate> <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>128000</MusicSyncBitrate> <MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc> <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> <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> <TimelineOffsetSeconds>0</TimelineOffsetSeconds>

View File

@ -52,6 +52,12 @@
<SubtitleProfile format="srt" method="External" /> <SubtitleProfile format="srt" method="External" />
<SubtitleProfile format="sub" method="External" /> <SubtitleProfile format="sub" method="External" />
<SubtitleProfile format="srt" method="Embed" didlMode="" /> <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="" /> <SubtitleProfile format="sub" method="Embed" didlMode="" />
</SubtitleProfiles> </SubtitleProfiles>
</Profile> </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

View File

@ -24,10 +24,10 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight> <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth> <MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight> <MaxIconHeight>48</MaxIconHeight>
<MaxStreamingBitrate>12000000</MaxStreamingBitrate> <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
<MaxStaticBitrate>12000000</MaxStaticBitrate> <MaxStaticBitrate>15000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>128000</MusicStreamingTranscodingBitrate> <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>128000</MusicSyncBitrate> <MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc> <XDlnaDoc>DMS-1.50</XDlnaDoc>
<SonyAggregationFlags>10</SonyAggregationFlags> <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> <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