mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 19:37:55 +02:00
commit
f868dd81e8
419 changed files with 17959 additions and 88450 deletions
|
@ -285,14 +285,14 @@ namespace Emby.Drawing.ImageMagick
|
|||
|
||||
private MagickWand BuildThumbCollageWand(List<string> paths, int width, int height)
|
||||
{
|
||||
var inputPaths = ImageHelpers.ProjectPaths(paths, 8);
|
||||
var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
|
||||
using (var wandImages = new MagickWand(inputPaths.ToArray()))
|
||||
{
|
||||
var wand = new MagickWand(width, height);
|
||||
wand.OpenImage("gradient:#111111-#111111");
|
||||
using (var draw = new DrawingWand())
|
||||
{
|
||||
var iSlice = Convert.ToInt32(width * .1166666667);
|
||||
var iSlice = Convert.ToInt32(width * .1166666667 * 2);
|
||||
int iTrans = Convert.ToInt32(height * .25);
|
||||
int iHeight = Convert.ToInt32(height * .62);
|
||||
var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
|
||||
|
|
|
@ -189,7 +189,7 @@ namespace Emby.Drawing
|
|||
dateModified = tuple.Item2;
|
||||
}
|
||||
|
||||
var originalImageSize = GetImageSize(originalImagePath, dateModified);
|
||||
var originalImageSize = GetImageSize(originalImagePath, dateModified, true);
|
||||
|
||||
// Determine the output size based on incoming parameters
|
||||
var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight);
|
||||
|
@ -363,12 +363,12 @@ namespace Emby.Drawing
|
|||
/// <returns>ImageSize.</returns>
|
||||
public ImageSize GetImageSize(string path)
|
||||
{
|
||||
return GetImageSize(path, File.GetLastWriteTimeUtc(path));
|
||||
return GetImageSize(path, File.GetLastWriteTimeUtc(path), false);
|
||||
}
|
||||
|
||||
public ImageSize GetImageSize(ItemImageInfo info)
|
||||
{
|
||||
return GetImageSize(info.Path, info.DateModified);
|
||||
return GetImageSize(info.Path, info.DateModified, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -376,9 +376,10 @@ namespace Emby.Drawing
|
|||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="imageDateModified">The image date modified.</param>
|
||||
/// <param name="allowSlowMethod">if set to <c>true</c> [allow slow method].</param>
|
||||
/// <returns>ImageSize.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">path</exception>
|
||||
private ImageSize GetImageSize(string path, DateTime imageDateModified)
|
||||
private ImageSize GetImageSize(string path, DateTime imageDateModified, bool allowSlowMethod)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
|
@ -393,7 +394,7 @@ namespace Emby.Drawing
|
|||
|
||||
if (!_cachedImagedSizes.TryGetValue(cacheHash, out size))
|
||||
{
|
||||
size = GetImageSizeInternal(path);
|
||||
size = GetImageSizeInternal(path, allowSlowMethod);
|
||||
|
||||
_cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
|
||||
}
|
||||
|
@ -405,8 +406,9 @@ namespace Emby.Drawing
|
|||
/// Gets the image size internal.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="allowSlowMethod">if set to <c>true</c> [allow slow method].</param>
|
||||
/// <returns>ImageSize.</returns>
|
||||
private ImageSize GetImageSizeInternal(string path)
|
||||
private ImageSize GetImageSizeInternal(string path, bool allowSlowMethod)
|
||||
{
|
||||
ImageSize size;
|
||||
|
||||
|
@ -416,7 +418,11 @@ namespace Emby.Drawing
|
|||
}
|
||||
catch
|
||||
{
|
||||
_logger.Info("Failed to read image header for {0}. Doing it the slow way.", path);
|
||||
if (!allowSlowMethod)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
//_logger.Info("Failed to read image header for {0}. Doing it the slow way.", path);
|
||||
|
||||
CheckDisposed();
|
||||
|
||||
|
|
|
@ -336,12 +336,6 @@ namespace MediaBrowser.Api
|
|||
if (job.Type != TranscodingJobType.Progressive)
|
||||
{
|
||||
timerDuration = 1800000;
|
||||
|
||||
// We can really reduce the timeout for apps that are using the newer api
|
||||
if (!string.IsNullOrWhiteSpace(job.PlaySessionId))
|
||||
{
|
||||
timerDuration = 300000;
|
||||
}
|
||||
}
|
||||
|
||||
job.PingTimeout = timerDuration;
|
||||
|
|
|
@ -7,7 +7,6 @@ using MediaBrowser.Controller.Providers;
|
|||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using ServiceStack.Text.Controller;
|
||||
using ServiceStack.Web;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -26,7 +25,7 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
|
||||
[Route("/System/Configuration/{Key}", "GET", Summary = "Gets a named configuration")]
|
||||
[Authenticated]
|
||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
||||
public class GetNamedConfiguration
|
||||
{
|
||||
[ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
|
|
|
@ -221,7 +221,9 @@ namespace MediaBrowser.Api
|
|||
/// <returns>IEnumerable{FileSystemEntryInfo}.</returns>
|
||||
private IEnumerable<FileSystemEntryInfo> GetFileSystemEntries(GetDirectoryContents request)
|
||||
{
|
||||
var entries = new DirectoryInfo(request.Path).EnumerateFileSystemInfos().Where(i =>
|
||||
// using EnumerateFileSystemInfos doesn't handle reparse points (symlinks)
|
||||
var entries = new DirectoryInfo(request.Path).EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
|
||||
.Concat<FileSystemInfo>(new DirectoryInfo(request.Path).EnumerateFiles("*", SearchOption.TopDirectoryOnly)).Where(i =>
|
||||
{
|
||||
if (!request.IncludeHidden && i.Attributes.HasFlag(FileAttributes.Hidden))
|
||||
{
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
using MediaBrowser.Controller.Activity;
|
||||
using MediaBrowser.Api.Movies;
|
||||
using MediaBrowser.Api.Music;
|
||||
using MediaBrowser.Controller.Activity;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Localization;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
@ -225,6 +231,17 @@ namespace MediaBrowser.Api.Library
|
|||
public string TvdbId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Library/Movies/Added", "POST", Summary = "Reports that new movies have been added by an external source")]
|
||||
[Route("/Library/Movies/Updated", "POST", Summary = "Reports that new movies have been added by an external source")]
|
||||
[Authenticated]
|
||||
public class PostUpdatedMovies : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "TmdbId", Description = "Tmdb Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string TmdbId { get; set; }
|
||||
[ApiMember(Name = "ImdbId", Description = "Imdb Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string ImdbId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{Id}/Download", "GET", Summary = "Downloads item media")]
|
||||
[Authenticated(Roles = "download")]
|
||||
public class GetDownload
|
||||
|
@ -237,6 +254,12 @@ namespace MediaBrowser.Api.Library
|
|||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{Id}/Similar", "GET", Summary = "Gets similar items")]
|
||||
[Authenticated]
|
||||
public class GetSimilarItems : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class LibraryService
|
||||
/// </summary>
|
||||
|
@ -255,12 +278,16 @@ namespace MediaBrowser.Api.Library
|
|||
private readonly IAuthorizationContext _authContext;
|
||||
private readonly IActivityManager _activityManager;
|
||||
private readonly ILocalizationManager _localization;
|
||||
private readonly ILiveTvManager _liveTv;
|
||||
private readonly IChannelManager _channelManager;
|
||||
private readonly ITVSeriesManager _tvManager;
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LibraryService" /> class.
|
||||
/// </summary>
|
||||
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
|
||||
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization)
|
||||
IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, IChannelManager channelManager, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor)
|
||||
{
|
||||
_itemRepo = itemRepo;
|
||||
_libraryManager = libraryManager;
|
||||
|
@ -270,6 +297,117 @@ namespace MediaBrowser.Api.Library
|
|||
_authContext = authContext;
|
||||
_activityManager = activityManager;
|
||||
_localization = localization;
|
||||
_liveTv = liveTv;
|
||||
_channelManager = channelManager;
|
||||
_tvManager = tvManager;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
}
|
||||
|
||||
public object Get(GetSimilarItems request)
|
||||
{
|
||||
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);
|
||||
|
||||
if (item is Game)
|
||||
{
|
||||
return new GamesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService)
|
||||
{
|
||||
AuthorizationContext = AuthorizationContext,
|
||||
Logger = Logger,
|
||||
Request = Request,
|
||||
SessionContext = SessionContext,
|
||||
ResultFactory = ResultFactory
|
||||
|
||||
}.Get(new GetSimilarGames
|
||||
{
|
||||
Fields = request.Fields,
|
||||
Id = request.Id,
|
||||
Limit = request.Limit,
|
||||
UserId = request.UserId
|
||||
});
|
||||
}
|
||||
if (item is MusicAlbum)
|
||||
{
|
||||
return new AlbumsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService)
|
||||
{
|
||||
AuthorizationContext = AuthorizationContext,
|
||||
Logger = Logger,
|
||||
Request = Request,
|
||||
SessionContext = SessionContext,
|
||||
ResultFactory = ResultFactory
|
||||
|
||||
}.Get(new GetSimilarAlbums
|
||||
{
|
||||
Fields = request.Fields,
|
||||
Id = request.Id,
|
||||
Limit = request.Limit,
|
||||
UserId = request.UserId
|
||||
});
|
||||
}
|
||||
if (item is MusicArtist)
|
||||
{
|
||||
return new AlbumsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService)
|
||||
{
|
||||
AuthorizationContext = AuthorizationContext,
|
||||
Logger = Logger,
|
||||
Request = Request,
|
||||
SessionContext = SessionContext,
|
||||
ResultFactory = ResultFactory
|
||||
|
||||
}.Get(new GetSimilarArtists
|
||||
{
|
||||
Fields = request.Fields,
|
||||
Id = request.Id,
|
||||
Limit = request.Limit,
|
||||
UserId = request.UserId
|
||||
});
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _channelManager)
|
||||
{
|
||||
AuthorizationContext = AuthorizationContext,
|
||||
Logger = Logger,
|
||||
Request = Request,
|
||||
SessionContext = SessionContext,
|
||||
ResultFactory = ResultFactory
|
||||
|
||||
}.Get(new GetSimilarMovies
|
||||
{
|
||||
Fields = request.Fields,
|
||||
Id = request.Id,
|
||||
Limit = request.Limit,
|
||||
UserId = request.UserId
|
||||
});
|
||||
}
|
||||
|
||||
if (item is Series || (program != null && program.IsSeries) || (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Episode))
|
||||
{
|
||||
return new TvShowsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _tvManager)
|
||||
{
|
||||
AuthorizationContext = AuthorizationContext,
|
||||
Logger = Logger,
|
||||
Request = Request,
|
||||
SessionContext = SessionContext,
|
||||
ResultFactory = ResultFactory
|
||||
|
||||
}.Get(new GetSimilarShows
|
||||
{
|
||||
Fields = request.Fields,
|
||||
Id = request.Id,
|
||||
Limit = request.Limit,
|
||||
UserId = request.UserId
|
||||
});
|
||||
}
|
||||
|
||||
return new ItemsResult();
|
||||
}
|
||||
|
||||
public object Get(GetMediaFolders request)
|
||||
|
@ -297,7 +435,59 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
public void Post(PostUpdatedSeries request)
|
||||
{
|
||||
Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None));
|
||||
var series = _libraryManager.GetItems(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Series).Name }
|
||||
|
||||
}).Items;
|
||||
|
||||
series = series.Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProviders.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||
|
||||
if (series.Length > 0)
|
||||
{
|
||||
foreach (var item in series)
|
||||
{
|
||||
_libraryMonitor.ReportFileSystemChanged(item.Path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None));
|
||||
}
|
||||
}
|
||||
|
||||
public void Post(PostUpdatedMovies request)
|
||||
{
|
||||
var movies = _libraryManager.GetItems(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name }
|
||||
|
||||
}).Items;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.ImdbId))
|
||||
{
|
||||
movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(request.TmdbId))
|
||||
{
|
||||
movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
movies = new BaseItem[] { };
|
||||
}
|
||||
|
||||
if (movies.Length > 0)
|
||||
{
|
||||
foreach (var item in movies)
|
||||
{
|
||||
_libraryMonitor.ReportFileSystemChanged(item.Path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None));
|
||||
}
|
||||
}
|
||||
|
||||
public object Get(GetDownload request)
|
||||
|
@ -524,7 +714,6 @@ namespace MediaBrowser.Api.Library
|
|||
public void Delete(DeleteItem request)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var auth = _authContext.GetAuthorizationInfo(Request);
|
||||
var user = _userManager.GetUserById(auth.UserId);
|
||||
|
||||
|
@ -533,9 +722,16 @@ namespace MediaBrowser.Api.Library
|
|||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
var task = _libraryManager.DeleteItem(item);
|
||||
|
||||
Task.WaitAll(task);
|
||||
if (item is ILiveTvRecording)
|
||||
{
|
||||
var task = _liveTv.DeleteRecording(request.Id);
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
else
|
||||
{
|
||||
var task = _libraryManager.DeleteItem(item);
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Net;
|
||||
|
@ -8,6 +10,7 @@ using MediaBrowser.Model.LiveTv;
|
|||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
@ -26,7 +29,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
[Route("/LiveTv/Channels", "GET", Summary = "Gets available live tv channels.")]
|
||||
[Authenticated]
|
||||
public class GetChannels : IReturn<QueryResult<ChannelInfoDto>>
|
||||
public class GetChannels : IReturn<QueryResult<ChannelInfoDto>>, IHasDtoOptions
|
||||
{
|
||||
[ApiMember(Name = "Type", Description = "Optional filter by channel type.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public ChannelType? Type { get; set; }
|
||||
|
@ -59,6 +62,30 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
[ApiMember(Name = "EnableFavoriteSorting", Description = "Incorporate favorite and like status into channel sorting.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool EnableFavoriteSorting { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
[ApiMember(Name = "AddCurrentProgram", Description = "Optional. Adds current program info to each channel", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool AddCurrentProgram { get; set; }
|
||||
|
||||
public GetChannels()
|
||||
{
|
||||
AddCurrentProgram = true;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")]
|
||||
|
@ -78,7 +105,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
[Route("/LiveTv/Recordings", "GET", Summary = "Gets live tv recordings")]
|
||||
[Authenticated]
|
||||
public class GetRecordings : IReturn<QueryResult<BaseItemDto>>
|
||||
public class GetRecordings : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
|
||||
{
|
||||
[ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ChannelId { get; set; }
|
||||
|
@ -103,6 +130,22 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
[ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string SeriesTimerId { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
|
||||
|
@ -161,7 +204,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
[Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")]
|
||||
[Authenticated]
|
||||
public class GetPrograms : IReturn<QueryResult<BaseItemDto>>
|
||||
public class GetPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
|
||||
{
|
||||
[ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
|
||||
public string ChannelIds { get; set; }
|
||||
|
@ -187,6 +230,9 @@ namespace MediaBrowser.Api.LiveTv
|
|||
[ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
|
||||
public bool? IsMovie { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
|
||||
public bool? IsKids { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
|
||||
public bool? IsSports { get; set; }
|
||||
|
||||
|
@ -204,11 +250,27 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
[ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
|
||||
public string Genres { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")]
|
||||
[Authenticated]
|
||||
public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>>
|
||||
public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
|
||||
{
|
||||
[ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
|
||||
public string UserId { get; set; }
|
||||
|
@ -227,6 +289,25 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
[ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsMovie { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsKids { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")]
|
||||
|
@ -330,15 +411,108 @@ namespace MediaBrowser.Api.LiveTv
|
|||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/TunerHosts", "POST", Summary = "Adds a tuner host")]
|
||||
[Authenticated]
|
||||
public class AddTunerHost : TunerHostInfo, IReturn<TunerHostInfo>
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/LiveTv/TunerHosts", "DELETE", Summary = "Deletes a tuner host")]
|
||||
[Authenticated]
|
||||
public class DeleteTunerHost : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Tuner host id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
|
||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
||||
public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
|
||||
{
|
||||
public bool ValidateLogin { get; set; }
|
||||
public bool ValidateListings { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
|
||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
||||
public class DeleteListingProvider : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/ListingProviders/Lineups", "GET", Summary = "Gets available lineups")]
|
||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
||||
public class GetLineups : IReturn<List<NameIdPair>>
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "Type", Description = "Provider Type", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[ApiMember(Name = "Location", Description = "Location", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Location { get; set; }
|
||||
|
||||
[ApiMember(Name = "Country", Description = "Country", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Country { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/ListingProviders/SchedulesDirect/Countries", "GET", Summary = "Gets available lineups")]
|
||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
||||
public class GetSchedulesDirectCountries
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Registration", "GET")]
|
||||
[Authenticated]
|
||||
public class GetLiveTvRegistrationInfo : IReturn<MBRegistrationRecord>
|
||||
{
|
||||
[ApiMember(Name = "ChannelId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
[ApiMember(Name = "ProgramId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ProgramId { get; set; }
|
||||
|
||||
[ApiMember(Name = "Feature", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Feature { get; set; }
|
||||
}
|
||||
|
||||
public class LiveTvService : BaseApiService
|
||||
{
|
||||
private readonly ILiveTvManager _liveTvManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager)
|
||||
public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config, IHttpClient httpClient)
|
||||
{
|
||||
_liveTvManager = liveTvManager;
|
||||
_userManager = userManager;
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetLiveTvRegistrationInfo request)
|
||||
{
|
||||
var result = await _liveTvManager.GetRegistrationInfo(request.ChannelId, request.ProgramId, request.Feature).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetSchedulesDirectCountries request)
|
||||
{
|
||||
// https://json.schedulesdirect.org/20141201/available/countries
|
||||
|
||||
var response = await _httpClient.Get(new HttpRequestOptions
|
||||
{
|
||||
Url = "https://json.schedulesdirect.org/20141201/available/countries",
|
||||
CacheLength = TimeSpan.FromDays(1),
|
||||
CacheMode = CacheMode.Unconditional
|
||||
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
return ResultFactory.GetResult(response, "application/json");
|
||||
}
|
||||
|
||||
private void AssertUserCanManageLiveTv()
|
||||
|
@ -356,6 +530,48 @@ namespace MediaBrowser.Api.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<object> Post(AddListingProvider request)
|
||||
{
|
||||
var result = await _liveTvManager.SaveListingProvider(request, request.ValidateLogin, request.ValidateListings).ConfigureAwait(false);
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public void Delete(DeleteListingProvider request)
|
||||
{
|
||||
var config = GetConfiguration();
|
||||
|
||||
config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
_config.SaveConfiguration("livetv", config);
|
||||
}
|
||||
|
||||
public async Task<object> Post(AddTunerHost request)
|
||||
{
|
||||
var result = await _liveTvManager.SaveTunerHost(request).ConfigureAwait(false);
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public void Delete(DeleteTunerHost request)
|
||||
{
|
||||
var config = GetConfiguration();
|
||||
|
||||
config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
_config.SaveConfiguration("livetv", config);
|
||||
}
|
||||
|
||||
private LiveTvOptions GetConfiguration()
|
||||
{
|
||||
return _config.GetConfiguration<LiveTvOptions>("livetv");
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetLineups request)
|
||||
{
|
||||
var info = await _liveTvManager.GetLineups(request.Type, request.Id, request.Country, request.Location).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(info);
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetLiveTvInfo request)
|
||||
{
|
||||
var info = await _liveTvManager.GetLiveTvInfo(CancellationToken.None).ConfigureAwait(false);
|
||||
|
@ -374,9 +590,10 @@ namespace MediaBrowser.Api.LiveTv
|
|||
IsFavorite = request.IsFavorite,
|
||||
IsLiked = request.IsLiked,
|
||||
IsDisliked = request.IsDisliked,
|
||||
EnableFavoriteSorting = request.EnableFavoriteSorting
|
||||
EnableFavoriteSorting = request.EnableFavoriteSorting,
|
||||
AddCurrentProgram = request.AddCurrentProgram
|
||||
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
}, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
@ -429,10 +646,11 @@ namespace MediaBrowser.Api.LiveTv
|
|||
query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
query.SortOrder = request.SortOrder;
|
||||
query.IsMovie = request.IsMovie;
|
||||
query.IsKids = request.IsKids;
|
||||
query.IsSports = request.IsSports;
|
||||
query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false);
|
||||
var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
@ -446,10 +664,11 @@ namespace MediaBrowser.Api.LiveTv
|
|||
Limit = request.Limit,
|
||||
HasAired = request.HasAired,
|
||||
IsMovie = request.IsMovie,
|
||||
IsKids = request.IsKids,
|
||||
IsSports = request.IsSports
|
||||
};
|
||||
|
||||
var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false);
|
||||
var result = await _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
@ -461,7 +680,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
|
||||
public async Task<object> Get(GetRecordings request)
|
||||
{
|
||||
var options = new DtoOptions();
|
||||
var options = GetDtoOptions(request);
|
||||
options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
|
||||
|
||||
var result = await _liveTvManager.GetRecordings(new RecordingQuery
|
||||
|
|
|
@ -84,22 +84,26 @@
|
|||
<Compile Include="Playback\MediaInfoService.cs" />
|
||||
<Compile Include="Playback\TranscodingThrottler.cs" />
|
||||
<Compile Include="PlaylistService.cs" />
|
||||
<Compile Include="Reports\Activities\ReportActivitiesBuilder.cs" />
|
||||
<Compile Include="Reports\Common\HeaderActivitiesMetadata.cs" />
|
||||
<Compile Include="Reports\Common\HeaderMetadata.cs" />
|
||||
<Compile Include="Reports\Common\ItemViewType.cs" />
|
||||
<Compile Include="Reports\Common\ReportBuilderBase.cs" />
|
||||
<Compile Include="Reports\Common\ReportDisplayType.cs" />
|
||||
<Compile Include="Reports\Common\ReportExportType.cs" />
|
||||
<Compile Include="Reports\Common\ReportFieldType.cs" />
|
||||
<Compile Include="Reports\Common\ReportHeaderIdType.cs" />
|
||||
<Compile Include="Reports\Common\ReportHelper.cs" />
|
||||
<Compile Include="Reports\Common\ReportIncludeItemTypes.cs" />
|
||||
<Compile Include="Reports\Common\ReportViewType.cs" />
|
||||
<Compile Include="Reports\Data\ReportBuilder.cs" />
|
||||
<Compile Include="Reports\Data\ReportExport.cs" />
|
||||
<Compile Include="Reports\Data\ReportGroup.cs" />
|
||||
<Compile Include="Reports\Data\ReportHeader.cs" />
|
||||
<Compile Include="Reports\Data\ReportItem.cs" />
|
||||
<Compile Include="Reports\Data\ReportOptions.cs" />
|
||||
<Compile Include="Reports\Data\ReportResult.cs" />
|
||||
<Compile Include="Reports\Data\ReportRow.cs" />
|
||||
<Compile Include="Reports\Model\ReportGroup.cs" />
|
||||
<Compile Include="Reports\Model\ReportHeader.cs" />
|
||||
<Compile Include="Reports\Model\ReportItem.cs" />
|
||||
<Compile Include="Reports\Model\ReportResult.cs" />
|
||||
<Compile Include="Reports\Model\ReportRow.cs" />
|
||||
<Compile Include="Reports\ReportRequests.cs" />
|
||||
<Compile Include="Reports\ReportsService.cs" />
|
||||
<Compile Include="Reports\Stat\ReportStatBuilder.cs" />
|
||||
|
|
|
@ -28,6 +28,14 @@ namespace MediaBrowser.Api.Movies
|
|||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetSimilarTrailers
|
||||
/// </summary>
|
||||
[Route("/Trailers/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given trailer.")]
|
||||
public class GetSimilarTrailers : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Movies/Recommendations", "GET", Summary = "Gets movie recommendations")]
|
||||
public class GetMovieRecommendations : IReturn<RecommendationDto[]>, IHasItemFields
|
||||
{
|
||||
|
@ -117,6 +125,17 @@ namespace MediaBrowser.Api.Movies
|
|||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetSimilarTrailers request)
|
||||
{
|
||||
var result = await GetSimilarItemsResult(
|
||||
// Strip out secondary versions
|
||||
request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue,
|
||||
|
||||
SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetMovieRecommendations request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
@ -126,7 +145,7 @@ namespace MediaBrowser.Api.Movies
|
|||
movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
|
||||
|
||||
var listEligibleForCategories = new List<BaseItem>();
|
||||
var listEligibleForSuggestion = new List<BaseItem> ();
|
||||
var listEligibleForSuggestion = new List<BaseItem>();
|
||||
|
||||
var list = movies.ToList();
|
||||
|
||||
|
@ -181,7 +200,7 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
var list = inputItems.ToList();
|
||||
|
||||
if (item is Movie && user != null && user.Configuration.IncludeTrailersInSuggestions)
|
||||
if (user != null && user.Configuration.IncludeTrailersInSuggestions)
|
||||
{
|
||||
var trailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery
|
||||
{
|
||||
|
|
|
@ -2,15 +2,12 @@
|
|||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
@ -18,23 +15,9 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Api.Movies
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetSimilarTrailers
|
||||
/// </summary>
|
||||
[Route("/Trailers/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given trailer.")]
|
||||
public class GetSimilarTrailers : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Trailers", "GET", Summary = "Finds movies and trailers similar to a given trailer.")]
|
||||
public class Getrailers : BaseItemsRequest, IReturn<ItemsResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -57,7 +40,6 @@ namespace MediaBrowser.Api.Movies
|
|||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
private readonly IItemRepository _itemRepo;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IChannelManager _channelManager;
|
||||
|
||||
|
@ -67,40 +49,15 @@ namespace MediaBrowser.Api.Movies
|
|||
/// <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, IItemRepository itemRepo, IDtoService dtoService, IChannelManager channelManager)
|
||||
public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, IChannelManager channelManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_libraryManager = libraryManager;
|
||||
_itemRepo = itemRepo;
|
||||
_dtoService = dtoService;
|
||||
_channelManager = channelManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetSimilarTrailers request)
|
||||
{
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||
_itemRepo,
|
||||
_libraryManager,
|
||||
_userDataRepository,
|
||||
_dtoService,
|
||||
Logger,
|
||||
|
||||
// Strip out secondary versions
|
||||
request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue,
|
||||
|
||||
SimilarItemsHelper.GetSimiliarityScore);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
||||
public async Task<object> Get(Getrailers request)
|
||||
{
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
|
|
|
@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.Audio;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -16,6 +17,11 @@ namespace MediaBrowser.Api.Music
|
|||
{
|
||||
}
|
||||
|
||||
[Route("/Artists/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")]
|
||||
public class GetSimilarArtists : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
public class AlbumsService : BaseApiService
|
||||
{
|
||||
|
@ -44,6 +50,17 @@ namespace MediaBrowser.Api.Music
|
|||
_dtoService = dtoService;
|
||||
}
|
||||
|
||||
public object Get(GetSimilarArtists request)
|
||||
{
|
||||
var result = GetSimilarItemsResult(
|
||||
|
||||
request,
|
||||
|
||||
SimilarItemsHelper.GetSimiliarityScore);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
|
@ -65,6 +82,39 @@ namespace MediaBrowser.Api.Music
|
|||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
||||
private ItemsResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
|
||||
{
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
|
||||
var item = string.IsNullOrEmpty(request.Id) ?
|
||||
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
|
||||
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var inputItems = _libraryManager.GetArtists(user.RootFolder.GetRecursiveChildren(user, i => i is IHasArtist).OfType<IHasArtist>());
|
||||
|
||||
var list = inputItems.ToList();
|
||||
|
||||
var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList();
|
||||
|
||||
IEnumerable<BaseItem> returnItems = items;
|
||||
|
||||
if (request.Limit.HasValue)
|
||||
{
|
||||
returnItems = returnItems.Take(request.Limit.Value);
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
|
||||
|
||||
TotalRecordCount = items.Count
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album similarity score.
|
||||
/// </summary>
|
||||
|
|
|
@ -54,6 +54,11 @@ namespace MediaBrowser.Api.Music
|
|||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given item")]
|
||||
public class GetInstantMixFromItem : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
public class InstantMixService : BaseApiService
|
||||
{
|
||||
|
@ -71,6 +76,17 @@ namespace MediaBrowser.Api.Music
|
|||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromItem request)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromItem(item, user);
|
||||
|
||||
return GetResult(items, user, request);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromArtistId request)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(request.Id);
|
||||
|
@ -138,8 +154,9 @@ namespace MediaBrowser.Api.Music
|
|||
public object Get(GetInstantMixFromArtist request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
var artist = _libraryManager.GetArtist(request.Name);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromArtist(request.Name, user);
|
||||
var items = _musicManager.GetInstantMixFromArtist(artist, user);
|
||||
|
||||
return GetResult(items, user, request);
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ namespace MediaBrowser.Api
|
|||
/// <returns>System.Object.</returns>
|
||||
public async Task<object> Get(GetPackages request)
|
||||
{
|
||||
var packages = await _installationManager.GetAvailablePackages(CancellationToken.None, request.PackageType, _appHost.ApplicationVersion).ConfigureAwait(false);
|
||||
var packages = await _installationManager.GetAvailablePackages(CancellationToken.None, false, request.PackageType, _appHost.ApplicationVersion).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(request.TargetSystems))
|
||||
{
|
||||
|
|
|
@ -263,38 +263,27 @@ namespace MediaBrowser.Api.Playback
|
|||
return returnFirstIfNoIndex ? streams.FirstOrDefault() : null;
|
||||
}
|
||||
|
||||
protected EncodingQuality GetQualitySetting()
|
||||
{
|
||||
var quality = ApiEntryPoint.Instance.GetEncodingOptions().EncodingQuality;
|
||||
|
||||
if (quality == EncodingQuality.Auto)
|
||||
{
|
||||
var cpuCount = Environment.ProcessorCount;
|
||||
|
||||
if (cpuCount >= 4)
|
||||
{
|
||||
//return EncodingQuality.HighQuality;
|
||||
}
|
||||
|
||||
return EncodingQuality.HighSpeed;
|
||||
}
|
||||
|
||||
return quality;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of threads.
|
||||
/// </summary>
|
||||
/// <returns>System.Int32.</returns>
|
||||
protected int GetNumberOfThreads(StreamState state, bool isWebm)
|
||||
{
|
||||
var threads = ApiEntryPoint.Instance.GetEncodingOptions().EncodingThreadCount;
|
||||
|
||||
if (isWebm)
|
||||
{
|
||||
// Recommended per docs
|
||||
return Math.Max(Environment.ProcessorCount - 1, 2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
// Automatic
|
||||
if (threads == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return threads;
|
||||
}
|
||||
|
||||
protected string H264Encoder
|
||||
|
@ -326,77 +315,31 @@ namespace MediaBrowser.Api.Playback
|
|||
var isVc1 = state.VideoStream != null &&
|
||||
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var qualitySetting = GetQualitySetting();
|
||||
|
||||
if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset superfast";
|
||||
|
||||
switch (qualitySetting)
|
||||
{
|
||||
case EncodingQuality.HighSpeed:
|
||||
param += " -crf 23";
|
||||
break;
|
||||
case EncodingQuality.HighQuality:
|
||||
param += " -crf 20";
|
||||
break;
|
||||
case EncodingQuality.MaxQuality:
|
||||
param += " -crf 18";
|
||||
break;
|
||||
}
|
||||
param += " -crf 23";
|
||||
}
|
||||
|
||||
else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-preset fast";
|
||||
|
||||
switch (qualitySetting)
|
||||
{
|
||||
case EncodingQuality.HighSpeed:
|
||||
param += " -crf 28";
|
||||
break;
|
||||
case EncodingQuality.HighQuality:
|
||||
param += " -crf 25";
|
||||
break;
|
||||
case EncodingQuality.MaxQuality:
|
||||
param += " -crf 21";
|
||||
break;
|
||||
}
|
||||
param += " -crf 28";
|
||||
}
|
||||
|
||||
// h264 (h264_qsv)
|
||||
else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
switch (qualitySetting)
|
||||
{
|
||||
case EncodingQuality.HighSpeed:
|
||||
param = "-preset 7";
|
||||
break;
|
||||
case EncodingQuality.HighQuality:
|
||||
param = "-preset 4";
|
||||
break;
|
||||
case EncodingQuality.MaxQuality:
|
||||
param = "-preset 1";
|
||||
break;
|
||||
}
|
||||
param = "-preset 7";
|
||||
|
||||
}
|
||||
|
||||
// h264 (libnvenc)
|
||||
else if (string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
switch (qualitySetting)
|
||||
{
|
||||
case EncodingQuality.HighSpeed:
|
||||
param = "-preset high-performance";
|
||||
break;
|
||||
case EncodingQuality.HighQuality:
|
||||
param = "";
|
||||
break;
|
||||
case EncodingQuality.MaxQuality:
|
||||
param = "-preset high-quality";
|
||||
break;
|
||||
}
|
||||
param = "-preset high-performance";
|
||||
}
|
||||
|
||||
// webm
|
||||
|
@ -409,20 +352,7 @@ namespace MediaBrowser.Api.Playback
|
|||
var qmin = "0";
|
||||
var qmax = "50";
|
||||
|
||||
switch (qualitySetting)
|
||||
{
|
||||
case EncodingQuality.HighSpeed:
|
||||
crf = "10";
|
||||
break;
|
||||
case EncodingQuality.HighQuality:
|
||||
crf = "6";
|
||||
break;
|
||||
case EncodingQuality.MaxQuality:
|
||||
crf = "4";
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Unrecognized quality setting");
|
||||
}
|
||||
crf = "10";
|
||||
|
||||
if (isVc1)
|
||||
{
|
||||
|
@ -689,7 +619,7 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
// TODO: Perhaps also use original_size=1920x800 ??
|
||||
return string.Format("subtitles=filename='{0}'{1},setpts=PTS -{2}/TB",
|
||||
subtitlePath.Replace('\\', '/').Replace("'", "\\'").Replace(":/", "\\:/"),
|
||||
MediaEncoder.EscapeSubtitleFilterPath(subtitlePath),
|
||||
charsetParam,
|
||||
seconds.ToString(UsCulture));
|
||||
}
|
||||
|
@ -697,7 +627,7 @@ namespace MediaBrowser.Api.Playback
|
|||
var mediaPath = state.MediaPath ?? string.Empty;
|
||||
|
||||
return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB",
|
||||
mediaPath.Replace('\\', '/').Replace("'", "\\'").Replace(":/", "\\:/"),
|
||||
MediaEncoder.EscapeSubtitleFilterPath(mediaPath),
|
||||
state.InternalSubtitleStreamOffset.ToString(UsCulture),
|
||||
seconds.ToString(UsCulture));
|
||||
}
|
||||
|
@ -794,7 +724,7 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
var channelLimit = codec.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1
|
||||
? 2
|
||||
: 5;
|
||||
: 6;
|
||||
|
||||
// If we don't have any media info then limit it to 5 to prevent encoding errors due to asking for too many channels
|
||||
return Math.Min(request.MaxAudioChannels.Value, channelLimit);
|
||||
|
@ -819,11 +749,11 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the audio encoder.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetAudioEncoder(StreamRequest request)
|
||||
protected string GetAudioEncoder(StreamState state)
|
||||
{
|
||||
var codec = request.AudioCodec;
|
||||
var codec = state.OutputAudioCodec;
|
||||
|
||||
if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -848,11 +778,11 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the name of the output video codec
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetVideoEncoder(VideoStreamRequest request)
|
||||
protected string GetVideoEncoder(StreamState state)
|
||||
{
|
||||
var codec = request.VideoCodec;
|
||||
var codec = state.OutputVideoCodec;
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
|
@ -924,7 +854,7 @@ namespace MediaBrowser.Api.Playback
|
|||
state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (state.MediaSource.RequiresOpening)
|
||||
if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Request.LiveStreamId))
|
||||
{
|
||||
var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
|
||||
{
|
||||
|
@ -1704,11 +1634,6 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
private void TryStreamCopy(StreamState state, VideoStreamRequest videoRequest)
|
||||
{
|
||||
if (!EnableStreamCopy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream))
|
||||
{
|
||||
state.OutputVideoCodec = "copy";
|
||||
|
@ -1720,14 +1645,6 @@ namespace MediaBrowser.Api.Playback
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual bool EnableStreamCopy
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachMediaSourceInfo(StreamState state,
|
||||
MediaSourceInfo mediaSource,
|
||||
VideoStreamRequest videoRequest,
|
||||
|
@ -1811,13 +1728,18 @@ namespace MediaBrowser.Api.Playback
|
|||
state.MediaSource = mediaSource;
|
||||
}
|
||||
|
||||
private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
|
||||
protected virtual bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
|
||||
{
|
||||
if (videoStream.IsInterlaced)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (videoStream.IsAnamorphic ?? false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Can't stream copy if we're burning in subtitles
|
||||
if (request.SubtitleStreamIndex.HasValue)
|
||||
{
|
||||
|
@ -1954,7 +1876,7 @@ namespace MediaBrowser.Api.Playback
|
|||
return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs)
|
||||
protected virtual bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs)
|
||||
{
|
||||
// Source and target codecs must match
|
||||
if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase))
|
||||
|
|
|
@ -378,7 +378,7 @@ namespace MediaBrowser.Api.Playback.Dash
|
|||
|
||||
protected override string GetAudioArguments(StreamState state)
|
||||
{
|
||||
var codec = GetAudioEncoder(state.Request);
|
||||
var codec = GetAudioEncoder(state);
|
||||
|
||||
if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -408,7 +408,7 @@ namespace MediaBrowser.Api.Playback.Dash
|
|||
|
||||
protected override string GetVideoArguments(StreamState state)
|
||||
{
|
||||
var codec = GetVideoEncoder(state.VideoRequest);
|
||||
var codec = GetVideoEncoder(state);
|
||||
|
||||
var args = "-codec:v:0 " + codec;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ using MediaBrowser.Controller.Devices;
|
|||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
@ -310,5 +311,35 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
|
||||
{
|
||||
if (videoStream.KeyFrames == null || videoStream.KeyFrames.Count == 0)
|
||||
{
|
||||
Logger.Debug("Cannot stream copy video due to missing keyframe info");
|
||||
return false;
|
||||
}
|
||||
|
||||
var previousSegment = 0;
|
||||
foreach (var frame in videoStream.KeyFrames)
|
||||
{
|
||||
var length = frame - previousSegment;
|
||||
|
||||
// Don't allow really long segments because this could result in long download times
|
||||
if (length > 10000)
|
||||
{
|
||||
Logger.Debug("Cannot stream copy video due to long segment length of {0}ms", length);
|
||||
return false;
|
||||
}
|
||||
previousSegment = frame;
|
||||
}
|
||||
|
||||
return base.CanStreamCopyVideo(request, videoStream);
|
||||
}
|
||||
|
||||
protected override bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ using MediaBrowser.Model.IO;
|
|||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
@ -161,7 +160,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
|
||||
|
||||
var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex);
|
||||
var segmentLength = state.SegmentLength;
|
||||
|
||||
var segmentExtension = GetSegmentFileExtension(state);
|
||||
|
||||
|
@ -170,7 +168,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
if (File.Exists(segmentPath))
|
||||
{
|
||||
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
||||
return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false);
|
||||
return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
|
@ -179,7 +177,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
if (File.Exists(segmentPath))
|
||||
{
|
||||
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
||||
return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false);
|
||||
return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -210,14 +208,12 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, p => false);
|
||||
|
||||
await ReadSegmentLengths(playlistPath).ConfigureAwait(false);
|
||||
|
||||
if (currentTranscodingIndex.HasValue)
|
||||
{
|
||||
DeleteLastFile(playlistPath, segmentExtension, 0);
|
||||
}
|
||||
|
||||
request.StartTimeTicks = GetSeekPositionTicks(state, playlistPath, requestedIndex);
|
||||
request.StartTimeTicks = GetStartPositionTicks(state, requestedIndex);
|
||||
|
||||
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -252,84 +248,76 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
Logger.Info("returning {0}", segmentPath);
|
||||
job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
|
||||
return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false);
|
||||
return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<string, double> SegmentLengths = new ConcurrentDictionary<string, double>(StringComparer.OrdinalIgnoreCase);
|
||||
private async Task ReadSegmentLengths(string playlist)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var fileStream = GetPlaylistFileStream(playlist))
|
||||
{
|
||||
using (var reader = new StreamReader(fileStream))
|
||||
{
|
||||
double duration = -1;
|
||||
// 256k
|
||||
private const int BufferSize = 262144;
|
||||
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var text = await reader.ReadLineAsync().ConfigureAwait(false);
|
||||
|
||||
if (text.StartsWith("#EXTINF", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var parts = text.Split(new[] { ':' }, 2);
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
var time = parts[1].Trim(new[] { ',' }).Trim();
|
||||
double timeValue;
|
||||
if (double.TryParse(time, NumberStyles.Any, CultureInfo.InvariantCulture, out timeValue))
|
||||
{
|
||||
duration = timeValue;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (duration != -1)
|
||||
{
|
||||
SegmentLengths.AddOrUpdate(text, duration, (k, v) => duration);
|
||||
Logger.Debug("Added segment length of {0} for {1}", duration, text);
|
||||
}
|
||||
|
||||
duration = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private long GetSeekPositionTicks(StreamState state, string playlist, int requestedIndex)
|
||||
private long GetStartPositionTicks(StreamState state, int requestedIndex)
|
||||
{
|
||||
double startSeconds = 0;
|
||||
var lengths = GetSegmentLengths(state);
|
||||
|
||||
for (var i = 0; i < requestedIndex; i++)
|
||||
{
|
||||
var segmentPath = GetSegmentPath(state, playlist, i);
|
||||
|
||||
//double length;
|
||||
//if (SegmentLengths.TryGetValue(Path.GetFileName(segmentPath), out length))
|
||||
//{
|
||||
// Logger.Debug("Found segment length of {0} for index {1}", length, i);
|
||||
// startSeconds += length;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// startSeconds += state.SegmentLength;
|
||||
//}
|
||||
startSeconds += state.SegmentLength;
|
||||
startSeconds += lengths[requestedIndex];
|
||||
}
|
||||
|
||||
var position = TimeSpan.FromSeconds(startSeconds).Ticks;
|
||||
return position;
|
||||
}
|
||||
|
||||
private long GetEndPositionTicks(StreamState state, int requestedIndex)
|
||||
{
|
||||
double startSeconds = 0;
|
||||
var lengths = GetSegmentLengths(state);
|
||||
|
||||
for (var i = 0; i <= requestedIndex; i++)
|
||||
{
|
||||
startSeconds += lengths[requestedIndex];
|
||||
}
|
||||
|
||||
var position = TimeSpan.FromSeconds(startSeconds).Ticks;
|
||||
return position;
|
||||
}
|
||||
|
||||
private double[] GetSegmentLengths(StreamState state)
|
||||
{
|
||||
var result = new List<double>();
|
||||
var encoder = GetVideoEncoder(state);
|
||||
|
||||
if (string.Equals(encoder, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var videoStream = state.VideoStream;
|
||||
if (videoStream.KeyFrames != null && videoStream.KeyFrames.Count > 0)
|
||||
{
|
||||
foreach (var frame in videoStream.KeyFrames)
|
||||
{
|
||||
var seconds = TimeSpan.FromMilliseconds(frame).TotalSeconds;
|
||||
seconds -= result.Sum();
|
||||
result.Add(seconds);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
var ticks = state.RunTimeTicks ?? 0;
|
||||
|
||||
var segmentLengthTicks = TimeSpan.FromSeconds(state.SegmentLength).Ticks;
|
||||
|
||||
while (ticks > 0)
|
||||
{
|
||||
var length = ticks >= segmentLengthTicks ? segmentLengthTicks : ticks;
|
||||
|
||||
result.Add(TimeSpan.FromTicks(length).TotalSeconds);
|
||||
|
||||
ticks -= length;
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension)
|
||||
{
|
||||
var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType);
|
||||
|
@ -434,17 +422,16 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
return Path.Combine(folder, filename + index.ToString(UsCulture) + GetSegmentFileExtension(state));
|
||||
}
|
||||
|
||||
private async Task<object> GetSegmentResult(string playlistPath,
|
||||
private async Task<object> GetSegmentResult(StreamState state, string playlistPath,
|
||||
string segmentPath,
|
||||
int segmentIndex,
|
||||
int segmentLength,
|
||||
TranscodingJob transcodingJob,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// If all transcoding has completed, just return immediately
|
||||
if (transcodingJob != null && transcodingJob.HasExited && File.Exists(segmentPath))
|
||||
{
|
||||
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
|
||||
return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
|
||||
}
|
||||
|
||||
var segmentFilename = Path.GetFileName(segmentPath);
|
||||
|
@ -455,21 +442,18 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
using (var fileStream = GetPlaylistFileStream(playlistPath))
|
||||
{
|
||||
using (var reader = new StreamReader(fileStream))
|
||||
using (var reader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var text = await reader.ReadLineAsync().ConfigureAwait(false);
|
||||
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
|
||||
// If it appears in the playlist, it's done
|
||||
if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
|
||||
// If it appears in the playlist, it's done
|
||||
if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
if (File.Exists(segmentPath))
|
||||
{
|
||||
if (File.Exists(segmentPath))
|
||||
{
|
||||
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
|
||||
}
|
||||
break;
|
||||
return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
|
||||
}
|
||||
//break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -518,13 +502,12 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
//}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
|
||||
return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
|
||||
}
|
||||
|
||||
private object GetSegmentResult(string segmentPath, int index, int segmentLength, TranscodingJob transcodingJob)
|
||||
private object GetSegmentResult(StreamState state, string segmentPath, int index, TranscodingJob transcodingJob)
|
||||
{
|
||||
var segmentEndingSeconds = (1 + index) * segmentLength;
|
||||
var segmentEndingPositionTicks = TimeSpan.FromSeconds(segmentEndingSeconds).Ticks;
|
||||
var segmentEndingPositionTicks = GetEndPositionTicks(state, index);
|
||||
|
||||
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
||||
{
|
||||
|
@ -751,25 +734,23 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
var segmentLengths = GetSegmentLengths(state);
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("#EXTM3U");
|
||||
builder.AppendLine("#EXT-X-VERSION:3");
|
||||
builder.AppendLine("#EXT-X-TARGETDURATION:" + (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");
|
||||
|
||||
var queryStringIndex = Request.RawUrl.IndexOf('?');
|
||||
var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
|
||||
|
||||
var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds;
|
||||
|
||||
var index = 0;
|
||||
|
||||
while (seconds > 0)
|
||||
foreach (var length in segmentLengths)
|
||||
{
|
||||
var length = seconds >= state.SegmentLength ? state.SegmentLength : seconds;
|
||||
|
||||
builder.AppendLine("#EXTINF:" + length.ToString(UsCulture) + ",");
|
||||
builder.AppendLine("#EXTINF:" + length.ToString("0.000000", UsCulture) + ",");
|
||||
|
||||
builder.AppendLine(string.Format("hlsdynamic/{0}/{1}{2}{3}",
|
||||
|
||||
|
@ -778,7 +759,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
GetSegmentFileExtension(isOutputVideo),
|
||||
queryString));
|
||||
|
||||
seconds -= state.SegmentLength;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
@ -791,7 +771,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
protected override string GetAudioArguments(StreamState state)
|
||||
{
|
||||
var codec = GetAudioEncoder(state.Request);
|
||||
var codec = GetAudioEncoder(state);
|
||||
|
||||
if (!state.IsOutputVideo)
|
||||
{
|
||||
|
@ -856,7 +836,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
return string.Empty;
|
||||
}
|
||||
|
||||
var codec = GetVideoEncoder(state.VideoRequest);
|
||||
var codec = GetVideoEncoder(state);
|
||||
|
||||
var args = "-codec:v:0 " + codec;
|
||||
|
||||
|
@ -877,7 +857,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
}
|
||||
else
|
||||
{
|
||||
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));
|
||||
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
||||
|
@ -889,7 +869,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
// Add resolution params, if specified
|
||||
if (!hasGraphicalSubs)
|
||||
{
|
||||
args += GetOutputSizeParam(state, codec, false);
|
||||
args += GetOutputSizeParam(state, codec, EnableCopyTs(state));
|
||||
}
|
||||
|
||||
// This is for internal graphical subs
|
||||
|
@ -898,17 +878,17 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
args += GetGraphicalSubtitleParam(state, codec);
|
||||
}
|
||||
|
||||
args += " -flags +loop-global_header -sc_threshold 0";
|
||||
}
|
||||
|
||||
if (!EnableSplitTranscoding(state))
|
||||
{
|
||||
//args += " -copyts";
|
||||
args += " -flags -global_header -sc_threshold 0";
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
private bool EnableCopyTs(StreamState state)
|
||||
{
|
||||
return state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream;
|
||||
}
|
||||
|
||||
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
|
||||
{
|
||||
var threads = GetNumberOfThreads(state, false);
|
||||
|
@ -921,22 +901,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
var toTimeParam = string.Empty;
|
||||
var timestampOffsetParam = string.Empty;
|
||||
|
||||
if (EnableSplitTranscoding(state))
|
||||
{
|
||||
var startTime = state.Request.StartTimeTicks ?? 0;
|
||||
var durationSeconds = ApiEntryPoint.Instance.GetEncodingOptions().ThrottleThresholdInSeconds;
|
||||
|
||||
var endTime = startTime + TimeSpan.FromSeconds(durationSeconds).Ticks;
|
||||
endTime = Math.Min(endTime, state.RunTimeTicks.Value);
|
||||
|
||||
if (endTime < state.RunTimeTicks.Value)
|
||||
{
|
||||
//toTimeParam = " -to " + MediaEncoder.GetTimeParameter(endTime);
|
||||
toTimeParam = " -t " + MediaEncoder.GetTimeParameter(TimeSpan.FromSeconds(durationSeconds).Ticks);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.IsOutputVideo && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && (state.Request.StartTimeTicks ?? 0) > 0)
|
||||
if (state.IsOutputVideo && !EnableCopyTs(state) && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && (state.Request.StartTimeTicks ?? 0) > 0)
|
||||
{
|
||||
timestampOffsetParam = " -output_ts_offset " + MediaEncoder.GetTimeParameter(state.Request.StartTimeTicks ?? 0).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
@ -978,36 +943,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
protected override bool EnableThrottling(StreamState state)
|
||||
{
|
||||
return !EnableSplitTranscoding(state);
|
||||
}
|
||||
|
||||
private bool EnableSplitTranscoding(StreamState state)
|
||||
{
|
||||
return false;
|
||||
if (string.Equals(Request.QueryString["EnableSplitTranscoding"], "false", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return state.RunTimeTicks.HasValue && state.IsOutputVideo;
|
||||
}
|
||||
|
||||
protected override bool EnableStreamCopy
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string GetAudioArguments(StreamState state)
|
||||
{
|
||||
var codec = GetAudioEncoder(state.Request);
|
||||
var codec = GetAudioEncoder(state);
|
||||
|
||||
if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -83,7 +83,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string GetVideoArguments(StreamState state)
|
||||
{
|
||||
var codec = GetVideoEncoder(state.VideoRequest);
|
||||
var codec = GetVideoEncoder(state);
|
||||
|
||||
var args = "-codec:v:0 " + codec;
|
||||
|
||||
|
@ -100,7 +100,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
args;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
|
||||
|
|
|
@ -91,6 +91,9 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
private readonly IFileSystem _fileSystem;
|
||||
private readonly TranscodingJob _job;
|
||||
|
||||
// 256k
|
||||
private const int BufferSize = 262144;
|
||||
|
||||
private long _bytesWritten = 0;
|
||||
|
||||
public ProgressiveFileCopier(IFileSystem fileSystem, TranscodingJob job)
|
||||
|
@ -108,7 +111,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
{
|
||||
while (eofCount < 15)
|
||||
{
|
||||
CopyToInternal(fs, outputStream, 81920);
|
||||
CopyToInternal(fs, outputStream, BufferSize);
|
||||
|
||||
var fsPosition = fs.Position;
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
|
||||
{
|
||||
// Get the output codec name
|
||||
var videoCodec = GetVideoEncoder(state.VideoRequest);
|
||||
var videoCodec = GetVideoEncoder(state);
|
||||
|
||||
var format = string.Empty;
|
||||
var keyFrame = string.Empty;
|
||||
|
@ -183,7 +183,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
}
|
||||
|
||||
// Get the output codec name
|
||||
var codec = GetAudioEncoder(state.Request);
|
||||
var codec = GetAudioEncoder(state);
|
||||
|
||||
var args = "-codec:a:0 " + codec;
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
private async void DisposeLiveStream()
|
||||
{
|
||||
if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Request.LiveStreamId))
|
||||
if ((MediaSource.RequiresClosing) && string.IsNullOrWhiteSpace(Request.LiveStreamId))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
259
MediaBrowser.Api/Reports/Activities/ReportActivitiesBuilder.cs
Normal file
259
MediaBrowser.Api/Reports/Activities/ReportActivitiesBuilder.cs
Normal file
|
@ -0,0 +1,259 @@
|
|||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Library;
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
/// <summary> A report activities builder. </summary>
|
||||
/// <seealso cref="T:MediaBrowser.Api.Reports.ReportBuilderBase"/>
|
||||
public class ReportActivitiesBuilder : ReportBuilderBase
|
||||
{
|
||||
#region [Constructors]
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportActivitiesBuilder class. </summary>
|
||||
/// <param name="libraryManager"> Manager for library. </param>
|
||||
/// <param name="userManager"> Manager for user. </param>
|
||||
public ReportActivitiesBuilder(ILibraryManager libraryManager, IUserManager userManager)
|
||||
: base(libraryManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region [Private Fields]
|
||||
|
||||
private readonly IUserManager _userManager; ///< Manager for user
|
||||
|
||||
#endregion
|
||||
|
||||
#region [Public Methods]
|
||||
|
||||
/// <summary> Gets a result. </summary>
|
||||
/// <param name="queryResult"> The query result. </param>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <returns> The result. </returns>
|
||||
public ReportResult GetResult(QueryResult<ActivityLogEntry> queryResult, IReportsQuery request)
|
||||
{
|
||||
ReportDisplayType displayType = ReportHelper.GetReportDisplayType(request.DisplayType);
|
||||
List<ReportOptions<ActivityLogEntry>> options = this.GetReportOptions<ActivityLogEntry>(request,
|
||||
() => this.GetDefaultHeaderMetadata(),
|
||||
(hm) => this.GetOption(hm)).Where(x => this.DisplayTypeVisible(x.Header.DisplayType, displayType)).ToList();
|
||||
|
||||
var headers = GetHeaders<ActivityLogEntry>(options);
|
||||
var rows = GetReportRows(queryResult.Items, options);
|
||||
|
||||
ReportResult result = new ReportResult { Headers = headers };
|
||||
HeaderMetadata groupBy = ReportHelper.GetHeaderMetadataType(request.GroupBy);
|
||||
int i = headers.FindIndex(x => x.FieldName == groupBy);
|
||||
if (groupBy != HeaderMetadata.None && i >= 0)
|
||||
{
|
||||
var rowsGroup = rows.SelectMany(x => x.Columns[i].Name.Split(';'), (x, g) => new { Group = g.Trim(), Rows = x })
|
||||
.GroupBy(x => x.Group)
|
||||
.OrderBy(x => x.Key)
|
||||
.Select(x => new ReportGroup { Name = x.Key, Rows = x.Select(r => r.Rows).ToList() });
|
||||
|
||||
result.Groups = rowsGroup.ToList();
|
||||
result.IsGrouped = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Rows = rows;
|
||||
result.IsGrouped = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region [Protected Internal Methods]
|
||||
|
||||
/// <summary> Gets the headers. </summary>
|
||||
/// <typeparam name="H"> Type of the header. </typeparam>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <returns> The headers. </returns>
|
||||
/// <seealso cref="M:MediaBrowser.Api.Reports.ReportBuilderBase.GetHeaders{H}(H)"/>
|
||||
protected internal override List<ReportHeader> GetHeaders<H>(H request)
|
||||
{
|
||||
return this.GetHeaders<ActivityLogEntry>(request, () => this.GetDefaultHeaderMetadata(), (hm) => this.GetOption(hm));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region [Private Methods]
|
||||
|
||||
/// <summary> Gets default header metadata. </summary>
|
||||
/// <returns> The default header metadata. </returns>
|
||||
private List<HeaderMetadata> GetDefaultHeaderMetadata()
|
||||
{
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.UserPrimaryImage,
|
||||
HeaderMetadata.Date,
|
||||
HeaderMetadata.User,
|
||||
HeaderMetadata.Type,
|
||||
HeaderMetadata.Severity,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.ShortOverview,
|
||||
HeaderMetadata.Overview,
|
||||
//HeaderMetadata.UserId
|
||||
//HeaderMetadata.Item,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary> Gets an option. </summary>
|
||||
/// <param name="header"> The header. </param>
|
||||
/// <param name="sortField"> The sort field. </param>
|
||||
/// <returns> The option. </returns>
|
||||
private ReportOptions<ActivityLogEntry> GetOption(HeaderMetadata header, string sortField = "")
|
||||
{
|
||||
HeaderMetadata internalHeader = header;
|
||||
|
||||
ReportOptions<ActivityLogEntry> option = new ReportOptions<ActivityLogEntry>()
|
||||
{
|
||||
Header = new ReportHeader
|
||||
{
|
||||
HeaderFieldType = ReportFieldType.String,
|
||||
SortField = sortField,
|
||||
Type = "",
|
||||
ItemViewType = ItemViewType.None
|
||||
}
|
||||
};
|
||||
|
||||
switch (header)
|
||||
{
|
||||
case HeaderMetadata.Name:
|
||||
option.Column = (i, r) => i.Name;
|
||||
option.Header.SortField = "";
|
||||
break;
|
||||
case HeaderMetadata.Overview:
|
||||
option.Column = (i, r) => i.Overview;
|
||||
option.Header.SortField = "";
|
||||
option.Header.CanGroup = false;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.ShortOverview:
|
||||
option.Column = (i, r) => i.ShortOverview;
|
||||
option.Header.SortField = "";
|
||||
option.Header.CanGroup = false;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Type:
|
||||
option.Column = (i, r) => i.Type;
|
||||
option.Header.SortField = "";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Date:
|
||||
option.Column = (i, r) => i.Date;
|
||||
option.Header.SortField = "";
|
||||
option.Header.HeaderFieldType = ReportFieldType.DateTime;
|
||||
option.Header.Type = "";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.UserPrimaryImage:
|
||||
//option.Column = (i, r) => i.UserPrimaryImageTag;
|
||||
option.Header.DisplayType = ReportDisplayType.Screen;
|
||||
option.Header.ItemViewType = ItemViewType.UserPrimaryImage;
|
||||
option.Header.ShowHeaderLabel = false;
|
||||
internalHeader = HeaderMetadata.User;
|
||||
option.Header.CanGroup = false;
|
||||
option.Column = (i, r) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(i.UserId))
|
||||
{
|
||||
MediaBrowser.Controller.Entities.User user = _userManager.GetUserById(i.UserId);
|
||||
if (user != null)
|
||||
{
|
||||
var dto = _userManager.GetUserDto(user);
|
||||
return dto.PrimaryImageTag;
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
};
|
||||
option.Header.SortField = "";
|
||||
break;
|
||||
case HeaderMetadata.Severity:
|
||||
option.Column = (i, r) => i.Severity;
|
||||
option.Header.SortField = "";
|
||||
break;
|
||||
case HeaderMetadata.Item:
|
||||
option.Column = (i, r) => i.ItemId;
|
||||
option.Header.SortField = "";
|
||||
break;
|
||||
case HeaderMetadata.User:
|
||||
option.Column = (i, r) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(i.UserId))
|
||||
{
|
||||
MediaBrowser.Controller.Entities.User user = _userManager.GetUserById(i.UserId);
|
||||
if (user != null)
|
||||
return user.Name;
|
||||
}
|
||||
return string.Empty;
|
||||
};
|
||||
option.Header.SortField = "";
|
||||
break;
|
||||
case HeaderMetadata.UserId:
|
||||
option.Column = (i, r) => i.UserId;
|
||||
option.Header.SortField = "";
|
||||
break;
|
||||
}
|
||||
|
||||
option.Header.Name = GetLocalizedHeader(internalHeader);
|
||||
option.Header.FieldName = header;
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
/// <summary> Gets report rows. </summary>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="options"> Options for controlling the operation. </param>
|
||||
/// <returns> The report rows. </returns>
|
||||
private List<ReportRow> GetReportRows(IEnumerable<ActivityLogEntry> items, List<ReportOptions<ActivityLogEntry>> options)
|
||||
{
|
||||
var rows = new List<ReportRow>();
|
||||
|
||||
foreach (ActivityLogEntry item in items)
|
||||
{
|
||||
ReportRow rRow = GetRow(item);
|
||||
foreach (ReportOptions<ActivityLogEntry> option in options)
|
||||
{
|
||||
object itemColumn = option.Column != null ? option.Column(item, rRow) : "";
|
||||
object itemId = option.ItemID != null ? option.ItemID(item) : "";
|
||||
ReportItem rItem = new ReportItem
|
||||
{
|
||||
Name = ReportHelper.ConvertToString(itemColumn, option.Header.HeaderFieldType),
|
||||
Id = ReportHelper.ConvertToString(itemId, ReportFieldType.Object)
|
||||
};
|
||||
rRow.Columns.Add(rItem);
|
||||
}
|
||||
|
||||
rows.Add(rRow);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
/// <summary> Gets a row. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The row. </returns>
|
||||
private ReportRow GetRow(ActivityLogEntry item)
|
||||
{
|
||||
ReportRow rRow = new ReportRow
|
||||
{
|
||||
Id = item.Id,
|
||||
UserId = item.UserId
|
||||
};
|
||||
return rRow;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
20
MediaBrowser.Api/Reports/Common/HeaderActivitiesMetadata.cs
Normal file
20
MediaBrowser.Api/Reports/Common/HeaderActivitiesMetadata.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
public enum HeaderActivitiesMetadata
|
||||
{
|
||||
None,
|
||||
Name,
|
||||
Overview,
|
||||
ShortOverview,
|
||||
Type,
|
||||
Date,
|
||||
UserPrimaryImageTag,
|
||||
Severity,
|
||||
Item,
|
||||
User
|
||||
}
|
||||
}
|
|
@ -35,13 +35,39 @@ namespace MediaBrowser.Api.Reports
|
|||
Subtitles,
|
||||
Genres,
|
||||
Countries,
|
||||
StatusImage,
|
||||
Status,
|
||||
Tracks,
|
||||
EpisodeSeries,
|
||||
EpisodeSeason,
|
||||
AudioAlbumArtist,
|
||||
MusicArtist,
|
||||
AudioAlbum,
|
||||
Status
|
||||
Locked,
|
||||
Unidentified,
|
||||
ImagePrimary,
|
||||
ImageBackdrop,
|
||||
ImageLogo,
|
||||
Actor,
|
||||
Studios,
|
||||
Composer,
|
||||
Director,
|
||||
GuestStar,
|
||||
Producer,
|
||||
Writer,
|
||||
Artist,
|
||||
Years,
|
||||
ParentalRatings,
|
||||
CommunityRatings,
|
||||
|
||||
//Activity logs
|
||||
Overview,
|
||||
ShortOverview,
|
||||
Type,
|
||||
Date,
|
||||
UserPrimaryImage,
|
||||
Severity,
|
||||
Item,
|
||||
User,
|
||||
UserId
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,23 @@ using System.Linq;
|
|||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
public enum ItemViewType
|
||||
{
|
||||
None,
|
||||
Detail,
|
||||
Edit,
|
||||
List,
|
||||
ItemByNameDetails,
|
||||
StatusImage,
|
||||
EmbeddedImage,
|
||||
SubtitleImage,
|
||||
TrailersImage,
|
||||
SpecialsImage
|
||||
}
|
||||
public enum ItemViewType
|
||||
{
|
||||
None,
|
||||
Detail,
|
||||
Edit,
|
||||
List,
|
||||
ItemByNameDetails,
|
||||
StatusImage,
|
||||
EmbeddedImage,
|
||||
SubtitleImage,
|
||||
TrailersImage,
|
||||
SpecialsImage,
|
||||
LockDataImage,
|
||||
UnidentifiedImage,
|
||||
TagsPrimaryImage,
|
||||
TagsBackdropImage,
|
||||
TagsLogoImage,
|
||||
UserPrimaryImage
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,217 +13,351 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
/// <summary> A report builder base. </summary>
|
||||
public class ReportBuilderBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportBuilderBase class. </summary>
|
||||
/// <param name="libraryManager"> Manager for library. </param>
|
||||
public ReportBuilderBase(ILibraryManager libraryManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
/// <summary> A report builder base. </summary>
|
||||
public abstract class ReportBuilderBase
|
||||
{
|
||||
|
||||
/// <summary> Manager for library. </summary>
|
||||
protected readonly ILibraryManager _libraryManager;
|
||||
#region [Constructors]
|
||||
|
||||
/// <summary> Gets audio stream. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The audio stream. </returns>
|
||||
protected string GetAudioStream(BaseItem item)
|
||||
{
|
||||
var stream = GetStream(item, MediaStreamType.Audio);
|
||||
if (stream != null)
|
||||
return stream.Codec.ToUpper() == "DCA" ? stream.Profile : stream.Codec.
|
||||
ToUpper();
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportBuilderBase class. </summary>
|
||||
/// <param name="libraryManager"> Manager for library. </param>
|
||||
public ReportBuilderBase(ILibraryManager libraryManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary> Gets an episode. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The episode. </returns>
|
||||
protected string GetEpisode(BaseItem item)
|
||||
{
|
||||
#region [Protected Fields]
|
||||
|
||||
if (item.GetClientTypeName() == ChannelMediaContentType.Episode.ToString() && item.ParentIndexNumber != null)
|
||||
return "Season " + item.ParentIndexNumber;
|
||||
else
|
||||
return item.Name;
|
||||
}
|
||||
/// <summary> Manager for library. </summary>
|
||||
protected readonly ILibraryManager _libraryManager; ///< Manager for library
|
||||
|
||||
/// <summary> Gets a genre. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The genre. </returns>
|
||||
protected Genre GetGenre(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return null;
|
||||
return _libraryManager.GetGenre(name);
|
||||
}
|
||||
protected Func<bool, string> GetBoolString = s => s == true ? "x" : ""; ///< .
|
||||
|
||||
/// <summary> Gets genre identifier. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The genre identifier. </returns>
|
||||
protected string GetGenreID(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return string.Empty;
|
||||
return string.Format("{0:N}",
|
||||
GetGenre(name).Id);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary> Gets list as string. </summary>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <returns> The list as string. </returns>
|
||||
protected string GetListAsString(List<string> items)
|
||||
{
|
||||
return String.Join("; ", items);
|
||||
}
|
||||
#region [Protected Internal Methods]
|
||||
|
||||
/// <summary> Gets media source information. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The media source information. </returns>
|
||||
protected MediaSourceInfo GetMediaSourceInfo(BaseItem item)
|
||||
{
|
||||
var mediaSource = item as IHasMediaSources;
|
||||
if (mediaSource != null)
|
||||
return mediaSource.GetMediaSources(false).FirstOrDefault(n => n.Type == MediaSourceType.Default);
|
||||
/// <summary> Gets the headers. </summary>
|
||||
/// <typeparam name="H"> Type of the header. </typeparam>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <returns> The headers. </returns>
|
||||
protected internal abstract List<ReportHeader> GetHeaders<H>(H request) where H : IReportsHeader;
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary> Gets an object. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <typeparam name="R"> Type of the r. </typeparam>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <param name="function"> The function. </param>
|
||||
/// <param name="defaultValue"> The default value. </param>
|
||||
/// <returns> The object. </returns>
|
||||
protected R GetObject<T, R>(BaseItem item, Func<T, R> function, R defaultValue = default(R)) where T : class
|
||||
{
|
||||
var value = item as T;
|
||||
if (value != null && function != null)
|
||||
return function(value);
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
#region [Protected Methods]
|
||||
|
||||
/// <summary> Gets a person. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The person. </returns>
|
||||
protected Person GetPerson(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return null;
|
||||
return _libraryManager.GetPerson(name);
|
||||
}
|
||||
/// <summary> Gets active headers. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <param name="options"> Options for controlling the operation. </param>
|
||||
/// <returns> The active headers. </returns>
|
||||
protected List<ReportHeader> GetActiveHeaders<T>(List<ReportOptions<T>> options, ReportDisplayType displayType)
|
||||
{
|
||||
List<ReportHeader> headers = new List<ReportHeader>();
|
||||
foreach (ReportOptions<T> option in options.Where(x => this.DisplayTypeVisible(x.Header.DisplayType, displayType)))
|
||||
{
|
||||
headers.Add(option.Header);
|
||||
}
|
||||
|
||||
/// <summary> Gets person identifier. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The person identifier. </returns>
|
||||
protected string GetPersonID(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return string.Empty;
|
||||
return string.Format("{0:N}",
|
||||
GetPerson(name).Id);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
/// <summary> Gets runtime date time. </summary>
|
||||
/// <param name="runtime"> The runtime. </param>
|
||||
/// <returns> The runtime date time. </returns>
|
||||
protected double? GetRuntimeDateTime(long? runtime)
|
||||
{
|
||||
if (runtime.HasValue)
|
||||
/// <summary> Gets audio stream. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The audio stream. </returns>
|
||||
protected string GetAudioStream(BaseItem item)
|
||||
{
|
||||
var stream = GetStream(item, MediaStreamType.Audio);
|
||||
if (stream != null)
|
||||
return stream.Codec.ToUpper() == "DCA" ? stream.Profile : stream.Codec.
|
||||
ToUpper();
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary> Gets an episode. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The episode. </returns>
|
||||
protected string GetEpisode(BaseItem item)
|
||||
{
|
||||
|
||||
if (item.GetClientTypeName() == ChannelMediaContentType.Episode.ToString() && item.ParentIndexNumber != null)
|
||||
return "Season " + item.ParentIndexNumber;
|
||||
else
|
||||
return item.Name;
|
||||
}
|
||||
|
||||
/// <summary> Gets a genre. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The genre. </returns>
|
||||
protected Genre GetGenre(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return null;
|
||||
return _libraryManager.GetGenre(name);
|
||||
}
|
||||
|
||||
/// <summary> Gets genre identifier. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The genre identifier. </returns>
|
||||
protected string GetGenreID(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return string.Empty;
|
||||
return string.Format("{0:N}",
|
||||
GetGenre(name).Id);
|
||||
}
|
||||
|
||||
/// <summary> Gets the headers. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <param name="options"> Options for controlling the operation. </param>
|
||||
/// <returns> The headers. </returns>
|
||||
protected List<ReportHeader> GetHeaders<T>(List<ReportOptions<T>> options)
|
||||
{
|
||||
List<ReportHeader> headers = new List<ReportHeader>();
|
||||
foreach (ReportOptions<T> option in options)
|
||||
{
|
||||
headers.Add(option.Header);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
/// <summary> Gets the headers. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <param name="getHeadersMetadata"> The get headers metadata. </param>
|
||||
/// <param name="getOptions"> Options for controlling the get. </param>
|
||||
/// <returns> The headers. </returns>
|
||||
protected List<ReportHeader> GetHeaders<T>(IReportsHeader request, Func<List<HeaderMetadata>> getHeadersMetadata, Func<HeaderMetadata, ReportOptions<T>> getOptions)
|
||||
{
|
||||
List<ReportOptions<T>> options = this.GetReportOptions(request, getHeadersMetadata, getOptions);
|
||||
return this.GetHeaders(options);
|
||||
}
|
||||
|
||||
/// <summary> Gets list as string. </summary>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <returns> The list as string. </returns>
|
||||
protected string GetListAsString(List<string> items)
|
||||
{
|
||||
return String.Join("; ", items);
|
||||
}
|
||||
|
||||
/// <summary> Gets localized header. </summary>
|
||||
/// <param name="internalHeader"> The internal header. </param>
|
||||
/// <returns> The localized header. </returns>
|
||||
protected static string GetLocalizedHeader(HeaderMetadata internalHeader)
|
||||
{
|
||||
string headerName = "";
|
||||
if (internalHeader != HeaderMetadata.None)
|
||||
{
|
||||
string localHeader = "Header" + internalHeader.ToString();
|
||||
headerName = ReportHelper.GetCoreLocalizedString(localHeader);
|
||||
}
|
||||
return headerName;
|
||||
}
|
||||
|
||||
/// <summary> Gets media source information. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The media source information. </returns>
|
||||
protected MediaSourceInfo GetMediaSourceInfo(BaseItem item)
|
||||
{
|
||||
var mediaSource = item as IHasMediaSources;
|
||||
if (mediaSource != null)
|
||||
return mediaSource.GetMediaSources(false).FirstOrDefault(n => n.Type == MediaSourceType.Default);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary> Gets an object. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <typeparam name="R"> Type of the r. </typeparam>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <param name="function"> The function. </param>
|
||||
/// <param name="defaultValue"> The default value. </param>
|
||||
/// <returns> The object. </returns>
|
||||
protected R GetObject<T, R>(BaseItem item, Func<T, R> function, R defaultValue = default(R)) where T : class
|
||||
{
|
||||
var value = item as T;
|
||||
if (value != null && function != null)
|
||||
return function(value);
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary> Gets a person. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The person. </returns>
|
||||
protected Person GetPerson(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return null;
|
||||
return _libraryManager.GetPerson(name);
|
||||
}
|
||||
|
||||
/// <summary> Gets person identifier. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The person identifier. </returns>
|
||||
protected string GetPersonID(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return string.Empty;
|
||||
return string.Format("{0:N}",
|
||||
GetPerson(name).Id);
|
||||
}
|
||||
|
||||
/// <summary> Gets report options. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <param name="getHeadersMetadata"> The get headers metadata. </param>
|
||||
/// <param name="getOptions"> Options for controlling the get. </param>
|
||||
/// <returns> The report options. </returns>
|
||||
protected List<ReportOptions<T>> GetReportOptions<T>(IReportsHeader request, Func<List<HeaderMetadata>> getHeadersMetadata, Func<HeaderMetadata, ReportOptions<T>> getOptions)
|
||||
{
|
||||
List<HeaderMetadata> headersMetadata = getHeadersMetadata();
|
||||
List<ReportOptions<T>> options = new List<ReportOptions<T>>();
|
||||
ReportDisplayType displayType = ReportHelper.GetReportDisplayType(request.DisplayType);
|
||||
foreach (HeaderMetadata header in headersMetadata)
|
||||
{
|
||||
ReportOptions<T> headerOptions = getOptions(header);
|
||||
if (this.DisplayTypeVisible(headerOptions.Header.DisplayType, displayType))
|
||||
options.Add(headerOptions);
|
||||
}
|
||||
|
||||
if (request != null && !string.IsNullOrEmpty(request.ReportColumns))
|
||||
{
|
||||
List<HeaderMetadata> headersMetadataFiltered = ReportHelper.GetFilteredReportHeaderMetadata(request.ReportColumns, () => headersMetadata);
|
||||
foreach (ReportHeader header in options.Select(x => x.Header))
|
||||
{
|
||||
|
||||
if (this.DisplayTypeVisible(header.DisplayType, displayType))
|
||||
{
|
||||
|
||||
if (!headersMetadataFiltered.Contains(header.FieldName) && displayType != ReportDisplayType.Export)
|
||||
{
|
||||
header.DisplayType = ReportDisplayType.None;
|
||||
}
|
||||
}
|
||||
else
|
||||
header.DisplayType = ReportDisplayType.None;
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <summary> Gets runtime date time. </summary>
|
||||
/// <param name="runtime"> The runtime. </param>
|
||||
/// <returns> The runtime date time. </returns>
|
||||
protected double? GetRuntimeDateTime(long? runtime)
|
||||
{
|
||||
if (runtime.HasValue)
|
||||
return Math.Ceiling(new TimeSpan(runtime.Value).TotalMinutes);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary> Gets series production year. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The series production year. </returns>
|
||||
protected string GetSeriesProductionYear(BaseItem item)
|
||||
{
|
||||
/// <summary> Gets series production year. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The series production year. </returns>
|
||||
protected string GetSeriesProductionYear(BaseItem item)
|
||||
{
|
||||
|
||||
string productionYear = item.ProductionYear.ToString();
|
||||
var series = item as Series;
|
||||
if (series == null)
|
||||
{
|
||||
if (item.ProductionYear == null || item.ProductionYear == 0)
|
||||
return string.Empty;
|
||||
return productionYear;
|
||||
}
|
||||
string productionYear = item.ProductionYear.ToString();
|
||||
var series = item as Series;
|
||||
if (series == null)
|
||||
{
|
||||
if (item.ProductionYear == null || item.ProductionYear == 0)
|
||||
return string.Empty;
|
||||
return productionYear;
|
||||
}
|
||||
|
||||
if (series.Status == SeriesStatus.Continuing)
|
||||
return productionYear += "-Present";
|
||||
if (series.Status == SeriesStatus.Continuing)
|
||||
return productionYear += "-Present";
|
||||
|
||||
if (series.EndDate != null && series.EndDate.Value.Year != series.ProductionYear)
|
||||
return productionYear += "-" + series.EndDate.Value.Year;
|
||||
if (series.EndDate != null && series.EndDate.Value.Year != series.ProductionYear)
|
||||
return productionYear += "-" + series.EndDate.Value.Year;
|
||||
|
||||
return productionYear;
|
||||
}
|
||||
return productionYear;
|
||||
}
|
||||
|
||||
/// <summary> Gets a stream. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <param name="streamType"> Type of the stream. </param>
|
||||
/// <returns> The stream. </returns>
|
||||
protected MediaStream GetStream(BaseItem item, MediaStreamType streamType)
|
||||
{
|
||||
var itemInfo = GetMediaSourceInfo(item);
|
||||
if (itemInfo != null)
|
||||
return itemInfo.MediaStreams.FirstOrDefault(n => n.Type == streamType);
|
||||
/// <summary> Gets a stream. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <param name="streamType"> Type of the stream. </param>
|
||||
/// <returns> The stream. </returns>
|
||||
protected MediaStream GetStream(BaseItem item, MediaStreamType streamType)
|
||||
{
|
||||
var itemInfo = GetMediaSourceInfo(item);
|
||||
if (itemInfo != null)
|
||||
return itemInfo.MediaStreams.FirstOrDefault(n => n.Type == streamType);
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary> Gets a studio. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The studio. </returns>
|
||||
protected Studio GetStudio(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return null;
|
||||
return _libraryManager.GetStudio(name);
|
||||
}
|
||||
/// <summary> Gets a studio. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The studio. </returns>
|
||||
protected Studio GetStudio(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return null;
|
||||
return _libraryManager.GetStudio(name);
|
||||
}
|
||||
|
||||
/// <summary> Gets studio identifier. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The studio identifier. </returns>
|
||||
protected string GetStudioID(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return string.Empty;
|
||||
return string.Format("{0:N}",
|
||||
GetStudio(name).Id);
|
||||
}
|
||||
/// <summary> Gets studio identifier. </summary>
|
||||
/// <param name="name"> The name. </param>
|
||||
/// <returns> The studio identifier. </returns>
|
||||
protected string GetStudioID(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return string.Empty;
|
||||
return string.Format("{0:N}",
|
||||
GetStudio(name).Id);
|
||||
}
|
||||
|
||||
/// <summary> Gets video resolution. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The video resolution. </returns>
|
||||
protected string GetVideoResolution(BaseItem item)
|
||||
{
|
||||
var stream = GetStream(item,
|
||||
MediaStreamType.Video);
|
||||
if (stream != null && stream.Width != null)
|
||||
return string.Format("{0} * {1}",
|
||||
stream.Width,
|
||||
(stream.Height != null ? stream.Height.ToString() : "-"));
|
||||
/// <summary> Gets video resolution. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The video resolution. </returns>
|
||||
protected string GetVideoResolution(BaseItem item)
|
||||
{
|
||||
var stream = GetStream(item,
|
||||
MediaStreamType.Video);
|
||||
if (stream != null && stream.Width != null)
|
||||
return string.Format("{0} * {1}",
|
||||
stream.Width,
|
||||
(stream.Height != null ? stream.Height.ToString() : "-"));
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary> Gets video stream. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The video stream. </returns>
|
||||
protected string GetVideoStream(BaseItem item)
|
||||
{
|
||||
var stream = GetStream(item, MediaStreamType.Video);
|
||||
if (stream != null)
|
||||
return stream.Codec.ToUpper();
|
||||
/// <summary> Gets video stream. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The video stream. </returns>
|
||||
protected string GetVideoStream(BaseItem item)
|
||||
{
|
||||
var stream = GetStream(item, MediaStreamType.Video);
|
||||
if (stream != null)
|
||||
return stream.Codec.ToUpper();
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary> Displays a type visible. </summary>
|
||||
/// <param name="headerDisplayType"> Type of the header display. </param>
|
||||
/// <param name="displayType"> Type of the display. </param>
|
||||
/// <returns> true if it succeeds, false if it fails. </returns>
|
||||
protected bool DisplayTypeVisible(ReportDisplayType headerDisplayType, ReportDisplayType displayType)
|
||||
{
|
||||
if (headerDisplayType == ReportDisplayType.None)
|
||||
return false;
|
||||
|
||||
bool rval = headerDisplayType == displayType || headerDisplayType == ReportDisplayType.ScreenExport && (displayType == ReportDisplayType.Screen || displayType == ReportDisplayType.Export);
|
||||
return rval;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
14
MediaBrowser.Api/Reports/Common/ReportDisplayType.cs
Normal file
14
MediaBrowser.Api/Reports/Common/ReportDisplayType.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
public enum ReportDisplayType
|
||||
{
|
||||
None,
|
||||
Screen,
|
||||
Export,
|
||||
ScreenExport
|
||||
}
|
||||
}
|
|
@ -2,100 +2,137 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
public class ReportHelper
|
||||
{
|
||||
/// <summary> Gets java script localized string. </summary>
|
||||
/// <param name="phrase"> The phrase. </param>
|
||||
/// <returns> The java script localized string. </returns>
|
||||
public static string GetJavaScriptLocalizedString(string phrase)
|
||||
{
|
||||
var dictionary = BaseItem.LocalizationManager.GetJavaScriptLocalizationDictionary(BaseItem.ConfigurationManager.Configuration.UICulture);
|
||||
/// <summary> A report helper. </summary>
|
||||
public class ReportHelper
|
||||
{
|
||||
#region [Public Methods]
|
||||
|
||||
string value;
|
||||
|
||||
if (dictionary.TryGetValue(phrase, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return phrase;
|
||||
}
|
||||
|
||||
/// <summary> Gets server localized string. </summary>
|
||||
/// <param name="phrase"> The phrase. </param>
|
||||
/// <returns> The server localized string. </returns>
|
||||
public static string GetServerLocalizedString(string phrase)
|
||||
{
|
||||
return BaseItem.LocalizationManager.GetLocalizedString(phrase, BaseItem.ConfigurationManager.Configuration.UICulture);
|
||||
}
|
||||
|
||||
/// <summary> Gets row type. </summary>
|
||||
/// <param name="rowType"> The type. </param>
|
||||
/// <returns> The row type. </returns>
|
||||
public static ReportViewType GetRowType(string rowType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(rowType))
|
||||
return ReportViewType.BaseItem;
|
||||
|
||||
ReportViewType rType;
|
||||
|
||||
if (!Enum.TryParse<ReportViewType>(rowType, out rType))
|
||||
return ReportViewType.BaseItem;
|
||||
|
||||
return rType;
|
||||
}
|
||||
|
||||
/// <summary> Gets header metadata type. </summary>
|
||||
/// <param name="header"> The header. </param>
|
||||
/// <returns> The header metadata type. </returns>
|
||||
public static HeaderMetadata GetHeaderMetadataType(string header)
|
||||
{
|
||||
if (string.IsNullOrEmpty(header))
|
||||
return HeaderMetadata.None;
|
||||
|
||||
HeaderMetadata rType;
|
||||
|
||||
if (!Enum.TryParse<HeaderMetadata>(header, out rType))
|
||||
return HeaderMetadata.None;
|
||||
|
||||
return rType;
|
||||
}
|
||||
|
||||
/// <summary> Convert field to string. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <param name="value"> The value. </param>
|
||||
/// <param name="fieldType"> Type of the field. </param>
|
||||
/// <returns> The field converted to string. </returns>
|
||||
public static string ConvertToString<T>(T value, ReportFieldType fieldType)
|
||||
{
|
||||
if (value == null)
|
||||
return "";
|
||||
switch (fieldType)
|
||||
{
|
||||
case ReportFieldType.String:
|
||||
return value.ToString();
|
||||
case ReportFieldType.Boolean:
|
||||
return value.ToString();
|
||||
case ReportFieldType.Date:
|
||||
return string.Format("{0:d}", value);
|
||||
case ReportFieldType.Time:
|
||||
return string.Format("{0:t}", value);
|
||||
case ReportFieldType.DateTime:
|
||||
return string.Format("{0:d}", value);
|
||||
/// <summary> Convert field to string. </summary>
|
||||
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||
/// <param name="value"> The value. </param>
|
||||
/// <param name="fieldType"> Type of the field. </param>
|
||||
/// <returns> The field converted to string. </returns>
|
||||
public static string ConvertToString<T>(T value, ReportFieldType fieldType)
|
||||
{
|
||||
if (value == null)
|
||||
return "";
|
||||
switch (fieldType)
|
||||
{
|
||||
case ReportFieldType.String:
|
||||
return value.ToString();
|
||||
case ReportFieldType.Boolean:
|
||||
return value.ToString();
|
||||
case ReportFieldType.Date:
|
||||
return string.Format("{0:d}", value);
|
||||
case ReportFieldType.Time:
|
||||
return string.Format("{0:t}", value);
|
||||
case ReportFieldType.DateTime:
|
||||
return string.Format("{0:d}", value);
|
||||
case ReportFieldType.Minutes:
|
||||
return string.Format("{0}mn", value);
|
||||
case ReportFieldType.Int:
|
||||
return string.Format("", value);
|
||||
default:
|
||||
if (value is Guid)
|
||||
return string.Format("{0:N}", value);
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
case ReportFieldType.Int:
|
||||
return string.Format("", value);
|
||||
default:
|
||||
if (value is Guid)
|
||||
return string.Format("{0:N}", value);
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Gets filtered report header metadata. </summary>
|
||||
/// <param name="reportColumns"> The report columns. </param>
|
||||
/// <param name="defaultReturnValue"> The default return value. </param>
|
||||
/// <returns> The filtered report header metadata. </returns>
|
||||
public static List<HeaderMetadata> GetFilteredReportHeaderMetadata(string reportColumns, Func<List<HeaderMetadata>> defaultReturnValue = null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(reportColumns))
|
||||
{
|
||||
var s = reportColumns.Split('|').Select(x => ReportHelper.GetHeaderMetadataType(x)).Where(x => x != HeaderMetadata.None);
|
||||
return s.ToList();
|
||||
}
|
||||
else
|
||||
if (defaultReturnValue != null)
|
||||
return defaultReturnValue();
|
||||
else
|
||||
return new List<HeaderMetadata>();
|
||||
}
|
||||
|
||||
/// <summary> Gets header metadata type. </summary>
|
||||
/// <param name="header"> The header. </param>
|
||||
/// <returns> The header metadata type. </returns>
|
||||
public static HeaderMetadata GetHeaderMetadataType(string header)
|
||||
{
|
||||
if (string.IsNullOrEmpty(header))
|
||||
return HeaderMetadata.None;
|
||||
|
||||
HeaderMetadata rType;
|
||||
|
||||
if (!Enum.TryParse<HeaderMetadata>(header, out rType))
|
||||
return HeaderMetadata.None;
|
||||
|
||||
return rType;
|
||||
}
|
||||
|
||||
/// <summary> Gets report view type. </summary>
|
||||
/// <param name="rowType"> The type. </param>
|
||||
/// <returns> The report view type. </returns>
|
||||
public static ReportViewType GetReportViewType(string rowType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(rowType))
|
||||
return ReportViewType.ReportData;
|
||||
|
||||
ReportViewType rType;
|
||||
|
||||
if (!Enum.TryParse<ReportViewType>(rowType, out rType))
|
||||
return ReportViewType.ReportData;
|
||||
|
||||
return rType;
|
||||
}
|
||||
|
||||
/// <summary> Gets row type. </summary>
|
||||
/// <param name="rowType"> The type. </param>
|
||||
/// <returns> The row type. </returns>
|
||||
public static ReportIncludeItemTypes GetRowType(string rowType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(rowType))
|
||||
return ReportIncludeItemTypes.BaseItem;
|
||||
|
||||
ReportIncludeItemTypes rType;
|
||||
|
||||
if (!Enum.TryParse<ReportIncludeItemTypes>(rowType, out rType))
|
||||
return ReportIncludeItemTypes.BaseItem;
|
||||
|
||||
return rType;
|
||||
}
|
||||
|
||||
/// <summary> Gets report display type. </summary>
|
||||
/// <param name="displayType"> Type of the display. </param>
|
||||
/// <returns> The report display type. </returns>
|
||||
public static ReportDisplayType GetReportDisplayType(string displayType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(displayType))
|
||||
return ReportDisplayType.ScreenExport;
|
||||
|
||||
ReportDisplayType rType;
|
||||
|
||||
if (!Enum.TryParse<ReportDisplayType>(displayType, out rType))
|
||||
return ReportDisplayType.ScreenExport;
|
||||
|
||||
return rType;
|
||||
}
|
||||
|
||||
/// <summary> Gets core localized string. </summary>
|
||||
/// <param name="phrase"> The phrase. </param>
|
||||
/// <returns> The core localized string. </returns>
|
||||
public static string GetCoreLocalizedString(string phrase)
|
||||
{
|
||||
return BaseItem.LocalizationManager.GetLocalizedString(phrase);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
25
MediaBrowser.Api/Reports/Common/ReportIncludeItemTypes.cs
Normal file
25
MediaBrowser.Api/Reports/Common/ReportIncludeItemTypes.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
public enum ReportIncludeItemTypes
|
||||
{
|
||||
MusicArtist,
|
||||
MusicAlbum,
|
||||
Book,
|
||||
BoxSet,
|
||||
Episode,
|
||||
Game,
|
||||
Video,
|
||||
Movie,
|
||||
MusicVideo,
|
||||
Trailer,
|
||||
Season,
|
||||
Series,
|
||||
Audio,
|
||||
BaseItem,
|
||||
Artist
|
||||
}
|
||||
}
|
|
@ -6,20 +6,9 @@ namespace MediaBrowser.Api.Reports
|
|||
{
|
||||
public enum ReportViewType
|
||||
{
|
||||
MusicArtist,
|
||||
MusicAlbum,
|
||||
Book,
|
||||
BoxSet,
|
||||
Episode,
|
||||
Game,
|
||||
Video,
|
||||
Movie,
|
||||
MusicVideo,
|
||||
Trailer,
|
||||
Season,
|
||||
Series,
|
||||
Audio,
|
||||
BaseItem,
|
||||
Artist
|
||||
ReportData,
|
||||
ReportStatistics,
|
||||
ReportActivities
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,164 +17,98 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
/// <summary> A report builder. </summary>
|
||||
/// <seealso cref="T:MediaBrowser.Api.Reports.ReportBuilderBase"/>
|
||||
public class ReportBuilder : ReportBuilderBase
|
||||
{
|
||||
/// <summary> A report builder. </summary>
|
||||
/// <seealso cref="T:MediaBrowser.Api.Reports.ReportBuilderBase"/>
|
||||
public class ReportBuilder : ReportBuilderBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportBuilder class. </summary>
|
||||
/// <param name="libraryManager"> Manager for library. </param>
|
||||
public ReportBuilder(ILibraryManager libraryManager)
|
||||
: base(libraryManager)
|
||||
{
|
||||
}
|
||||
#region [Constructors]
|
||||
|
||||
private Func<bool, string> GetBoolString = s => s == true ? "x" : "";
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportBuilder class. </summary>
|
||||
/// <param name="libraryManager"> Manager for library. </param>
|
||||
public ReportBuilder(ILibraryManager libraryManager)
|
||||
: base(libraryManager)
|
||||
{
|
||||
}
|
||||
|
||||
public ReportResult GetReportResult(BaseItem[] items, ReportViewType reportRowType, BaseReportRequest request)
|
||||
{
|
||||
List<HeaderMetadata> headersMetadata = this.GetFilteredReportHeaderMetadata(reportRowType, request);
|
||||
#endregion
|
||||
|
||||
var headers = GetReportHeaders(reportRowType, headersMetadata);
|
||||
var rows = GetReportRows(items, headersMetadata);
|
||||
#region [Public Methods]
|
||||
|
||||
ReportResult result = new ReportResult { Headers = headers };
|
||||
HeaderMetadata groupBy = ReportHelper.GetHeaderMetadataType(request.GroupBy);
|
||||
int i = headers.FindIndex(x => x.FieldName == groupBy);
|
||||
if (groupBy != HeaderMetadata.None && i > 0)
|
||||
{
|
||||
var rowsGroup = rows.SelectMany(x => x.Columns[i].Name.Split(';'), (x, g) => new { Genre = g.Trim(), Rows = x })
|
||||
.GroupBy(x => x.Genre)
|
||||
.OrderBy(x => x.Key)
|
||||
.Select(x => new ReportGroup { Name = x.Key, Rows = x.Select(r => r.Rows).ToList() });
|
||||
/// <summary> Gets report result. </summary>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <returns> The report result. </returns>
|
||||
public ReportResult GetResult(BaseItem[] items, IReportsQuery request)
|
||||
{
|
||||
ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
|
||||
ReportDisplayType displayType = ReportHelper.GetReportDisplayType(request.DisplayType);
|
||||
|
||||
result.Groups = rowsGroup.ToList();
|
||||
result.IsGrouped = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Rows = rows;
|
||||
result.IsGrouped = false;
|
||||
}
|
||||
List<ReportOptions<BaseItem>> options = this.GetReportOptions<BaseItem>(request,
|
||||
() => this.GetDefaultHeaderMetadata(reportRowType),
|
||||
(hm) => this.GetOption(hm)).Where(x => this.DisplayTypeVisible(x.Header.DisplayType, displayType)).ToList();
|
||||
|
||||
return result;
|
||||
}
|
||||
var headers = GetHeaders<BaseItem>(options);
|
||||
var rows = GetReportRows(items, options);
|
||||
|
||||
public List<ReportHeader> GetReportHeaders(ReportViewType reportRowType, BaseReportRequest request)
|
||||
{
|
||||
List<ReportHeader> headersMetadata = this.GetReportHeaders(reportRowType);
|
||||
if (request != null && !string.IsNullOrEmpty(request.ReportColumns))
|
||||
{
|
||||
List<HeaderMetadata> headersMetadataFiltered = this.GetFilteredReportHeaderMetadata(reportRowType, request);
|
||||
foreach (ReportHeader reportHeader in headersMetadata)
|
||||
{
|
||||
if (!headersMetadataFiltered.Contains(reportHeader.FieldName))
|
||||
ReportResult result = new ReportResult { Headers = headers };
|
||||
HeaderMetadata groupBy = ReportHelper.GetHeaderMetadataType(request.GroupBy);
|
||||
int i = headers.FindIndex(x => x.FieldName == groupBy);
|
||||
if (groupBy != HeaderMetadata.None && i >= 0)
|
||||
{
|
||||
var rowsGroup = rows.SelectMany(x => x.Columns[i].Name.Split(';'), (x, g) => new { Group = g.Trim(), Rows = x })
|
||||
.GroupBy(x => x.Group)
|
||||
.OrderBy(x => x.Key)
|
||||
.Select(x => new ReportGroup { Name = x.Key, Rows = x.Select(r => r.Rows).ToList() });
|
||||
|
||||
result.Groups = rowsGroup.ToList();
|
||||
result.IsGrouped = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Rows = rows;
|
||||
result.IsGrouped = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region [Protected Internal Methods]
|
||||
|
||||
/// <summary> Gets the headers. </summary>
|
||||
/// <typeparam name="H"> Type of the header. </typeparam>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <returns> The headers. </returns>
|
||||
/// <seealso cref="M:MediaBrowser.Api.Reports.ReportBuilderBase.GetHeaders{H}(H)"/>
|
||||
protected internal override List<ReportHeader> GetHeaders<H>(H request)
|
||||
{
|
||||
ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
|
||||
return this.GetHeaders<BaseItem>(request, () => this.GetDefaultHeaderMetadata(reportRowType), (hm) => this.GetOption(hm));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region [Private Methods]
|
||||
|
||||
/// <summary> Gets default report header metadata. </summary>
|
||||
/// <param name="reportIncludeItemTypes"> Type of the report row. </param>
|
||||
/// <returns> The default report header metadata. </returns>
|
||||
private List<HeaderMetadata> GetDefaultHeaderMetadata(ReportIncludeItemTypes reportIncludeItemTypes)
|
||||
{
|
||||
switch (reportIncludeItemTypes)
|
||||
{
|
||||
case ReportIncludeItemTypes.Season:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
reportHeader.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return headersMetadata;
|
||||
}
|
||||
|
||||
public List<ReportHeader> GetReportHeaders(ReportViewType reportRowType, List<HeaderMetadata> headersMetadata = null)
|
||||
{
|
||||
if (headersMetadata == null)
|
||||
headersMetadata = this.GetDefaultReportHeaderMetadata(reportRowType);
|
||||
|
||||
List<ReportOptions<BaseItem>> options = new List<ReportOptions<BaseItem>>();
|
||||
foreach (HeaderMetadata header in headersMetadata)
|
||||
{
|
||||
options.Add(GetReportOption(header));
|
||||
}
|
||||
|
||||
|
||||
List<ReportHeader> headers = new List<ReportHeader>();
|
||||
foreach (ReportOptions<BaseItem> option in options)
|
||||
{
|
||||
headers.Add(option.Header);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
private List<ReportRow> GetReportRows(IEnumerable<BaseItem> items, List<HeaderMetadata> headersMetadata)
|
||||
{
|
||||
List<ReportOptions<BaseItem>> options = new List<ReportOptions<BaseItem>>();
|
||||
foreach (HeaderMetadata header in headersMetadata)
|
||||
{
|
||||
options.Add(GetReportOption(header));
|
||||
}
|
||||
|
||||
var rows = new List<ReportRow>();
|
||||
|
||||
foreach (BaseItem item in items)
|
||||
{
|
||||
ReportRow rRow = GetRow(item);
|
||||
foreach (ReportOptions<BaseItem> option in options)
|
||||
{
|
||||
object itemColumn = option.Column != null ? option.Column(item, rRow) : "";
|
||||
object itemId = option.ItemID != null ? option.ItemID(item) : "";
|
||||
ReportItem rItem = new ReportItem
|
||||
{
|
||||
Name = ReportHelper.ConvertToString(itemColumn, option.Header.HeaderFieldType),
|
||||
Id = ReportHelper.ConvertToString(itemId, ReportFieldType.Object)
|
||||
};
|
||||
rRow.Columns.Add(rItem);
|
||||
}
|
||||
|
||||
rows.Add(rRow);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
/// <summary> Gets a row. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The row. </returns>
|
||||
private ReportRow GetRow(BaseItem item)
|
||||
{
|
||||
var hasTrailers = item as IHasTrailers;
|
||||
var hasSpecialFeatures = item as IHasSpecialFeatures;
|
||||
var video = item as Video;
|
||||
ReportRow rRow = new ReportRow
|
||||
{
|
||||
Id = item.Id.ToString("N"),
|
||||
HasLockData = item.IsLocked,
|
||||
IsUnidentified = item.IsUnidentified,
|
||||
HasLocalTrailer = hasTrailers != null ? hasTrailers.GetTrailerIds().Count() > 0 : false,
|
||||
HasImageTagsPrimary = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Primary) > 0),
|
||||
HasImageTagsBackdrop = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Backdrop) > 0),
|
||||
HasImageTagsLogo = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Logo) > 0),
|
||||
HasSpecials = hasSpecialFeatures != null ? hasSpecialFeatures.SpecialFeatureIds.Count > 0 : false,
|
||||
HasSubtitles = video != null ? video.HasSubtitles : false,
|
||||
RowType = ReportHelper.GetRowType(item.GetClientTypeName())
|
||||
};
|
||||
return rRow;
|
||||
}
|
||||
public List<HeaderMetadata> GetFilteredReportHeaderMetadata(ReportViewType reportRowType, BaseReportRequest request)
|
||||
{
|
||||
if (request != null && !string.IsNullOrEmpty(request.ReportColumns))
|
||||
{
|
||||
var s = request.ReportColumns.Split('|').Select(x => ReportHelper.GetHeaderMetadataType(x)).Where(x => x != HeaderMetadata.None);
|
||||
return s.ToList();
|
||||
}
|
||||
else
|
||||
return this.GetDefaultReportHeaderMetadata(reportRowType);
|
||||
|
||||
}
|
||||
|
||||
public List<HeaderMetadata> GetDefaultReportHeaderMetadata(ReportViewType reportRowType)
|
||||
{
|
||||
switch (reportRowType)
|
||||
{
|
||||
case ReportViewType.Season:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Series,
|
||||
HeaderMetadata.Season,
|
||||
HeaderMetadata.SeasonNumber,
|
||||
|
@ -183,10 +117,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Genres
|
||||
};
|
||||
|
||||
case ReportViewType.Series:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.Series:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.Network,
|
||||
HeaderMetadata.DateAdded,
|
||||
|
@ -199,10 +138,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Specials
|
||||
};
|
||||
|
||||
case ReportViewType.MusicAlbum:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.MusicAlbum:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.AlbumArtist,
|
||||
HeaderMetadata.DateAdded,
|
||||
|
@ -212,10 +156,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Genres
|
||||
};
|
||||
|
||||
case ReportViewType.MusicArtist:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.MusicArtist:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.MusicArtist,
|
||||
HeaderMetadata.Countries,
|
||||
HeaderMetadata.DateAdded,
|
||||
|
@ -223,10 +172,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Genres
|
||||
};
|
||||
|
||||
case ReportViewType.Game:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.Game:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.GameSystem,
|
||||
HeaderMetadata.DateAdded,
|
||||
|
@ -239,10 +193,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Trailers
|
||||
};
|
||||
|
||||
case ReportViewType.Movie:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.Movie:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.DateAdded,
|
||||
HeaderMetadata.ReleaseDate,
|
||||
|
@ -259,10 +218,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Specials
|
||||
};
|
||||
|
||||
case ReportViewType.Book:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.Book:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.DateAdded,
|
||||
HeaderMetadata.ReleaseDate,
|
||||
|
@ -272,10 +236,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.CommunityRating
|
||||
};
|
||||
|
||||
case ReportViewType.BoxSet:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.BoxSet:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.DateAdded,
|
||||
HeaderMetadata.ReleaseDate,
|
||||
|
@ -286,10 +255,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Trailers
|
||||
};
|
||||
|
||||
case ReportViewType.Audio:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.Audio:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.AudioAlbumArtist,
|
||||
HeaderMetadata.AudioAlbum,
|
||||
|
@ -305,10 +279,15 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Audio
|
||||
};
|
||||
|
||||
case ReportViewType.Episode:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.Episode:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.EpisodeSeries,
|
||||
HeaderMetadata.Season,
|
||||
|
@ -327,14 +306,23 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Specials
|
||||
};
|
||||
|
||||
case ReportViewType.Video:
|
||||
case ReportViewType.MusicVideo:
|
||||
case ReportViewType.Trailer:
|
||||
case ReportViewType.BaseItem:
|
||||
default:
|
||||
return new List<HeaderMetadata>
|
||||
case ReportIncludeItemTypes.Video:
|
||||
case ReportIncludeItemTypes.MusicVideo:
|
||||
case ReportIncludeItemTypes.Trailer:
|
||||
case ReportIncludeItemTypes.BaseItem:
|
||||
default:
|
||||
return new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.StatusImage,
|
||||
HeaderMetadata.Status,
|
||||
HeaderMetadata.Locked,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Unidentified,
|
||||
HeaderMetadata.ImagePrimary,
|
||||
HeaderMetadata.ImageBackdrop,
|
||||
HeaderMetadata.ImageLogo,
|
||||
HeaderMetadata.Name,
|
||||
HeaderMetadata.DateAdded,
|
||||
HeaderMetadata.ReleaseDate,
|
||||
|
@ -351,239 +339,313 @@ namespace MediaBrowser.Api.Reports
|
|||
HeaderMetadata.Specials
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Gets report option. </summary>
|
||||
/// <param name="header"> The header. </param>
|
||||
/// <param name="sortField"> The sort field. </param>
|
||||
/// <returns> The report option. </returns>
|
||||
private ReportOptions<BaseItem> GetReportOption(HeaderMetadata header, string sortField = "")
|
||||
{
|
||||
ReportHeader reportHeader = new ReportHeader
|
||||
{
|
||||
HeaderFieldType = ReportFieldType.String,
|
||||
SortField = sortField,
|
||||
Type = "",
|
||||
ItemViewType = ItemViewType.None
|
||||
};
|
||||
/// <summary> Gets report option. </summary>
|
||||
/// <param name="header"> The header. </param>
|
||||
/// <param name="sortField"> The sort field. </param>
|
||||
/// <returns> The report option. </returns>
|
||||
private ReportOptions<BaseItem> GetOption(HeaderMetadata header, string sortField = "")
|
||||
{
|
||||
HeaderMetadata internalHeader = header;
|
||||
|
||||
Func<BaseItem, ReportRow, object> column = null;
|
||||
Func<BaseItem, object> itemId = null;
|
||||
HeaderMetadata internalHeader = header;
|
||||
ReportOptions<BaseItem> option = new ReportOptions<BaseItem>()
|
||||
{
|
||||
Header = new ReportHeader
|
||||
{
|
||||
HeaderFieldType = ReportFieldType.String,
|
||||
SortField = sortField,
|
||||
Type = "",
|
||||
ItemViewType = ItemViewType.None
|
||||
}
|
||||
};
|
||||
|
||||
switch (header)
|
||||
{
|
||||
case HeaderMetadata.StatusImage:
|
||||
reportHeader.ItemViewType = ItemViewType.StatusImage;
|
||||
internalHeader = HeaderMetadata.Status;
|
||||
reportHeader.CanGroup = false;
|
||||
break;
|
||||
switch (header)
|
||||
{
|
||||
case HeaderMetadata.Status:
|
||||
option.Header.ItemViewType = ItemViewType.StatusImage;
|
||||
internalHeader = HeaderMetadata.Status;
|
||||
option.Header.CanGroup = false;
|
||||
option.Header.DisplayType = ReportDisplayType.Screen;
|
||||
break;
|
||||
case HeaderMetadata.Locked:
|
||||
option.Column = (i, r) => this.GetBoolString(r.HasLockData);
|
||||
option.Header.ItemViewType = ItemViewType.LockDataImage;
|
||||
option.Header.CanGroup = false;
|
||||
option.Header.DisplayType = ReportDisplayType.Export;
|
||||
break;
|
||||
case HeaderMetadata.Unidentified:
|
||||
option.Column = (i, r) => this.GetBoolString(r.IsUnidentified);
|
||||
option.Header.ItemViewType = ItemViewType.UnidentifiedImage;
|
||||
option.Header.CanGroup = false;
|
||||
option.Header.DisplayType = ReportDisplayType.Export;
|
||||
break;
|
||||
case HeaderMetadata.ImagePrimary:
|
||||
option.Column = (i, r) => this.GetBoolString(r.HasImageTagsPrimary);
|
||||
option.Header.ItemViewType = ItemViewType.TagsPrimaryImage;
|
||||
option.Header.CanGroup = false;
|
||||
option.Header.DisplayType = ReportDisplayType.Export;
|
||||
break;
|
||||
case HeaderMetadata.ImageBackdrop:
|
||||
option.Column = (i, r) => this.GetBoolString(r.HasImageTagsBackdrop);
|
||||
option.Header.ItemViewType = ItemViewType.TagsBackdropImage;
|
||||
option.Header.CanGroup = false;
|
||||
option.Header.DisplayType = ReportDisplayType.Export;
|
||||
break;
|
||||
case HeaderMetadata.ImageLogo:
|
||||
option.Column = (i, r) => this.GetBoolString(r.HasImageTagsLogo);
|
||||
option.Header.ItemViewType = ItemViewType.TagsLogoImage;
|
||||
option.Header.CanGroup = false;
|
||||
option.Header.DisplayType = ReportDisplayType.Export;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Name:
|
||||
column = (i, r) => i.Name;
|
||||
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||
reportHeader.SortField = "SortName";
|
||||
break;
|
||||
case HeaderMetadata.Name:
|
||||
option.Column = (i, r) => i.Name;
|
||||
option.Header.ItemViewType = ItemViewType.Detail;
|
||||
option.Header.SortField = "SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.DateAdded:
|
||||
column = (i, r) => i.DateCreated;
|
||||
reportHeader.SortField = "DateCreated,SortName";
|
||||
reportHeader.HeaderFieldType = ReportFieldType.DateTime;
|
||||
reportHeader.Type = "";
|
||||
break;
|
||||
case HeaderMetadata.DateAdded:
|
||||
option.Column = (i, r) => i.DateCreated;
|
||||
option.Header.SortField = "DateCreated,SortName";
|
||||
option.Header.HeaderFieldType = ReportFieldType.DateTime;
|
||||
option.Header.Type = "";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.PremiereDate:
|
||||
case HeaderMetadata.ReleaseDate:
|
||||
column = (i, r) => i.PremiereDate;
|
||||
reportHeader.HeaderFieldType = ReportFieldType.DateTime;
|
||||
reportHeader.SortField = "ProductionYear,PremiereDate,SortName";
|
||||
break;
|
||||
case HeaderMetadata.PremiereDate:
|
||||
case HeaderMetadata.ReleaseDate:
|
||||
option.Column = (i, r) => i.PremiereDate;
|
||||
option.Header.HeaderFieldType = ReportFieldType.DateTime;
|
||||
option.Header.SortField = "ProductionYear,PremiereDate,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Runtime:
|
||||
column = (i, r) => this.GetRuntimeDateTime(i.RunTimeTicks);
|
||||
reportHeader.HeaderFieldType = ReportFieldType.Minutes;
|
||||
reportHeader.SortField = "Runtime,SortName";
|
||||
break;
|
||||
case HeaderMetadata.Runtime:
|
||||
option.Column = (i, r) => this.GetRuntimeDateTime(i.RunTimeTicks);
|
||||
option.Header.HeaderFieldType = ReportFieldType.Minutes;
|
||||
option.Header.SortField = "Runtime,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.PlayCount:
|
||||
reportHeader.HeaderFieldType = ReportFieldType.Int;
|
||||
break;
|
||||
case HeaderMetadata.PlayCount:
|
||||
option.Header.HeaderFieldType = ReportFieldType.Int;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Season:
|
||||
column = (i, r) => this.GetEpisode(i);
|
||||
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||
reportHeader.SortField = "SortName";
|
||||
break;
|
||||
case HeaderMetadata.Season:
|
||||
option.Column = (i, r) => this.GetEpisode(i);
|
||||
option.Header.ItemViewType = ItemViewType.Detail;
|
||||
option.Header.SortField = "SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.SeasonNumber:
|
||||
column = (i, r) => this.GetObject<Season, string>(i, (x) => x.IndexNumber == null ? "" : x.IndexNumber.ToString());
|
||||
reportHeader.SortField = "IndexNumber";
|
||||
reportHeader.HeaderFieldType = ReportFieldType.Int;
|
||||
break;
|
||||
case HeaderMetadata.SeasonNumber:
|
||||
option.Column = (i, r) => this.GetObject<Season, string>(i, (x) => x.IndexNumber == null ? "" : x.IndexNumber.ToString());
|
||||
option.Header.SortField = "IndexNumber";
|
||||
option.Header.HeaderFieldType = ReportFieldType.Int;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Series:
|
||||
column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||
reportHeader.SortField = "SeriesSortName,SortName";
|
||||
break;
|
||||
case HeaderMetadata.Series:
|
||||
option.Column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||
option.Header.ItemViewType = ItemViewType.Detail;
|
||||
option.Header.SortField = "SeriesSortName,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.EpisodeSeries:
|
||||
column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||
itemId = (i) =>
|
||||
{
|
||||
Series series = this.GetObject<Episode, Series>(i, (x) => x.Series);
|
||||
if (series == null)
|
||||
return string.Empty;
|
||||
return series.Id;
|
||||
};
|
||||
reportHeader.SortField = "SeriesSortName,SortName";
|
||||
internalHeader = HeaderMetadata.Series;
|
||||
break;
|
||||
case HeaderMetadata.EpisodeSeries:
|
||||
option.Column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||
option.Header.ItemViewType = ItemViewType.Detail;
|
||||
option.ItemID = (i) =>
|
||||
{
|
||||
Series series = this.GetObject<Episode, Series>(i, (x) => x.Series);
|
||||
if (series == null)
|
||||
return string.Empty;
|
||||
return series.Id;
|
||||
};
|
||||
option.Header.SortField = "SeriesSortName,SortName";
|
||||
internalHeader = HeaderMetadata.Series;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.EpisodeSeason:
|
||||
column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||
itemId = (i) =>
|
||||
{
|
||||
Season season = this.GetObject<Episode, Season>(i, (x) => x.Season);
|
||||
if (season == null)
|
||||
return string.Empty;
|
||||
return season.Id;
|
||||
};
|
||||
reportHeader.SortField = "SortName";
|
||||
internalHeader = HeaderMetadata.Season;
|
||||
break;
|
||||
case HeaderMetadata.EpisodeSeason:
|
||||
option.Column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||
option.Header.ItemViewType = ItemViewType.Detail;
|
||||
option.ItemID = (i) =>
|
||||
{
|
||||
Season season = this.GetObject<Episode, Season>(i, (x) => x.Season);
|
||||
if (season == null)
|
||||
return string.Empty;
|
||||
return season.Id;
|
||||
};
|
||||
option.Header.SortField = "SortName";
|
||||
internalHeader = HeaderMetadata.Season;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Network:
|
||||
column = (i, r) => this.GetListAsString(i.Studios);
|
||||
itemId = (i) => this.GetStudioID(i.Studios.FirstOrDefault());
|
||||
reportHeader.ItemViewType = ItemViewType.ItemByNameDetails;
|
||||
reportHeader.SortField = "Studio,SortName";
|
||||
break;
|
||||
case HeaderMetadata.Network:
|
||||
option.Column = (i, r) => this.GetListAsString(i.Studios);
|
||||
option.ItemID = (i) => this.GetStudioID(i.Studios.FirstOrDefault());
|
||||
option.Header.ItemViewType = ItemViewType.ItemByNameDetails;
|
||||
option.Header.SortField = "Studio,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Year:
|
||||
column = (i, r) => this.GetSeriesProductionYear(i);
|
||||
reportHeader.SortField = "ProductionYear,PremiereDate,SortName";
|
||||
break;
|
||||
case HeaderMetadata.Year:
|
||||
option.Column = (i, r) => this.GetSeriesProductionYear(i);
|
||||
option.Header.SortField = "ProductionYear,PremiereDate,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.ParentalRating:
|
||||
column = (i, r) => i.OfficialRating;
|
||||
reportHeader.SortField = "OfficialRating,SortName";
|
||||
break;
|
||||
case HeaderMetadata.ParentalRating:
|
||||
option.Column = (i, r) => i.OfficialRating;
|
||||
option.Header.SortField = "OfficialRating,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.CommunityRating:
|
||||
column = (i, r) => i.CommunityRating;
|
||||
reportHeader.SortField = "CommunityRating,SortName";
|
||||
break;
|
||||
case HeaderMetadata.CommunityRating:
|
||||
option.Column = (i, r) => i.CommunityRating;
|
||||
option.Header.SortField = "CommunityRating,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Trailers:
|
||||
column = (i, r) => this.GetBoolString(r.HasLocalTrailer);
|
||||
reportHeader.ItemViewType = ItemViewType.TrailersImage;
|
||||
break;
|
||||
case HeaderMetadata.Trailers:
|
||||
option.Column = (i, r) => this.GetBoolString(r.HasLocalTrailer);
|
||||
option.Header.ItemViewType = ItemViewType.TrailersImage;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Specials:
|
||||
column = (i, r) => this.GetBoolString(r.HasSpecials);
|
||||
reportHeader.ItemViewType = ItemViewType.SpecialsImage;
|
||||
break;
|
||||
case HeaderMetadata.Specials:
|
||||
option.Column = (i, r) => this.GetBoolString(r.HasSpecials);
|
||||
option.Header.ItemViewType = ItemViewType.SpecialsImage;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.GameSystem:
|
||||
column = (i, r) => this.GetObject<Game, string>(i, (x) => x.GameSystem);
|
||||
reportHeader.SortField = "GameSystem,SortName";
|
||||
break;
|
||||
case HeaderMetadata.GameSystem:
|
||||
option.Column = (i, r) => this.GetObject<Game, string>(i, (x) => x.GameSystem);
|
||||
option.Header.SortField = "GameSystem,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Players:
|
||||
column = (i, r) => this.GetObject<Game, int?>(i, (x) => x.PlayersSupported);
|
||||
reportHeader.SortField = "Players,GameSystem,SortName";
|
||||
break;
|
||||
case HeaderMetadata.Players:
|
||||
option.Column = (i, r) => this.GetObject<Game, int?>(i, (x) => x.PlayersSupported);
|
||||
option.Header.SortField = "Players,GameSystem,SortName";
|
||||
break;
|
||||
|
||||
case HeaderMetadata.AlbumArtist:
|
||||
column = (i, r) => this.GetObject<MusicAlbum, string>(i, (x) => x.AlbumArtist);
|
||||
itemId = (i) => this.GetPersonID(this.GetObject<MusicAlbum, string>(i, (x) => x.AlbumArtist));
|
||||
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||
reportHeader.SortField = "AlbumArtist,Album,SortName";
|
||||
case HeaderMetadata.AlbumArtist:
|
||||
option.Column = (i, r) => this.GetObject<MusicAlbum, string>(i, (x) => x.AlbumArtist);
|
||||
option.ItemID = (i) => this.GetPersonID(this.GetObject<MusicAlbum, string>(i, (x) => x.AlbumArtist));
|
||||
option.Header.ItemViewType = ItemViewType.Detail;
|
||||
option.Header.SortField = "AlbumArtist,Album,SortName";
|
||||
|
||||
break;
|
||||
case HeaderMetadata.MusicArtist:
|
||||
column = (i, r) => this.GetObject<MusicArtist, string>(i, (x) => x.GetLookupInfo().Name);
|
||||
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||
reportHeader.SortField = "AlbumArtist,Album,SortName";
|
||||
internalHeader = HeaderMetadata.AlbumArtist;
|
||||
break;
|
||||
case HeaderMetadata.AudioAlbumArtist:
|
||||
column = (i, r) => this.GetListAsString(this.GetObject<Audio, List<string>>(i, (x) => x.AlbumArtists));
|
||||
reportHeader.SortField = "AlbumArtist,Album,SortName";
|
||||
internalHeader = HeaderMetadata.AlbumArtist;
|
||||
break;
|
||||
break;
|
||||
case HeaderMetadata.MusicArtist:
|
||||
option.Column = (i, r) => this.GetObject<MusicArtist, string>(i, (x) => x.GetLookupInfo().Name);
|
||||
option.Header.ItemViewType = ItemViewType.Detail;
|
||||
option.Header.SortField = "AlbumArtist,Album,SortName";
|
||||
internalHeader = HeaderMetadata.AlbumArtist;
|
||||
break;
|
||||
case HeaderMetadata.AudioAlbumArtist:
|
||||
option.Column = (i, r) => this.GetListAsString(this.GetObject<Audio, List<string>>(i, (x) => x.AlbumArtists));
|
||||
option.Header.SortField = "AlbumArtist,Album,SortName";
|
||||
internalHeader = HeaderMetadata.AlbumArtist;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.AudioAlbum:
|
||||
column = (i, r) => this.GetObject<Audio, string>(i, (x) => x.Album);
|
||||
reportHeader.SortField = "Album,SortName";
|
||||
internalHeader = HeaderMetadata.Album;
|
||||
break;
|
||||
case HeaderMetadata.AudioAlbum:
|
||||
option.Column = (i, r) => this.GetObject<Audio, string>(i, (x) => x.Album);
|
||||
option.Header.SortField = "Album,SortName";
|
||||
internalHeader = HeaderMetadata.Album;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Countries:
|
||||
column = (i, r) => this.GetListAsString(this.GetObject<IHasProductionLocations, List<string>>(i, (x) => x.ProductionLocations));
|
||||
break;
|
||||
case HeaderMetadata.Countries:
|
||||
option.Column = (i, r) => this.GetListAsString(this.GetObject<IHasProductionLocations, List<string>>(i, (x) => x.ProductionLocations));
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Disc:
|
||||
column = (i, r) => i.ParentIndexNumber;
|
||||
break;
|
||||
case HeaderMetadata.Disc:
|
||||
option.Column = (i, r) => i.ParentIndexNumber;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Track:
|
||||
column = (i, r) => i.IndexNumber;
|
||||
break;
|
||||
case HeaderMetadata.Track:
|
||||
option.Column = (i, r) => i.IndexNumber;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Tracks:
|
||||
column = (i, r) => this.GetObject<MusicAlbum, List<Audio>>(i, (x) => x.Tracks.ToList(), new List<Audio>()).Count();
|
||||
break;
|
||||
case HeaderMetadata.Tracks:
|
||||
option.Column = (i, r) => this.GetObject<MusicAlbum, List<Audio>>(i, (x) => x.Tracks.ToList(), new List<Audio>()).Count();
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Audio:
|
||||
column = (i, r) => this.GetAudioStream(i);
|
||||
break;
|
||||
case HeaderMetadata.Audio:
|
||||
option.Column = (i, r) => this.GetAudioStream(i);
|
||||
break;
|
||||
|
||||
case HeaderMetadata.EmbeddedImage:
|
||||
break;
|
||||
case HeaderMetadata.EmbeddedImage:
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Video:
|
||||
column = (i, r) => this.GetVideoStream(i);
|
||||
break;
|
||||
case HeaderMetadata.Video:
|
||||
option.Column = (i, r) => this.GetVideoStream(i);
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Resolution:
|
||||
column = (i, r) => this.GetVideoResolution(i);
|
||||
break;
|
||||
case HeaderMetadata.Resolution:
|
||||
option.Column = (i, r) => this.GetVideoResolution(i);
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Subtitles:
|
||||
column = (i, r) => this.GetBoolString(r.HasSubtitles);
|
||||
reportHeader.ItemViewType = ItemViewType.SubtitleImage;
|
||||
break;
|
||||
case HeaderMetadata.Subtitles:
|
||||
option.Column = (i, r) => this.GetBoolString(r.HasSubtitles);
|
||||
option.Header.ItemViewType = ItemViewType.SubtitleImage;
|
||||
break;
|
||||
|
||||
case HeaderMetadata.Genres:
|
||||
column = (i, r) => this.GetListAsString(i.Genres);
|
||||
break;
|
||||
case HeaderMetadata.Genres:
|
||||
option.Column = (i, r) => this.GetListAsString(i.Genres);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
string headerName = "";
|
||||
if (internalHeader != HeaderMetadata.None)
|
||||
{
|
||||
string localHeader = "Header" + internalHeader.ToString();
|
||||
headerName = internalHeader != HeaderMetadata.None ? ReportHelper.GetJavaScriptLocalizedString(localHeader) : "";
|
||||
if (string.Compare(localHeader, headerName, StringComparison.CurrentCultureIgnoreCase) == 0)
|
||||
headerName = ReportHelper.GetServerLocalizedString(localHeader);
|
||||
}
|
||||
option.Header.Name = GetLocalizedHeader(internalHeader);
|
||||
option.Header.FieldName = header;
|
||||
|
||||
reportHeader.Name = headerName;
|
||||
reportHeader.FieldName = header;
|
||||
ReportOptions<BaseItem> option = new ReportOptions<BaseItem>()
|
||||
{
|
||||
Header = reportHeader,
|
||||
Column = column,
|
||||
ItemID = itemId
|
||||
};
|
||||
return option;
|
||||
}
|
||||
}
|
||||
return option;
|
||||
}
|
||||
|
||||
/// <summary> Gets report rows. </summary>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="options"> Options for controlling the operation. </param>
|
||||
/// <returns> The report rows. </returns>
|
||||
private List<ReportRow> GetReportRows(IEnumerable<BaseItem> items, List<ReportOptions<BaseItem>> options)
|
||||
{
|
||||
var rows = new List<ReportRow>();
|
||||
|
||||
foreach (BaseItem item in items)
|
||||
{
|
||||
ReportRow rRow = GetRow(item);
|
||||
foreach (ReportOptions<BaseItem> option in options)
|
||||
{
|
||||
object itemColumn = option.Column != null ? option.Column(item, rRow) : "";
|
||||
object itemId = option.ItemID != null ? option.ItemID(item) : "";
|
||||
ReportItem rItem = new ReportItem
|
||||
{
|
||||
Name = ReportHelper.ConvertToString(itemColumn, option.Header.HeaderFieldType),
|
||||
Id = ReportHelper.ConvertToString(itemId, ReportFieldType.Object)
|
||||
};
|
||||
rRow.Columns.Add(rItem);
|
||||
}
|
||||
|
||||
rows.Add(rRow);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
/// <summary> Gets a row. </summary>
|
||||
/// <param name="item"> The item. </param>
|
||||
/// <returns> The row. </returns>
|
||||
private ReportRow GetRow(BaseItem item)
|
||||
{
|
||||
var hasTrailers = item as IHasTrailers;
|
||||
var hasSpecialFeatures = item as IHasSpecialFeatures;
|
||||
var video = item as Video;
|
||||
ReportRow rRow = new ReportRow
|
||||
{
|
||||
Id = item.Id.ToString("N"),
|
||||
HasLockData = item.IsLocked,
|
||||
IsUnidentified = item.IsUnidentified,
|
||||
HasLocalTrailer = hasTrailers != null ? hasTrailers.GetTrailerIds().Count() > 0 : false,
|
||||
HasImageTagsPrimary = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Primary) > 0),
|
||||
HasImageTagsBackdrop = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Backdrop) > 0),
|
||||
HasImageTagsLogo = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Logo) > 0),
|
||||
HasSpecials = hasSpecialFeatures != null ? hasSpecialFeatures.SpecialFeatureIds.Count > 0 : false,
|
||||
HasSubtitles = video != null ? video.HasSubtitles : false,
|
||||
RowType = ReportHelper.GetRowType(item.GetClientTypeName())
|
||||
};
|
||||
return rRow;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
|
||||
/// <summary> A report options. </summary>
|
||||
internal class ReportOptions<I>
|
||||
public class ReportOptions<I>
|
||||
{
|
||||
/// <summary> Initializes a new instance of the ReportOptions class. </summary>
|
||||
public ReportOptions()
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace MediaBrowser.Api.Reports
|
|||
ItemViewType = ItemViewType.None;
|
||||
Visible = true;
|
||||
CanGroup = true;
|
||||
ShowHeaderLabel = true;
|
||||
DisplayType = ReportDisplayType.ScreenExport;
|
||||
}
|
||||
|
||||
/// <summary> Gets or sets the type of the header field. </summary>
|
||||
|
@ -46,6 +48,14 @@ namespace MediaBrowser.Api.Reports
|
|||
/// <value> true if visible, false if not. </value>
|
||||
public bool Visible { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the type of the display. </summary>
|
||||
/// <value> The type of the display. </value>
|
||||
public ReportDisplayType DisplayType { get; set; }
|
||||
|
||||
/// <summary> Gets or sets a value indicating whether the header label is shown. </summary>
|
||||
/// <value> true if show header label, false if not. </value>
|
||||
public bool ShowHeaderLabel { get; set; }
|
||||
|
||||
/// <summary> Gets or sets a value indicating whether we can group. </summary>
|
||||
/// <value> true if we can group, false if not. </value>
|
||||
public bool CanGroup { get; set; }
|
|
@ -66,6 +66,10 @@ namespace MediaBrowser.Api.Reports
|
|||
|
||||
/// <summary> Gets or sets the type. </summary>
|
||||
/// <value> The type. </value>
|
||||
public ReportViewType RowType { get; set; }
|
||||
public ReportIncludeItemTypes RowType { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the identifier of the user. </summary>
|
||||
/// <value> The identifier of the user. </value>
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,251 +7,90 @@ using System.Linq;
|
|||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
public class BaseReportRequest : BaseItemsRequest
|
||||
{
|
||||
public interface IReportsDownload : IReportsQuery
|
||||
{
|
||||
/// <summary> Gets or sets the minimum date. </summary>
|
||||
/// <value> The minimum date. </value>
|
||||
string MinDate { get; set; }
|
||||
}
|
||||
|
||||
/// <summary> Interface for reports query. </summary>
|
||||
public interface IReportsQuery : IReportsHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
/// Gets or sets a value indicating whether this MediaBrowser.Api.Reports.GetActivityLogs has
|
||||
/// query limit. </summary>
|
||||
/// <value>
|
||||
/// true if this MediaBrowser.Api.Reports.GetActivityLogs has query limit, false if not. </value>
|
||||
bool HasQueryLimit { get; set; }
|
||||
/// <summary> Gets or sets who group this MediaBrowser.Api.Reports.GetActivityLogs. </summary>
|
||||
/// <value> Describes who group this MediaBrowser.Api.Reports.GetActivityLogs. </value>
|
||||
string GroupBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limit results to items containing a specific person
|
||||
/// Skips over a given number of items within the results. Use for paging.
|
||||
/// </summary>
|
||||
/// <value>The person.</value>
|
||||
[ApiMember(Name = "Person", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Person { get; set; }
|
||||
/// <value>The start index.</value>
|
||||
int? StartIndex { get; set; }
|
||||
/// <summary>
|
||||
/// The maximum number of items to return
|
||||
/// </summary>
|
||||
/// <value>The limit.</value>
|
||||
int? Limit { get; set; }
|
||||
|
||||
[ApiMember(Name = "PersonIds", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string PersonIds { get; set; }
|
||||
}
|
||||
public interface IReportsHeader
|
||||
{
|
||||
/// <summary> Gets or sets the report view. </summary>
|
||||
/// <value> The report view. </value>
|
||||
string ReportView { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the report columns. </summary>
|
||||
/// <value> The report columns. </value>
|
||||
string ReportColumns { get; set; }
|
||||
|
||||
/// <summary> Gets or sets a list of types of the include items. </summary>
|
||||
/// <value> A list of types of the include items. </value>
|
||||
string IncludeItemTypes { get; set; }
|
||||
|
||||
/// <summary> Gets or sets a list of types of the displays. </summary>
|
||||
/// <value> A list of types of the displays. </value>
|
||||
string DisplayType { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class BaseReportRequest : BaseItemsRequest, IReportsQuery
|
||||
{
|
||||
/// <summary> Gets or sets the report view. </summary>
|
||||
/// <value> The report view. </value>
|
||||
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ReportView { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the report view. </summary>
|
||||
/// <value> The report view. </value>
|
||||
[ApiMember(Name = "DisplayType", Description = "The report display type. Values (None, Screen, Export, ScreenExport)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string DisplayType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the Person filter is used, this can also be used to restrict to a specific person type
|
||||
/// </summary>
|
||||
/// <value>The type of the person.</value>
|
||||
[ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string PersonTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limit results to items containing specific studios
|
||||
/// </summary>
|
||||
/// <value>The studios.</value>
|
||||
[ApiMember(Name = "Studios", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Studios { get; set; }
|
||||
|
||||
[ApiMember(Name = "StudioIds", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string StudioIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the studios.
|
||||
/// </summary>
|
||||
/// <value>The studios.</value>
|
||||
[ApiMember(Name = "Artists", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Artists { get; set; }
|
||||
|
||||
[ApiMember(Name = "ArtistIds", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string ArtistIds { get; set; }
|
||||
|
||||
[ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Albums { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item ids.
|
||||
/// </summary>
|
||||
/// <value>The item ids.</value>
|
||||
[ApiMember(Name = "Ids", Description = "Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Ids { get; set; }
|
||||
|
||||
/// Gets or sets a value indicating whether this MediaBrowser.Api.Reports.BaseReportRequest has
|
||||
/// query limit. </summary>
|
||||
/// <value>
|
||||
/// true if this MediaBrowser.Api.Reports.BaseReportRequest has query limit, false if not. </value>
|
||||
[ApiMember(Name = "HasQueryLimit", Description = "Optional. If specified, results will include all records.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool HasQueryLimit { get; set; }
|
||||
public string GroupBy { get; set; }
|
||||
|
||||
public string ReportColumns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video types.
|
||||
/// </summary>
|
||||
/// <value>The video types.</value>
|
||||
[ApiMember(Name = "VideoTypes", Description = "Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string VideoTypes { get; set; }
|
||||
/// Gets or sets who group this MediaBrowser.Api.Reports.BaseReportRequest. </summary>
|
||||
/// <value> Describes who group this MediaBrowser.Api.Reports.BaseReportRequest. </value>
|
||||
[ApiMember(Name = "GroupBy", Description = "Optional. If specified, results will include grouped records.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string GroupBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video formats.
|
||||
/// </summary>
|
||||
/// <value>The video formats.</value>
|
||||
[ApiMember(Name = "Is3D", Description = "Optional filter by items that are 3D, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? Is3D { get; set; }
|
||||
/// <summary> Gets or sets the report columns. </summary>
|
||||
/// <value> The report columns. </value>
|
||||
[ApiMember(Name = "ReportColumns", Description = "Optional. The columns to show.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ReportColumns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the series status.
|
||||
/// </summary>
|
||||
/// <value>The series status.</value>
|
||||
[ApiMember(Name = "SeriesStatus", Description = "Optional filter by Series Status. Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string SeriesStatus { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameStartsWithOrGreater { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameStartsWith { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameLessThan", Description = "Optional filter by items whose name is equally or lesser than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameLessThan { get; set; }
|
||||
|
||||
[ApiMember(Name = "AlbumArtistStartsWithOrGreater", Description = "Optional filter by items whose album artist is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AlbumArtistStartsWithOrGreater { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the air days.
|
||||
/// </summary>
|
||||
/// <value>The air days.</value>
|
||||
[ApiMember(Name = "AirDays", Description = "Optional filter by Series Air Days. Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string AirDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the min offical rating.
|
||||
/// </summary>
|
||||
/// <value>The min offical rating.</value>
|
||||
[ApiMember(Name = "MinOfficialRating", Description = "Optional filter by minimum official rating (PG, PG-13, TV-MA, etc).", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string MinOfficialRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the max offical rating.
|
||||
/// </summary>
|
||||
/// <value>The max offical rating.</value>
|
||||
[ApiMember(Name = "MaxOfficialRating", Description = "Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string MaxOfficialRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasThemeSong", Description = "Optional filter by items with theme songs.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasThemeSong { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasThemeVideo", Description = "Optional filter by items with theme videos.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasThemeVideo { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasSubtitles", Description = "Optional filter by items with subtitles.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasSubtitles { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasSpecialFeature", Description = "Optional filter by items with special features.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasSpecialFeature { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTrailer", Description = "Optional filter by items with trailers.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTrailer { get; set; }
|
||||
|
||||
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AdjacentTo { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinIndexNumber", Description = "Optional filter by minimum index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MinIndexNumber { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinPlayers", Description = "Optional filter by minimum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MinPlayers { get; set; }
|
||||
|
||||
[ApiMember(Name = "MaxPlayers", Description = "Optional filter by maximum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MaxPlayers { get; set; }
|
||||
|
||||
[ApiMember(Name = "ParentIndexNumber", Description = "Optional filter by parent index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ParentIndexNumber { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasParentalRating", Description = "Optional filter by items that have or do not have a parental rating", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasParentalRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsHD", Description = "Optional filter by items that are HD or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsHD { get; set; }
|
||||
|
||||
[ApiMember(Name = "LocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string LocationTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string ExcludeLocationTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsUnaired", Description = "Optional filter by items that are unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsUnaired { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsVirtualUnaired { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinCommunityRating", Description = "Optional filter by minimum community rating.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public double? MinCommunityRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinCriticRating", Description = "Optional filter by minimum critic rating.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public double? MinCriticRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "AiredDuringSeason", Description = "Gets all episodes that aired during a season, including specials.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? AiredDuringSeason { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinPremiereDate", Description = "Optional. The minimum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MinPremiereDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "MaxPremiereDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MaxPremiereDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasOverview", Description = "Optional filter by items that have an overview or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasOverview { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasImdbId", Description = "Optional filter by items that have an imdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasImdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTmdbId", Description = "Optional filter by items that have a tmdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTmdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTvdbId", Description = "Optional filter by items that have a tvdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTvdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsYearMismatched", Description = "Optional filter by items that are potentially misidentified.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsYearMismatched { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsInBoxSet { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsLocked", Description = "Optional filter by items that are locked.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsLocked { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsUnidentified", Description = "Optional filter by items that are unidentified by internet metadata providers.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsUnidentified { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsPlaceHolder", Description = "Optional filter by items that are placeholders", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsPlaceHolder { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasOfficialRating", Description = "Optional filter by items that have official ratings", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasOfficialRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "CollapseBoxSetItems", Description = "Whether or not to hide items behind their boxsets.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? CollapseBoxSetItems { get; set; }
|
||||
|
||||
public string[] GetStudios()
|
||||
{
|
||||
return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetStudioIds()
|
||||
{
|
||||
return (StudioIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetPersonTypes()
|
||||
{
|
||||
return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetPersonIds()
|
||||
{
|
||||
return (PersonIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public VideoType[] GetVideoTypes()
|
||||
{
|
||||
var val = VideoTypes;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return new VideoType[] { };
|
||||
}
|
||||
|
||||
return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
[Route("/Reports/Items", "GET", Summary = "Gets reports based on library items")]
|
||||
|
@ -261,8 +100,27 @@ namespace MediaBrowser.Api.Reports
|
|||
}
|
||||
|
||||
[Route("/Reports/Headers", "GET", Summary = "Gets reports headers based on library items")]
|
||||
public class GetReportHeaders : BaseReportRequest, IReturn<List<ReportHeader>>
|
||||
{
|
||||
public class GetReportHeaders : IReturn<List<ReportHeader>>, IReportsHeader
|
||||
{
|
||||
/// <summary> Gets or sets the report view. </summary>
|
||||
/// <value> The report view. </value>
|
||||
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ReportView { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the report view. </summary>
|
||||
/// <value> The report view. </value>
|
||||
[ApiMember(Name = "DisplayType", Description = "The report display type. Values (None, Screen, Export, ScreenExport)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string DisplayType { get; set; }
|
||||
|
||||
/// <summary> Gets or sets a list of types of the include items. </summary>
|
||||
/// <value> A list of types of the include items. </value>
|
||||
[ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string IncludeItemTypes { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the report columns. </summary>
|
||||
/// <value> The report columns. </value>
|
||||
[ApiMember(Name = "ReportColumns", Description = "Optional. The columns to show.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ReportColumns { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Reports/Statistics", "GET", Summary = "Gets reports statistics based on library items")]
|
||||
|
@ -273,7 +131,7 @@ namespace MediaBrowser.Api.Reports
|
|||
}
|
||||
|
||||
[Route("/Reports/Items/Download", "GET", Summary = "Downloads report")]
|
||||
public class GetReportDownload : BaseReportRequest
|
||||
public class GetReportDownload : BaseReportRequest, IReportsDownload
|
||||
{
|
||||
public GetReportDownload()
|
||||
{
|
||||
|
@ -281,6 +139,66 @@ namespace MediaBrowser.Api.Reports
|
|||
}
|
||||
|
||||
public ReportExportType ExportType { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the minimum date. </summary>
|
||||
/// <value> The minimum date. </value>
|
||||
[ApiMember(Name = "MinDate", Description = "Optional. The minimum date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MinDate { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Route("/Reports/Activities", "GET", Summary = "Gets activities entries")]
|
||||
public class GetActivityLogs : IReturn<ReportResult>, IReportsQuery, IReportsDownload
|
||||
{
|
||||
/// <summary> Gets or sets the report view. </summary>
|
||||
/// <value> The report view. </value>
|
||||
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ReportView { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the report view. </summary>
|
||||
/// <value> The report view. </value>
|
||||
[ApiMember(Name = "DisplayType", Description = "The report display type. Values (None, Screen, Export, ScreenExport)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string DisplayType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this MediaBrowser.Api.Reports.GetActivityLogs has
|
||||
/// query limit. </summary>
|
||||
/// <value>
|
||||
/// true if this MediaBrowser.Api.Reports.GetActivityLogs has query limit, false if not. </value>
|
||||
[ApiMember(Name = "HasQueryLimit", Description = "Optional. If specified, results will include all records.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool HasQueryLimit { get; set; }
|
||||
|
||||
/// <summary> Gets or sets who group this MediaBrowser.Api.Reports.GetActivityLogs. </summary>
|
||||
/// <value> Describes who group this MediaBrowser.Api.Reports.GetActivityLogs. </value>
|
||||
[ApiMember(Name = "GroupBy", Description = "Optional. If specified, results will include grouped records.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string GroupBy { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the report columns. </summary>
|
||||
/// <value> The report columns. </value>
|
||||
[ApiMember(Name = "ReportColumns", Description = "Optional. The columns to show.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ReportColumns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Skips over a given number of items within the results. Use for paging.
|
||||
/// </summary>
|
||||
/// <value>The start index.</value>
|
||||
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? StartIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of items to return
|
||||
/// </summary>
|
||||
/// <value>The limit.</value>
|
||||
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? Limit { get; set; }
|
||||
|
||||
/// <summary> Gets or sets the minimum date. </summary>
|
||||
/// <value> The minimum date. </value>
|
||||
[ApiMember(Name = "MinDate", Description = "Optional. The minimum date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MinDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string IncludeItemTypes { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,206 +9,276 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
/// <summary> A report stat builder. </summary>
|
||||
/// <seealso cref="T:MediaBrowser.Api.Reports.ReportBuilderBase"/>
|
||||
public class ReportStatBuilder : ReportBuilderBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportStatBuilder class. </summary>
|
||||
/// <param name="libraryManager"> Manager for library. </param>
|
||||
public ReportStatBuilder(ILibraryManager libraryManager)
|
||||
: base(libraryManager)
|
||||
{
|
||||
}
|
||||
/// <summary> A report stat builder. </summary>
|
||||
/// <seealso cref="T:MediaBrowser.Api.Reports.ReportBuilderBase"/>
|
||||
public class ReportStatBuilder : ReportBuilderBase
|
||||
{
|
||||
#region [Constructors]
|
||||
|
||||
/// <summary> Gets report stat result. </summary>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="reportRowType"> Type of the report row. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The report stat result. </returns>
|
||||
public ReportStatResult GetReportStatResult(BaseItem[] items, ReportViewType reportRowType, int topItem = 5)
|
||||
{
|
||||
ReportStatResult result = new ReportStatResult();
|
||||
result = this.GetResultGenres(result, items, topItem);
|
||||
result = this.GetResultStudios(result, items, topItem);
|
||||
result = this.GetResultPersons(result, items, topItem);
|
||||
result = this.GetResultProductionYears(result, items, topItem);
|
||||
result = this.GetResulProductionLocations(result, items, topItem);
|
||||
result = this.GetResultCommunityRatings(result, items, topItem);
|
||||
result = this.GetResultParentalRatings(result, items, topItem);
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportStatBuilder class. </summary>
|
||||
/// <param name="libraryManager"> Manager for library. </param>
|
||||
public ReportStatBuilder(ILibraryManager libraryManager)
|
||||
: base(libraryManager)
|
||||
{
|
||||
}
|
||||
|
||||
switch (reportRowType)
|
||||
{
|
||||
case ReportViewType.Season:
|
||||
case ReportViewType.Series:
|
||||
case ReportViewType.MusicAlbum:
|
||||
case ReportViewType.MusicArtist:
|
||||
case ReportViewType.Game:
|
||||
break;
|
||||
case ReportViewType.Movie:
|
||||
case ReportViewType.BoxSet:
|
||||
#endregion
|
||||
|
||||
break;
|
||||
case ReportViewType.Book:
|
||||
case ReportViewType.Episode:
|
||||
case ReportViewType.Video:
|
||||
case ReportViewType.MusicVideo:
|
||||
case ReportViewType.Trailer:
|
||||
case ReportViewType.Audio:
|
||||
case ReportViewType.BaseItem:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#region [Public Methods]
|
||||
|
||||
result.Groups = result.Groups.OrderByDescending(n => n.Items.Count()).ToList();
|
||||
/// <summary> Gets report stat result. </summary>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="reportIncludeItemTypes"> List of types of the report include items. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The report stat result. </returns>
|
||||
public ReportStatResult GetResult(BaseItem[] items, ReportIncludeItemTypes reportIncludeItemTypes, int topItem = 5)
|
||||
{
|
||||
ReportStatResult result = new ReportStatResult();
|
||||
result = this.GetResultGenres(result, items, topItem);
|
||||
result = this.GetResultStudios(result, items, topItem);
|
||||
result = this.GetResultPersons(result, items, topItem);
|
||||
result = this.GetResultProductionYears(result, items, topItem);
|
||||
result = this.GetResulProductionLocations(result, items, topItem);
|
||||
result = this.GetResultCommunityRatings(result, items, topItem);
|
||||
result = this.GetResultParentalRatings(result, items, topItem);
|
||||
|
||||
return result;
|
||||
}
|
||||
switch (reportIncludeItemTypes)
|
||||
{
|
||||
case ReportIncludeItemTypes.Season:
|
||||
case ReportIncludeItemTypes.Series:
|
||||
case ReportIncludeItemTypes.MusicAlbum:
|
||||
case ReportIncludeItemTypes.MusicArtist:
|
||||
case ReportIncludeItemTypes.Game:
|
||||
break;
|
||||
case ReportIncludeItemTypes.Movie:
|
||||
case ReportIncludeItemTypes.BoxSet:
|
||||
|
||||
private ReportStatResult GetResultGenres(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderGenres"), topItem,
|
||||
items.SelectMany(x => x.Genres)
|
||||
.GroupBy(x => x)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key,
|
||||
Value = x.Count().ToString(),
|
||||
Id = GetGenreID(x.Key)
|
||||
}));
|
||||
return result;
|
||||
break;
|
||||
case ReportIncludeItemTypes.Book:
|
||||
case ReportIncludeItemTypes.Episode:
|
||||
case ReportIncludeItemTypes.Video:
|
||||
case ReportIncludeItemTypes.MusicVideo:
|
||||
case ReportIncludeItemTypes.Trailer:
|
||||
case ReportIncludeItemTypes.Audio:
|
||||
case ReportIncludeItemTypes.BaseItem:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
result.Groups = result.Groups.OrderByDescending(n => n.Items.Count()).ToList();
|
||||
|
||||
private ReportStatResult GetResultStudios(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderStudios"), topItem,
|
||||
items.SelectMany(x => x.Studios)
|
||||
.GroupBy(x => x)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key,
|
||||
Value = x.Count().ToString(),
|
||||
Id = GetStudioID(x.Key)
|
||||
})
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region [Protected Internal Methods]
|
||||
/// <summary> Gets the headers. </summary>
|
||||
/// <typeparam name="H"> Type of the header. </typeparam>
|
||||
/// <param name="request"> The request. </param>
|
||||
/// <returns> The headers. </returns>
|
||||
/// <seealso cref="M:MediaBrowser.Api.Reports.ReportBuilderBase.GetHeaders{H}(H)"/>
|
||||
protected internal override List<ReportHeader> GetHeaders<H>(H request)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private ReportStatResult GetResultPersons(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
List<string> t = new List<string> { PersonType.Actor, PersonType.Composer, PersonType.Director, PersonType.GuestStar, PersonType.Producer, PersonType.Writer, "Artist", "AlbumArtist" };
|
||||
foreach (var item in t)
|
||||
{
|
||||
this.GetGroups(result, ReportHelper.GetServerLocalizedString("Option" + item), topItem,
|
||||
items.SelectMany(x => _libraryManager.GetPeople(x))
|
||||
.Where(n => n.Type == item)
|
||||
.GroupBy(x => x.Name)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key,
|
||||
Value = x.Count().ToString(),
|
||||
Id = GetPersonID(x.Key)
|
||||
})
|
||||
);
|
||||
}
|
||||
#endregion
|
||||
|
||||
return result;
|
||||
}
|
||||
#region [Private Methods]
|
||||
|
||||
private ReportStatResult GetResultCommunityRatings(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, ReportHelper.GetServerLocalizedString("LabelCommunityRating"), topItem,
|
||||
items.Where(x => x.CommunityRating != null && x.CommunityRating > 0)
|
||||
.GroupBy(x => x.CommunityRating)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key.ToString(),
|
||||
Value = x.Count().ToString()
|
||||
})
|
||||
);
|
||||
/// <summary> Gets the groups. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="header"> The header. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <param name="top"> The top. </param>
|
||||
private void GetGroups(ReportStatResult result, string header, int topItem, IEnumerable<ReportStatItem> top)
|
||||
{
|
||||
if (top != null && top.Count() > 0)
|
||||
{
|
||||
var group = new ReportStatGroup { Header = ReportStatGroup.FormatedHeader(header, topItem) };
|
||||
group.Items.AddRange(top);
|
||||
result.Groups.Add(group);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary> Gets resul production locations. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The resul production locations. </returns>
|
||||
private ReportStatResult GetResulProductionLocations(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.Countries), topItem,
|
||||
items.OfType<IHasProductionLocations>()
|
||||
.Where(x => x.ProductionLocations != null)
|
||||
.SelectMany(x => x.ProductionLocations)
|
||||
.GroupBy(x => x)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key.ToString(),
|
||||
Value = x.Count().ToString()
|
||||
})
|
||||
);
|
||||
|
||||
private ReportStatResult GetResultParentalRatings(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderParentalRatings"), topItem,
|
||||
items.Where(x => x.OfficialRating != null)
|
||||
.GroupBy(x => x.OfficialRating)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key.ToString(),
|
||||
Value = x.Count().ToString()
|
||||
})
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary> Gets result community ratings. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The result community ratings. </returns>
|
||||
private ReportStatResult GetResultCommunityRatings(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.CommunityRating), topItem,
|
||||
items.Where(x => x.CommunityRating != null && x.CommunityRating > 0)
|
||||
.GroupBy(x => x.CommunityRating)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key.ToString(),
|
||||
Value = x.Count().ToString()
|
||||
})
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ReportStatResult GetResultProductionYears(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderYears"), topItem,
|
||||
items.Where(x => x.ProductionYear != null && x.ProductionYear > 0)
|
||||
.GroupBy(x => x.ProductionYear)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key.ToString(),
|
||||
Value = x.Count().ToString()
|
||||
})
|
||||
);
|
||||
/// <summary> Gets result genres. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The result genres. </returns>
|
||||
private ReportStatResult GetResultGenres(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.Genres), topItem,
|
||||
items.SelectMany(x => x.Genres)
|
||||
.GroupBy(x => x)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key,
|
||||
Value = x.Count().ToString(),
|
||||
Id = GetGenreID(x.Key)
|
||||
}));
|
||||
return result;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private ReportStatResult GetResulProductionLocations(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderCountries"), topItem,
|
||||
items.OfType<IHasProductionLocations>()
|
||||
.Where(x => x.ProductionLocations != null)
|
||||
.SelectMany(x => x.ProductionLocations)
|
||||
.GroupBy(x => x)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key.ToString(),
|
||||
Value = x.Count().ToString()
|
||||
})
|
||||
);
|
||||
/// <summary> Gets result parental ratings. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The result parental ratings. </returns>
|
||||
private ReportStatResult GetResultParentalRatings(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.ParentalRatings), topItem,
|
||||
items.Where(x => x.OfficialRating != null)
|
||||
.GroupBy(x => x.OfficialRating)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key.ToString(),
|
||||
Value = x.Count().ToString()
|
||||
})
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Gets result persons. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The result persons. </returns>
|
||||
private ReportStatResult GetResultPersons(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
List<HeaderMetadata> t = new List<HeaderMetadata>
|
||||
{
|
||||
HeaderMetadata.Actor,
|
||||
HeaderMetadata.Composer,
|
||||
HeaderMetadata.Director,
|
||||
HeaderMetadata.GuestStar,
|
||||
HeaderMetadata.Producer,
|
||||
HeaderMetadata.Writer,
|
||||
HeaderMetadata.Artist,
|
||||
HeaderMetadata.AlbumArtist
|
||||
};
|
||||
foreach (var item in t)
|
||||
{
|
||||
var ps = items.Where(x => x.People != null && x.SupportsPeople).SelectMany(x => x.People)
|
||||
.Where(n => n.Type == item.ToString())
|
||||
.GroupBy(x => x.Name)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem);
|
||||
if (ps != null && ps.Count() > 0)
|
||||
this.GetGroups(result, GetLocalizedHeader(item), topItem,
|
||||
ps.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key,
|
||||
Value = x.Count().ToString(),
|
||||
Id = GetPersonID(x.Key)
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary> Gets the groups. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="header"> The header. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <param name="top"> The top. </param>
|
||||
private void GetGroups(ReportStatResult result, string header, int topItem, IEnumerable<ReportStatItem> top)
|
||||
{
|
||||
if (top.Count() > 0)
|
||||
{
|
||||
var group = new ReportStatGroup { Header = ReportStatGroup.FormatedHeader(header, topItem) };
|
||||
group.Items.AddRange(top);
|
||||
result.Groups.Add(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Gets result production years. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The result production years. </returns>
|
||||
private ReportStatResult GetResultProductionYears(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.Year), topItem,
|
||||
items.Where(x => x.ProductionYear != null && x.ProductionYear > 0)
|
||||
.GroupBy(x => x.ProductionYear)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key.ToString(),
|
||||
Value = x.Count().ToString()
|
||||
})
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Gets result studios. </summary>
|
||||
/// <param name="result"> The result. </param>
|
||||
/// <param name="items"> The items. </param>
|
||||
/// <param name="topItem"> The top item. </param>
|
||||
/// <returns> The result studios. </returns>
|
||||
private ReportStatResult GetResultStudios(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||
{
|
||||
this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.Studios), topItem,
|
||||
items.SelectMany(x => x.Studios)
|
||||
.GroupBy(x => x)
|
||||
.OrderByDescending(x => x.Count())
|
||||
.Take(topItem)
|
||||
.Select(x => new ReportStatItem
|
||||
{
|
||||
Name = x.Key,
|
||||
Value = x.Count().ToString(),
|
||||
Id = GetStudioID(x.Key)
|
||||
})
|
||||
);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities;
|
|||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Search;
|
||||
|
@ -171,6 +172,8 @@ namespace MediaBrowser.Api
|
|||
ProductionYear = item.ProductionYear
|
||||
};
|
||||
|
||||
result.ChannelId = item.ChannelId;
|
||||
|
||||
var primaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary);
|
||||
|
||||
if (primaryImageTag != null)
|
||||
|
@ -181,24 +184,19 @@ namespace MediaBrowser.Api
|
|||
SetThumbImageInfo(result, item);
|
||||
SetBackdropImageInfo(result, item);
|
||||
|
||||
var episode = item as Episode;
|
||||
|
||||
if (episode != null)
|
||||
var hasSeries = item as IHasSeries;
|
||||
if (hasSeries != null)
|
||||
{
|
||||
result.Series = episode.Series.Name;
|
||||
result.Series = hasSeries.SeriesName;
|
||||
}
|
||||
|
||||
var season = item as Season;
|
||||
|
||||
if (season != null)
|
||||
{
|
||||
result.Series = season.Series.Name;
|
||||
|
||||
result.EpisodeCount = season.GetRecursiveChildren(i => i is Episode).Count;
|
||||
}
|
||||
|
||||
var series = item as Series;
|
||||
|
||||
if (series != null)
|
||||
{
|
||||
result.EpisodeCount = series.GetRecursiveChildren(i => i is Episode).Count;
|
||||
|
@ -223,6 +221,12 @@ namespace MediaBrowser.Api
|
|||
result.Artists = song.Artists.ToArray();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(item.ChannelId))
|
||||
{
|
||||
var channel = _libraryManager.GetItemById(item.ChannelId);
|
||||
result.ChannelName = channel == null ? null : channel.Name;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ using MediaBrowser.Controller;
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Connect;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
@ -49,13 +51,15 @@ namespace MediaBrowser.Api
|
|||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IConnectManager _connectManager;
|
||||
private readonly ILiveTvManager _liveTvManager;
|
||||
|
||||
public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager)
|
||||
public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, ILiveTvManager liveTvManager)
|
||||
{
|
||||
_config = config;
|
||||
_appHost = appHost;
|
||||
_userManager = userManager;
|
||||
_connectManager = connectManager;
|
||||
_liveTvManager = liveTvManager;
|
||||
}
|
||||
|
||||
public void Post(ReportStartupWizardComplete request)
|
||||
|
@ -67,6 +71,8 @@ namespace MediaBrowser.Api
|
|||
_config.Configuration.EnableLibraryMetadataSubFolder = true;
|
||||
_config.Configuration.EnableUserSpecificUserViews = true;
|
||||
_config.Configuration.EnableCustomPathSubFolders = true;
|
||||
_config.Configuration.DisableXmlSavers = true;
|
||||
_config.Configuration.DisableStartupScan = true;
|
||||
_config.SaveConfiguration();
|
||||
}
|
||||
|
||||
|
@ -82,7 +88,7 @@ namespace MediaBrowser.Api
|
|||
|
||||
public object Get(GetStartupConfiguration request)
|
||||
{
|
||||
return new StartupConfiguration
|
||||
var result = new StartupConfiguration
|
||||
{
|
||||
UICulture = _config.Configuration.UICulture,
|
||||
EnableInternetProviders = _config.Configuration.EnableInternetProviders,
|
||||
|
@ -90,6 +96,22 @@ namespace MediaBrowser.Api
|
|||
MetadataCountryCode = _config.Configuration.MetadataCountryCode,
|
||||
PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
|
||||
};
|
||||
|
||||
var tvConfig = GetLiveTVConfiguration();
|
||||
|
||||
if (tvConfig.TunerHosts.Count > 0)
|
||||
{
|
||||
result.LiveTvTunerPath = tvConfig.TunerHosts[0].Url;
|
||||
result.LiveTvTunerType = tvConfig.TunerHosts[0].Type;
|
||||
}
|
||||
|
||||
if (tvConfig.ListingProviders.Count > 0)
|
||||
{
|
||||
result.LiveTvGuideProviderId = tvConfig.ListingProviders[0].Id;
|
||||
result.LiveTvGuideProviderType = tvConfig.ListingProviders[0].Type;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Post(UpdateStartupConfiguration request)
|
||||
|
@ -100,6 +122,9 @@ namespace MediaBrowser.Api
|
|||
_config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
|
||||
_config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
|
||||
_config.SaveConfiguration();
|
||||
|
||||
var task = UpdateTuners(request);
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public object Get(GetStartupUser request)
|
||||
|
@ -140,6 +165,51 @@ namespace MediaBrowser.Api
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task UpdateTuners(UpdateStartupConfiguration request)
|
||||
{
|
||||
var config = GetLiveTVConfiguration();
|
||||
var save = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.LiveTvTunerPath) ||
|
||||
string.IsNullOrWhiteSpace(request.LiveTvTunerType))
|
||||
{
|
||||
if (config.TunerHosts.Count > 0)
|
||||
{
|
||||
config.TunerHosts.Clear();
|
||||
save = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!config.TunerHosts.Any(i => string.Equals(i.Type, request.LiveTvTunerType, StringComparison.OrdinalIgnoreCase) && string.Equals(i.Url, request.LiveTvTunerPath, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
// Add tuner
|
||||
await _liveTvManager.SaveTunerHost(new TunerHostInfo
|
||||
{
|
||||
IsEnabled = true,
|
||||
Type = request.LiveTvTunerType,
|
||||
Url = request.LiveTvTunerPath
|
||||
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (save)
|
||||
{
|
||||
SaveLiveTVConfiguration(config);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveLiveTVConfiguration(LiveTvOptions config)
|
||||
{
|
||||
_config.SaveConfiguration("livetv", config);
|
||||
}
|
||||
|
||||
private LiveTvOptions GetLiveTVConfiguration()
|
||||
{
|
||||
return _config.GetConfiguration<LiveTvOptions>("livetv");
|
||||
}
|
||||
}
|
||||
|
||||
public class StartupConfiguration
|
||||
|
@ -149,6 +219,10 @@ namespace MediaBrowser.Api
|
|||
public bool SaveLocalMeta { get; set; }
|
||||
public string MetadataCountryCode { get; set; }
|
||||
public string PreferredMetadataLanguage { get; set; }
|
||||
public string LiveTvTunerType { get; set; }
|
||||
public string LiveTvTunerPath { get; set; }
|
||||
public string LiveTvGuideProviderId { get; set; }
|
||||
public string LiveTvGuideProviderType { get; set; }
|
||||
}
|
||||
|
||||
public class StartupInfo
|
||||
|
|
|
@ -10,11 +10,6 @@ namespace MediaBrowser.Api.Sync
|
|||
{
|
||||
List<SyncJobOption> options = new List<SyncJobOption>();
|
||||
|
||||
if (items.Count > 1)
|
||||
{
|
||||
options.Add(SyncJobOption.Name);
|
||||
}
|
||||
|
||||
foreach (BaseItemDto item in items)
|
||||
{
|
||||
if (item.SupportsSync ?? false)
|
||||
|
@ -65,7 +60,6 @@ namespace MediaBrowser.Api.Sync
|
|||
{
|
||||
List<SyncJobOption> options = new List<SyncJobOption>();
|
||||
|
||||
options.Add(SyncJobOption.Name);
|
||||
options.Add(SyncJobOption.Quality);
|
||||
options.Add(SyncJobOption.Profile);
|
||||
options.Add(SyncJobOption.UnwatchedOnly);
|
||||
|
|
|
@ -6,7 +6,6 @@ using MediaBrowser.Controller.Net;
|
|||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -124,48 +123,18 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<MusicArtist> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
if (request is GetAlbumArtists)
|
||||
{
|
||||
return items
|
||||
.Where(i => !i.IsFolder)
|
||||
.OfType<IHasAlbumArtist>()
|
||||
.SelectMany(i => i.AlbumArtists)
|
||||
.DistinctNames()
|
||||
.Select(name =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return LibraryManager.GetArtist(name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error getting artist {0}", ex, name);
|
||||
return null;
|
||||
}
|
||||
|
||||
}).Where(i => i != null);
|
||||
return LibraryManager.GetAlbumArtists(items
|
||||
.Where(i => !i.IsFolder)
|
||||
.OfType<IHasAlbumArtist>());
|
||||
}
|
||||
|
||||
return items
|
||||
return LibraryManager.GetArtists(items
|
||||
.Where(i => !i.IsFolder)
|
||||
.OfType<IHasArtist>()
|
||||
.SelectMany(i => i.AllArtists)
|
||||
.DistinctNames()
|
||||
.Select(name =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return LibraryManager.GetArtist(name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error getting artist {0}", ex, name);
|
||||
return null;
|
||||
}
|
||||
|
||||
}).Where(i => i != null);
|
||||
.OfType<IHasArtist>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,42 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
DtoService = dtoService;
|
||||
}
|
||||
|
||||
protected BaseItem GetParentItem(GetItemsByName request)
|
||||
{
|
||||
BaseItem parentItem;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.UserId))
|
||||
{
|
||||
var user = UserManager.GetUserById(request.UserId);
|
||||
parentItem = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : LibraryManager.GetItemById(request.ParentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
parentItem = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId);
|
||||
}
|
||||
|
||||
return parentItem;
|
||||
}
|
||||
|
||||
protected string GetParentItemViewType(GetItemsByName request)
|
||||
{
|
||||
var parent = GetParentItem(request);
|
||||
|
||||
var collectionFolder = parent as ICollectionFolder;
|
||||
if (collectionFolder != null)
|
||||
{
|
||||
return collectionFolder.CollectionType;
|
||||
}
|
||||
|
||||
var view = parent as UserView;
|
||||
if (view != null)
|
||||
{
|
||||
return view.ViewType;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
|
@ -114,13 +150,13 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
var filteredItems = FilterItems(request, extractedItems, user);
|
||||
|
||||
filteredItems = FilterByLibraryItems(request, filteredItems, user, libraryItems);
|
||||
filteredItems = FilterByLibraryItems(request, filteredItems.Cast<IItemByName>(), user, libraryItems).Cast<BaseItem>();
|
||||
|
||||
filteredItems = LibraryManager.Sort(filteredItems, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending).Cast<TItemType>();
|
||||
filteredItems = LibraryManager.Sort(filteredItems, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending);
|
||||
|
||||
var ibnItemsArray = filteredItems.ToList();
|
||||
|
||||
IEnumerable<TItemType> ibnItems = ibnItemsArray;
|
||||
IEnumerable<BaseItem> ibnItems = ibnItemsArray;
|
||||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
|
@ -141,14 +177,14 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
}
|
||||
|
||||
IEnumerable<Tuple<TItemType, List<BaseItem>>> tuples;
|
||||
IEnumerable<Tuple<BaseItem, List<BaseItem>>> tuples;
|
||||
if (dtoOptions.Fields.Contains(ItemFields.ItemCounts))
|
||||
{
|
||||
tuples = ibnItems.Select(i => new Tuple<TItemType, List<BaseItem>>(i, i.GetTaggedItems(libraryItems).ToList()));
|
||||
tuples = ibnItems.Select(i => new Tuple<BaseItem, List<BaseItem>>(i, ((IItemByName)i).GetTaggedItems(libraryItems).ToList()));
|
||||
}
|
||||
else
|
||||
{
|
||||
tuples = ibnItems.Select(i => new Tuple<TItemType, List<BaseItem>>(i, new List<BaseItem>()));
|
||||
tuples = ibnItems.Select(i => new Tuple<BaseItem, List<BaseItem>>(i, new List<BaseItem>()));
|
||||
}
|
||||
|
||||
var dtos = tuples.Select(i => DtoService.GetItemByNameDto(i.Item1, dtoOptions, i.Item2, user));
|
||||
|
@ -180,7 +216,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return options.Fields.Contains(ItemFields.ItemCounts);
|
||||
}
|
||||
|
||||
private IEnumerable<TItemType> FilterByLibraryItems(GetItemsByName request, IEnumerable<TItemType> items, User user, IEnumerable<BaseItem> libraryItems)
|
||||
private IEnumerable<IItemByName> FilterByLibraryItems(GetItemsByName request, IEnumerable<IItemByName> items, User user, IEnumerable<BaseItem> libraryItems)
|
||||
{
|
||||
var filters = request.GetFilters().ToList();
|
||||
|
||||
|
@ -211,7 +247,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="items">The items.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>IEnumerable{`0}.</returns>
|
||||
private IEnumerable<TItemType> FilterItems(GetItemsByName request, IEnumerable<TItemType> items, User user)
|
||||
private IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
|
||||
{
|
||||
|
@ -375,7 +411,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Task{`0}}.</returns>
|
||||
protected abstract IEnumerable<TItemType> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items);
|
||||
protected abstract IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -383,22 +419,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// </summary>
|
||||
public class GetItemsByName : BaseItemsRequest, IReturn<ItemsResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameStartsWithOrGreater { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameStartsWith { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameLessThan", Description = "Optional filter by items whose name is sorted less than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameLessThan { get; set; }
|
||||
|
||||
public GetItemsByName()
|
||||
{
|
||||
Recursive = true;
|
||||
|
|
|
@ -14,6 +14,97 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
EnableImages = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the max offical rating.
|
||||
/// </summary>
|
||||
/// <value>The max offical rating.</value>
|
||||
[ApiMember(Name = "MaxOfficialRating", Description = "Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string MaxOfficialRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasThemeSong", Description = "Optional filter by items with theme songs.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasThemeSong { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasThemeVideo", Description = "Optional filter by items with theme videos.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasThemeVideo { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasSubtitles", Description = "Optional filter by items with subtitles.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasSubtitles { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasSpecialFeature", Description = "Optional filter by items with special features.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasSpecialFeature { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTrailer", Description = "Optional filter by items with trailers.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTrailer { get; set; }
|
||||
|
||||
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AdjacentTo { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinIndexNumber", Description = "Optional filter by minimum index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MinIndexNumber { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinPlayers", Description = "Optional filter by minimum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MinPlayers { get; set; }
|
||||
|
||||
[ApiMember(Name = "MaxPlayers", Description = "Optional filter by maximum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MaxPlayers { get; set; }
|
||||
|
||||
[ApiMember(Name = "ParentIndexNumber", Description = "Optional filter by parent index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ParentIndexNumber { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasParentalRating", Description = "Optional filter by items that have or do not have a parental rating", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasParentalRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsHD", Description = "Optional filter by items that are HD or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsHD { get; set; }
|
||||
|
||||
[ApiMember(Name = "LocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string LocationTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string ExcludeLocationTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsUnaired", Description = "Optional filter by items that are unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsUnaired { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsVirtualUnaired { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinCommunityRating", Description = "Optional filter by minimum community rating.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public double? MinCommunityRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinCriticRating", Description = "Optional filter by minimum critic rating.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public double? MinCriticRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "AiredDuringSeason", Description = "Gets all episodes that aired during a season, including specials.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? AiredDuringSeason { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinPremiereDate", Description = "Optional. The minimum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MinPremiereDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "MaxPremiereDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MaxPremiereDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasOverview", Description = "Optional filter by items that have an overview or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasOverview { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasImdbId", Description = "Optional filter by items that have an imdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasImdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTmdbId", Description = "Optional filter by items that have a tmdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTmdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTvdbId", Description = "Optional filter by items that have a tvdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTvdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsYearMismatched", Description = "Optional filter by items that are potentially misidentified.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsYearMismatched { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsInBoxSet { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Skips over a given number of items within the results. Use for paging.
|
||||
/// </summary>
|
||||
|
@ -130,6 +221,121 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limit results to items containing a specific person
|
||||
/// </summary>
|
||||
/// <value>The person.</value>
|
||||
[ApiMember(Name = "Person", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Person { get; set; }
|
||||
|
||||
[ApiMember(Name = "PersonIds", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string PersonIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the Person filter is used, this can also be used to restrict to a specific person type
|
||||
/// </summary>
|
||||
/// <value>The type of the person.</value>
|
||||
[ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string PersonTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limit results to items containing specific studios
|
||||
/// </summary>
|
||||
/// <value>The studios.</value>
|
||||
[ApiMember(Name = "Studios", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Studios { get; set; }
|
||||
|
||||
[ApiMember(Name = "StudioIds", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string StudioIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the studios.
|
||||
/// </summary>
|
||||
/// <value>The studios.</value>
|
||||
[ApiMember(Name = "Artists", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Artists { get; set; }
|
||||
|
||||
[ApiMember(Name = "ArtistIds", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string ArtistIds { get; set; }
|
||||
|
||||
[ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Albums { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item ids.
|
||||
/// </summary>
|
||||
/// <value>The item ids.</value>
|
||||
[ApiMember(Name = "Ids", Description = "Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Ids { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video types.
|
||||
/// </summary>
|
||||
/// <value>The video types.</value>
|
||||
[ApiMember(Name = "VideoTypes", Description = "Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string VideoTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the air days.
|
||||
/// </summary>
|
||||
/// <value>The air days.</value>
|
||||
[ApiMember(Name = "AirDays", Description = "Optional filter by Series Air Days. Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string AirDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the min offical rating.
|
||||
/// </summary>
|
||||
/// <value>The min offical rating.</value>
|
||||
[ApiMember(Name = "MinOfficialRating", Description = "Optional filter by minimum official rating (PG, PG-13, TV-MA, etc).", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string MinOfficialRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsLocked", Description = "Optional filter by items that are locked.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsLocked { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsUnidentified", Description = "Optional filter by items that are unidentified by internet metadata providers.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsUnidentified { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsPlaceHolder", Description = "Optional filter by items that are placeholders", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsPlaceHolder { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasOfficialRating", Description = "Optional filter by items that have official ratings", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasOfficialRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "CollapseBoxSetItems", Description = "Whether or not to hide items behind their boxsets.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? CollapseBoxSetItems { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the video formats.
|
||||
/// </summary>
|
||||
/// <value>The video formats.</value>
|
||||
[ApiMember(Name = "Is3D", Description = "Optional filter by items that are 3D, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? Is3D { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the series status.
|
||||
/// </summary>
|
||||
/// <value>The series status.</value>
|
||||
[ApiMember(Name = "SeriesStatus", Description = "Optional filter by Series Status. Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string SeriesStatus { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameStartsWithOrGreater { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameStartsWith { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameLessThan", Description = "Optional filter by items whose name is equally or lesser than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameLessThan { get; set; }
|
||||
|
||||
[ApiMember(Name = "AlbumArtistStartsWithOrGreater", Description = "Optional filter by items whose album artist is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AlbumArtistStartsWithOrGreater { get; set; }
|
||||
|
||||
public string[] GetGenres()
|
||||
{
|
||||
return (Genres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
@ -165,6 +371,43 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return (Years ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
|
||||
}
|
||||
|
||||
public string[] GetStudios()
|
||||
{
|
||||
return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetStudioIds()
|
||||
{
|
||||
return (StudioIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetPersonTypes()
|
||||
{
|
||||
return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetPersonIds()
|
||||
{
|
||||
return (PersonIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetItemIds()
|
||||
{
|
||||
return (Ids ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public VideoType[] GetVideoTypes()
|
||||
{
|
||||
var val = VideoTypes;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return new VideoType[] { };
|
||||
}
|
||||
|
||||
return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the filters.
|
||||
/// </summary>
|
||||
|
|
|
@ -99,14 +99,24 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<GameGenre> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
var itemsList = items.Where(i => i.Genres != null).ToList();
|
||||
|
||||
return itemsList
|
||||
return items
|
||||
.SelectMany(i => i.Genres)
|
||||
.DistinctNames()
|
||||
.Select(name => LibraryManager.GetGameGenre(name));
|
||||
.Select(name =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return LibraryManager.GetGameGenre(name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error getting genre {0}", ex, name);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(i => i != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -104,8 +103,38 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<Genre> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
var viewType = GetParentItemViewType(request);
|
||||
|
||||
if (string.Equals(viewType, CollectionType.Music) || string.Equals(viewType, CollectionType.MusicVideos))
|
||||
{
|
||||
return items
|
||||
.SelectMany(i => i.Genres)
|
||||
.DistinctNames()
|
||||
.Select(name => LibraryManager.GetMusicGenre(name));
|
||||
}
|
||||
|
||||
if (string.Equals(viewType, CollectionType.Games))
|
||||
{
|
||||
return items
|
||||
.SelectMany(i => i.Genres)
|
||||
.DistinctNames()
|
||||
.Select(name =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return LibraryManager.GetGameGenre(name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error getting genre {0}", ex, name);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(i => i != null);
|
||||
}
|
||||
|
||||
return items
|
||||
.SelectMany(i => i.Genres)
|
||||
.DistinctNames()
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Localization;
|
||||
|
@ -25,249 +24,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
[Route("/Users/{UserId}/Items", "GET", Summary = "Gets items based on a query.")]
|
||||
public class GetItems : BaseItemsRequest, IReturn<ItemsResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limit results to items containing a specific person
|
||||
/// </summary>
|
||||
/// <value>The person.</value>
|
||||
[ApiMember(Name = "Person", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Person { get; set; }
|
||||
|
||||
[ApiMember(Name = "PersonIds", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string PersonIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the Person filter is used, this can also be used to restrict to a specific person type
|
||||
/// </summary>
|
||||
/// <value>The type of the person.</value>
|
||||
[ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string PersonTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limit results to items containing specific studios
|
||||
/// </summary>
|
||||
/// <value>The studios.</value>
|
||||
[ApiMember(Name = "Studios", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Studios { get; set; }
|
||||
|
||||
[ApiMember(Name = "StudioIds", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string StudioIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the studios.
|
||||
/// </summary>
|
||||
/// <value>The studios.</value>
|
||||
[ApiMember(Name = "Artists", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Artists { get; set; }
|
||||
|
||||
[ApiMember(Name = "ArtistIds", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string ArtistIds { get; set; }
|
||||
|
||||
[ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Albums { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item ids.
|
||||
/// </summary>
|
||||
/// <value>The item ids.</value>
|
||||
[ApiMember(Name = "Ids", Description = "Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Ids { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video types.
|
||||
/// </summary>
|
||||
/// <value>The video types.</value>
|
||||
[ApiMember(Name = "VideoTypes", Description = "Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string VideoTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video formats.
|
||||
/// </summary>
|
||||
/// <value>The video formats.</value>
|
||||
[ApiMember(Name = "Is3D", Description = "Optional filter by items that are 3D, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? Is3D { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the series status.
|
||||
/// </summary>
|
||||
/// <value>The series status.</value>
|
||||
[ApiMember(Name = "SeriesStatus", Description = "Optional filter by Series Status. Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string SeriesStatus { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameStartsWithOrGreater { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameStartsWith { get; set; }
|
||||
|
||||
[ApiMember(Name = "NameLessThan", Description = "Optional filter by items whose name is equally or lesser than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string NameLessThan { get; set; }
|
||||
|
||||
[ApiMember(Name = "AlbumArtistStartsWithOrGreater", Description = "Optional filter by items whose album artist is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AlbumArtistStartsWithOrGreater { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the air days.
|
||||
/// </summary>
|
||||
/// <value>The air days.</value>
|
||||
[ApiMember(Name = "AirDays", Description = "Optional filter by Series Air Days. Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string AirDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the min offical rating.
|
||||
/// </summary>
|
||||
/// <value>The min offical rating.</value>
|
||||
[ApiMember(Name = "MinOfficialRating", Description = "Optional filter by minimum official rating (PG, PG-13, TV-MA, etc).", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string MinOfficialRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the max offical rating.
|
||||
/// </summary>
|
||||
/// <value>The max offical rating.</value>
|
||||
[ApiMember(Name = "MaxOfficialRating", Description = "Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string MaxOfficialRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasThemeSong", Description = "Optional filter by items with theme songs.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasThemeSong { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasThemeVideo", Description = "Optional filter by items with theme videos.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasThemeVideo { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasSubtitles", Description = "Optional filter by items with subtitles.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasSubtitles { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasSpecialFeature", Description = "Optional filter by items with special features.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasSpecialFeature { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTrailer", Description = "Optional filter by items with trailers.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTrailer { get; set; }
|
||||
|
||||
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AdjacentTo { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinIndexNumber", Description = "Optional filter by minimum index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MinIndexNumber { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinPlayers", Description = "Optional filter by minimum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MinPlayers { get; set; }
|
||||
|
||||
[ApiMember(Name = "MaxPlayers", Description = "Optional filter by maximum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MaxPlayers { get; set; }
|
||||
|
||||
[ApiMember(Name = "ParentIndexNumber", Description = "Optional filter by parent index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ParentIndexNumber { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasParentalRating", Description = "Optional filter by items that have or do not have a parental rating", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasParentalRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsHD", Description = "Optional filter by items that are HD or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsHD { get; set; }
|
||||
|
||||
[ApiMember(Name = "LocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string LocationTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string ExcludeLocationTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsUnaired", Description = "Optional filter by items that are unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsUnaired { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsVirtualUnaired { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinCommunityRating", Description = "Optional filter by minimum community rating.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public double? MinCommunityRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinCriticRating", Description = "Optional filter by minimum critic rating.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public double? MinCriticRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "AiredDuringSeason", Description = "Gets all episodes that aired during a season, including specials.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? AiredDuringSeason { get; set; }
|
||||
|
||||
[ApiMember(Name = "MinPremiereDate", Description = "Optional. The minimum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MinPremiereDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "MaxPremiereDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MaxPremiereDate { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasOverview", Description = "Optional filter by items that have an overview or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasOverview { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasImdbId", Description = "Optional filter by items that have an imdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasImdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTmdbId", Description = "Optional filter by items that have a tmdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTmdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasTvdbId", Description = "Optional filter by items that have a tvdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasTvdbId { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsYearMismatched", Description = "Optional filter by items that are potentially misidentified.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsYearMismatched { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsInBoxSet { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsLocked", Description = "Optional filter by items that are locked.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsLocked { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsUnidentified", Description = "Optional filter by items that are unidentified by internet metadata providers.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsUnidentified { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsPlaceHolder", Description = "Optional filter by items that are placeholders", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsPlaceHolder { get; set; }
|
||||
|
||||
[ApiMember(Name = "HasOfficialRating", Description = "Optional filter by items that have official ratings", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public bool? HasOfficialRating { get; set; }
|
||||
|
||||
[ApiMember(Name = "CollapseBoxSetItems", Description = "Whether or not to hide items behind their boxsets.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? CollapseBoxSetItems { get; set; }
|
||||
|
||||
public string[] GetStudios()
|
||||
{
|
||||
return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetStudioIds()
|
||||
{
|
||||
return (StudioIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetPersonTypes()
|
||||
{
|
||||
return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetPersonIds()
|
||||
{
|
||||
return (PersonIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetItemIds()
|
||||
{
|
||||
return (Ids ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public VideoType[] GetVideoTypes()
|
||||
{
|
||||
var val = VideoTypes;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return new VideoType[] { };
|
||||
}
|
||||
|
||||
return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -361,7 +117,16 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
if (!string.IsNullOrEmpty(request.Ids))
|
||||
{
|
||||
request.Recursive = true;
|
||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
|
||||
var query = GetItemsQuery(request, user);
|
||||
var result = await ((Folder)item).GetItems(query).ConfigureAwait(false);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.SortBy))
|
||||
{
|
||||
var ids = query.ItemIds.ToList();
|
||||
|
||||
// Try to preserve order
|
||||
result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
|
||||
}
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
}
|
||||
|
|
|
@ -99,11 +99,9 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<MusicGenre> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
var itemsList = items.ToList();
|
||||
|
||||
return itemsList
|
||||
return items
|
||||
.SelectMany(i => i.Genres)
|
||||
.DistinctNames()
|
||||
.Select(name => LibraryManager.GetMusicGenre(name));
|
||||
|
|
|
@ -16,12 +16,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
[Route("/Persons", "GET", Summary = "Gets all persons from a given item, folder, or the entire library")]
|
||||
public class GetPersons : GetItemsByName
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the person types.
|
||||
/// </summary>
|
||||
/// <value>The person types.</value>
|
||||
[ApiMember(Name = "PersonTypes", Description = "Optional filter by person type. Accepts multiple, comma-delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string PersonTypes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -114,7 +108,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<Person> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
var inputPersonTypes = ((GetPersons)request).PersonTypes;
|
||||
var personTypes = string.IsNullOrEmpty(inputPersonTypes) ? new string[] { } : inputPersonTypes.Split(',');
|
||||
|
|
|
@ -185,6 +185,9 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
[ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string PlaySessionId { get; set; }
|
||||
|
||||
[ApiMember(Name = "RepeatMode", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public RepeatMode RepeatMode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -325,7 +328,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
VolumeLevel = request.VolumeLevel,
|
||||
PlayMethod = request.PlayMethod,
|
||||
PlaySessionId = request.PlaySessionId,
|
||||
LiveStreamId = request.LiveStreamId
|
||||
LiveStreamId = request.LiveStreamId,
|
||||
RepeatMode = request.RepeatMode
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<Studio> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
var itemsList = items.Where(i => i.Studios != null).ToList();
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
var views = user.RootFolder
|
||||
.GetChildren(user, true)
|
||||
.OfType<ICollectionFolder>()
|
||||
.Where(i => IsEligibleForSpecialView(i))
|
||||
.Where(IsEligibleForSpecialView)
|
||||
.ToList();
|
||||
|
||||
var list = views
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<Year> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
||||
{
|
||||
var itemsList = items.Where(i => i.ProductionYear != null).ToList();
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
// http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
|
||||
ServicePointManager.Expect100Continue = false;
|
||||
|
||||
// Trakt requests sometimes fail without this
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -124,7 +127,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
|
||||
{
|
||||
var request = WebRequest.Create(options.Url);
|
||||
var request = CreateWebRequest(options.Url);
|
||||
var httpWebRequest = request as HttpWebRequest;
|
||||
|
||||
if (httpWebRequest != null)
|
||||
|
@ -432,7 +435,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
|
||||
var httpResponse = (HttpWebResponse)response;
|
||||
|
||||
EnsureSuccessStatusCode(httpResponse, options);
|
||||
EnsureSuccessStatusCode(client, httpResponse, options);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
|
@ -443,7 +446,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
{
|
||||
var httpResponse = (HttpWebResponse)response;
|
||||
|
||||
EnsureSuccessStatusCode(httpResponse, options);
|
||||
EnsureSuccessStatusCode(client, httpResponse, options);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
|
@ -629,7 +632,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
{
|
||||
var httpResponse = (HttpWebResponse)response;
|
||||
|
||||
EnsureSuccessStatusCode(httpResponse, options);
|
||||
var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
|
||||
EnsureSuccessStatusCode(client, httpResponse, options);
|
||||
|
||||
options.CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
|
@ -803,13 +807,20 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
return exception;
|
||||
}
|
||||
|
||||
private void EnsureSuccessStatusCode(HttpWebResponse response, HttpRequestOptions options)
|
||||
private void EnsureSuccessStatusCode(HttpClientInfo client, HttpWebResponse response, HttpRequestOptions options)
|
||||
{
|
||||
var statusCode = response.StatusCode;
|
||||
|
||||
var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299;
|
||||
|
||||
if (!isSuccessful)
|
||||
{
|
||||
if ((int) statusCode == 429)
|
||||
{
|
||||
client.LastTimeout = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
if (statusCode == HttpStatusCode.RequestEntityTooLarge)
|
||||
if (options.LogErrorResponseBody)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -234,10 +234,10 @@ namespace MediaBrowser.Common.Implementations.IO
|
|||
{
|
||||
if (_supportsAsyncFileStreams && isAsync)
|
||||
{
|
||||
return new FileStream(path, mode, access, share, 4096, true);
|
||||
return new FileStream(path, mode, access, share, StreamDefaults.DefaultFileStreamBufferSize, true);
|
||||
}
|
||||
|
||||
return new FileStream(path, mode, access, share);
|
||||
return new FileStream(path, mode, access, share, StreamDefaults.DefaultFileStreamBufferSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -312,7 +312,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
|
||||
trigger.Triggered -= trigger_Triggered;
|
||||
trigger.Triggered += trigger_Triggered;
|
||||
trigger.Start(isApplicationStartup);
|
||||
trigger.Start(LastExecutionResult, isApplicationStartup);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,7 +340,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
|
||||
trigger.Start(false);
|
||||
trigger.Start(LastExecutionResult, false);
|
||||
}
|
||||
|
||||
private Task _currentTask;
|
||||
|
|
|
@ -45,9 +45,6 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
|
|||
// Until we can vary these default triggers per server and MBT, we need something that makes sense for both
|
||||
return new ITaskTrigger[] {
|
||||
|
||||
// At startup
|
||||
new StartupTrigger {DelayMs = 60000},
|
||||
|
||||
// Every so often
|
||||
new IntervalTrigger { Interval = TimeSpan.FromHours(24)}
|
||||
};
|
||||
|
|
|
@ -42,9 +42,6 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
|
|||
// Until we can vary these default triggers per server and MBT, we need something that makes sense for both
|
||||
return new ITaskTrigger[] {
|
||||
|
||||
// At startup
|
||||
new StartupTrigger {DelayMs = 30000},
|
||||
|
||||
// Every so often
|
||||
new IntervalTrigger { Interval = TimeSpan.FromHours(24)}
|
||||
};
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
|
|||
|
||||
private Stream OpenFile(string path)
|
||||
{
|
||||
return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 131072);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -149,10 +149,12 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
/// Gets all available packages.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="withRegistration">if set to <c>true</c> [with registration].</param>
|
||||
/// <param name="packageType">Type of the package.</param>
|
||||
/// <param name="applicationVersion">The application version.</param>
|
||||
/// <returns>Task{List{PackageInfo}}.</returns>
|
||||
public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
|
||||
bool withRegistration = true,
|
||||
PackageType? packageType = null,
|
||||
Version applicationVersion = null)
|
||||
{
|
||||
|
@ -163,13 +165,22 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
{ "systemid", _applicationHost.SystemId }
|
||||
};
|
||||
|
||||
using (var json = await _httpClient.Post(MbAdmin.HttpsUrl + "service/package/retrieveall", data, cancellationToken).ConfigureAwait(false))
|
||||
if (withRegistration)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
using (var json = await _httpClient.Post(MbAdmin.HttpsUrl + "service/package/retrieveall", data, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(json).ToList();
|
||||
var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(json).ToList();
|
||||
|
||||
return FilterPackages(packages, packageType, applicationVersion);
|
||||
return FilterPackages(packages, packageType, applicationVersion);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return FilterPackages(packages.ToList(), packageType, applicationVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@ namespace MediaBrowser.Common.IO
|
|||
/// <summary>
|
||||
/// The default copy to buffer size
|
||||
/// </summary>
|
||||
public const int DefaultCopyToBufferSize = 81920;
|
||||
public const int DefaultCopyToBufferSize = 262144;
|
||||
|
||||
/// <summary>
|
||||
/// The default file stream buffer size
|
||||
/// </summary>
|
||||
public const int DefaultFileStreamBufferSize = 4096;
|
||||
public const int DefaultFileStreamBufferSize = 262144;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Model.Events;
|
||||
|
||||
namespace MediaBrowser.Common.ScheduledTasks
|
||||
{
|
||||
|
@ -32,8 +33,9 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
/// <summary>
|
||||
/// Stars waiting for the trigger action
|
||||
/// </summary>
|
||||
/// <param name="lastResult">The last result.</param>
|
||||
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
|
||||
public void Start(bool isApplicationStartup)
|
||||
public void Start(TaskResult lastResult, bool isApplicationStartup)
|
||||
{
|
||||
DisposeTimer();
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Common.ScheduledTasks
|
||||
{
|
||||
|
@ -16,8 +17,9 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
/// <summary>
|
||||
/// Stars waiting for the trigger action
|
||||
/// </summary>
|
||||
/// <param name="lastResult">The last result.</param>
|
||||
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
|
||||
void Start(bool isApplicationStartup);
|
||||
void Start(TaskResult lastResult, bool isApplicationStartup);
|
||||
|
||||
/// <summary>
|
||||
/// Stops waiting for the trigger action
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Model.Events;
|
||||
|
||||
namespace MediaBrowser.Common.ScheduledTasks
|
||||
{
|
||||
|
@ -29,15 +30,43 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
/// </value>
|
||||
public TaskExecutionOptions TaskOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the first run delay.
|
||||
/// </summary>
|
||||
/// <value>The first run delay.</value>
|
||||
public TimeSpan FirstRunDelay { get; set; }
|
||||
|
||||
public IntervalTrigger()
|
||||
{
|
||||
FirstRunDelay = TimeSpan.FromHours(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stars waiting for the trigger action
|
||||
/// </summary>
|
||||
/// <param name="lastResult">The last result.</param>
|
||||
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
|
||||
public void Start(bool isApplicationStartup)
|
||||
public void Start(TaskResult lastResult, bool isApplicationStartup)
|
||||
{
|
||||
DisposeTimer();
|
||||
|
||||
Timer = new Timer(state => OnTriggered(), null, Interval, TimeSpan.FromMilliseconds(-1));
|
||||
var triggerDate = lastResult != null ?
|
||||
lastResult.EndTimeUtc.Add(Interval) :
|
||||
DateTime.UtcNow.Add(FirstRunDelay);
|
||||
|
||||
if (DateTime.UtcNow > triggerDate)
|
||||
{
|
||||
if (isApplicationStartup)
|
||||
{
|
||||
triggerDate = DateTime.UtcNow.AddMinutes(5);
|
||||
}
|
||||
else
|
||||
{
|
||||
triggerDate = DateTime.UtcNow.Add(Interval);
|
||||
}
|
||||
}
|
||||
|
||||
Timer = new Timer(state => OnTriggered(), null, triggerDate - DateTime.UtcNow, TimeSpan.FromMilliseconds(-1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Events;
|
||||
|
||||
namespace MediaBrowser.Common.ScheduledTasks
|
||||
{
|
||||
|
@ -27,8 +28,9 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
/// <summary>
|
||||
/// Stars waiting for the trigger action
|
||||
/// </summary>
|
||||
/// <param name="lastResult">The last result.</param>
|
||||
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
|
||||
public async void Start(bool isApplicationStartup)
|
||||
public async void Start(TaskResult lastResult, bool isApplicationStartup)
|
||||
{
|
||||
if (isApplicationStartup)
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using MediaBrowser.Model.Tasks;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Events;
|
||||
|
||||
namespace MediaBrowser.Common.ScheduledTasks
|
||||
{
|
||||
|
@ -28,8 +28,9 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
/// <summary>
|
||||
/// Stars waiting for the trigger action
|
||||
/// </summary>
|
||||
/// <param name="lastResult">The last result.</param>
|
||||
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
|
||||
public void Start(bool isApplicationStartup)
|
||||
public void Start(TaskResult lastResult, bool isApplicationStartup)
|
||||
{
|
||||
switch (SystemEvent)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.ScheduledTasks
|
||||
{
|
||||
|
@ -38,8 +39,9 @@ namespace MediaBrowser.Common.ScheduledTasks
|
|||
/// <summary>
|
||||
/// Stars waiting for the trigger action
|
||||
/// </summary>
|
||||
/// <param name="lastResult">The last result.</param>
|
||||
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
|
||||
public void Start(bool isApplicationStartup)
|
||||
public void Start(TaskResult lastResult, bool isApplicationStartup)
|
||||
{
|
||||
DisposeTimer();
|
||||
|
||||
|
|
|
@ -45,10 +45,12 @@ namespace MediaBrowser.Common.Updates
|
|||
/// Gets all available packages.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="withRegistration">if set to <c>true</c> [with registration].</param>
|
||||
/// <param name="packageType">Type of the package.</param>
|
||||
/// <param name="applicationVersion">The application version.</param>
|
||||
/// <returns>Task{List{PackageInfo}}.</returns>
|
||||
Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
|
||||
bool withRegistration = true,
|
||||
PackageType? packageType = null,
|
||||
Version applicationVersion = null);
|
||||
|
||||
|
|
|
@ -121,10 +121,9 @@ namespace MediaBrowser.Controller.Channels
|
|||
/// <summary>
|
||||
/// Gets the channel folder.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>BaseItemDto.</returns>
|
||||
Task<Folder> GetInternalChannelFolder(string userId, CancellationToken cancellationToken);
|
||||
Task<Folder> GetInternalChannelFolder(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel folder.
|
||||
|
|
10
MediaBrowser.Controller/Dlna/IDeviceDiscovery.cs
Normal file
10
MediaBrowser.Controller/Dlna/IDeviceDiscovery.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public interface IDeviceDiscovery
|
||||
{
|
||||
event EventHandler<SsdpMessageEventArgs> DeviceDiscovered;
|
||||
event EventHandler<SsdpMessageEventArgs> DeviceLeft;
|
||||
}
|
||||
}
|
|
@ -81,13 +81,11 @@ namespace MediaBrowser.Controller.Dto
|
|||
/// <summary>
|
||||
/// Gets the item by name dto.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="taggedItems">The tagged items.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>BaseItemDto.</returns>
|
||||
BaseItemDto GetItemByNameDto<T>(T item, DtoOptions options, List<BaseItem> taggedItems, User user = null)
|
||||
where T : BaseItem, IItemByName;
|
||||
BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, User user = null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
get { return AlbumArtists.FirstOrDefault(); }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPeople
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -142,7 +142,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
public virtual string Path { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected internal bool IsOffline { get; set; }
|
||||
public bool IsOffline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
|
@ -419,6 +419,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
return _sortName ?? (_sortName = CreateSortName());
|
||||
}
|
||||
set
|
||||
{
|
||||
_sortName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetInternalMetadataPath()
|
||||
|
@ -485,6 +489,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets or sets the parent.
|
||||
/// </summary>
|
||||
/// <value>The parent.</value>
|
||||
[IgnoreDataMember]
|
||||
public Folder Parent
|
||||
{
|
||||
get
|
||||
|
@ -1115,6 +1120,23 @@ namespace MediaBrowser.Controller.Entities
|
|||
return value.Value <= maxAllowedRating.Value;
|
||||
}
|
||||
|
||||
public int? GetParentalRatingValue()
|
||||
{
|
||||
var rating = CustomRatingForComparison;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rating))
|
||||
{
|
||||
rating = OfficialRatingForComparison;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(rating))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return LocalizationManager.GetRatingLevel(rating);
|
||||
}
|
||||
|
||||
private bool IsVisibleViaTags(User user)
|
||||
{
|
||||
var hasTags = this as IHasTags;
|
||||
|
|
|
@ -35,6 +35,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected override bool SupportsShortcutChildren
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Localization;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -14,7 +13,6 @@ using System.Linq;
|
|||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -50,7 +48,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
public virtual bool IsPreSorted
|
||||
{
|
||||
get { return false; }
|
||||
get { return ConfigurationManager.Configuration.EnableWindowsShortcuts; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -122,7 +120,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
protected virtual bool SupportsShortcutChildren
|
||||
{
|
||||
get { return true; }
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1070,7 +1068,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var changesFound = false;
|
||||
|
||||
if (SupportsShortcutChildren && LocationType == LocationType.FileSystem)
|
||||
if (LocationType == LocationType.FileSystem)
|
||||
{
|
||||
if (RefreshLinkedChildren(fileSystemChildren))
|
||||
{
|
||||
|
@ -1092,37 +1090,43 @@ namespace MediaBrowser.Controller.Entities
|
|||
var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList();
|
||||
var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();
|
||||
|
||||
var newShortcutLinks = fileSystemChildren
|
||||
.Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory && FileSystem.IsShortcut(i.FullName))
|
||||
.Select(i =>
|
||||
{
|
||||
try
|
||||
List<LinkedChild> newShortcutLinks;
|
||||
|
||||
if (SupportsShortcutChildren)
|
||||
{
|
||||
newShortcutLinks = fileSystemChildren
|
||||
.Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory && FileSystem.IsShortcut(i.FullName))
|
||||
.Select(i =>
|
||||
{
|
||||
Logger.Debug("Found shortcut at {0}", i.FullName);
|
||||
|
||||
var resolvedPath = FileSystem.ResolveShortcut(i.FullName);
|
||||
|
||||
if (!string.IsNullOrEmpty(resolvedPath))
|
||||
try
|
||||
{
|
||||
return new LinkedChild
|
||||
Logger.Debug("Found shortcut at {0}", i.FullName);
|
||||
|
||||
var resolvedPath = FileSystem.ResolveShortcut(i.FullName);
|
||||
|
||||
if (!string.IsNullOrEmpty(resolvedPath))
|
||||
{
|
||||
Path = resolvedPath,
|
||||
Type = LinkedChildType.Shortcut
|
||||
};
|
||||
return new LinkedChild
|
||||
{
|
||||
Path = resolvedPath,
|
||||
Type = LinkedChildType.Shortcut
|
||||
};
|
||||
}
|
||||
|
||||
Logger.Error("Error resolving shortcut {0}", i.FullName);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Logger.Error("Error resolving shortcut {0}", i.FullName);
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Logger.ErrorException("Error resolving shortcut {0}", ex, i.FullName);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.ToList();
|
||||
catch (IOException ex)
|
||||
{
|
||||
Logger.ErrorException("Error resolving shortcut {0}", ex, i.FullName);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.ToList();
|
||||
}
|
||||
else { newShortcutLinks = new List<LinkedChild>(); }
|
||||
|
||||
if (!newShortcutLinks.SequenceEqual(currentShortcutLinks, new LinkedChildComparer()))
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -14,4 +15,17 @@ namespace MediaBrowser.Controller.Entities
|
|||
Guid Id { get; }
|
||||
IEnumerable<string> PhysicalLocations { get; }
|
||||
}
|
||||
|
||||
public static class CollectionFolderExtensions
|
||||
{
|
||||
public static string GetViewType(this ICollectionFolder folder, User user)
|
||||
{
|
||||
if (user.Configuration.PlainFolderViews.Contains(folder.Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return folder.CollectionType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
bool IsKids { get; set; }
|
||||
bool IsRepeat { get; set; }
|
||||
bool? IsHD { get; set; }
|
||||
bool IsSeries { get; set; }
|
||||
bool IsLive { get; set; }
|
||||
bool IsPremiere { get; set; }
|
||||
ProgramAudio? Audio { get; set; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -40,6 +40,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
public string NameStartsWithOrGreater { get; set; }
|
||||
public string NameStartsWith { get; set; }
|
||||
public string NameLessThan { get; set; }
|
||||
public string NameContains { get; set; }
|
||||
|
||||
public string Person { get; set; }
|
||||
public string[] PersonIds { get; set; }
|
||||
|
@ -93,6 +94,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
public string[] ChannelIds { get; set; }
|
||||
|
||||
internal List<Guid> ItemIdsFromPersonFilters { get; set; }
|
||||
public int? MaxParentalRating { get; set; }
|
||||
|
||||
public bool? IsCurrentSchema { get; set; }
|
||||
public bool? HasDeadParentId { get; set; }
|
||||
|
||||
public InternalItemsQuery()
|
||||
{
|
||||
|
|
|
@ -74,6 +74,15 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected override bool SupportsShortcutChildren
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsAuthorizedToDelete(User user)
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -100,12 +100,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
var key = this.GetProviderId(MetadataProviders.Tmdb);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
key = this.GetProviderId(MetadataProviders.Imdb);
|
||||
}
|
||||
var key = GetMovieUserDataKey(this);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
|
@ -115,6 +110,18 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
return key;
|
||||
}
|
||||
|
||||
public static string GetMovieUserDataKey(BaseItem movie)
|
||||
{
|
||||
var key = movie.GetProviderId(MetadataProviders.Tmdb);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
key = movie.GetProviderId(MetadataProviders.Imdb);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
||||
|
|
|
@ -150,7 +150,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
{
|
||||
var series = Series;
|
||||
|
||||
if (ParentIndexNumber.HasValue)
|
||||
if (series != null && ParentIndexNumber.HasValue)
|
||||
{
|
||||
var findNumber = ParentIndexNumber.Value;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Controller.Providers;
|
||||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Library;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
@ -36,6 +37,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
return PostFilterAndSort(result.Where(filter), query);
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected override bool SupportsShortcutChildren
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool IsPreSorted
|
||||
{
|
||||
get
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var result = await _channelManager.GetChannelsInternal(new ChannelQuery
|
||||
{
|
||||
UserId = user.Id.ToString("N"),
|
||||
UserId = user == null ? null : user.Id.ToString("N"),
|
||||
Limit = query.Limit,
|
||||
StartIndex = query.StartIndex
|
||||
|
||||
|
@ -264,10 +264,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
private async Task<QueryResult<BaseItem>> FindPlaylists(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var collectionFolders = user.RootFolder.GetChildren(user, true).Select(i => i.Id).ToList();
|
||||
|
||||
var list = _playlistManager.GetPlaylists(user.Id.ToString("N"))
|
||||
.Where(i => i.GetChildren(user, true).Any(media => _libraryManager.GetCollectionFolders(media).Select(c => c.Id).Any(collectionFolders.Contains)));
|
||||
var list = _playlistManager.GetPlaylists(user.Id.ToString("N"));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
@ -288,14 +285,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
list.Add(await GetUserView(SpecialFolder.MusicLatest, user, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicPlaylists, user, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicAlbums, user, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicAlbumArtists, user, "3", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicLatest, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicPlaylists, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicAlbums, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicAlbumArtists, "3", parent).ConfigureAwait(false));
|
||||
//list.Add(await GetUserView(SpecialFolder.MusicArtists, user, "4", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicSongs, user, "5", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicGenres, user, "6", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavorites, user, "7", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicSongs, "5", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicGenres, "6", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavorites, "7", parent).ConfigureAwait(false));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
@ -304,9 +301,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavoriteAlbums, user, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavoriteArtists, user, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavoriteSongs, user, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavoriteAlbums, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavoriteArtists, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MusicFavoriteSongs, "2", parent).ConfigureAwait(false));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
@ -332,7 +329,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.MusicGenre, user, i.SortName, parent));
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.MusicGenre, i.SortName, parent));
|
||||
|
||||
var genres = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
|
@ -344,94 +341,42 @@ namespace MediaBrowser.Controller.Entities
|
|||
var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
|
||||
.Where(i => !i.IsFolder)
|
||||
.Where(i => i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase))
|
||||
.OfType<IHasAlbumArtist>()
|
||||
.SelectMany(i => i.AlbumArtists)
|
||||
.DistinctNames()
|
||||
.Select(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _libraryManager.GetArtist(i);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Already logged at lower levels
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(i => i != null);
|
||||
.OfType<IHasAlbumArtist>();
|
||||
|
||||
return GetResult(items, queryParent, query);
|
||||
var artists = _libraryManager.GetAlbumArtists(items);
|
||||
|
||||
return GetResult(artists, queryParent, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
|
||||
.Where(i => !i.IsFolder)
|
||||
.OfType<IHasAlbumArtist>()
|
||||
.SelectMany(i => i.AlbumArtists)
|
||||
.DistinctNames()
|
||||
.Select(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _libraryManager.GetArtist(i);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Already logged at lower levels
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(i => i != null);
|
||||
.OfType<IHasAlbumArtist>();
|
||||
|
||||
var artists = _libraryManager.GetAlbumArtists(items);
|
||||
|
||||
return GetResult(artists, parent, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
|
||||
.Where(i => !i.IsFolder)
|
||||
.OfType<IHasArtist>()
|
||||
.SelectMany(i => i.Artists)
|
||||
.DistinctNames()
|
||||
.Select(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _libraryManager.GetArtist(i);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Already logged at lower levels
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(i => i != null);
|
||||
.OfType<IHasArtist>();
|
||||
|
||||
var artists = _libraryManager.GetArtists(items);
|
||||
|
||||
return GetResult(artists, parent, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetFavoriteArtists(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
|
||||
var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
|
||||
.Where(i => !i.IsFolder)
|
||||
.OfType<IHasAlbumArtist>()
|
||||
.SelectMany(i => i.AlbumArtists)
|
||||
.DistinctNames()
|
||||
.Select(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _libraryManager.GetArtist(i);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Already logged at lower levels
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(i => i != null && _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite);
|
||||
.OfType<IHasAlbumArtist>();
|
||||
|
||||
var artists = _libraryManager.GetAlbumArtists(items).Where(i => _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite);
|
||||
|
||||
return GetResult(artists, parent, query);
|
||||
}
|
||||
|
@ -498,12 +443,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
list.Add(await GetUserView(SpecialFolder.MovieResume, user, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieLatest, user, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieMovies, user, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieCollections, user, "3", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieFavorites, user, "4", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieGenres, user, "5", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieResume, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieLatest, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieMovies, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieCollections, "3", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieFavorites, "4", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.MovieGenres, "5", parent).ConfigureAwait(false));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
@ -609,7 +554,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.MovieGenre, user, i.SortName, parent));
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.MovieGenre, i.SortName, parent));
|
||||
|
||||
var genres = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
|
@ -671,13 +616,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
list.Add(await GetUserView(SpecialFolder.TvResume, user, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvNextUp, user, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvLatest, user, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvShowSeries, user, "3", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvFavoriteSeries, user, "4", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvFavoriteEpisodes, user, "5", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvGenres, user, "6", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvResume, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvNextUp, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvLatest, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvShowSeries, "3", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvFavoriteSeries, "4", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvFavoriteEpisodes, "5", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.TvGenres, "6", parent).ConfigureAwait(false));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
@ -692,11 +637,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
list.Add(await GetUserView(SpecialFolder.LatestGames, user, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameFavorites, user, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameSystems, user, "3", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameGenres, user, "4", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.LatestGames, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.RecentlyPlayedGames, "1", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameFavorites, "2", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameSystems, "3", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.GameGenres, "4", parent).ConfigureAwait(false));
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
}
|
||||
|
@ -794,7 +739,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.TvGenre, user, i.SortName, parent));
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.TvGenre, i.SortName, parent));
|
||||
|
||||
var genres = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
|
@ -846,7 +791,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.GameGenre, user, i.SortName, parent));
|
||||
.Select(i => GetUserView(i.Name, SpecialFolder.GameGenre, i.SortName, parent));
|
||||
|
||||
var genres = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
|
@ -1926,26 +1871,20 @@ namespace MediaBrowser.Controller.Entities
|
|||
var list = new List<BaseItem>();
|
||||
|
||||
//list.Add(await GetUserSubView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.LiveTvChannels, user, string.Empty, user.RootFolder).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, user, string.Empty, user.RootFolder).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.LiveTvChannels, string.Empty, user.RootFolder).ConfigureAwait(false));
|
||||
list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, string.Empty, user.RootFolder).ConfigureAwait(false));
|
||||
|
||||
return GetResult(list, queryParent, query);
|
||||
}
|
||||
|
||||
private async Task<UserView> GetUserView(string name, string type, User user, string sortName, BaseItem parent)
|
||||
private Task<UserView> GetUserView(string name, string type, string sortName, BaseItem parent)
|
||||
{
|
||||
var view = await _userViewManager.GetUserSubView(name, parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return view;
|
||||
return _userViewManager.GetUserSubView(name, parent.Id.ToString("N"), type, sortName, CancellationToken.None);
|
||||
}
|
||||
|
||||
private async Task<UserView> GetUserView(string type, User user, string sortName, BaseItem parent)
|
||||
private Task<UserView> GetUserView(string type, string sortName, BaseItem parent)
|
||||
{
|
||||
var view = await _userViewManager.GetUserSubView(parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return view;
|
||||
return _userViewManager.GetUserSubView(parent.Id.ToString("N"), type, sortName, CancellationToken.None);
|
||||
}
|
||||
|
||||
public static bool IsYearMismatched(BaseItem item, ILibraryManager libraryManager)
|
||||
|
|
|
@ -5,12 +5,12 @@ using MediaBrowser.Controller.Providers;
|
|||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
|
@ -61,7 +61,18 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="name">The name.</param>
|
||||
/// <returns>Task{Artist}.</returns>
|
||||
MusicArtist GetArtist(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album artists.
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable<MusicArtist>.</returns>
|
||||
IEnumerable<MusicArtist> GetAlbumArtists(IEnumerable<IHasAlbumArtist> items);
|
||||
/// <summary>
|
||||
/// Gets the artists.
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable<MusicArtist>.</returns>
|
||||
IEnumerable<MusicArtist> GetArtists(IEnumerable<IHasArtist> items);
|
||||
/// <summary>
|
||||
/// Gets a Studio
|
||||
/// </summary>
|
||||
|
@ -343,6 +354,36 @@ namespace MediaBrowser.Controller.Library
|
|||
string sortName,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the named view.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="viewType">Type of the view.</param>
|
||||
/// <param name="sortName">Name of the sort.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<UserView>.</returns>
|
||||
Task<UserView> GetNamedView(string name,
|
||||
string viewType,
|
||||
string sortName,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the named view.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="parentId">The parent identifier.</param>
|
||||
/// <param name="viewType">Type of the view.</param>
|
||||
/// <param name="sortName">Name of the sort.</param>
|
||||
/// <param name="uniqueId">The unique identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<UserView>.</returns>
|
||||
Task<UserView> GetNamedView(string name,
|
||||
string parentId,
|
||||
string viewType,
|
||||
string sortName,
|
||||
string uniqueId,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is video file] [the specified path].
|
||||
/// </summary>
|
||||
|
@ -461,5 +502,12 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="query">The query.</param>
|
||||
/// <returns>List<System.String>.</returns>
|
||||
List<string> GetPeopleNames(InternalPeopleQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Queries the items.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>QueryResult<BaseItem>.</returns>
|
||||
QueryResult<BaseItem> QueryItems(InternalItemsQuery query);
|
||||
}
|
||||
}
|
|
@ -11,4 +11,9 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <returns>System.String.</returns>
|
||||
string GetSavePath(IHasMetadata item);
|
||||
}
|
||||
|
||||
public interface IConfigurableProvider
|
||||
{
|
||||
bool IsEnabled { get; }
|
||||
}
|
||||
}
|
|
@ -16,10 +16,10 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <summary>
|
||||
/// Gets the instant mix from artist.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="artist">The artist.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>IEnumerable{Audio}.</returns>
|
||||
IEnumerable<Audio> GetInstantMixFromArtist(string name, User user);
|
||||
IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist artist, User user);
|
||||
/// <summary>
|
||||
/// Gets the instant mix from genre.
|
||||
/// </summary>
|
||||
|
|
|
@ -12,10 +12,9 @@ namespace MediaBrowser.Controller.Library
|
|||
{
|
||||
Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken);
|
||||
|
||||
Task<UserView> GetUserSubView(string name, string parentId, string type, User user, string sortName,
|
||||
CancellationToken cancellationToken);
|
||||
Task<UserView> GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken);
|
||||
|
||||
Task<UserView> GetUserSubView(string category, string type, User user, string sortName, CancellationToken cancellationToken);
|
||||
Task<UserView> GetUserSubView(string category, string type, string sortName, CancellationToken cancellationToken);
|
||||
|
||||
List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,10 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// </summary>
|
||||
/// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
|
||||
public bool? HasImage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is favorite.
|
||||
/// </summary>
|
||||
/// <value><c>null</c> if [is favorite] contains no value, <c>true</c> if [is favorite]; otherwise, <c>false</c>.</value>
|
||||
public bool? IsFavorite { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
15
MediaBrowser.Controller/LiveTv/IHasRegistrationInfo.cs
Normal file
15
MediaBrowser.Controller/LiveTv/IHasRegistrationInfo.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public interface IHasRegistrationInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the registration information.
|
||||
/// </summary>
|
||||
/// <param name="feature">The feature.</param>
|
||||
/// <returns>Task<MBRegistrationRecord>.</returns>
|
||||
Task<MBRegistrationRecord> GetRegistrationInfo(string feature);
|
||||
}
|
||||
}
|
19
MediaBrowser.Controller/LiveTv/IListingsProvider.cs
Normal file
19
MediaBrowser.Controller/LiveTv/IListingsProvider.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public interface IListingsProvider
|
||||
{
|
||||
string Name { get; }
|
||||
string Type { get; }
|
||||
Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
|
||||
Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
|
||||
Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
|
||||
Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System.Collections.Generic;
|
||||
|
@ -61,15 +62,18 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// Adds the parts.
|
||||
/// </summary>
|
||||
/// <param name="services">The services.</param>
|
||||
void AddParts(IEnumerable<ILiveTvService> services);
|
||||
/// <param name="tunerHosts">The tuner hosts.</param>
|
||||
/// <param name="listingProviders">The listing providers.</param>
|
||||
void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channels.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>IEnumerable{Channel}.</returns>
|
||||
Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, CancellationToken cancellationToken);
|
||||
Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recording.
|
||||
|
@ -176,9 +180,10 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// Gets the programs.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>IEnumerable{ProgramInfo}.</returns>
|
||||
Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken);
|
||||
Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the timer.
|
||||
|
@ -238,10 +243,10 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// Gets the recommended programs.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{QueryResult{ProgramInfoDto}}.</returns>
|
||||
Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query,
|
||||
CancellationToken cancellationToken);
|
||||
Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recommended programs internal.
|
||||
|
@ -249,8 +254,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <param name="query">The query.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<QueryResult<LiveTvProgram>>.</returns>
|
||||
Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query,
|
||||
CancellationToken cancellationToken);
|
||||
Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the live tv information.
|
||||
|
@ -270,10 +274,9 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <summary>
|
||||
/// Gets the live tv folder.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>BaseItemDto.</returns>
|
||||
Task<Folder> GetInternalLiveTvFolder(string userId, CancellationToken cancellationToken);
|
||||
Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the live tv folder.
|
||||
|
@ -337,5 +340,46 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <param name="dto">The dto.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, User user = null);
|
||||
/// <summary>
|
||||
/// Saves the tuner host.
|
||||
/// </summary>
|
||||
/// <param name="info">The information.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info);
|
||||
/// <summary>
|
||||
/// Saves the listing provider.
|
||||
/// </summary>
|
||||
/// <param name="info">The information.</param>
|
||||
/// <param name="validateLogin">if set to <c>true</c> [validate login].</param>
|
||||
/// <param name="validateListings">if set to <c>true</c> [validate listings].</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info, bool validateLogin, bool validateListings);
|
||||
/// <summary>
|
||||
/// Gets the lineups.
|
||||
/// </summary>
|
||||
/// <param name="providerType">Type of the provider.</param>
|
||||
/// <param name="providerId">The provider identifier.</param>
|
||||
/// <param name="country">The country.</param>
|
||||
/// <param name="location">The location.</param>
|
||||
/// <returns>Task<List<NameIdPair>>.</returns>
|
||||
Task<List<NameIdPair>> GetLineups(string providerType, string providerId, string country, string location);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registration information.
|
||||
/// </summary>
|
||||
/// <param name="channelId">The channel identifier.</param>
|
||||
/// <param name="programId">The program identifier.</param>
|
||||
/// <param name="feature">The feature.</param>
|
||||
/// <returns>Task<MBRegistrationRecord>.</returns>
|
||||
Task<MBRegistrationRecord> GetRegistrationInfo(string channelId, string programId, string feature);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the channel information.
|
||||
/// </summary>
|
||||
/// <param name="dto">The dto.</param>
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
void AddChannelInfo(BaseItemDto dto, LiveTvChannel channel, DtoOptions options, User user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,10 +37,12 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
|
||||
string ExternalId { get; set; }
|
||||
string EpisodeTitle { get; set; }
|
||||
bool IsSeries { get; set; }
|
||||
string SeriesTimerId { get; set; }
|
||||
RecordingStatus Status { get; set; }
|
||||
DateTime? EndDate { get; set; }
|
||||
ChannelType ChannelType { get; set; }
|
||||
DateTime DateLastSaved { get; set; }
|
||||
DateTime DateCreated { get; set; }
|
||||
DateTime DateModified { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
55
MediaBrowser.Controller/LiveTv/ITunerHost.cs
Normal file
55
MediaBrowser.Controller/LiveTv/ITunerHost.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public interface ITunerHost
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
string Name { get; }
|
||||
/// <summary>
|
||||
/// Gets the type.
|
||||
/// </summary>
|
||||
/// <value>The type.</value>
|
||||
string Type { get; }
|
||||
/// <summary>
|
||||
/// Gets the channels.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<IEnumerable<ChannelInfo>>.</returns>
|
||||
Task<IEnumerable<ChannelInfo>> GetChannels(CancellationToken cancellationToken);
|
||||
/// <summary>
|
||||
/// Gets the tuner infos.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<List<LiveTvTunerInfo>>.</returns>
|
||||
Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken);
|
||||
/// <summary>
|
||||
/// Gets the channel stream.
|
||||
/// </summary>
|
||||
/// <param name="channelId">The channel identifier.</param>
|
||||
/// <param name="streamId">The stream identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<MediaSourceInfo>.</returns>
|
||||
Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
|
||||
/// <summary>
|
||||
/// Gets the channel stream media sources.
|
||||
/// </summary>
|
||||
/// <param name="channelId">The channel identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<List<MediaSourceInfo>>.</returns>
|
||||
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
|
||||
/// <summary>
|
||||
/// Validates the specified information.
|
||||
/// </summary>
|
||||
/// <param name="info">The information.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task Validate(TunerHostInfo info);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
@ -17,9 +18,24 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
if (IsMovie)
|
||||
{
|
||||
var key = Movie.GetMovieUserDataKey(this);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return GetClientTypeName() + "-" + Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the etag.
|
||||
/// </summary>
|
||||
/// <value>The etag.</value>
|
||||
public string Etag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id of the program.
|
||||
/// </summary>
|
||||
|
@ -227,5 +243,19 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
info.IsMovie = IsMovie;
|
||||
return info;
|
||||
}
|
||||
|
||||
public override bool SupportsPeople
|
||||
{
|
||||
get
|
||||
{
|
||||
// Optimization
|
||||
if (IsNews || IsSports)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.SupportsPeople;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,10 +34,16 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// </summary>
|
||||
/// <value>The tuners.</value>
|
||||
public List<LiveTvTunerInfo> Tuners { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is visible; otherwise, <c>false</c>.</value>
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public LiveTvServiceStatusInfo()
|
||||
{
|
||||
Tuners = new List<LiveTvTunerInfo>();
|
||||
IsVisible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -40,6 +41,16 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
if (IsMovie)
|
||||
{
|
||||
var key = Movie.GetMovieUserDataKey(this);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
var name = GetClientTypeName();
|
||||
|
||||
if (!string.IsNullOrEmpty(ProgramId))
|
||||
|
|
|
@ -33,6 +33,11 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// </summary>
|
||||
/// <value>The overview.</value>
|
||||
public string Overview { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the short overview.
|
||||
/// </summary>
|
||||
/// <value>The short overview.</value>
|
||||
public string ShortOverview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the program, in UTC.
|
||||
|
@ -150,6 +155,36 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// </summary>
|
||||
/// <value>The production year.</value>
|
||||
public int? ProductionYear { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the home page URL.
|
||||
/// </summary>
|
||||
/// <value>The home page URL.</value>
|
||||
public string HomePageUrl { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the series identifier.
|
||||
/// </summary>
|
||||
/// <value>The series identifier.</value>
|
||||
public string SeriesId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the show identifier.
|
||||
/// </summary>
|
||||
/// <value>The show identifier.</value>
|
||||
public string ShowId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the season number.
|
||||
/// </summary>
|
||||
/// <value>The season number.</value>
|
||||
public int? SeasonNumber { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the episode number.
|
||||
/// </summary>
|
||||
/// <value>The episode number.</value>
|
||||
public int? EpisodeNumber { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the etag.
|
||||
/// </summary>
|
||||
/// <value>The etag.</value>
|
||||
public string Etag { get; set; }
|
||||
|
||||
public ProgramInfo()
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue