Merge pull request #1899 from MediaBrowser/beta

Beta
This commit is contained in:
Luke 2016-06-30 15:27:06 -04:00 committed by GitHub
commit 2708df6cc2
362 changed files with 16795 additions and 9358 deletions

View File

@ -80,7 +80,6 @@
<Compile Include="ImageMagick\UnplayedCountIndicator.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ImageMagick\fonts\MontserratLight.otf" />
<EmbeddedResource Include="ImageMagick\fonts\robotoregular.ttf" />
</ItemGroup>
<ItemGroup>

View File

@ -111,7 +111,6 @@ namespace Emby.Drawing.ImageMagick
wand.CurrentImage.TrimImage(10);
wand.SaveImage(outputPath);
}
SaveDelay();
}
public ImageSize GetImageSize(string path)
@ -189,7 +188,6 @@ namespace Emby.Drawing.ImageMagick
}
}
}
SaveDelay();
}
private void AddForegroundLayer(MagickWand wand, ImageProcessingOptions options)
@ -284,25 +282,16 @@ namespace Emby.Drawing.ImageMagick
if (ratio >= 1.4)
{
new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
}
else if (ratio >= .9)
{
new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
}
else
{
new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
}
SaveDelay();
}
private void SaveDelay()
{
// For some reason the images are not always getting released right away
//var task = Task.Delay(300);
//Task.WaitAll(task);
}
public string Name

View File

@ -9,140 +9,35 @@ namespace Emby.Drawing.ImageMagick
public class StripCollageBuilder
{
private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
private readonly IFileSystem _fileSystem;
public StripCollageBuilder(IApplicationPaths appPaths, IFileSystem fileSystem)
public StripCollageBuilder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
_fileSystem = fileSystem;
_fileSystem = fileSystem;
}
public void BuildPosterCollage(List<string> paths, string outputPath, int width, int height, string text)
public void BuildPosterCollage(List<string> paths, string outputPath, int width, int height)
{
if (!string.IsNullOrWhiteSpace(text))
using (var wand = BuildPosterCollageWand(paths, width, height))
{
using (var wand = BuildPosterCollageWandWithText(paths, text, width, height))
{
wand.SaveImage(outputPath);
}
}
else
{
using (var wand = BuildPosterCollageWand(paths, width, height))
{
wand.SaveImage(outputPath);
}
wand.SaveImage(outputPath);
}
}
public void BuildSquareCollage(List<string> paths, string outputPath, int width, int height, string text)
public void BuildSquareCollage(List<string> paths, string outputPath, int width, int height)
{
if (!string.IsNullOrWhiteSpace(text))
using (var wand = BuildSquareCollageWand(paths, width, height))
{
using (var wand = BuildSquareCollageWandWithText(paths, text, width, height))
{
wand.SaveImage(outputPath);
}
}
else
{
using (var wand = BuildSquareCollageWand(paths, width, height))
{
wand.SaveImage(outputPath);
}
wand.SaveImage(outputPath);
}
}
public void BuildThumbCollage(List<string> paths, string outputPath, int width, int height, string text)
public void BuildThumbCollage(List<string> paths, string outputPath, int width, int height)
{
if (!string.IsNullOrWhiteSpace(text))
using (var wand = BuildThumbCollageWand(paths, width, height))
{
using (var wand = BuildThumbCollageWandWithText(paths, text, width, height))
{
wand.SaveImage(outputPath);
}
}
else
{
using (var wand = BuildThumbCollageWand(paths, width, height))
{
wand.SaveImage(outputPath);
}
}
}
private MagickWand BuildThumbCollageWandWithText(List<string> paths, string text, int width, int height)
{
var inputPaths = ImageHelpers.ProjectPaths(paths, 8);
using (var wandImages = new MagickWand(inputPaths.ToArray()))
{
var wand = new MagickWand(width, height);
wand.OpenImage("gradient:#111111-#111111");
using (var draw = new DrawingWand())
{
using (var fcolor = new PixelWand(ColorName.White))
{
draw.FillColor = fcolor;
draw.Font = MontserratLightFont;
draw.FontSize = 60;
draw.FontWeight = FontWeightType.LightStyle;
draw.TextAntialias = true;
}
var fontMetrics = wand.QueryFontMetrics(draw, text);
var textContainerY = Convert.ToInt32(height * .165);
wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, text);
var iSlice = Convert.ToInt32(width * .1166666667);
int iTrans = Convert.ToInt32(height * 0.2);
int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296);
var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
foreach (var element in wandImages.ImageList)
{
int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
element.Gravity = GravityType.CenterGravity;
element.BackgroundColor = new PixelWand("none", 1);
element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
element.CropImage(iSlice, iHeight, ix, 0);
element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
}
wandImages.SetFirstIterator();
using (var wandList = wandImages.AppendImages())
{
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
using (var blackPixelWand = new PixelWand(ColorName.Black))
{
using (var greyPixelWand = new PixelWand(ColorName.Grey70))
{
mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
mwr.CurrentImage.FlipImage();
mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
{
mwg.OpenImage("gradient:black-none");
var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
wandList.AddImage(mwr);
int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
}
}
}
}
}
}
return wand;
wand.SaveImage(outputPath);
}
}
@ -211,81 +106,6 @@ namespace Emby.Drawing.ImageMagick
}
}
private MagickWand BuildPosterCollageWandWithText(List<string> paths, string label, int width, int height)
{
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())
{
using (var fcolor = new PixelWand(ColorName.White))
{
draw.FillColor = fcolor;
draw.Font = MontserratLightFont;
draw.FontSize = 60;
draw.FontWeight = FontWeightType.LightStyle;
draw.TextAntialias = true;
}
var fontMetrics = wand.QueryFontMetrics(draw, label);
var textContainerY = Convert.ToInt32(height * .165);
wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, label);
var iSlice = Convert.ToInt32(width * 0.225);
int iTrans = Convert.ToInt32(height * 0.2);
int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296);
var horizontalImagePadding = Convert.ToInt32(width * 0.0275);
foreach (var element in wandImages.ImageList)
{
int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
element.Gravity = GravityType.CenterGravity;
element.BackgroundColor = new PixelWand("none", 1);
element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
element.CropImage(iSlice, iHeight, ix, 0);
element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
}
wandImages.SetFirstIterator();
using (var wandList = wandImages.AppendImages())
{
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
using (var blackPixelWand = new PixelWand(ColorName.Black))
{
using (var greyPixelWand = new PixelWand(ColorName.Grey70))
{
mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
mwr.CurrentImage.FlipImage();
mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
{
mwg.OpenImage("gradient:black-none");
var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
wandList.AddImage(mwr);
int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
}
}
}
}
}
}
return wand;
}
}
private MagickWand BuildThumbCollageWand(List<string> paths, int width, int height)
{
var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
@ -352,148 +172,29 @@ namespace Emby.Drawing.ImageMagick
}
private MagickWand BuildSquareCollageWand(List<string> paths, int width, int height)
{
var inputPaths = ImageHelpers.ProjectPaths(paths, 3);
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 * .32);
int iTrans = Convert.ToInt32(height * .25);
int iHeight = Convert.ToInt32(height * .68);
var horizontalImagePadding = Convert.ToInt32(width * 0.02);
foreach (var element in wandImages.ImageList)
{
using (var blackPixelWand = new PixelWand(ColorName.Black))
{
int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
element.Gravity = GravityType.CenterGravity;
element.BackgroundColor = blackPixelWand;
element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
element.CropImage(iSlice, iHeight, ix, 0);
element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
}
}
wandImages.SetFirstIterator();
using (var wandList = wandImages.AppendImages())
{
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
using (var blackPixelWand = new PixelWand(ColorName.Black))
{
using (var greyPixelWand = new PixelWand(ColorName.Grey70))
{
mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
mwr.CurrentImage.FlipImage();
mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
{
mwg.OpenImage("gradient:black-none");
var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
wandList.AddImage(mwr);
int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .03));
}
}
}
}
}
}
return wand;
}
}
private MagickWand BuildSquareCollageWandWithText(List<string> paths, string label, int width, int height)
{
var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
using (var wandImages = new MagickWand(inputPaths.ToArray()))
var outputWand = new MagickWand(width, height, new PixelWand("none", 1));
var imageIndex = 0;
var cellWidth = width/2;
var cellHeight = height/2;
for (var x = 0; x < 2; x++)
{
var wand = new MagickWand(width, height);
wand.OpenImage("gradient:#111111-#111111");
using (var draw = new DrawingWand())
for (var y = 0; y < 2; y++)
{
using (var fcolor = new PixelWand(ColorName.White))
using (var temp = new MagickWand(inputPaths[imageIndex]))
{
draw.FillColor = fcolor;
draw.Font = MontserratLightFont;
draw.FontSize = 60;
draw.FontWeight = FontWeightType.LightStyle;
draw.TextAntialias = true;
}
var fontMetrics = wand.QueryFontMetrics(draw, label);
var textContainerY = Convert.ToInt32(height * .165);
wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, label);
var iSlice = Convert.ToInt32(width * .225);
int iTrans = Convert.ToInt32(height * 0.2);
int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296);
var horizontalImagePadding = Convert.ToInt32(width * 0.02);
foreach (var element in wandImages.ImageList)
{
int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
element.Gravity = GravityType.CenterGravity;
element.BackgroundColor = new PixelWand("none", 1);
element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
element.CropImage(iSlice, iHeight, ix, 0);
element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
}
wandImages.SetFirstIterator();
using (var wandList = wandImages.AppendImages())
{
wandList.CurrentImage.TrimImage(1);
using (var mwr = wandList.CloneMagickWand())
{
using (var blackPixelWand = new PixelWand(ColorName.Black))
{
using (var greyPixelWand = new PixelWand(ColorName.Grey70))
{
mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
mwr.CurrentImage.FlipImage();
mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
{
mwg.OpenImage("gradient:black-none");
var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
wandList.AddImage(mwr);
int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
}
}
}
}
temp.CurrentImage.ScaleImage(cellWidth, cellHeight);
// draw this image into the strip at the next position
var xPos = x*cellWidth;
var yPos = y*cellHeight;
outputWand.CurrentImage.CompositeImage(temp, CompositeOperator.OverCompositeOp, xPos, yPos);
}
imageIndex++;
}
return wand;
}
}
private string MontserratLightFont
{
get { return PlayedIndicatorDrawer.ExtractFont("MontserratLight.otf", _appPaths, _fileSystem); }
return outputWand;
}
}
}

View File

@ -115,7 +115,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
protected object ToStaticFileResult(string path)
{
return ResultFactory.GetStaticFileResult(Request, path);
return ResultFactory.GetStaticFileResult(Request, path).Result;
}
protected DtoOptions GetDtoOptions(object request)

View File

@ -9,7 +9,9 @@ using ServiceStack.Web;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Api
{
@ -71,6 +73,16 @@ namespace MediaBrowser.Api
}
[Route("/System/MediaEncoder/Path", "POST", Summary = "Updates the path to the media encoder")]
[Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)]
public class UpdateMediaEncoderPath : IReturnVoid
{
[ApiMember(Name = "Path", Description = "Path", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Path { get; set; }
[ApiMember(Name = "PathType", Description = "PathType", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string PathType { get; set; }
}
public class ConfigurationService : BaseApiService
{
/// <summary>
@ -86,14 +98,22 @@ namespace MediaBrowser.Api
private readonly IFileSystem _fileSystem;
private readonly IProviderManager _providerManager;
private readonly ILibraryManager _libraryManager;
private readonly IMediaEncoder _mediaEncoder;
public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager, ILibraryManager libraryManager)
public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
{
_jsonSerializer = jsonSerializer;
_configurationManager = configurationManager;
_fileSystem = fileSystem;
_providerManager = providerManager;
_libraryManager = libraryManager;
_mediaEncoder = mediaEncoder;
}
public void Post(UpdateMediaEncoderPath request)
{
var task = _mediaEncoder.UpdateEncoderPath(request.Path, request.PathType);
Task.WaitAll(task);
}
/// <summary>

View File

@ -80,7 +80,7 @@ namespace MediaBrowser.Api
.OrderBy(i => i)
.ToArray();
result.Tags = items.OfType<IHasTags>()
result.Tags = items
.SelectMany(i => i.Tags)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(i => i)

View File

@ -10,6 +10,8 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api
{
@ -107,8 +109,7 @@ namespace MediaBrowser.Api
{
IncludeItemTypes = new[] { typeof(GameSystem).Name }
};
var parentIds = new string[] { } ;
var gameSystems = _libraryManager.GetItemList(query, parentIds)
var gameSystems = _libraryManager.GetItemList(query)
.Cast<GameSystem>()
.ToList();
@ -128,8 +129,7 @@ namespace MediaBrowser.Api
{
IncludeItemTypes = new[] { typeof(Game).Name }
};
var parentIds = new string[] { };
var games = _libraryManager.GetItemList(query, parentIds)
var games = _libraryManager.GetItemList(query)
.Cast<Game>()
.ToList();
@ -185,20 +185,42 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetSimilarGames request)
public async Task<object> Get(GetSimilarGames request)
{
var dtoOptions = GetDtoOptions(request);
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataRepository,
_dtoService,
Logger,
request, new[] { typeof(Game) },
SimilarItemsHelper.GetSimiliarityScore);
var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem 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);
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Limit = request.Limit,
IncludeItemTypes = new[]
{
typeof(Game).Name
},
SimilarTo = item
}).ToList();
var dtoOptions = GetDtoOptions(request);
var result = new QueryResult<BaseItemDto>
{
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
TotalRecordCount = itemsResult.Count
};
return result;
}
}
}

View File

@ -514,7 +514,7 @@ namespace MediaBrowser.Api.Images
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
/// <returns>System.Object.</returns>
/// <exception cref="ResourceNotFoundException"></exception>
public object GetImage(ImageRequest request, IHasImages item, bool isHeadRequest)
public Task<object> GetImage(ImageRequest request, IHasImages item, bool isHeadRequest)
{
if (request.PercentPlayed.HasValue)
{
@ -594,8 +594,7 @@ namespace MediaBrowser.Api.Images
supportedImageEnhancers,
cacheDuration,
responseHeaders,
isHeadRequest)
.Result;
isHeadRequest);
}
private async Task<object> GetImageResult(IHasImages item,
@ -632,7 +631,7 @@ namespace MediaBrowser.Api.Images
headers["Vary"] = "Accept";
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
CacheDuration = cacheDuration,
ResponseHeaders = headers,
@ -643,7 +642,8 @@ namespace MediaBrowser.Api.Images
// Sometimes imagemagick keeps a hold on the file briefly even after it's done writing to it.
// I'd rather do this than add a delay after saving the file
FileShare = FileShare.ReadWrite
});
}).ConfigureAwait(false);
}
private List<ImageFormat> GetOutputFormats(ImageRequest request, ItemImageInfo image, bool cropwhitespace, List<IImageEnhancer> enhancers)

View File

@ -238,9 +238,9 @@ namespace MediaBrowser.Api.Images
}
if (_fileSystem.FileExists(contentPath))
{
return ToStaticFileResult(contentPath);
}
{
return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
}
}
catch (DirectoryNotFoundException)
{
@ -259,9 +259,9 @@ namespace MediaBrowser.Api.Images
contentPath = await reader.ReadToEndAsync().ConfigureAwait(false);
}
return ToStaticFileResult(contentPath);
return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
}
/// <summary>
/// Downloads the image.
/// </summary>

View File

@ -38,6 +38,12 @@ namespace MediaBrowser.Api
{
}
[Route("/Items/RemoteSearch/Trailer", "POST")]
[Authenticated]
public class GetTrailerRemoteSearchResults : RemoteSearchQuery<TrailerInfo>, IReturn<List<RemoteSearchResult>>
{
}
[Route("/Items/RemoteSearch/AdultVideo", "POST")]
[Authenticated]
public class GetAdultVideoRemoteSearchResults : RemoteSearchQuery<ItemLookupInfo>, IReturn<List<RemoteSearchResult>>
@ -132,60 +138,65 @@ namespace MediaBrowser.Api
return ToOptimizedResult(infos);
}
public object Post(GetMovieRemoteSearchResults request)
public async Task<object> Post(GetTrailerRemoteSearchResults request)
{
var result = _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).Result;
var result = await _providerManager.GetRemoteSearchResults<Trailer, TrailerInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public object Post(GetSeriesRemoteSearchResults request)
public async Task<object> Post(GetMovieRemoteSearchResults request)
{
var result = _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(request, CancellationToken.None).Result;
var result = await _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public object Post(GetGameRemoteSearchResults request)
public async Task<object> Post(GetSeriesRemoteSearchResults request)
{
var result = _providerManager.GetRemoteSearchResults<Game, GameInfo>(request, CancellationToken.None).Result;
var result = await _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public object Post(GetBoxSetRemoteSearchResults request)
public async Task<object> Post(GetGameRemoteSearchResults request)
{
var result = _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(request, CancellationToken.None).Result;
var result = await _providerManager.GetRemoteSearchResults<Game, GameInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public object Post(GetPersonRemoteSearchResults request)
public async Task<object> Post(GetBoxSetRemoteSearchResults request)
{
var result = _providerManager.GetRemoteSearchResults<Person, PersonLookupInfo>(request, CancellationToken.None).Result;
var result = await _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public object Post(GetMusicAlbumRemoteSearchResults request)
public async Task<object> Post(GetPersonRemoteSearchResults request)
{
var result = _providerManager.GetRemoteSearchResults<MusicAlbum, AlbumInfo>(request, CancellationToken.None).Result;
var result = await _providerManager.GetRemoteSearchResults<Person, PersonLookupInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public object Post(GetMusicArtistRemoteSearchResults request)
public async Task<object> Post(GetMusicAlbumRemoteSearchResults request)
{
var result = _providerManager.GetRemoteSearchResults<MusicArtist, ArtistInfo>(request, CancellationToken.None).Result;
var result = await _providerManager.GetRemoteSearchResults<MusicAlbum, AlbumInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
public object Get(GetRemoteSearchImage request)
public async Task<object> Post(GetMusicArtistRemoteSearchResults request)
{
var result = GetRemoteImage(request).Result;
var result = await _providerManager.GetRemoteSearchResults<MusicArtist, ArtistInfo>(request, CancellationToken.None).ConfigureAwait(false);
return result;
return ToOptimizedResult(result);
}
public Task<object> Get(GetRemoteSearchImage request)
{
return GetRemoteImage(request);
}
public void Post(ApplySearchCriteria request)
@ -241,7 +252,7 @@ namespace MediaBrowser.Api
if (_fileSystem.FileExists(contentPath))
{
return ToStaticFileResult(contentPath);
return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
}
}
catch (DirectoryNotFoundException)
@ -261,7 +272,7 @@ namespace MediaBrowser.Api
contentPath = await reader.ReadToEndAsync().ConfigureAwait(false);
}
return ToStaticFileResult(contentPath);
return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
}
/// <summary>

View File

@ -70,26 +70,21 @@ namespace MediaBrowser.Api
Cultures = _localizationManager.GetCultures().ToList()
};
var locationType = item.LocationType;
if (locationType == LocationType.FileSystem ||
locationType == LocationType.Offline)
if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName))
{
if (!(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName))
var inheritedContentType = _libraryManager.GetInheritedContentType(item);
var configuredContentType = _libraryManager.GetConfiguredContentType(item);
if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || !string.IsNullOrWhiteSpace(configuredContentType))
{
var inheritedContentType = _libraryManager.GetInheritedContentType(item);
var configuredContentType = _libraryManager.GetConfiguredContentType(item);
info.ContentTypeOptions = GetContentTypeOptions(true);
info.ContentType = configuredContentType;
if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || !string.IsNullOrWhiteSpace(configuredContentType))
if (string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
info.ContentTypeOptions = GetContentTypeOptions(true);
info.ContentType = configuredContentType;
if (string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
info.ContentTypeOptions = info.ContentTypeOptions
.Where(i => string.IsNullOrWhiteSpace(i.Value) || string.Equals(i.Value, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
.ToList();
}
info.ContentTypeOptions = info.ContentTypeOptions
.Where(i => string.IsNullOrWhiteSpace(i.Value) || string.Equals(i.Value, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
.ToList();
}
}
}
@ -280,11 +275,7 @@ namespace MediaBrowser.Api
episode.AbsoluteEpisodeNumber = request.AbsoluteEpisodeNumber;
}
var hasTags = item as IHasTags;
if (hasTags != null)
{
hasTags.Tags = request.Tags;
}
item.Tags = request.Tags;
var hasTaglines = item as IHasTaglines;
if (hasTaglines != null)
@ -298,11 +289,7 @@ namespace MediaBrowser.Api
hasShortOverview.ShortOverview = request.ShortOverview;
}
var hasKeywords = item as IHasKeywords;
if (hasKeywords != null)
{
hasKeywords.Keywords = request.Keywords;
}
item.Keywords = request.Keywords;
if (request.Studios != null)
{
@ -427,11 +414,6 @@ namespace MediaBrowser.Api
series.Status = request.SeriesStatus;
series.AirDays = request.AirDays;
series.AirTime = request.AirTime;
if (request.DisplaySpecialsWithSeasons.HasValue)
{
series.DisplaySpecialsWithSeasons = request.DisplaySpecialsWithSeasons.Value;
}
}
}

View File

@ -493,7 +493,7 @@ namespace MediaBrowser.Api.Library
}
}
public object Get(GetDownload request)
public Task<object> Get(GetDownload request)
{
var item = _libraryManager.GetItemById(request.Id);
var auth = _authContext.GetAuthorizationInfo(Request);
@ -552,7 +552,7 @@ namespace MediaBrowser.Api.Library
}
}
public object Get(GetFile request)
public Task<object> Get(GetFile request)
{
var item = _libraryManager.GetItemById(request.Id);
var locationType = item.LocationType;
@ -565,7 +565,7 @@ namespace MediaBrowser.Api.Library
throw new ArgumentException("This command cannot be used for directories.");
}
return ToStaticFileResult(item.Path);
return ResultFactory.GetStaticFileResult(Request, item.Path);
}
/// <summary>

View File

@ -146,6 +146,13 @@ namespace MediaBrowser.Api.LiveTv
/// <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; }
public bool EnableTotalRecordCount { get; set; }
public GetRecordings()
{
EnableTotalRecordCount = true;
}
}
[Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
@ -200,6 +207,8 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "SeriesTimerId", Description = "Optional filter by timers belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string SeriesTimerId { get; set; }
public bool? IsActive { get; set; }
}
[Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")]
@ -439,6 +448,12 @@ namespace MediaBrowser.Api.LiveTv
public string Id { get; set; }
}
[Route("/LiveTv/ListingProviders/Default", "GET")]
[Authenticated(AllowBeforeStartupWizard = true)]
public class GetDefaultListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
{
}
[Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
[Authenticated(AllowBeforeStartupWizard = true)]
public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
@ -478,6 +493,32 @@ namespace MediaBrowser.Api.LiveTv
{
}
[Route("/LiveTv/ChannelMappingOptions")]
[Authenticated(AllowBeforeStartupWizard = true)]
public class GetChannelMappingOptions
{
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ProviderId { get; set; }
}
[Route("/LiveTv/ChannelMappings")]
[Authenticated(AllowBeforeStartupWizard = true)]
public class SetChannelMapping
{
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ProviderId { get; set; }
public string TunerChannelNumber { get; set; }
public string ProviderChannelNumber { get; set; }
}
public class ChannelMappingOptions
{
public List<TunerChannelMapping> TunerChannels { get; set; }
public List<NameIdPair> ProviderChannels { get; set; }
public List<NameValuePair> Mappings { get; set; }
public string ProviderName { get; set; }
}
[Route("/LiveTv/Registration", "GET")]
[Authenticated]
public class GetLiveTvRegistrationInfo : IReturn<MBRegistrationRecord>
@ -525,6 +566,11 @@ namespace MediaBrowser.Api.LiveTv
_dtoService = dtoService;
}
public object Get(GetDefaultListingProvider request)
{
return ToOptimizedResult(new ListingsProviderInfo());
}
public async Task<object> Get(GetSatChannnelScanResult request)
{
var result = await _liveTvManager.GetSatChannelScanResult(request, CancellationToken.None).ConfigureAwait(false);
@ -539,6 +585,46 @@ namespace MediaBrowser.Api.LiveTv
return ToOptimizedResult(result);
}
public async Task<object> Post(SetChannelMapping request)
{
return await _liveTvManager.SetChannelMapping(request.ProviderId, request.TunerChannelNumber, request.ProviderChannelNumber).ConfigureAwait(false);
}
public async Task<object> Get(GetChannelMappingOptions request)
{
var config = GetConfiguration();
var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase));
var listingsProviderName = _liveTvManager.ListingProviders.First(i => string.Equals(i.Type, listingsProviderInfo.Type, StringComparison.OrdinalIgnoreCase)).Name;
var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None)
.ConfigureAwait(false);
var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None)
.ConfigureAwait(false);
var mappings = listingsProviderInfo.ChannelMappings.ToList();
var result = new ChannelMappingOptions
{
TunerChannels = tunerChannels.Select(i => _liveTvManager.GetTunerChannelMapping(i, mappings, providerChannels)).ToList(),
ProviderChannels = providerChannels.Select(i => new NameIdPair
{
Name = i.Name,
Id = i.Number
}).ToList(),
Mappings = mappings,
ProviderName = listingsProviderName
};
return ToOptimizedResult(result);
}
public object Get(GetSatIniMappings request)
{
return ToOptimizedResult(_liveTvManager.GetSatIniMappings());
@ -550,9 +636,7 @@ namespace MediaBrowser.Api.LiveTv
var response = await _httpClient.Get(new HttpRequestOptions
{
Url = "https://json.schedulesdirect.org/20141201/available/countries",
CacheLength = TimeSpan.FromDays(1),
CacheMode = CacheMode.Unconditional
Url = "https://json.schedulesdirect.org/20141201/available/countries"
}).ConfigureAwait(false);
@ -582,11 +666,7 @@ namespace MediaBrowser.Api.LiveTv
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);
_liveTvManager.DeleteListingsProvider(request.Id);
}
public async Task<object> Post(AddTunerHost request)
@ -609,6 +689,11 @@ namespace MediaBrowser.Api.LiveTv
return _config.GetConfiguration<LiveTvOptions>("livetv");
}
private void UpdateConfiguration(LiveTvOptions options)
{
_config.SaveConfiguration("livetv", options);
}
public async Task<object> Get(GetLineups request)
{
var info = await _liveTvManager.GetLineups(request.Type, request.Id, request.Country, request.Location).ConfigureAwait(false);
@ -641,14 +726,14 @@ namespace MediaBrowser.Api.LiveTv
var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ToArray();
var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ConfigureAwait(false)).ToArray();
var result = new QueryResult<BaseItemDto>
{
Items = returnArray,
TotalRecordCount = channelResult.TotalRecordCount
};
return ToOptimizedSerializedResultUsingCache(result);
}
@ -752,7 +837,8 @@ namespace MediaBrowser.Api.LiveTv
Limit = request.Limit,
Status = request.Status,
SeriesTimerId = request.SeriesTimerId,
IsInProgress = request.IsInProgress
IsInProgress = request.IsInProgress,
EnableTotalRecordCount = request.EnableTotalRecordCount
}, options, CancellationToken.None).ConfigureAwait(false);
@ -783,7 +869,8 @@ namespace MediaBrowser.Api.LiveTv
var result = await _liveTvManager.GetTimers(new TimerQuery
{
ChannelId = request.ChannelId,
SeriesTimerId = request.SeriesTimerId
SeriesTimerId = request.SeriesTimerId,
IsActive = request.IsActive
}, CancellationToken.None).ConfigureAwait(false);

View File

@ -14,6 +14,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.LiveTv;
namespace MediaBrowser.Api.Movies
{
@ -112,16 +113,14 @@ namespace MediaBrowser.Api.Movies
/// <returns>System.Object.</returns>
public async Task<object> Get(GetSimilarMovies request)
{
var result = await GetSimilarItemsResult(
request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
public async Task<object> Get(GetSimilarTrailers request)
{
var result = await GetSimilarItemsResult(
request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
@ -130,148 +129,93 @@ namespace MediaBrowser.Api.Movies
{
var user = _userManager.GetUserById(request.UserId);
var query = new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Movie).Name }
};
if (user.Configuration.IncludeTrailersInSuggestions)
{
var includeList = query.IncludeItemTypes.ToList();
includeList.Add(typeof(Trailer).Name);
query.IncludeItemTypes = includeList.ToArray();
}
var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
var movies = _libraryManager.GetItemList(query, parentIds)
.OrderBy(i => (int)i.SourceType);
var listEligibleForCategories = new List<BaseItem>();
var listEligibleForSuggestion = new List<BaseItem>();
var list = movies.ToList();
listEligibleForCategories.AddRange(list);
listEligibleForSuggestion.AddRange(list);
listEligibleForCategories = listEligibleForCategories
// Exclude trailers from the suggestion categories
.Where(i => i is Movie)
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
.ToList();
listEligibleForSuggestion = listEligibleForSuggestion
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
.ToList();
var dtoOptions = GetDtoOptions(request);
dtoOptions.Fields = request.GetItemFields().ToList();
var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, dtoOptions);
var result = GetRecommendationCategories(user, request.ParentId, request.CategoryLimit, request.ItemLimit, dtoOptions);
return ToOptimizedResult(result);
}
private async Task<ItemsResult> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem 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);
var query = new InternalItemsQuery(user)
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Movie).Name }
};
if (user == null || user.Configuration.IncludeTrailersInSuggestions)
{
var includeList = query.IncludeItemTypes.ToList();
includeList.Add(typeof(Trailer).Name);
query.IncludeItemTypes = includeList.ToArray();
}
var list = _libraryManager.GetItemList(query)
.OrderBy(i => (int)i.SourceType)
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
.ToList();
if (item is Video)
{
var imdbId = item.GetProviderId(MetadataProviders.Imdb);
// Use imdb id to try to filter duplicates of the same item
if (!string.IsNullOrWhiteSpace(imdbId))
Limit = request.Limit,
IncludeItemTypes = new[]
{
list = list
.Where(i => !string.Equals(imdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase))
.ToList();
}
}
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true,
SimilarTo = item,
EnableGroupByMetadataKey = true
var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList();
IEnumerable<BaseItem> returnItems = items;
if (request.Limit.HasValue)
{
returnItems = returnItems.Take(request.Limit.Value);
}
}).ToList();
var dtoOptions = GetDtoOptions(request);
var result = new ItemsResult
var result = new QueryResult<BaseItemDto>
{
Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
TotalRecordCount = items.Count
TotalRecordCount = itemsResult.Count
};
return result;
}
private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, List<BaseItem> allMoviesForCategories, List<BaseItem> allMovies, int categoryLimit, int itemLimit, DtoOptions dtoOptions)
private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, string parentId, int categoryLimit, int itemLimit, DtoOptions dtoOptions)
{
var categories = new List<RecommendationDto>();
var recentlyPlayedMovies = allMoviesForCategories
.Select(i =>
var parentIdGuid = string.IsNullOrWhiteSpace(parentId) ? (Guid?)null : new Guid(parentId);
var query = new InternalItemsQuery(user)
{
IncludeItemTypes = new[]
{
var userdata = _userDataRepository.GetUserData(user, i);
return new Tuple<BaseItem, bool, DateTime>(i, userdata.Played, userdata.LastPlayedDate ?? DateTime.MinValue);
})
.Where(i => i.Item2)
.OrderByDescending(i => i.Item3)
.Select(i => i.Item1)
.ToList();
typeof(Movie).Name,
//typeof(Trailer).Name,
//typeof(LiveTvProgram).Name
},
// IsMovie = true
SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.Random },
SortOrder = SortOrder.Descending,
Limit = 7,
ParentId = parentIdGuid,
Recursive = true
};
var excludeFromLiked = recentlyPlayedMovies.Take(10);
var likedMovies = allMovies
.Select(i =>
var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList();
var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
IncludeItemTypes = new[]
{
var score = 0;
var userData = _userDataRepository.GetUserData(user, i);
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true,
SortBy = new[] { ItemSortBy.Random },
SortOrder = SortOrder.Descending,
Limit = 10,
IsFavoriteOrLiked = true,
ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(),
EnableGroupByMetadataKey = true,
ParentId = parentIdGuid,
Recursive = true
if (userData.IsFavorite)
{
score = 2;
}
else
{
score = userData.Likes.HasValue ? userData.Likes.Value ? 1 : -1 : 0;
}
return new Tuple<BaseItem, int>(i, score);
})
.OrderByDescending(i => i.Item2)
.ThenBy(i => Guid.NewGuid())
.Where(i => i.Item2 > 0)
.Select(i => i.Item1)
.Where(i => !excludeFromLiked.Contains(i));
}).ToList();
var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList();
// Get recently played directors
@ -284,11 +228,11 @@ namespace MediaBrowser.Api.Movies
.OrderBy(i => Guid.NewGuid())
.ToList();
var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToLikedItem).GetEnumerator();
var similarToRecentlyPlayed = GetSimilarTo(user, recentlyPlayedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
var similarToLiked = GetSimilarTo(user, likedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToLikedItem).GetEnumerator();
var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, dtoOptions, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
var hasActorFromRecentlyPlayed = GetWithActor(user, allMovies, recentActors, itemLimit, dtoOptions, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
var hasDirectorFromRecentlyPlayed = GetWithDirector(user, recentDirectors, itemLimit, dtoOptions, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
var hasActorFromRecentlyPlayed = GetWithActor(user, recentActors, itemLimit, dtoOptions, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
var categoryTypes = new List<IEnumerator<RecommendationDto>>
{
@ -331,44 +275,28 @@ namespace MediaBrowser.Api.Movies
return categories.OrderBy(i => i.RecommendationType).ThenBy(i => Guid.NewGuid());
}
private IEnumerable<RecommendationDto> GetWithDirector(User user, List<BaseItem> allMovies, IEnumerable<string> directors, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var userId = user.Id;
foreach (var director in directors)
{
var items = allMovies
.Where(i => _libraryManager.GetPeople(i).Any(p => string.Equals(p.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) && string.Equals(p.Name, director, StringComparison.OrdinalIgnoreCase)))
.Take(itemLimit)
.ToList();
if (items.Count > 0)
{
yield return new RecommendationDto
{
BaselineItemName = director,
CategoryId = director.GetMD5().ToString("N"),
RecommendationType = type,
Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
};
}
}
}
private IEnumerable<RecommendationDto> GetWithActor(User user, List<BaseItem> allMovies, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
private IEnumerable<RecommendationDto> GetWithDirector(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
foreach (var name in names)
{
var itemsWithActor = _libraryManager.GetItemIds(new InternalItemsQuery(user)
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Person = name
Person = name,
// Account for duplicates by imdb id, since the database doesn't support this yet
Limit = itemLimit + 2,
PersonTypes = new[] { PersonType.Director },
IncludeItemTypes = new[]
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true,
EnableGroupByMetadataKey = true
});
var items = allMovies
.Where(i => itemsWithActor.Contains(i.Id))
.Take(itemLimit)
.ToList();
}).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
.Take(itemLimit)
.ToList();
if (items.Count > 0)
{
@ -377,20 +305,65 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray()
};
}
}
}
private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> allMovies, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
private IEnumerable<RecommendationDto> GetWithActor(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
foreach (var name in names)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Person = name,
// Account for duplicates by imdb id, since the database doesn't support this yet
Limit = itemLimit + 2,
IncludeItemTypes = new[]
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true,
EnableGroupByMetadataKey = true
}).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
.Take(itemLimit)
.ToList();
if (items.Count > 0)
{
yield return new RecommendationDto
{
BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray()
};
}
}
}
private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
foreach (var item in baselineItems)
{
var similar = SimilarItemsHelper
.GetSimilaritems(item, _libraryManager, allMovies, SimilarItemsHelper.GetSimiliarityScore)
.Take(itemLimit)
.ToList();
var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Limit = itemLimit,
IncludeItemTypes = new[]
{
typeof(Movie).Name,
typeof(Trailer).Name,
typeof(LiveTvProgram).Name
},
IsMovie = true,
SimilarTo = item,
EnableGroupByMetadataKey = true
}).ToList();
if (similar.Count > 0)
{
@ -399,7 +372,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = item.Name,
CategoryId = item.Id.ToString("N"),
RecommendationType = type,
Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).ToArray()
Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).Result.ToArray()
};
}
}

View File

@ -58,7 +58,7 @@ namespace MediaBrowser.Api.Movies
getItems.IncludeItemTypes = "Trailer";
return new ItemsService(_userManager, _libraryManager, _userDataRepository, _localizationManager, _dtoService, _collectionManager)
return new ItemsService(_userManager, _libraryManager, _localizationManager, _dtoService)
{
AuthorizationContext = AuthorizationContext,
Logger = Logger,

View File

@ -8,6 +8,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.Api.Music
{
@ -49,18 +50,18 @@ namespace MediaBrowser.Api.Music
_dtoService = dtoService;
}
public object Get(GetSimilarArtists request)
public async Task<object> Get(GetSimilarArtists request)
{
var dtoOptions = GetDtoOptions(request);
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
var result = await SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataRepository,
_dtoService,
Logger,
request, new[] { typeof(MusicArtist) },
SimilarItemsHelper.GetSimiliarityScore);
SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
@ -70,18 +71,18 @@ namespace MediaBrowser.Api.Music
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetSimilarAlbums request)
public async Task<object> Get(GetSimilarAlbums request)
{
var dtoOptions = GetDtoOptions(request);
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
var result = await SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataRepository,
_dtoService,
Logger,
request, new[] { typeof(MusicAlbum) },
GetAlbumSimilarityScore);
GetAlbumSimilarityScore).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}

View File

@ -8,6 +8,7 @@ using MediaBrowser.Model.Querying;
using ServiceStack;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.Api.Music
{
@ -76,7 +77,7 @@ namespace MediaBrowser.Api.Music
_libraryManager = libraryManager;
}
public object Get(GetInstantMixFromItem request)
public Task<object> Get(GetInstantMixFromItem request)
{
var item = _libraryManager.GetItemById(request.Id);
@ -87,7 +88,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
public object Get(GetInstantMixFromArtistId request)
public Task<object> Get(GetInstantMixFromArtistId request)
{
var item = _libraryManager.GetItemById(request.Id);
@ -98,7 +99,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
public object Get(GetInstantMixFromMusicGenreId request)
public Task<object> Get(GetInstantMixFromMusicGenreId request)
{
var item = _libraryManager.GetItemById(request.Id);
@ -109,7 +110,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
public object Get(GetInstantMixFromSong request)
public Task<object> Get(GetInstantMixFromSong request)
{
var item = _libraryManager.GetItemById(request.Id);
@ -120,7 +121,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
public object Get(GetInstantMixFromAlbum request)
public Task<object> Get(GetInstantMixFromAlbum request)
{
var album = _libraryManager.GetItemById(request.Id);
@ -131,7 +132,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
public object Get(GetInstantMixFromPlaylist request)
public Task<object> Get(GetInstantMixFromPlaylist request)
{
var playlist = (Playlist)_libraryManager.GetItemById(request.Id);
@ -142,7 +143,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
public object Get(GetInstantMixFromMusicGenre request)
public Task<object> Get(GetInstantMixFromMusicGenre request)
{
var user = _userManager.GetUserById(request.UserId);
@ -151,7 +152,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
public object Get(GetInstantMixFromArtist request)
public Task<object> Get(GetInstantMixFromArtist request)
{
var user = _userManager.GetUserById(request.UserId);
var artist = _libraryManager.GetArtist(request.Name);
@ -161,7 +162,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
private object GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
private async Task<object> GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
{
var list = items.ToList();
@ -172,7 +173,7 @@ namespace MediaBrowser.Api.Music
var dtoOptions = GetDtoOptions(request);
result.Items = _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ToArray();
result.Items = (await _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ConfigureAwait(false)).ToArray();
return ToOptimizedResult(result);
}

View File

@ -112,7 +112,7 @@ namespace MediaBrowser.Api
_appHost = appHost;
}
public object Get(ReviewRequest request)
public async Task<object> Get(ReviewRequest request)
{
var parms = "?id=" + request.Id;
@ -133,11 +133,13 @@ namespace MediaBrowser.Api
parms += "&title=true";
}
var result = _httpClient.Get(MbAdminUrl + "/service/packageReview/retrieve" + parms, CancellationToken.None).Result;
using (var result = await _httpClient.Get(MbAdminUrl + "/service/packageReview/retrieve" + parms, CancellationToken.None)
.ConfigureAwait(false))
{
var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result);
var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result);
return ToOptimizedResult(reviews);
return ToOptimizedResult(reviews);
}
}
public void Post(CreateReviewRequest request)

View File

@ -286,11 +286,19 @@ namespace MediaBrowser.Api.Playback
protected string GetH264Encoder(StreamState state)
{
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "h264_qsv", StringComparison.OrdinalIgnoreCase))
{
return "h264_qsv";
}
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "libnvenc", StringComparison.OrdinalIgnoreCase))
{
return "libnvenc";
}
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "h264_omx", StringComparison.OrdinalIgnoreCase))
{
return "h264_omx";
}
return "libx264";
@ -395,15 +403,18 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrEmpty(state.VideoRequest.Profile))
{
param += " -profile:v " + state.VideoRequest.Profile;
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
{
// not supported by h264_omx
param += " -profile:v " + state.VideoRequest.Profile;
}
}
if (!string.IsNullOrEmpty(state.VideoRequest.Level))
{
var h264Encoder = GetH264Encoder(state);
// h264_qsv and libnvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
if (String.Equals(h264Encoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || String.Equals(h264Encoder, "libnvenc", StringComparison.OrdinalIgnoreCase))
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase))
{
switch (state.VideoRequest.Level)
{
@ -438,16 +449,21 @@ namespace MediaBrowser.Api.Playback
param += " -level " + state.VideoRequest.Level;
break;
}
return param;
}
else
else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
{
param += " -level " + state.VideoRequest.Level;
}
}
return "-pix_fmt yuv420p " + param;
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt yuv420p " + param;
}
return param;
}
protected string GetAudioFilterParam(StreamState state, bool isHls)
@ -563,14 +579,6 @@ namespace MediaBrowser.Api.Playback
filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(ih\\,{0})", maxHeightParam));
}
if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
{
if (filters.Count > 1)
{
//filters[filters.Count - 1] += ":flags=fast_bilinear";
}
}
var output = string.Empty;
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode)
@ -846,7 +854,7 @@ namespace MediaBrowser.Api.Playback
if (MediaEncoder.SupportsDecoder("h264_qsv"))
{
// Seeing stalls and failures with decoding. Not worth it compared to encoding.
//return "-c:v h264_qsv ";
return "-c:v h264_qsv ";
}
break;
case "mpeg2video":
@ -980,11 +988,6 @@ namespace MediaBrowser.Api.Playback
var transcodingId = Guid.NewGuid().ToString("N");
var commandLineArgs = GetCommandLineArguments(outputPath, state, true);
if (ApiEntryPoint.Instance.GetEncodingOptions().EnableDebugLogging)
{
commandLineArgs = "-loglevel debug " + commandLineArgs;
}
var process = new Process
{
StartInfo = new ProcessStartInfo
@ -1212,7 +1215,7 @@ namespace MediaBrowser.Api.Playback
}
}
private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream)
private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream, string outputVideoCodec)
{
var bitrate = request.VideoBitRate;
@ -1237,6 +1240,18 @@ namespace MediaBrowser.Api.Playback
}
}
if (bitrate.HasValue)
{
var inputVideoCodec = videoStream == null ? null : videoStream.Codec;
bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
// If a max bitrate was requested, don't let the scaled bitrate exceed it
if (request.VideoBitRate.HasValue)
{
bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
}
}
return bitrate;
}
@ -1518,6 +1533,13 @@ namespace MediaBrowser.Api.Playback
}
}
else if (i == 25)
{
if (videoRequest != null)
{
videoRequest.ForceLiveStream = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
}
}
else if (i == 26)
{
if (!string.IsNullOrWhiteSpace(val) && videoRequest != null)
{
@ -1528,7 +1550,7 @@ namespace MediaBrowser.Api.Playback
}
}
}
else if (i == 26)
else if (i == 27)
{
request.TranscodingMaxAudioChannels = int.Parse(val, UsCulture);
}
@ -1636,7 +1658,8 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrWhiteSpace(request.AudioCodec))
{
state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault();
state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToAudioCodec(i))
?? state.SupportedAudioCodecs.FirstOrDefault();
}
var item = LibraryManager.GetItemById(request.Id);
@ -1690,7 +1713,7 @@ namespace MediaBrowser.Api.Playback
if (videoRequest != null)
{
state.OutputVideoCodec = state.VideoRequest.VideoCodec;
state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream);
state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
if (state.OutputVideoBitrate.HasValue)
{

View File

@ -63,9 +63,9 @@ namespace MediaBrowser.Api.Playback.Hls
/// <param name="request">The request.</param>
/// <param name="isLive">if set to <c>true</c> [is live].</param>
/// <returns>System.Object.</returns>
protected object ProcessRequest(StreamRequest request, bool isLive)
protected async Task<object> ProcessRequest(StreamRequest request, bool isLive)
{
return ProcessRequestAsync(request, isLive).Result;
return await ProcessRequestAsync(request, isLive).ConfigureAwait(false);
}
/// <summary>

View File

@ -475,7 +475,7 @@ namespace MediaBrowser.Api.Playback.Hls
ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob);
}
}
});
}).Result;
}
private async Task<object> GetMasterPlaylistInternal(StreamRequest request, string method)

View File

@ -5,6 +5,7 @@ using ServiceStack;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.Api.Playback.Hls
{
@ -89,7 +90,7 @@ namespace MediaBrowser.Api.Playback.Hls
_config = config;
}
public object Get(GetHlsPlaylistLegacy request)
public Task<object> Get(GetHlsPlaylistLegacy request)
{
var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_appPaths.TranscodingTempPath, file);
@ -107,7 +108,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetHlsVideoSegmentLegacy request)
public Task<object> Get(GetHlsVideoSegmentLegacy request)
{
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, file);
@ -131,10 +132,10 @@ namespace MediaBrowser.Api.Playback.Hls
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_appPaths.TranscodingTempPath, file);
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite).Result;
}
private object GetFileResult(string path, string playlistPath)
private Task<object> GetFileResult(string path, string playlistPath)
{
var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls);

View File

@ -9,6 +9,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
using ServiceStack;
using System.Collections.Generic;
using System.Threading.Tasks;
using CommonIO;
namespace MediaBrowser.Api.Playback.Progressive
@ -40,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetAudioStream request)
public Task<object> Get(GetAudioStream request)
{
return ProcessRequest(request, false);
}
@ -50,7 +51,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Head(GetAudioStream request)
public Task<object> Head(GetAudioStream request)
{
return ProcessRequest(request, true);
}

View File

@ -113,11 +113,11 @@ namespace MediaBrowser.Api.Playback.Progressive
/// <param name="request">The request.</param>
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
/// <returns>Task.</returns>
protected object ProcessRequest(StreamRequest request, bool isHeadRequest)
protected async Task<object> ProcessRequest(StreamRequest request, bool isHeadRequest)
{
var cancellationTokenSource = new CancellationTokenSource();
var state = GetState(request, cancellationTokenSource.Token).Result;
var state = await GetState(request, cancellationTokenSource.Token).ConfigureAwait(false);
var responseHeaders = new Dictionary<string, string>();
@ -128,7 +128,8 @@ namespace MediaBrowser.Api.Playback.Progressive
using (state)
{
return GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).Result;
return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource)
.ConfigureAwait(false);
}
}
@ -138,7 +139,7 @@ namespace MediaBrowser.Api.Playback.Progressive
}
var outputPath = state.OutputFilePath;
var outputPathExists = FileSystem.FileExists(outputPath);
var outputPathExists = FileSystem.FileExists(outputPath);
var isTranscodeCached = outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive);
@ -151,13 +152,13 @@ namespace MediaBrowser.Api.Playback.Progressive
using (state)
{
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
ResponseHeaders = responseHeaders,
ContentType = contentType,
IsHeadRequest = isHeadRequest,
Path = state.MediaPath
});
}).ConfigureAwait(false);
}
}
@ -168,13 +169,13 @@ namespace MediaBrowser.Api.Playback.Progressive
try
{
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
ResponseHeaders = responseHeaders,
ContentType = contentType,
IsHeadRequest = isHeadRequest,
Path = outputPath
});
}).ConfigureAwait(false);
}
finally
{
@ -185,7 +186,8 @@ namespace MediaBrowser.Api.Playback.Progressive
// Need to start ffmpeg
try
{
return GetStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).Result;
return await GetStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource)
.ConfigureAwait(false);
}
catch
{
@ -229,7 +231,7 @@ namespace MediaBrowser.Api.Playback.Progressive
if (trySupportSeek)
{
foreach (var name in new[] {"Content-Range", "Accept-Ranges"})
foreach (var name in new[] { "Content-Range", "Accept-Ranges" })
{
var val = response.Headers[name];
if (!string.IsNullOrWhiteSpace(val))
@ -242,12 +244,12 @@ namespace MediaBrowser.Api.Playback.Progressive
{
responseHeaders["Accept-Ranges"] = "none";
}
if (response.ContentLength.HasValue)
{
responseHeaders["Content-Length"] = response.ContentLength.Value.ToString(UsCulture);
}
if (isHeadRequest)
{
using (response)
@ -324,7 +326,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{
TranscodingJob job;
if (!FileSystem.FileExists(outputPath))
if (!FileSystem.FileExists(outputPath))
{
job = await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false);
}

View File

@ -10,6 +10,7 @@ using MediaBrowser.Model.Serialization;
using ServiceStack;
using System;
using System.IO;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Model.Dlna;
@ -76,7 +77,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetVideoStream request)
public Task<object> Get(GetVideoStream request)
{
return ProcessRequest(request, false);
}
@ -86,7 +87,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Head(GetVideoStream request)
public Task<object> Head(GetVideoStream request)
{
return ProcessRequest(request, true);
}

View File

@ -96,7 +96,7 @@ namespace MediaBrowser.Api.Playback
public long? InputFileSize { get; set; }
public string OutputAudioSync = "1";
public string OutputVideoSync = "vfr";
public string OutputVideoSync = "-1";
public List<string> SupportedAudioCodecs { get; set; }

View File

@ -157,7 +157,7 @@ namespace MediaBrowser.Api
Task.WaitAll(task);
}
public object Get(GetPlaylistItems request)
public async Task<object> Get(GetPlaylistItems request)
{
var playlist = (Playlist)_libraryManager.GetItemById(request.Id);
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@ -178,7 +178,7 @@ namespace MediaBrowser.Api
var dtoOptions = GetDtoOptions(request);
var dtos = _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user)
var dtos = (await _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user).ConfigureAwait(false))
.ToArray();
var index = 0;

View File

@ -213,7 +213,6 @@ namespace MediaBrowser.Api.Reports
NameStartsWith = request.NameStartsWith,
NameStartsWithOrGreater = request.NameStartsWithOrGreater,
HasImdbId = request.HasImdbId,
IsYearMismatched = request.IsYearMismatched,
IsPlaceHolder = request.IsPlaceHolder,
IsLocked = request.IsLocked,
IsInBoxSet = request.IsInBoxSet,

View File

@ -9,6 +9,8 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api
{
@ -54,7 +56,7 @@ namespace MediaBrowser.Api
/// </summary>
public static class SimilarItemsHelper
{
internal static ItemsResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
internal static async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? userManager.GetUserById(request.UserId) : null;
@ -80,14 +82,14 @@ namespace MediaBrowser.Api
returnItems = returnItems.Take(request.Limit.Value);
}
var result = new ItemsResult
var dtos = await dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ConfigureAwait(false);
return new QueryResult<BaseItemDto>
{
Items = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
Items = dtos.ToArray(),
TotalRecordCount = items.Count
};
return result;
}
/// <summary>
@ -116,24 +118,12 @@ namespace MediaBrowser.Api
private static IEnumerable<string> GetTags(BaseItem item)
{
var hasTags = item as IHasTags;
if (hasTags != null)
{
return hasTags.Tags;
}
return new List<string>();
return item.Tags;
}
private static IEnumerable<string> GetKeywords(BaseItem item)
{
var hasTags = item as IHasKeywords;
if (hasTags != null)
{
return hasTags.Keywords;
}
return new List<string>();
return item.Keywords;
}
/// <summary>

View File

@ -11,6 +11,7 @@ using ServiceStack;
using System;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Api
{
@ -52,14 +53,16 @@ namespace MediaBrowser.Api
private readonly IUserManager _userManager;
private readonly IConnectManager _connectManager;
private readonly ILiveTvManager _liveTvManager;
private readonly IMediaEncoder _mediaEncoder;
public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, ILiveTvManager liveTvManager)
public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, ILiveTvManager liveTvManager, IMediaEncoder mediaEncoder)
{
_config = config;
_appHost = appHost;
_userManager = userManager;
_connectManager = connectManager;
_liveTvManager = liveTvManager;
_mediaEncoder = mediaEncoder;
}
public void Post(ReportStartupWizardComplete request)
@ -69,13 +72,14 @@ namespace MediaBrowser.Api
_config.SaveConfiguration();
}
public object Get(GetStartupInfo request)
public async Task<object> Get(GetStartupInfo request)
{
var info = _appHost.GetSystemInfo();
var info = await _appHost.GetSystemInfo().ConfigureAwait(false);
return new StartupInfo
{
SupportsRunningAsService = info.SupportsRunningAsService
SupportsRunningAsService = info.SupportsRunningAsService,
HasMediaEncoder = !string.IsNullOrWhiteSpace(_mediaEncoder.EncoderPath)
};
}
@ -111,10 +115,10 @@ namespace MediaBrowser.Api
{
config.EnableLocalizedGuids = true;
config.EnableCustomPathSubFolders = true;
config.EnableDateLastRefresh = true;
config.EnableStandaloneMusicKeys = true;
config.EnableCaseSensitiveItemIds = true;
config.SchemaVersion = 79;
config.EnableFolderView = true;
config.SchemaVersion = 97;
}
public void Post(UpdateStartupConfiguration request)
@ -231,6 +235,7 @@ namespace MediaBrowser.Api
public class StartupInfo
{
public bool SupportsRunningAsService { get; set; }
public bool HasMediaEncoder { get; set; }
}
public class StartupUser

View File

@ -98,6 +98,10 @@ namespace MediaBrowser.Api.Subtitles
[ApiMember(Name = "EndPositionTicks", Description = "EndPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public long? EndPositionTicks { get; set; }
[ApiMember(Name = "CopyTimestamps", Description = "CopyTimestamps", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool CopyTimestamps { get; set; }
public bool AddVttTimeMap { get; set; }
}
[Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
@ -175,7 +179,7 @@ namespace MediaBrowser.Api.Subtitles
var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks);
var url = string.Format("stream.vtt?StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}",
var url = string.Format("stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}",
positionTicks.ToString(CultureInfo.InvariantCulture),
endPositionTicks.ToString(CultureInfo.InvariantCulture),
accessToken);
@ -190,7 +194,7 @@ namespace MediaBrowser.Api.Subtitles
return ResultFactory.GetResult(builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
public object Get(GetSubtitle request)
public async Task<object> Get(GetSubtitle request)
{
if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase))
{
@ -206,23 +210,35 @@ namespace MediaBrowser.Api.Subtitles
var subtitleStream = mediaSource.MediaStreams
.First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index);
return ToStaticFileResult(subtitleStream.Path);
return await ResultFactory.GetStaticFileResult(Request, subtitleStream.Path).ConfigureAwait(false);
}
var stream = GetSubtitles(request).Result;
using (var stream = await GetSubtitles(request).ConfigureAwait(false))
{
using (var reader = new StreamReader(stream))
{
var text = reader.ReadToEnd();
return ResultFactory.GetResult(stream, MimeTypes.GetMimeType("file." + request.Format));
if (string.Equals(request.Format, "vtt", StringComparison.OrdinalIgnoreCase) && request.AddVttTimeMap)
{
text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000");
}
return ResultFactory.GetResult(text, MimeTypes.GetMimeType("file." + request.Format));
}
}
}
private async Task<Stream> GetSubtitles(GetSubtitle request)
private Task<Stream> GetSubtitles(GetSubtitle request)
{
return await _subtitleEncoder.GetSubtitles(request.Id,
return _subtitleEncoder.GetSubtitles(request.Id,
request.MediaSourceId,
request.Index,
request.Format,
request.StartPositionTicks,
request.EndPositionTicks,
CancellationToken.None).ConfigureAwait(false);
request.CopyTimestamps,
CancellationToken.None);
}
public object Get(SearchRemoteSubtitles request)
@ -248,9 +264,9 @@ namespace MediaBrowser.Api.Subtitles
return ToOptimizedResult(result);
}
public object Get(GetRemoteSubtitles request)
public async Task<object> Get(GetRemoteSubtitles request)
{
var result = _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).Result;
var result = await _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).ConfigureAwait(false);
return ResultFactory.GetResult(result.Stream, MimeTypes.GetMimeType("file." + result.Format));
}

View File

@ -227,7 +227,7 @@ namespace MediaBrowser.Api.Sync
Task.WaitAll(task);
}
public object Get(GetSyncJobItemFile request)
public async Task<object> Get(GetSyncJobItemFile request)
{
var jobItem = _syncManager.GetJobItem(request.Id);
@ -241,10 +241,9 @@ namespace MediaBrowser.Api.Sync
throw new ArgumentException("The job item is not yet ready for transfer.");
}
var task = _syncManager.ReportSyncJobItemTransferBeginning(request.Id);
Task.WaitAll(task);
await _syncManager.ReportSyncJobItemTransferBeginning(request.Id).ConfigureAwait(false);
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
Path = jobItem.OutputPath,
OnError = () =>
@ -252,10 +251,11 @@ namespace MediaBrowser.Api.Sync
var failedTask = _syncManager.ReportSyncJobItemTransferFailed(request.Id);
Task.WaitAll(failedTask);
}
});
}).ConfigureAwait(false);
}
public object Get(GetSyncDialogOptions request)
public async Task<object> Get(GetSyncDialogOptions request)
{
var result = new SyncDialogOptions();
@ -298,8 +298,7 @@ namespace MediaBrowser.Api.Sync
.Select(_libraryManager.GetItemById)
.Where(i => i != null);
var dtos = _dtoService.GetBaseItemDtos(items, dtoOptions, authenticatedUser)
.ToList();
var dtos = (await _dtoService.GetBaseItemDtos(items, dtoOptions, authenticatedUser).ConfigureAwait(false));
result.Options = SyncHelper.GetSyncOptions(dtos);
}
@ -343,7 +342,7 @@ namespace MediaBrowser.Api.Sync
Task.WaitAll(task);
}
public object Get(GetSyncJobItemAdditionalFile request)
public Task<object> Get(GetSyncJobItemAdditionalFile request)
{
var jobItem = _syncManager.GetJobItem(request.Id);
@ -359,7 +358,7 @@ namespace MediaBrowser.Api.Sync
throw new ArgumentException("Sync job additional file not found.");
}
return ToStaticFileResult(file.Path);
return ResultFactory.GetStaticFileResult(Request, file.Path);
}
public void Post(EnableSyncJobItem request)

View File

@ -43,7 +43,7 @@ namespace MediaBrowser.Api.System
/// <returns>Task{SystemInfo}.</returns>
protected override Task<SystemInfo> GetDataToSend(WebSocketListenerState state)
{
return Task.FromResult(_appHost.GetSystemInfo());
return _appHost.GetSystemInfo();
}
}
}

View File

@ -19,7 +19,7 @@ namespace MediaBrowser.Api.System
/// Class GetSystemInfo
/// </summary>
[Route("/System/Info", "GET", Summary = "Gets information about the server")]
[Authenticated(EscapeParentalControl = true)]
[Authenticated(EscapeParentalControl = true, AllowBeforeStartupWizard = true)]
public class GetSystemInfo : IReturn<SystemInfo>
{
@ -120,7 +120,7 @@ namespace MediaBrowser.Api.System
try
{
files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
.Where(i => string.Equals(i.Extension, ".txt", StringComparison.OrdinalIgnoreCase))
.ToList();
}
@ -144,9 +144,9 @@ namespace MediaBrowser.Api.System
return ToOptimizedResult(result);
}
public object Get(GetLogFile request)
public Task<object> Get(GetLogFile request)
{
var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
.First(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase));
return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShare.ReadWrite);
@ -157,16 +157,16 @@ namespace MediaBrowser.Api.System
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetSystemInfo request)
public async Task<object> Get(GetSystemInfo request)
{
var result = _appHost.GetSystemInfo();
var result = await _appHost.GetSystemInfo().ConfigureAwait(false);
return ToOptimizedResult(result);
}
public object Get(GetPublicSystemInfo request)
public async Task<object> Get(GetPublicSystemInfo request)
{
var result = _appHost.GetSystemInfo();
var result = await _appHost.GetSystemInfo().ConfigureAwait(false);
var publicInfo = new PublicSystemInfo
{

View File

@ -12,6 +12,8 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api
{
@ -271,29 +273,51 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetSimilarShows request)
public async Task<object> Get(GetSimilarShows request)
{
var dtoOptions = GetDtoOptions(request);
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataManager,
_dtoService,
Logger,
request, new[] { typeof(Series) },
SimilarItemsHelper.GetSimiliarityScore);
var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
public object Get(GetUpcomingEpisodes request)
private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem 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);
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Limit = request.Limit,
IncludeItemTypes = new[]
{
typeof(Series).Name
},
SimilarTo = item
}).ToList();
var dtoOptions = GetDtoOptions(request);
var result = new QueryResult<BaseItemDto>
{
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
TotalRecordCount = itemsResult.Count
};
return result;
}
public async Task<object> Get(GetUpcomingEpisodes request)
{
var user = _userManager.GetUserById(request.UserId);
var minPremiereDate = DateTime.Now.Date.ToUniversalTime().AddDays(-1);
var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
var parentIdGuid = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId);
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
@ -302,13 +326,15 @@ namespace MediaBrowser.Api
SortOrder = SortOrder.Ascending,
MinPremiereDate = minPremiereDate,
StartIndex = request.StartIndex,
Limit = request.Limit
Limit = request.Limit,
ParentId = parentIdGuid,
Recursive = true
}, parentIds).ToList();
}).ToList();
var options = GetDtoOptions(request);
var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user).ToArray();
var returnItems = (await _dtoService.GetBaseItemDtos(itemsResult, options, user).ConfigureAwait(false)).ToArray();
var result = new ItemsResult
{
@ -324,7 +350,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
public object Get(GetNextUpEpisodes request)
public async Task<object> Get(GetNextUpEpisodes request)
{
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
{
@ -339,7 +365,7 @@ namespace MediaBrowser.Api
var options = GetDtoOptions(request);
var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user).ToArray();
var returnItems = (await _dtoService.GetBaseItemDtos(result.Items, options, user).ConfigureAwait(false)).ToArray();
return ToOptimizedSerializedResultUsingCache(new ItemsResult
{
@ -372,7 +398,7 @@ namespace MediaBrowser.Api
return items;
}
public object Get(GetSeasons request)
public async Task<object> Get(GetSeasons request)
{
var user = _userManager.GetUserById(request.UserId);
@ -403,7 +429,7 @@ namespace MediaBrowser.Api
var dtoOptions = GetDtoOptions(request);
var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user)
var returnItems = (await _dtoService.GetBaseItemDtos(seasons, dtoOptions, user).ConfigureAwait(false))
.ToArray();
return new ItemsResult
@ -430,7 +456,7 @@ namespace MediaBrowser.Api
return items;
}
public object Get(GetEpisodes request)
public async Task<object> Get(GetEpisodes request)
{
var user = _userManager.GetUserById(request.UserId);
@ -512,7 +538,7 @@ namespace MediaBrowser.Api
var dtoOptions = GetDtoOptions(request);
var dtos = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user)
var dtos = (await _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ConfigureAwait(false))
.ToArray();
return new ItemsResult

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Dto;
using System;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
@ -8,6 +9,8 @@ using MediaBrowser.Model.Dto;
using ServiceStack;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
@ -100,7 +103,12 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetArtists request)
{
var result = GetResult(request);
if (string.IsNullOrWhiteSpace(request.IncludeItemTypes))
{
//request.IncludeItemTypes = "Audio,MusicVideo";
}
var result = GetResultSlim(request);
return ToOptimizedResult(result);
}
@ -112,11 +120,26 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetAlbumArtists request)
{
var result = GetResult(request);
if (string.IsNullOrWhiteSpace(request.IncludeItemTypes))
{
//request.IncludeItemTypes = "Audio,MusicVideo";
}
var result = GetResultSlim(request);
return ToOptimizedResult(result);
}
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
{
if (request is GetAlbumArtists)
{
return LibraryManager.GetAlbumArtists(query);
}
return LibraryManager.GetArtists(query);
}
/// <summary>
/// Gets all items.
/// </summary>
@ -125,16 +148,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
if (request is GetAlbumArtists)
{
return LibraryManager.GetAlbumArtists(items
.Where(i => !i.IsFolder)
.OfType<IHasAlbumArtist>());
}
return LibraryManager.GetArtists(items
.Where(i => !i.IsFolder)
.OfType<IHasArtist>());
throw new NotImplementedException();
}
}
}

View File

@ -8,6 +8,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api.UserLibrary
{
@ -83,6 +84,137 @@ namespace MediaBrowser.Api.UserLibrary
return null;
}
protected ItemsResult GetResultSlim(GetItemsByName request)
{
var dtoOptions = GetDtoOptions(request);
User user = null;
BaseItem parentItem;
if (!string.IsNullOrWhiteSpace(request.UserId))
{
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);
}
var excludeItemTypes = request.GetExcludeItemTypes();
var includeItemTypes = request.GetIncludeItemTypes();
var mediaTypes = request.GetMediaTypes();
var query = new InternalItemsQuery(user)
{
ExcludeItemTypes = excludeItemTypes,
IncludeItemTypes = includeItemTypes,
MediaTypes = mediaTypes,
StartIndex = request.StartIndex,
Limit = request.Limit,
IsFavorite = request.IsFavorite,
NameLessThan = request.NameLessThan,
NameStartsWith = request.NameStartsWith,
NameStartsWithOrGreater = request.NameStartsWithOrGreater,
AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater,
Tags = request.GetTags(),
OfficialRatings = request.GetOfficialRatings(),
Genres = request.GetGenres(),
GenreIds = request.GetGenreIds(),
Studios = request.GetStudios(),
StudioIds = request.GetStudioIds(),
Person = request.Person,
PersonIds = request.GetPersonIds(),
PersonTypes = request.GetPersonTypes(),
Years = request.GetYears(),
MinCommunityRating = request.MinCommunityRating
};
if (!string.IsNullOrWhiteSpace(request.ParentId))
{
if (parentItem is Folder)
{
query.AncestorIds = new[] { request.ParentId };
}
else
{
query.ItemIds = new[] { request.ParentId };
}
}
foreach (var filter in request.GetFilters())
{
switch (filter)
{
case ItemFilter.Dislikes:
query.IsLiked = false;
break;
case ItemFilter.IsFavorite:
query.IsFavorite = true;
break;
case ItemFilter.IsFavoriteOrLikes:
query.IsFavoriteOrLiked = true;
break;
case ItemFilter.IsFolder:
query.IsFolder = true;
break;
case ItemFilter.IsNotFolder:
query.IsFolder = false;
break;
case ItemFilter.IsPlayed:
query.IsPlayed = true;
break;
case ItemFilter.IsRecentlyAdded:
break;
case ItemFilter.IsResumable:
query.IsResumable = true;
break;
case ItemFilter.IsUnplayed:
query.IsPlayed = false;
break;
case ItemFilter.Likes:
query.IsLiked = true;
break;
}
}
var result = GetItems(request, query);
var dtos = result.Items.Select(i =>
{
var dto = DtoService.GetItemByNameDto(i.Item1, dtoOptions, null, user);
if (!string.IsNullOrWhiteSpace(request.IncludeItemTypes))
{
SetItemCounts(dto, i.Item2);
}
return dto;
});
return new ItemsResult
{
Items = dtos.ToArray(),
TotalRecordCount = result.TotalRecordCount
};
}
protected virtual QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
{
return new QueryResult<Tuple<BaseItem, ItemCounts>>();
}
private void SetItemCounts(BaseItemDto dto, ItemCounts counts)
{
dto.ChildCount = counts.ItemCount;
dto.SeriesCount = counts.SeriesCount;
dto.EpisodeCount = counts.EpisodeCount;
dto.MovieCount = counts.MovieCount;
dto.TrailerCount = counts.TrailerCount;
dto.AlbumCount = counts.AlbumCount;
dto.SongCount = counts.SongCount;
dto.GameCount = counts.GameCount;
}
/// <summary>
/// Gets the specified request.
/// </summary>
@ -333,12 +465,7 @@ namespace MediaBrowser.Api.UserLibrary
var tags = request.GetTags();
if (tags.Length > 0)
{
var hasTags = i as IHasTags;
if (hasTags == null)
{
return false;
}
if (!tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
if (!tags.Any(v => i.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
{
return false;
}
@ -379,7 +506,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="includeItemTypes">The include item types.</param>
/// <param name="mediaTypes">The media types.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
protected bool FilterItem(GetItemsByName request, BaseItem f, string[] excludeItemTypes, string[] includeItemTypes, string[] mediaTypes)
private bool FilterItem(GetItemsByName request, BaseItem f, string[] excludeItemTypes, string[] includeItemTypes, string[] mediaTypes)
{
// Exclude item types
if (excludeItemTypes.Length > 0)

View File

@ -100,9 +100,6 @@ namespace MediaBrowser.Api.UserLibrary
[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; }

View File

@ -9,16 +9,13 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
[Route("/GameGenres", "GET", Summary = "Gets all Game genres from a given item, folder, or the entire library")]
public class GetGameGenres : GetItemsByName
{
public GetGameGenres()
{
MediaTypes = MediaType.Game;
}
}
[Route("/GameGenres/{Name}", "GET", Summary = "Gets a Game genre, by name")]
@ -87,11 +84,16 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetGameGenres request)
{
var result = GetResult(request);
var result = GetResultSlim(request);
return ToOptimizedSerializedResultUsingCache(result);
}
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
{
return LibraryManager.GetGameGenres(query);
}
/// <summary>
/// Gets all items.
/// </summary>
@ -100,22 +102,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
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);
throw new NotImplementedException();
}
}
}

View File

@ -9,6 +9,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
@ -92,11 +93,28 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetGenres request)
{
var result = GetResult(request);
var result = GetResultSlim(request);
return ToOptimizedSerializedResultUsingCache(result);
}
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
{
var viewType = GetParentItemViewType(request);
if (string.Equals(viewType, CollectionType.Music) || string.Equals(viewType, CollectionType.MusicVideos))
{
return LibraryManager.GetMusicGenres(query);
}
if (string.Equals(viewType, CollectionType.Games))
{
return LibraryManager.GetGameGenres(query);
}
return LibraryManager.GetGenres(query);
}
/// <summary>
/// Gets all items.
/// </summary>
@ -105,52 +123,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
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()
.Select(name =>
{
try
{
return LibraryManager.GetGenre(name);
}
catch (Exception ex)
{
Logger.ErrorException("Error getting genre {0}", ex, name);
return null;
}
})
.Where(i => i != null);
throw new NotImplementedException();
}
}
}

View File

@ -34,7 +34,6 @@ namespace MediaBrowser.Api.UserLibrary
/// The _user manager
/// </summary>
private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataRepository;
/// <summary>
/// The _library manager
@ -43,25 +42,37 @@ namespace MediaBrowser.Api.UserLibrary
private readonly ILocalizationManager _localization;
private readonly IDtoService _dtoService;
private readonly ICollectionManager _collectionManager;
/// <summary>
/// Initializes a new instance of the <see cref="ItemsService" /> class.
/// </summary>
/// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param>
/// <param name="userDataRepository">The user data repository.</param>
/// <param name="localization">The localization.</param>
/// <param name="dtoService">The dto service.</param>
/// <param name="collectionManager">The collection manager.</param>
public ItemsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, ILocalizationManager localization, IDtoService dtoService, ICollectionManager collectionManager)
public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILocalizationManager localization, IDtoService dtoService)
{
if (userManager == null)
{
throw new ArgumentNullException("userManager");
}
if (libraryManager == null)
{
throw new ArgumentNullException("libraryManager");
}
if (localization == null)
{
throw new ArgumentNullException("localization");
}
if (dtoService == null)
{
throw new ArgumentNullException("dtoService");
}
_userManager = userManager;
_libraryManager = libraryManager;
_userDataRepository = userDataRepository;
_localization = localization;
_dtoService = dtoService;
_collectionManager = collectionManager;
}
/// <summary>
@ -71,6 +82,11 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public async Task<object> Get(GetItems request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
var result = await GetItems(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
@ -84,15 +100,32 @@ namespace MediaBrowser.Api.UserLibrary
private async Task<ItemsResult> GetItems(GetItems request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
var result = await GetItemsToSerialize(request, user).ConfigureAwait(false);
if (result == null)
{
throw new InvalidOperationException("GetItemsToSerialize returned null");
}
if (result.Items == null)
{
throw new InvalidOperationException("GetItemsToSerialize result.Items returned null");
}
var dtoOptions = GetDtoOptions(request);
var dtoList = await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false);
if (dtoList == null)
{
throw new InvalidOperationException("GetBaseItemDtos returned null");
}
return new ItemsResult
{
TotalRecordCount = result.TotalRecordCount,
Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ToArray()
Items = dtoList.ToArray()
};
}
@ -119,11 +152,17 @@ namespace MediaBrowser.Api.UserLibrary
// Default list type = children
var folder = item as Folder;
if (folder == null)
{
folder = user == null ? _libraryManager.RootFolder : _libraryManager.GetUserRootFolder();
}
if (!string.IsNullOrEmpty(request.Ids))
{
request.Recursive = true;
var query = GetItemsQuery(request, user);
var result = await ((Folder)item).GetItems(query).ConfigureAwait(false);
var result = await folder.GetItems(query).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(request.SortBy))
{
@ -138,22 +177,22 @@ namespace MediaBrowser.Api.UserLibrary
if (request.Recursive)
{
return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
}
if (user == null)
{
return await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
return await folder.GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
}
var userRoot = item as UserRootFolder;
if (userRoot == null)
{
return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
}
IEnumerable<BaseItem> items = ((Folder)item).GetChildren(user, true);
IEnumerable<BaseItem> items = folder.GetChildren(user, true);
var itemsArray = items.ToArray();
@ -187,7 +226,6 @@ namespace MediaBrowser.Api.UserLibrary
NameStartsWith = request.NameStartsWith,
NameStartsWithOrGreater = request.NameStartsWithOrGreater,
HasImdbId = request.HasImdbId,
IsYearMismatched = request.IsYearMismatched,
IsPlaceHolder = request.IsPlaceHolder,
IsLocked = request.IsLocked,
IsInBoxSet = request.IsInBoxSet,
@ -301,7 +339,7 @@ namespace MediaBrowser.Api.UserLibrary
{
query.LocationTypes = request.LocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();
}
// Min official rating
if (!string.IsNullOrWhiteSpace(request.MinOfficialRating))
{

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Dto;
using System;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
@ -8,16 +9,14 @@ using MediaBrowser.Model.Dto;
using ServiceStack;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
[Route("/MusicGenres", "GET", Summary = "Gets all music genres from a given item, folder, or the entire library")]
public class GetMusicGenres : GetItemsByName
{
public GetMusicGenres()
{
IncludeItemTypes = typeof(Audio).Name;
}
}
[Route("/MusicGenres/{Name}", "GET", Summary = "Gets a music genre, by name")]
@ -86,11 +85,16 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetMusicGenres request)
{
var result = GetResult(request);
var result = GetResultSlim(request);
return ToOptimizedSerializedResultUsingCache(result);
}
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
{
return LibraryManager.GetMusicGenres(query);
}
/// <summary>
/// Gets all items.
/// </summary>
@ -99,10 +103,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
return items
.SelectMany(i => i.Genres)
.DistinctNames()
.Select(name => LibraryManager.GetMusicGenre(name));
throw new NotImplementedException();
}
}
}

View File

@ -247,9 +247,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public object Post(MarkPlayedItem request)
public async Task<object> Post(MarkPlayedItem request)
{
var result = MarkPlayed(request).Result;
var result = await MarkPlayed(request).ConfigureAwait(false);
return ToOptimizedResult(result);
}
@ -429,7 +429,7 @@ namespace MediaBrowser.Api.UserLibrary
await item.MarkUnplayed(user).ConfigureAwait(false);
}
return _userDataRepository.GetUserDataDto(item, user);
return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false);
}
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Dto;
using System;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
@ -7,6 +8,7 @@ using MediaBrowser.Model.Dto;
using ServiceStack;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
@ -90,11 +92,16 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetStudios request)
{
var result = GetResult(request);
var result = GetResultSlim(request);
return ToOptimizedSerializedResultUsingCache(result);
}
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
{
return LibraryManager.GetStudios(query);
}
/// <summary>
/// Gets all items.
/// </summary>

View File

@ -488,9 +488,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public object Post(MarkFavoriteItem request)
public async Task<object> Post(MarkFavoriteItem request)
{
var dto = MarkFavorite(request.UserId, request.Id, true).Result;
var dto = await MarkFavorite(request.UserId, request.Id, true).ConfigureAwait(false);
return ToOptimizedResult(dto);
}
@ -527,7 +527,7 @@ namespace MediaBrowser.Api.UserLibrary
await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
return _userDataRepository.GetUserDataDto(item, user);
return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false);
}
/// <summary>
@ -545,9 +545,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public object Post(UpdateUserItemRating request)
public async Task<object> Post(UpdateUserItemRating request)
{
var dto = UpdateUserItemRating(request.UserId, request.Id, request.Likes).Result;
var dto = await UpdateUserItemRating(request.UserId, request.Id, request.Likes).ConfigureAwait(false);
return ToOptimizedResult(dto);
}
@ -572,7 +572,7 @@ namespace MediaBrowser.Api.UserLibrary
await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
return _userDataRepository.GetUserDataDto(item, user);
return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false);
}
}
}

View File

@ -385,7 +385,7 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("User not found");
}
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), null).ConfigureAwait(false);
await _userManager.DeleteUser(user).ConfigureAwait(false);
}
@ -465,6 +465,10 @@ namespace MediaBrowser.Api
}
await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false);
var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
}
}
@ -602,7 +606,8 @@ namespace MediaBrowser.Api
throw new ArgumentException("There must be at least one enabled user in the system.");
}
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
}
await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false);

View File

@ -199,7 +199,7 @@ namespace MediaBrowser.Common.Implementations
ILogManager logManager,
IFileSystem fileSystem)
{
XmlSerializer = new MediaBrowser.Common.Implementations.Serialization.XmlSerializer (fileSystem);
XmlSerializer = new XmlSerializer (fileSystem, logManager.GetLogger("XmlSerializer"));
FailedAssemblies = new List<string>();
ApplicationPaths = applicationPaths;
@ -321,7 +321,7 @@ namespace MediaBrowser.Common.Implementations
protected virtual IJsonSerializer CreateJsonSerializer()
{
return new JsonSerializer(FileSystemManager);
return new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
}
private void SetHttpLimit()
@ -552,7 +552,7 @@ namespace MediaBrowser.Common.Implementations
}
catch (Exception ex)
{
Logger.Error("Error creating {0}", ex, type.Name);
Logger.ErrorException("Error creating {0}", ex, type.Name);
throw;
}
@ -571,7 +571,7 @@ namespace MediaBrowser.Common.Implementations
}
catch (Exception ex)
{
Logger.Error("Error creating {0}", ex, type.Name);
Logger.ErrorException("Error creating {0}", ex, type.Name);
// Don't blow up in release mode
return null;
}

View File

@ -128,11 +128,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
private void AddIpv4Option(HttpWebRequest request, HttpRequestOptions options)
{
if (!options.PreferIpv4)
{
return;
}
request.ServicePoint.BindIPEndPointDelegate = (servicePount, remoteEndPoint, retryCount) =>
{
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork)
@ -143,18 +138,23 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
};
}
private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
private WebRequest GetRequest(HttpRequestOptions options, string method)
{
var request = CreateWebRequest(options.Url);
var httpWebRequest = request as HttpWebRequest;
if (httpWebRequest != null)
{
AddIpv4Option(httpWebRequest, options);
if (options.PreferIpv4)
{
AddIpv4Option(httpWebRequest, options);
}
AddRequestHeaders(httpWebRequest, options);
httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
httpWebRequest.AutomaticDecompression = options.EnableHttpCompression ?
(options.DecompressionMethod ?? DecompressionMethods.Deflate) :
DecompressionMethods.None;
}
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
@ -366,7 +366,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
};
}
var httpWebRequest = GetRequest(options, httpMethod, options.EnableHttpCompression);
var httpWebRequest = GetRequest(options, httpMethod);
if (options.RequestContentBytes != null ||
!string.IsNullOrEmpty(options.RequestContent) ||
@ -556,7 +556,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
options.CancellationToken.ThrowIfCancellationRequested();
var httpWebRequest = GetRequest(options, "GET", options.EnableHttpCompression);
var httpWebRequest = GetRequest(options, "GET");
if (options.ResourcePool != null)
{

View File

@ -55,7 +55,7 @@
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.4\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.4.3.5\lib\net45\NLog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Patterns.Logging">
@ -65,8 +65,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="SimpleInjector, Version=3.1.4.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.3.1.4\lib\net45\SimpleInjector.dll</HintPath>
<Reference Include="SimpleInjector, Version=3.2.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.3.2.0\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />

View File

@ -122,30 +122,27 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
get
{
if (_lastExecutionResult == null)
{
var path = GetHistoryFilePath();
var path = GetHistoryFilePath();
lock (_lastExecutionResultSyncLock)
lock (_lastExecutionResultSyncLock)
{
if (_lastExecutionResult == null)
{
if (_lastExecutionResult == null)
try
{
try
{
return JsonSerializer.DeserializeFromFile<TaskResult>(path);
}
catch (DirectoryNotFoundException)
{
// File doesn't exist. No biggie
}
catch (FileNotFoundException)
{
// File doesn't exist. No biggie
}
catch (Exception ex)
{
Logger.ErrorException("Error deserializing {0}", ex, path);
}
_lastExecutionResult = JsonSerializer.DeserializeFromFile<TaskResult>(path);
}
catch (DirectoryNotFoundException)
{
// File doesn't exist. No biggie
}
catch (FileNotFoundException)
{
// File doesn't exist. No biggie
}
catch (Exception ex)
{
Logger.ErrorException("Error deserializing {0}", ex, path);
}
}
}

View File

@ -2,6 +2,7 @@
using System;
using System.IO;
using CommonIO;
using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.Implementations.Serialization
{
@ -11,10 +12,12 @@ namespace MediaBrowser.Common.Implementations.Serialization
public class JsonSerializer : IJsonSerializer
{
private readonly IFileSystem _fileSystem;
public JsonSerializer(IFileSystem fileSystem)
private readonly ILogger _logger;
public JsonSerializer(IFileSystem fileSystem, ILogger logger)
{
_fileSystem = fileSystem;
_logger = logger;
Configure();
}
@ -65,6 +68,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
private Stream OpenFile(string path)
{
_logger.Debug("Deserializing file {0}", path);
return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 131072);
}

View File

@ -4,6 +4,7 @@ using System.Collections.Concurrent;
using System.IO;
using System.Xml;
using CommonIO;
using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.Implementations.Serialization
{
@ -12,12 +13,14 @@ namespace MediaBrowser.Common.Implementations.Serialization
/// </summary>
public class XmlSerializer : IXmlSerializer
{
private IFileSystem _fileSystem;
private readonly IFileSystem _fileSystem;
private readonly ILogger _logger;
public XmlSerializer(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
public XmlSerializer(IFileSystem fileSystem, ILogger logger)
{
_fileSystem = fileSystem;
_logger = logger;
}
// Need to cache these
// http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html
@ -91,6 +94,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
/// <returns>System.Object.</returns>
public object DeserializeFromFile(Type type, string file)
{
_logger.Debug("Deserializing file {0}", file);
using (var stream = _fileSystem.OpenRead(file))
{
return DeserializeFromStream(type, stream);

View File

@ -2,7 +2,7 @@
<packages>
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="NLog" version="4.3.4" targetFramework="net45" />
<package id="NLog" version="4.3.5" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
<package id="SimpleInjector" version="3.1.4" targetFramework="net45" />
<package id="SimpleInjector" version="3.2.0" targetFramework="net45" />
</packages>

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
namespace MediaBrowser.Common.Net
@ -16,6 +17,8 @@ namespace MediaBrowser.Common.Net
/// <value>The URL.</value>
public string Url { get; set; }
public DecompressionMethods? DecompressionMethod { get; set; }
/// <summary>
/// Gets or sets the accept header.
/// </summary>

View File

@ -53,6 +53,12 @@ namespace MediaBrowser.Controller.Channels
public bool IsInfiniteStream { get; set; }
public string HomePageUrl { get; set; }
public List<string> Artists { get; set; }
public List<string> AlbumArtists { get; set; }
public ChannelItemInfo()
{
MediaSources = new List<ChannelMediaInfo>();
@ -62,6 +68,8 @@ namespace MediaBrowser.Controller.Channels
People = new List<PersonInfo>();
Tags = new List<string>();
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Artists = new List<string>();
AlbumArtists = new List<string>();
}
}
}

View File

@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Chapters
/// <param name="chapters">The chapters.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveChapters(string itemId, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken);
Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken);
/// <summary>
/// Searches the specified video.

View File

@ -23,10 +23,5 @@ namespace MediaBrowser.Controller.Drawing
/// </summary>
/// <value>The height.</value>
public int Height { get; set; }
/// <summary>
/// Gets or sets the text.
/// </summary>
/// <value>The text.</value>
public string Text { get; set; }
}
}

View File

@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Dto
{
@ -68,7 +69,7 @@ namespace MediaBrowser.Controller.Dto
/// <param name="user">The user.</param>
/// <param name="owner">The owner.</param>
/// <returns>IEnumerable&lt;BaseItemDto&gt;.</returns>
IEnumerable<BaseItemDto> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null,
Task<List<BaseItemDto>> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null,
BaseItem owner = null);
/// <summary>

View File

@ -20,15 +20,12 @@ namespace MediaBrowser.Controller.Entities.Audio
IHasArtist,
IHasMusicGenres,
IHasLookupInfo<SongInfo>,
IHasTags,
IHasMediaSources,
IThemeMedia,
IArchivable
{
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
public long? Size { get; set; }
public string Container { get; set; }
public int? TotalBitrate { get; set; }
public ExtraType? ExtraType { get; set; }

View File

@ -179,17 +179,13 @@ namespace MediaBrowser.Controller.Entities.Audio
{
var items = GetRecursiveChildren().ToList();
var songs = items.OfType<Audio>().ToList();
var others = items.Except(songs).ToList();
var totalItems = songs.Count + others.Count;
var totalItems = items.Count;
var numComplete = 0;
var childUpdateType = ItemUpdateType.None;
// Refresh songs
foreach (var item in songs)
foreach (var item in items)
{
cancellationToken.ThrowIfCancellationRequested();
@ -199,7 +195,7 @@ namespace MediaBrowser.Controller.Entities.Audio
numComplete++;
double percent = numComplete;
percent /= totalItems;
progress.Report(percent * 100);
progress.Report(percent * 95);
}
var parentRefreshOptions = refreshOptions;
@ -212,19 +208,6 @@ namespace MediaBrowser.Controller.Entities.Audio
// Refresh current item
await RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
// Refresh all non-songs
foreach (var item in others)
{
cancellationToken.ThrowIfCancellationRequested();
var updateType = await item.RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
numComplete++;
double percent = numComplete;
percent /= totalItems;
progress.Report(percent * 100);
}
progress.Report(100);
}
}

View File

@ -9,6 +9,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities.Audio
{
@ -62,13 +63,6 @@ namespace MediaBrowser.Controller.Entities.Audio
query.ArtistNames = new[] { Name };
}
// Need this for now since the artist filter isn't yet supported by the db
if (ConfigurationManager.Configuration.SchemaVersion < 79)
{
var filter = GetItemFilter();
return LibraryManager.GetItemList(query).Where(filter);
}
return LibraryManager.GetItemList(query);
}
@ -86,6 +80,15 @@ namespace MediaBrowser.Controller.Entities.Audio
}
}
public override int GetChildCount(User user)
{
if (IsAccessedByName)
{
return 0;
}
return base.GetChildCount(user);
}
public override bool IsSaveLocalMetadataEnabled()
{
if (IsAccessedByName)
@ -163,10 +166,17 @@ namespace MediaBrowser.Controller.Entities.Audio
list.Add("Artist-Musicbrainz-" + id);
}
list.Add("Artist-" + item.Name);
list.Add("Artist-" + (item.Name ?? string.Empty).RemoveDiacritics());
return list;
}
public override string PresentationUniqueKey
{
get
{
return "Artist-" + (Name ?? string.Empty).RemoveDiacritics();
}
}
protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Music);

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities.Audio
{
@ -14,10 +15,18 @@ namespace MediaBrowser.Controller.Entities.Audio
{
var list = base.GetUserDataKeys();
list.Insert(0, "MusicGenre-" + Name);
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
public override string PresentationUniqueKey
{
get
{
return GetUserDataKeys()[0];
}
}
[IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{

View File

@ -26,6 +26,7 @@ using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Entities
{
@ -36,6 +37,7 @@ namespace MediaBrowser.Controller.Entities
{
protected BaseItem()
{
Keywords = new List<string>();
Tags = new List<string>();
Genres = new List<string>();
Studios = new List<string>();
@ -67,12 +69,20 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public string PreferredMetadataLanguage { get; set; }
public long? Size { get; set; }
public string Container { get; set; }
public string ShortOverview { get; set; }
public List<ItemImageInfo> ImageInfos { get; set; }
[IgnoreDataMember]
public bool IsVirtualItem { get; set; }
/// <summary>
/// Gets or sets the album.
/// </summary>
/// <value>The album.</value>
[IgnoreDataMember]
public string Album { get; set; }
/// <summary>
@ -810,6 +820,8 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public List<string> Tags { get; set; }
public List<string> Keywords { get; set; }
/// <summary>
/// Gets or sets the home page URL.
/// </summary>
@ -1031,9 +1043,7 @@ namespace MediaBrowser.Controller.Entities
}
: options;
var result = await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
return result;
return await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
}
[IgnoreDataMember]
@ -1394,15 +1404,10 @@ namespace MediaBrowser.Controller.Entities
private bool IsVisibleViaTags(User user)
{
var hasTags = this as IHasTags;
if (hasTags != null)
var policy = user.Policy;
if (policy.BlockedTags.Any(i => Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
{
var policy = user.Policy;
if (policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
{
return false;
}
return false;
}
return true;
@ -2088,7 +2093,7 @@ namespace MediaBrowser.Controller.Entities
return path;
}
public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
public virtual Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user)
{
if (RunTimeTicks.HasValue)
{
@ -2104,6 +2109,8 @@ namespace MediaBrowser.Controller.Entities
}
}
}
return Task.FromResult(true);
}
protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, string path, CancellationToken cancellationToken)
@ -2168,7 +2175,7 @@ namespace MediaBrowser.Controller.Entities
{
get
{
if (GetParent() is AggregateFolder || this is BasePluginFolder)
if (GetParent() is AggregateFolder || this is BasePluginFolder || this is Channel)
{
return true;
}
@ -2214,5 +2221,10 @@ namespace MediaBrowser.Controller.Entities
DeleteFileLocation = false
});
}
public virtual List<ExternalUrl> GetRelatedUrls()
{
return new List<ExternalUrl>();
}
}
}

View File

@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
{
public class Book : BaseItem, IHasTags, IHasLookupInfo<BookInfo>, IHasSeries
public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries
{
[IgnoreDataMember]
public override string MediaType

View File

@ -13,6 +13,7 @@ using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Model.Channels;
namespace MediaBrowser.Controller.Entities
@ -20,7 +21,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Class Folder
/// </summary>
public class Folder : BaseItem, IHasThemeMedia, IHasTags
public class Folder : BaseItem, IHasThemeMedia
{
public static IUserManager UserManager { get; set; }
public static IUserViewManager UserViewManager { get; set; }
@ -164,49 +165,15 @@ namespace MediaBrowser.Controller.Entities
item.DateModified = DateTime.UtcNow;
}
AddChildInternal(item.Id);
await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
}
protected void AddChildrenInternal(List<Guid> children)
{
lock (_childrenSyncLock)
{
var newChildren = ChildIds.ToList();
newChildren.AddRange(children);
_children = newChildren.ToList();
}
}
protected void AddChildInternal(Guid child)
{
lock (_childrenSyncLock)
{
var childIds = ChildIds.ToList();
if (!childIds.Contains(child))
{
childIds.Add(child);
_children = childIds.ToList();
}
}
}
protected void RemoveChildrenInternal(List<Guid> children)
{
lock (_childrenSyncLock)
{
_children = ChildIds.Except(children).ToList();
}
}
/// <summary>
/// Removes the child.
/// </summary>
/// <param name="item">The item.</param>
public void RemoveChild(BaseItem item)
{
RemoveChildrenInternal(new[] { item.Id }.ToList());
item.SetParent(null);
}
@ -241,33 +208,6 @@ namespace MediaBrowser.Controller.Entities
#endregion
/// <summary>
/// The children
/// </summary>
private IReadOnlyList<Guid> _children;
/// <summary>
/// The _children sync lock
/// </summary>
private readonly object _childrenSyncLock = new object();
/// <summary>
/// Gets or sets the actual children.
/// </summary>
/// <value>The actual children.</value>
protected virtual IEnumerable<Guid> ChildIds
{
get
{
lock (_childrenSyncLock)
{
if (_children == null)
{
_children = LoadChildren().ToList();
}
return _children.ToList();
}
}
}
/// <summary>
/// Gets the actual children.
/// </summary>
@ -277,7 +217,7 @@ namespace MediaBrowser.Controller.Entities
{
get
{
return ChildIds.Select(LibraryManager.GetItemById).Where(i => i != null);
return LoadChildren();
}
}
@ -331,7 +271,7 @@ namespace MediaBrowser.Controller.Entities
/// Loads our children. Validation will occur externally.
/// We want this sychronous.
/// </summary>
protected virtual IEnumerable<Guid> LoadChildren()
protected virtual IEnumerable<BaseItem> LoadChildren()
{
//just load our children from the repo - the library will be validated and maintained in other processes
return GetCachedChildren();
@ -461,17 +401,15 @@ namespace MediaBrowser.Controller.Entities
foreach (var item in itemsRemoved)
{
if (item.LocationType == LocationType.Virtual ||
item.LocationType == LocationType.Remote)
var itemLocationType = item.LocationType;
if (itemLocationType == LocationType.Virtual ||
itemLocationType == LocationType.Remote)
{
// Don't remove these because there's no way to accurately validate them.
validChildren.Add(item);
}
else if (!string.IsNullOrEmpty(item.Path) && IsPathOffline(item.Path))
{
await UpdateIsOffline(item, true).ConfigureAwait(false);
validChildren.Add(item);
}
else
{
@ -481,8 +419,6 @@ namespace MediaBrowser.Controller.Entities
if (actualRemovals.Count > 0)
{
RemoveChildrenInternal(actualRemovals.Select(i => i.Id).ToList());
foreach (var item in actualRemovals)
{
Logger.Debug("Removed item: " + item.Path);
@ -495,8 +431,6 @@ namespace MediaBrowser.Controller.Entities
}
await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);
AddChildrenInternal(newItems.Select(i => i.Id).ToList());
}
}
@ -724,15 +658,36 @@ namespace MediaBrowser.Controller.Entities
/// Get our children from the repo - stubbed for now
/// </summary>
/// <returns>IEnumerable{BaseItem}.</returns>
protected IEnumerable<Guid> GetCachedChildren()
protected IEnumerable<BaseItem> GetCachedChildren()
{
return ItemRepository.GetItemIdsList(new InternalItemsQuery
return ItemRepository.GetItemList(new InternalItemsQuery
{
ParentId = Id,
GroupByPresentationUniqueKey = false
});
}
public virtual int GetChildCount(User user)
{
if (LinkedChildren.Count > 0)
{
if (!(this is ICollectionFolder))
{
return GetChildren(user, true).Count();
}
}
var result = GetItems(new InternalItemsQuery(user)
{
Recursive = false,
Limit = 0,
ParentId = Id
}).Result;
return result.TotalRecordCount;
}
public QueryResult<BaseItem> QueryRecursive(InternalItemsQuery query)
{
var user = query.User;
@ -768,58 +723,13 @@ namespace MediaBrowser.Controller.Entities
{
if (!(this is ICollectionFolder))
{
Logger.Debug("Query requires post-filtering due to LinkedChildren");
Logger.Debug("Query requires post-filtering due to LinkedChildren. Type: " + GetType().Name);
return true;
}
}
var supportsUserDataQueries = ConfigurationManager.Configuration.SchemaVersion >= 76;
if (query.SortBy != null && query.SortBy.Length > 0)
{
if (!supportsUserDataQueries)
{
if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
return true;
}
if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.PlayCount");
return true;
}
if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
return true;
}
if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.IsPlayed");
return true;
}
if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.IsUnplayed");
return true;
}
}
if (ConfigurationManager.Configuration.SchemaVersion < 79)
{
if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist");
return true;
}
if (query.SortBy.Contains(ItemSortBy.Artist, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Artist");
return true;
}
}
if (query.SortBy.Contains(ItemSortBy.AiredEpisodeOrder, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder");
@ -840,11 +750,6 @@ namespace MediaBrowser.Controller.Entities
Logger.Debug("Query requires post-filtering due to ItemSortBy.Metascore");
return true;
}
if (query.SortBy.Contains(ItemSortBy.OfficialRating, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.OfficialRating");
return true;
}
if (query.SortBy.Contains(ItemSortBy.Players, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Players");
@ -860,11 +765,6 @@ namespace MediaBrowser.Controller.Entities
Logger.Debug("Query requires post-filtering due to ItemSortBy.SeriesSortName");
return true;
}
if (query.SortBy.Contains(ItemSortBy.Studio, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Studio");
return true;
}
if (query.SortBy.Contains(ItemSortBy.VideoBitRate, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.VideoBitRate");
@ -878,45 +778,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
if (query.PersonIds.Length > 0)
{
Logger.Debug("Query requires post-filtering due to PersonIds");
return true;
}
if (!supportsUserDataQueries)
{
if (query.IsLiked.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsLiked");
return true;
}
if (query.IsFavoriteOrLiked.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsFavoriteOrLiked");
return true;
}
if (query.IsFavorite.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsFavorite");
return true;
}
if (query.IsResumable.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsResumable");
return true;
}
if (query.IsPlayed.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsPlayed");
return true;
}
}
if (query.IsInBoxSet.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsInBoxSet");
@ -930,30 +791,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
if (query.HasImdbId.HasValue)
{
Logger.Debug("Query requires post-filtering due to HasImdbId");
return true;
}
if (query.HasTmdbId.HasValue)
{
Logger.Debug("Query requires post-filtering due to HasTmdbId");
return true;
}
if (query.HasTvdbId.HasValue)
{
Logger.Debug("Query requires post-filtering due to HasTvdbId");
return true;
}
if (query.IsYearMismatched.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsYearMismatched");
return true;
}
if (query.HasOfficialRating.HasValue)
{
Logger.Debug("Query requires post-filtering due to HasOfficialRating");
@ -1003,26 +840,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
if (query.ImageTypes.Length > 0)
{
Logger.Debug("Query requires post-filtering due to ImageTypes");
return true;
}
// Apply studio filter
if (query.StudioIds.Length > 0)
{
Logger.Debug("Query requires post-filtering due to StudioIds");
return true;
}
// Apply genre filter
if (query.GenreIds.Length > 0)
{
Logger.Debug("Query requires post-filtering due to GenreIds");
return true;
}
// Apply person filter
if (query.ItemIdsFromPersonFilters != null)
{
@ -1042,12 +859,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
if (query.OfficialRatings.Length > 0)
{
Logger.Debug("Query requires post-filtering due to OfficialRatings");
return true;
}
if (query.IsMissing.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsMissing");
@ -1066,7 +877,7 @@ namespace MediaBrowser.Controller.Entities
return true;
}
if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User))
if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User, ConfigurationManager))
{
Logger.Debug("Query requires post-filtering due to CollapseBoxSetItems");
return true;
@ -1102,15 +913,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
if (ConfigurationManager.Configuration.SchemaVersion < 79)
{
if (query.ArtistNames.Length > 0)
{
Logger.Debug("Query requires post-filtering due to ArtistNames");
return true;
}
}
return false;
}
@ -1183,7 +985,7 @@ namespace MediaBrowser.Controller.Entities
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query)
{
return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager);
return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager);
}
public virtual IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
@ -1601,72 +1403,61 @@ namespace MediaBrowser.Controller.Entities
{
return false;
}
if (this is Channel)
{
return false;
}
if (SourceType != SourceType.Library)
{
return false;
}
return true;
}
}
public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
public override async Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user)
{
if (!SupportsUserDataFromChildren)
{
return;
}
var recursiveItemCount = 0;
var unplayed = 0;
double totalPercentPlayed = 0;
var itemsResult = GetItems(new InternalItemsQuery(user)
var unplayedQueryResult = await GetItems(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false,
ExcludeLocationTypes = new[] { LocationType.Virtual },
EnableTotalRecordCount = false
IsVirtualItem = false,
EnableTotalRecordCount = true,
Limit = 0,
IsPlayed = false
}).Result;
}).ConfigureAwait(false);
var children = itemsResult.Items;
// Loop through each recursive child
foreach (var child in children)
var allItemsQueryResult = await GetItems(new InternalItemsQuery(user)
{
recursiveItemCount++;
Recursive = true,
IsFolder = false,
IsVirtualItem = false,
EnableTotalRecordCount = true,
Limit = 0
var isUnplayed = true;
}).ConfigureAwait(false);
var itemUserData = UserDataManager.GetUserData(user, child);
// Incrememt totalPercentPlayed
if (itemUserData != null)
{
if (itemUserData.Played)
{
totalPercentPlayed += 100;
isUnplayed = false;
}
else if (itemUserData.PlaybackPositionTicks > 0 && child.RunTimeTicks.HasValue && child.RunTimeTicks.Value > 0)
{
double itemPercent = itemUserData.PlaybackPositionTicks;
itemPercent /= child.RunTimeTicks.Value;
totalPercentPlayed += itemPercent;
}
}
if (isUnplayed)
{
unplayed++;
}
if (itemDto != null)
{
itemDto.RecursiveItemCount = allItemsQueryResult.TotalRecordCount;
}
dto.UnplayedItemCount = unplayed;
double recursiveItemCount = allItemsQueryResult.TotalRecordCount;
double unplayedCount = unplayedQueryResult.TotalRecordCount;
if (recursiveItemCount > 0)
{
dto.PlayedPercentage = totalPercentPlayed / recursiveItemCount;
var unplayedPercentage = (unplayedCount / recursiveItemCount) * 100;
dto.PlayedPercentage = 100 - unplayedPercentage;
dto.Played = dto.PlayedPercentage.Value >= 100;
dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount;
}
}
}

View File

@ -7,7 +7,7 @@ using System.Linq;
namespace MediaBrowser.Controller.Entities
{
public class Game : BaseItem, IHasTrailers, IHasThemeMedia, IHasTags, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
public class Game : BaseItem, IHasTrailers, IHasThemeMedia, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
{
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities
{
@ -11,10 +12,18 @@ namespace MediaBrowser.Controller.Entities
{
var list = base.GetUserDataKeys();
list.Insert(0, "GameGenre-" + Name);
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
public override string PresentationUniqueKey
{
get
{
return GetUserDataKeys()[0];
}
}
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself

View File

@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.Audio;
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities
{
@ -15,10 +16,18 @@ namespace MediaBrowser.Controller.Entities
{
var list = base.GetUserDataKeys();
list.Insert(0, "Genre-" + Name);
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
public override string PresentationUniqueKey
{
get
{
return GetUserDataKeys()[0];
}
}
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.Entities
@ -16,7 +17,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="dto">The dto.</param>
/// <param name="userData">The user data.</param>
/// <param name="user">The user.</param>
void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user);
Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
bool EnableRememberingTrackSelections { get; }
}

View File

@ -19,6 +19,8 @@ namespace MediaBrowser.Controller.Entities
public User User { get; set; }
public BaseItem SimilarTo { get; set; }
public bool? IsFolder { get; set; }
public bool? IsFavorite { get; set; }
public bool? IsFavoriteOrLiked { get; set; }
@ -33,6 +35,7 @@ namespace MediaBrowser.Controller.Entities
public string[] ExcludeTags { get; set; }
public string[] ExcludeInheritedTags { get; set; }
public string[] Genres { get; set; }
public string[] Keywords { get; set; }
public bool? IsMissing { get; set; }
public bool? IsUnaired { get; set; }
@ -43,6 +46,7 @@ namespace MediaBrowser.Controller.Entities
public string NameStartsWith { get; set; }
public string NameLessThan { get; set; }
public string NameContains { get; set; }
public string MinSortName { get; set; }
public string PresentationUniqueKey { get; set; }
public string Path { get; set; }
@ -52,6 +56,7 @@ namespace MediaBrowser.Controller.Entities
public string Person { get; set; }
public string[] PersonIds { get; set; }
public string[] ItemIds { get; set; }
public string[] ExcludeItemIds { get; set; }
public string AdjacentTo { get; set; }
public string[] PersonTypes { get; set; }
@ -60,7 +65,6 @@ namespace MediaBrowser.Controller.Entities
public bool? IsInBoxSet { get; set; }
public bool? IsLocked { get; set; }
public bool? IsPlaceHolder { get; set; }
public bool? IsYearMismatched { get; set; }
public bool? HasImdbId { get; set; }
public bool? HasOverview { get; set; }
@ -107,6 +111,7 @@ namespace MediaBrowser.Controller.Entities
internal List<Guid> ItemIdsFromPersonFilters { get; set; }
public int? ParentIndexNumber { get; set; }
public int? ParentIndexNumberNotEquals { get; set; }
public int? IndexNumber { get; set; }
public int? MinParentalRating { get; set; }
public int? MaxParentalRating { get; set; }
@ -114,6 +119,7 @@ namespace MediaBrowser.Controller.Entities
public bool? IsCurrentSchema { get; set; }
public bool? HasDeadParentId { get; set; }
public bool? IsOffline { get; set; }
public bool? IsVirtualItem { get; set; }
public Guid? ParentId { get; set; }
public string[] AncestorIds { get; set; }
@ -137,6 +143,8 @@ namespace MediaBrowser.Controller.Entities
public bool GroupByPresentationUniqueKey { get; set; }
public bool EnableTotalRecordCount { get; set; }
public bool ForceDirect { get; set; }
public Dictionary<string, string> ExcludeProviderIds { get; set; }
public bool EnableGroupByMetadataKey { get; set; }
public InternalItemsQuery()
{
@ -145,12 +153,14 @@ namespace MediaBrowser.Controller.Entities
AlbumNames = new string[] { };
ArtistNames = new string[] { };
ExcludeProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
BlockUnratedItems = new UnratedItem[] { };
Tags = new string[] { };
OfficialRatings = new string[] { };
SortBy = new string[] { };
MediaTypes = new string[] { };
Keywords = new string[] { };
IncludeItemTypes = new string[] { };
ExcludeItemTypes = new string[] { };
Genres = new string[] { };
@ -164,6 +174,7 @@ namespace MediaBrowser.Controller.Entities
PersonIds = new string[] { };
ChannelIds = new string[] { };
ItemIds = new string[] { };
ExcludeItemIds = new string[] { };
AncestorIds = new string[] { };
TopParentIds = new string[] { };
ExcludeTags = new string[] { };

View File

@ -1,21 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Controller.Entities
{
public interface IHasKeywords
{
/// <summary>
/// Gets or sets the keywords.
/// </summary>
/// <value>The keywords.</value>
List<string> Keywords { get; set; }
}
public static class KeywordExtensions
{
public static void AddKeyword(this IHasKeywords item, string name)
public static void AddKeyword(this BaseItem item, string name)
{
if (string.IsNullOrWhiteSpace(name))
{

View File

@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <summary>
/// Class BoxSet
/// </summary>
public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IHasShares
public class BoxSet : Folder, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IHasShares
{
public List<Share> Shares { get; set; }
@ -26,7 +26,6 @@ namespace MediaBrowser.Controller.Entities.Movies
RemoteTrailerIds = new List<Guid>();
DisplayOrder = ItemSortBy.PremiereDate;
Keywords = new List<string>();
Shares = new List<Share>();
}
@ -47,12 +46,6 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <value>The remote trailers.</value>
public List<MediaUrl> RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the tags.
/// </summary>
/// <value>The tags.</value>
public List<string> Keywords { get; set; }
/// <summary>
/// Gets or sets the display order.
/// </summary>

View File

@ -8,13 +8,14 @@ using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Entities.Movies
{
/// <summary>
/// Class Movie
/// </summary>
public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasProductionLocations, IHasBudget, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
{
public List<Guid> SpecialFeatureIds { get; set; }
@ -31,7 +32,6 @@ namespace MediaBrowser.Controller.Entities.Movies
ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>();
Taglines = new List<string>();
Keywords = new List<string>();
ProductionLocations = new List<string>();
}
@ -41,7 +41,6 @@ namespace MediaBrowser.Controller.Entities.Movies
public List<Guid> LocalTrailerIds { get; set; }
public List<Guid> RemoteTrailerIds { get; set; }
public List<string> Keywords { get; set; }
public List<MediaUrl> RemoteTrailers { get; set; }
@ -163,5 +162,22 @@ namespace MediaBrowser.Controller.Entities.Movies
return hasChanges;
}
public override List<ExternalUrl> GetRelatedUrls()
{
var list = base.GetRelatedUrls();
var imdbId = this.GetProviderId(MetadataProviders.Imdb);
if (!string.IsNullOrWhiteSpace(imdbId))
{
list.Add(new ExternalUrl
{
Name = "Trakt",
Url = string.Format("https://trakt.tv/movies/{0}", imdbId)
});
}
return list;
}
}
}

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
@ -22,10 +23,18 @@ namespace MediaBrowser.Controller.Entities
{
var list = base.GetUserDataKeys();
list.Insert(0, "Person-" + Name);
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
public override string PresentationUniqueKey
{
get
{
return GetUserDataKeys()[0];
}
}
public PersonLookupInfo GetLookupInfo()
{
return GetItemLookupInfo<PersonLookupInfo>();

View File

@ -5,7 +5,7 @@ using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities
{
public class Photo : BaseItem, IHasTags, IHasTaglines
public class Photo : BaseItem, IHasTaglines
{
public List<string> Taglines { get; set; }

View File

@ -2,22 +2,31 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Class Studio
/// </summary>
public class Studio : BaseItem, IItemByName, IHasTags
public class Studio : BaseItem, IItemByName
{
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
list.Insert(0, "Studio-" + Name);
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
public override string PresentationUniqueKey
{
get
{
return GetUserDataKeys()[0];
}
}
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself

View File

@ -11,13 +11,25 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary>
/// Class Episode
/// </summary>
public class Episode : Video, IHasLookupInfo<EpisodeInfo>, IHasSeries
{
/// <summary>
/// Gets the season in which it aired.
/// </summary>
/// <value>The aired season.</value>
public int? AirsBeforeSeasonNumber { get; set; }
public class Episode : Video, IHasTrailers, IHasLookupInfo<EpisodeInfo>, IHasSeries
{
public Episode()
{
RemoteTrailers = new List<MediaUrl>();
LocalTrailerIds = new List<Guid>();
RemoteTrailerIds = new List<Guid>();
}
public List<Guid> LocalTrailerIds { get; set; }
public List<Guid> RemoteTrailerIds { get; set; }
public List<MediaUrl> RemoteTrailers { get; set; }
/// <summary>
/// Gets the season in which it aired.
/// </summary>
/// <value>The aired season.</value>
public int? AirsBeforeSeasonNumber { get; set; }
public int? AirsAfterSeasonNumber { get; set; }
public int? AirsBeforeEpisodeNumber { get; set; }
@ -96,7 +108,13 @@ namespace MediaBrowser.Controller.Entities.TV
var series = Series;
if (series != null && ParentIndexNumber.HasValue && IndexNumber.HasValue)
{
list.InsertRange(0, series.GetUserDataKeys().Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000")));
var seriesUserDataKeys = series.GetUserDataKeys();
var take = seriesUserDataKeys.Count;
if (seriesUserDataKeys.Count > 1)
{
take--;
}
list.InsertRange(0, seriesUserDataKeys.Take(take).Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000")));
}
return list;

View File

@ -75,6 +75,11 @@ namespace MediaBrowser.Controller.Entities.TV
return list;
}
public override int GetChildCount(User user)
{
return GetChildren(user, true).Count();
}
/// <summary>
/// This Episode's Series Instance
/// </summary>
@ -128,39 +133,16 @@ namespace MediaBrowser.Controller.Entities.TV
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
}
public override bool RequiresRefresh()
{
var result = base.RequiresRefresh();
if (!result)
{
if (!IsVirtualItem.HasValue)
{
return true;
}
}
return result;
}
[IgnoreDataMember]
public bool? IsVirtualItem { get; set; }
[IgnoreDataMember]
public bool IsMissingSeason
{
get { return (IsVirtualItem ?? DetectIsVirtualItem()) && !IsUnaired; }
get { return (IsVirtualItem) && !IsUnaired; }
}
[IgnoreDataMember]
public bool IsVirtualUnaired
{
get { return (IsVirtualItem ?? DetectIsVirtualItem()) && IsUnaired; }
}
private bool DetectIsVirtualItem()
{
return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.LocationType == LocationType.Virtual);
get { return (IsVirtualItem) && IsUnaired; }
}
[IgnoreDataMember]
@ -196,52 +178,17 @@ namespace MediaBrowser.Controller.Entities.TV
{
var config = user.Configuration;
return GetEpisodes(user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes);
return GetEpisodes(Series, user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes);
}
public IEnumerable<Episode> GetEpisodes(User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
public IEnumerable<Episode> GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
{
var series = Series;
return GetEpisodes(series, user, includeMissingEpisodes, includeVirtualUnairedEpisodes, null);
}
if (IndexNumber.HasValue && series != null)
{
return series.GetEpisodes(user, this, includeMissingEpisodes, includeVirtualUnairedEpisodes);
}
var episodes = GetRecursiveChildren(user)
.OfType<Episode>();
if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
{
var seasonNumber = IndexNumber;
var list = episodes.ToList();
if (seasonNumber.HasValue)
{
list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>()
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value));
}
else
{
list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>()
.Where(i => !i.ParentIndexNumber.HasValue));
}
episodes = list.DistinctBy(i => i.Id);
}
if (!includeMissingEpisodes)
{
episodes = episodes.Where(i => !i.IsMissingEpisode);
}
if (!includeVirtualUnairedEpisodes)
{
episodes = episodes.Where(i => !i.IsVirtualUnaired);
}
return LibraryManager
.Sort(episodes, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending)
.Cast<Episode>();
public IEnumerable<Episode> GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> allSeriesEpisodes)
{
return series.GetEpisodes(user, this, includeMissingEpisodes, includeVirtualUnairedEpisodes, allSeriesEpisodes);
}
public IEnumerable<Episode> GetEpisodes()

View File

@ -9,6 +9,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Providers;
using MoreLinq;
namespace MediaBrowser.Controller.Entities.TV
@ -30,7 +31,6 @@ namespace MediaBrowser.Controller.Entities.TV
RemoteTrailers = new List<MediaUrl>();
LocalTrailerIds = new List<Guid>();
RemoteTrailerIds = new List<Guid>();
DisplaySpecialsWithSeasons = true;
}
[IgnoreDataMember]
@ -57,8 +57,6 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
public bool DisplaySpecialsWithSeasons { get; set; }
public List<Guid> LocalTrailerIds { get; set; }
public List<Guid> RemoteTrailerIds { get; set; }
@ -94,10 +92,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
return GetRecursiveChildren(i => i is Episode)
.Select(i => i.DateCreated)
.OrderByDescending(i => i)
.FirstOrDefault();
return DateLastMediaAdded ?? DateTime.MinValue;
}
}
@ -106,14 +101,30 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
if (EnablePooling())
var userdatakeys = GetUserDataKeys();
if (userdatakeys.Count > 1)
{
return GetUserDataKeys().First();
return userdatakeys[0];
}
return base.PresentationUniqueKey;
}
}
public override int GetChildCount(User user)
{
var result = LibraryManager.GetItemsResult(new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = PresentationUniqueKey,
IncludeItemTypes = new[] { typeof(Season).Name },
SortBy = new[] { ItemSortBy.SortName },
IsVirtualItem = false,
Limit = 0
});
return result.TotalRecordCount;
}
/// <summary>
/// Gets the user data key.
/// </summary>
@ -182,27 +193,32 @@ namespace MediaBrowser.Controller.Entities.TV
protected override Task<QueryResult<BaseItem>> GetItemsInternal(InternalItemsQuery query)
{
if (query.User == null)
{
return base.GetItemsInternal(query);
}
var user = query.User;
if (query.Recursive)
{
query.AncestorWithPresentationUniqueKey = PresentationUniqueKey;
if (query.SortBy.Length == 0)
{
query.SortBy = new[] { ItemSortBy.SortName };
}
if (query.IncludeItemTypes.Length == 0)
{
query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
}
query.IsVirtualItem = false;
return Task.FromResult(LibraryManager.GetItemsResult(query));
}
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
IEnumerable<BaseItem> items;
if (query.User == null)
{
items = query.Recursive
? GetRecursiveChildren(filter)
: Children.Where(filter);
}
else
{
items = query.Recursive
? GetSeasons(user).Cast<BaseItem>().Concat(GetEpisodes(user)).Where(filter)
: GetSeasons(user).Where(filter);
}
var items = GetSeasons(user).Where(filter);
var result = PostFilterAndSort(items, query);
return Task.FromResult(result);
}
@ -210,33 +226,13 @@ namespace MediaBrowser.Controller.Entities.TV
{
IEnumerable<Season> seasons;
if (EnablePooling())
seasons = LibraryManager.GetItemList(new InternalItemsQuery(user)
{
var seriesIds = LibraryManager.GetItemIds(new InternalItemsQuery(user)
{
PresentationUniqueKey = PresentationUniqueKey,
IncludeItemTypes = new[] { typeof(Series).Name }
});
AncestorWithPresentationUniqueKey = PresentationUniqueKey,
IncludeItemTypes = new[] { typeof(Season).Name },
SortBy = new[] { ItemSortBy.SortName }
if (seriesIds.Count > 1)
{
seasons = LibraryManager.GetItemList(new InternalItemsQuery(user)
{
AncestorIds = seriesIds.Select(i => i.ToString("N")).ToArray(),
IncludeItemTypes = new[] { typeof(Season).Name },
SortBy = new[] { ItemSortBy.SortName }
}).Cast<Season>();
}
else
{
seasons = LibraryManager.Sort(base.GetChildren(user, true), user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).OfType<Season>();
}
}
else
{
seasons = LibraryManager.Sort(base.GetChildren(user, true), user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).OfType<Season>();
}
}).Cast<Season>();
if (!includeMissingSeasons)
{
@ -259,8 +255,18 @@ namespace MediaBrowser.Controller.Entities.TV
public IEnumerable<Episode> GetEpisodes(User user, bool includeMissing, bool includeVirtualUnaired)
{
var allEpisodes = GetSeasons(user, true, true)
.SelectMany(i => i.GetEpisodes(user, includeMissing, includeVirtualUnaired))
var allItems = LibraryManager.GetItemList(new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = PresentationUniqueKey,
IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name },
SortBy = new[] { ItemSortBy.SortName }
}).ToList();
var allSeriesEpisodes = allItems.OfType<Episode>().ToList();
var allEpisodes = allItems.OfType<Season>()
.SelectMany(i => i.GetEpisodes(this, user, includeMissing, includeVirtualUnaired, allSeriesEpisodes))
.Reverse()
.ToList();
@ -283,9 +289,6 @@ namespace MediaBrowser.Controller.Entities.TV
var totalItems = seasons.Count + otherItems.Count;
var numComplete = 0;
refreshOptions = new MetadataRefreshOptions(refreshOptions);
refreshOptions.IsPostRecursiveRefresh = true;
// Refresh current item
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
@ -315,7 +318,7 @@ namespace MediaBrowser.Controller.Entities.TV
&& refreshOptions.MetadataRefreshMode != MetadataRefreshMode.FullRefresh
&& !refreshOptions.ReplaceAllMetadata
&& episode.IsMissingEpisode
&& episode.LocationType == Model.Entities.LocationType.Virtual
&& episode.LocationType == LocationType.Virtual
&& episode.PremiereDate.HasValue
&& (DateTime.UtcNow - episode.PremiereDate.Value).TotalDays > 30)
{
@ -333,6 +336,8 @@ namespace MediaBrowser.Controller.Entities.TV
progress.Report(percent * 100);
}
refreshOptions = new MetadataRefreshOptions(refreshOptions);
refreshOptions.IsPostRecursiveRefresh = true;
await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
progress.Report(100);
@ -345,50 +350,32 @@ namespace MediaBrowser.Controller.Entities.TV
return GetEpisodes(user, season, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes);
}
private bool EnablePooling()
private IEnumerable<Episode> GetAllEpisodes(User user)
{
return false;
return LibraryManager.GetItemList(new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = PresentationUniqueKey,
IncludeItemTypes = new[] { typeof(Episode).Name },
SortBy = new[] { ItemSortBy.SortName }
}).Cast<Episode>();
}
public IEnumerable<Episode> GetEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
{
IEnumerable<Episode> episodes;
IEnumerable<Episode> episodes = GetAllEpisodes(user);
if (EnablePooling())
return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes);
}
public IEnumerable<Episode> GetEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> allSeriesEpisodes)
{
if (allSeriesEpisodes == null)
{
var seriesIds = LibraryManager.GetItemIds(new InternalItemsQuery(user)
{
PresentationUniqueKey = PresentationUniqueKey,
IncludeItemTypes = new[] { typeof(Series).Name }
});
if (seriesIds.Count > 1)
{
episodes = LibraryManager.GetItemList(new InternalItemsQuery(user)
{
AncestorIds = seriesIds.Select(i => i.ToString("N")).ToArray(),
IncludeItemTypes = new[] { typeof(Episode).Name },
SortBy = new[] { ItemSortBy.SortName }
}).Cast<Episode>();
}
else
{
episodes = GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Episode).Name }
}).Cast<Episode>();
}
}
else
{
episodes = GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Episode).Name }
}).Cast<Episode>();
return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes);
}
episodes = FilterEpisodesBySeason(episodes, parentSeason, DisplaySpecialsWithSeasons);
var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons);
if (!includeMissingEpisodes)
{
@ -436,38 +423,31 @@ namespace MediaBrowser.Controller.Entities.TV
public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, Season parentSeason, bool includeSpecials)
{
var seasonNumber = parentSeason.IndexNumber;
if (!includeSpecials || (seasonNumber.HasValue && seasonNumber.Value == 0))
var seasonPresentationKey = parentSeason.PresentationUniqueKey;
var supportSpecialsInSeason = includeSpecials && seasonNumber.HasValue && seasonNumber.Value != 0;
return episodes.Where(episode =>
{
var seasonPresentationKey = parentSeason.PresentationUniqueKey;
return episodes.Where(i =>
var currentSeasonNumber = supportSpecialsInSeason ? episode.AiredSeasonNumber : episode.ParentIndexNumber;
if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
{
if ((i.ParentIndexNumber ?? -1) == seasonNumber)
{
return true;
}
return true;
}
var season = i.Season;
return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
});
}
else
{
var seasonPresentationKey = parentSeason.PresentationUniqueKey;
return episodes.Where(episode =>
if (!currentSeasonNumber.HasValue && !seasonNumber.HasValue && parentSeason.LocationType == LocationType.Virtual)
{
var currentSeasonNumber = episode.AiredSeasonNumber;
if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
{
return true;
}
return true;
}
if (!episode.ParentIndexNumber.HasValue)
{
var season = episode.Season;
return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
});
}
}
return false;
});
}
protected override bool GetBlockUnratedValue(UserPolicy config)
@ -508,5 +488,22 @@ namespace MediaBrowser.Controller.Entities.TV
return hasChanges;
}
public override List<ExternalUrl> GetRelatedUrls()
{
var list = base.GetRelatedUrls();
var imdbId = this.GetProviderId(MetadataProviders.Imdb);
if (!string.IsNullOrWhiteSpace(imdbId))
{
list.Add(new ExternalUrl
{
Name = "Trakt",
Url = string.Format("https://trakt.tv/shows/{0}", imdbId)
});
}
return list;
}
}
}

View File

@ -1,24 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasTags
/// </summary>
public interface IHasTags
{
/// <summary>
/// Gets or sets the tags.
/// </summary>
/// <value>The tags.</value>
List<string> Tags { get; set; }
}
public static class TagExtensions
{
public static void AddTag(this IHasTags item, string name)
public static void AddTag(this BaseItem item, string name)
{
if (string.IsNullOrWhiteSpace(name))
{

View File

@ -5,13 +5,14 @@ using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Class Trailer
/// </summary>
public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasTaglines, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
{
public List<string> ProductionLocations { get; set; }
@ -30,8 +31,6 @@ namespace MediaBrowser.Controller.Entities
public List<MediaUrl> RemoteTrailers { get; set; }
public List<string> Keywords { get; set; }
[IgnoreDataMember]
public bool IsLocalTrailer
{
@ -110,5 +109,22 @@ namespace MediaBrowser.Controller.Entities
return hasChanges;
}
public override List<ExternalUrl> GetRelatedUrls()
{
var list = base.GetRelatedUrls();
var imdbId = this.GetProviderId(MetadataProviders.Imdb);
if (!string.IsNullOrWhiteSpace(imdbId))
{
list.Add(new ExternalUrl
{
Name = "Trakt",
Url = string.Format("https://trakt.tv/movies/{0}", imdbId)
});
}
return list;
}
}
}

View File

@ -38,6 +38,11 @@ namespace MediaBrowser.Controller.Entities
return PostFilterAndSort(result.Where(filter), query);
}
public override int GetChildCount(User user)
{
return GetChildren(user, true).Count();
}
[IgnoreDataMember]
protected override bool SupportsShortcutChildren
{

View File

@ -45,6 +45,11 @@ namespace MediaBrowser.Controller.Entities
return list;
}
public override int GetChildCount(User user)
{
return GetChildren(user, true).Count();
}
protected override Task<QueryResult<BaseItem>> GetItemsInternal(InternalItemsQuery query)
{
var parent = this as Folder;
@ -58,7 +63,7 @@ namespace MediaBrowser.Controller.Entities
parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
}
return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, CollectionManager, PlaylistManager)
return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager, PlaylistManager)
.GetUserItems(parent, this, ViewType, query);
}

View File

@ -18,6 +18,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Controller.Entities
{
@ -30,10 +32,10 @@ namespace MediaBrowser.Controller.Entities
private readonly ILogger _logger;
private readonly IUserDataManager _userDataManager;
private readonly ITVSeriesManager _tvSeriesManager;
private readonly ICollectionManager _collectionManager;
private readonly IServerConfigurationManager _config;
private readonly IPlaylistManager _playlistManager;
public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager, IPlaylistManager playlistManager)
public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, IServerConfigurationManager config, IPlaylistManager playlistManager)
{
_userViewManager = userViewManager;
_liveTvManager = liveTvManager;
@ -42,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
_logger = logger;
_userDataManager = userDataManager;
_tvSeriesManager = tvSeriesManager;
_collectionManager = collectionManager;
_config = config;
_playlistManager = playlistManager;
}
@ -159,7 +161,7 @@ namespace MediaBrowser.Controller.Entities
return await GetTvGenres(queryParent, user, query).ConfigureAwait(false);
case SpecialFolder.TvGenre:
return await GetTvGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false);
return GetTvGenreItems(queryParent, displayParent, user, query);
case SpecialFolder.TvResume:
return GetTvResume(queryParent, user, query);
@ -332,13 +334,14 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, InternalItemsQuery query)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
var items = parent.QueryRecursive(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
IncludeItemTypes = new[] { typeof(Audio.Audio).Name }
IncludeItemTypes = new[] { typeof(Audio.Audio).Name },
EnableTotalRecordCount = false
}).Cast<IHasAlbumArtist>();
}).Items.Cast<IHasAlbumArtist>();
var artists = _libraryManager.GetAlbumArtists(items);
@ -347,13 +350,14 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, InternalItemsQuery query)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
var items = parent.QueryRecursive(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
IncludeItemTypes = new[] { typeof(Audio.Audio).Name, typeof(MusicVideo).Name }
IncludeItemTypes = new[] { typeof(Audio.Audio).Name, typeof(MusicVideo).Name },
EnableTotalRecordCount = false
}).Cast<IHasArtist>();
}).Items.Cast<IHasArtist>();
var artists = _libraryManager.GetArtists(items);
@ -362,13 +366,14 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetFavoriteArtists(Folder parent, User user, InternalItemsQuery query)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
var items = parent.QueryRecursive(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
IncludeItemTypes = new[] { typeof(Audio.Audio).Name }
IncludeItemTypes = new[] { typeof(Audio.Audio).Name },
EnableTotalRecordCount = false
}).Cast<IHasAlbumArtist>();
}).Items.Cast<IHasAlbumArtist>();
var artists = _libraryManager.GetAlbumArtists(items).Where(i => _userDataManager.GetUserData(user, i).IsFavorite);
@ -545,7 +550,7 @@ namespace MediaBrowser.Controller.Entities
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Movie).Name };
return _libraryManager.GetItemsResult(query);
return ConvertToResult(_libraryManager.GetItemList(query));
}
private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
@ -559,7 +564,17 @@ namespace MediaBrowser.Controller.Entities
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Movie).Name };
return _libraryManager.GetItemsResult(query);
return ConvertToResult(_libraryManager.GetItemList(query));
}
private QueryResult<BaseItem> ConvertToResult(IEnumerable<BaseItem> items)
{
var arr = items.ToArray();
return new QueryResult<BaseItem>
{
Items = arr,
TotalRecordCount = arr.Length
};
}
private async Task<QueryResult<BaseItem>> GetMovieGenres(Folder parent, User user, InternalItemsQuery query)
@ -660,8 +675,9 @@ namespace MediaBrowser.Controller.Entities
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Episode).Name };
query.ExcludeLocationTypes = new[] { LocationType.Virtual };
return _libraryManager.GetItemsResult(query);
return ConvertToResult(_libraryManager.GetItemList(query));
}
private QueryResult<BaseItem> GetTvNextUp(Folder parent, InternalItemsQuery query)
@ -690,7 +706,7 @@ namespace MediaBrowser.Controller.Entities
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Episode).Name };
return _libraryManager.GetItemsResult(query);
return ConvertToResult(_libraryManager.GetItemList(query));
}
private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, InternalItemsQuery query)
@ -737,7 +753,7 @@ namespace MediaBrowser.Controller.Entities
return GetResult(genres, parent, query);
}
private async Task<QueryResult<BaseItem>> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
{
query.Recursive = true;
query.ParentId = queryParent.Id;
@ -766,7 +782,7 @@ namespace MediaBrowser.Controller.Entities
{
items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager));
return PostFilterAndSort(items, queryParent, null, query, _libraryManager);
return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config);
}
public static bool FilterItem(BaseItem item, InternalItemsQuery query)
@ -779,14 +795,15 @@ namespace MediaBrowser.Controller.Entities
int? totalRecordLimit,
InternalItemsQuery query)
{
return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager);
return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager, _config);
}
public static QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items,
BaseItem queryParent,
int? totalRecordLimit,
InternalItemsQuery query,
ILibraryManager libraryManager)
ILibraryManager libraryManager,
IServerConfigurationManager configurationManager)
{
var user = query.User;
@ -795,7 +812,7 @@ namespace MediaBrowser.Controller.Entities
query.IsVirtualUnaired,
query.IsUnaired);
items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user);
items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager);
// This must be the last filter
if (!string.IsNullOrEmpty(query.AdjacentTo))
@ -809,14 +826,15 @@ namespace MediaBrowser.Controller.Entities
public static IEnumerable<BaseItem> CollapseBoxSetItemsIfNeeded(IEnumerable<BaseItem> items,
InternalItemsQuery query,
BaseItem queryParent,
User user)
User user,
IServerConfigurationManager configurationManager)
{
if (items == null)
{
throw new ArgumentNullException("items");
}
if (CollapseBoxSetItems(query, queryParent, user))
if (CollapseBoxSetItems(query, queryParent, user, configurationManager))
{
items = BaseItem.CollectionManager.CollapseItemsWithinBoxSets(items, user);
}
@ -849,7 +867,8 @@ namespace MediaBrowser.Controller.Entities
public static bool CollapseBoxSetItems(InternalItemsQuery query,
BaseItem queryParent,
User user)
User user,
IServerConfigurationManager configurationManager)
{
// Could end up stuck in a loop like this
if (queryParent is BoxSet)
@ -861,7 +880,7 @@ namespace MediaBrowser.Controller.Entities
if (!param.HasValue)
{
if (user != null && !user.Configuration.GroupMoviesIntoBoxSets)
if (user != null && !configurationManager.Configuration.EnableGroupingIntoCollections)
{
return false;
}
@ -992,11 +1011,6 @@ namespace MediaBrowser.Controller.Entities
return false;
}
if (request.IsYearMismatched.HasValue)
{
return false;
}
if (!string.IsNullOrWhiteSpace(request.Person))
{
return false;
@ -1415,16 +1429,6 @@ namespace MediaBrowser.Controller.Entities
}
}
if (query.IsYearMismatched.HasValue)
{
var filterValue = query.IsYearMismatched.Value;
if (IsYearMismatched(item, libraryManager) != filterValue)
{
return false;
}
}
if (query.HasOfficialRating.HasValue)
{
var filterValue = query.HasOfficialRating.Value;
@ -1658,12 +1662,7 @@ namespace MediaBrowser.Controller.Entities
var tags = query.Tags;
if (tags.Length > 0)
{
var hasTags = item as IHasTags;
if (hasTags == null)
{
return false;
}
if (!tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
if (!tags.Any(v => item.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
{
return false;
}
@ -1976,34 +1975,6 @@ namespace MediaBrowser.Controller.Entities
return _userViewManager.GetUserSubView(parent.Id.ToString("N"), type, sortName, CancellationToken.None);
}
public static bool IsYearMismatched(BaseItem item, ILibraryManager libraryManager)
{
if (item.ProductionYear.HasValue)
{
var path = item.Path;
if (!string.IsNullOrEmpty(path))
{
var info = libraryManager.ParseName(Path.GetFileName(path));
var yearInName = info.Year;
// Go up a level if we didn't get a year
if (!yearInName.HasValue)
{
info = libraryManager.ParseName(Path.GetFileName(Path.GetDirectoryName(path)));
yearInName = info.Year;
}
if (yearInName.HasValue)
{
return yearInName.Value != item.ProductionYear.Value;
}
}
}
return false;
}
public static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId)
{
var list = items.ToList();

View File

@ -21,7 +21,6 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Video : BaseItem,
IHasAspectRatio,
IHasTags,
ISupportsPlaceHolders,
IHasMediaSources,
IHasShortOverview,
@ -59,10 +58,7 @@ namespace MediaBrowser.Controller.Entities
}
}
public long? Size { get; set; }
public string Container { get; set; }
public int? TotalBitrate { get; set; }
public string ShortOverview { get; set; }
public ExtraType? ExtraType { get; set; }
/// <summary>

View File

@ -3,6 +3,7 @@ using MediaBrowser.Model.System;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Controller
{
@ -17,7 +18,7 @@ namespace MediaBrowser.Controller
/// Gets the system info.
/// </summary>
/// <returns>SystemInfo.</returns>
SystemInfo GetSystemInfo();
Task<SystemInfo> GetSystemInfo();
/// <summary>
/// Gets a value indicating whether [supports automatic run at startup].
@ -65,13 +66,13 @@ namespace MediaBrowser.Controller
/// Gets the local ip address.
/// </summary>
/// <value>The local ip address.</value>
List<IPAddress> LocalIpAddresses { get; }
Task<List<IPAddress>> GetLocalIpAddresses();
/// <summary>
/// Gets the local API URL.
/// </summary>
/// <value>The local API URL.</value>
string LocalApiUrl { get; }
Task<string> GetLocalApiUrl();
/// <summary>
/// Gets the local API URL.

View File

@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.Library
{
@ -150,13 +151,6 @@ namespace MediaBrowser.Controller.Library
/// <returns>BaseItem.</returns>
BaseItem GetItemById(Guid id);
/// <summary>
/// Gets the memory item by identifier.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>BaseItem.</returns>
BaseItem GetMemoryItemById(Guid id);
/// <summary>
/// Gets the intros.
/// </summary>
@ -574,5 +568,12 @@ namespace MediaBrowser.Controller.Library
void RemoveVirtualFolder(string name, bool refreshLibrary);
void AddMediaPath(string virtualFolderName, string path);
void RemoveMediaPath(string virtualFolderName, string path);
QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
}
}

View File

@ -40,7 +40,9 @@ namespace MediaBrowser.Controller.Library
/// <param name="item">The item.</param>
/// <param name="user">The user.</param>
/// <returns>UserItemDataDto.</returns>
UserItemDataDto GetUserDataDto(IHasUserData item, User user);
Task<UserItemDataDto> GetUserDataDto(IHasUserData item, User user);
Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user);
/// <summary>
/// Get all user data for the given user

View File

@ -15,5 +15,6 @@ namespace MediaBrowser.Controller.LiveTv
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);
Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken);
}
}

View File

@ -8,6 +8,7 @@ using MediaBrowser.Model.Querying;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Events;
namespace MediaBrowser.Controller.LiveTv
{
@ -344,6 +345,13 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="validateListings">if set to <c>true</c> [validate listings].</param>
/// <returns>Task.</returns>
Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info, bool validateLogin, bool validateListings);
void DeleteListingsProvider(string id);
Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelNumber, string providerChannelNumber);
TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, List<NameValuePair> mappings, List<ChannelInfo> providerChannels);
/// <summary>
/// Gets the lineups.
/// </summary>
@ -385,5 +393,15 @@ namespace MediaBrowser.Controller.LiveTv
List<NameValuePair> GetSatIniMappings();
Task<List<ChannelInfo>> GetSatChannelScanResult(TunerHostInfo info, CancellationToken cancellationToken);
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
List<IListingsProvider> ListingProviders { get;}
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
}
}

View File

@ -226,4 +226,23 @@ namespace MediaBrowser.Controller.LiveTv
/// <returns>Task.</returns>
Task ResetTuner(string id, CancellationToken cancellationToken);
}
public interface ISupportsNewTimerIds
{
/// <summary>
/// Creates the timer asynchronous.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task<string> CreateTimer(TimerInfo info, CancellationToken cancellationToken);
/// <summary>
/// Creates the series timer asynchronous.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken);
}
}

View File

@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.LiveTv
{
@ -235,5 +236,25 @@ namespace MediaBrowser.Controller.LiveTv
return false;
}
}
public override List<ExternalUrl> GetRelatedUrls()
{
var list = base.GetRelatedUrls();
var imdbId = this.GetProviderId(MetadataProviders.Imdb);
if (!string.IsNullOrWhiteSpace(imdbId))
{
if (IsMovie)
{
list.Add(new ExternalUrl
{
Name = "Trakt",
Url = string.Format("https://trakt.tv/movies/{0}", imdbId)
});
}
}
return list;
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.LiveTv
{
public class TimerEventInfo
{
public string Id { get; set; }
public string ProgramId { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.LiveTv
{
public class TunerChannelMapping
{
public string Name { get; set; }
public string Number { get; set; }
public string ProviderChannelNumber { get; set; }
public string ProviderChannelName { get; set; }
}
}

View File

@ -142,7 +142,7 @@
<Compile Include="Entities\IHasDisplayOrder.cs" />
<Compile Include="Entities\IHasId.cs" />
<Compile Include="Entities\IHasImages.cs" />
<Compile Include="Entities\IHasKeywords.cs" />
<Compile Include="Entities\KeywordExtensions.cs" />
<Compile Include="Entities\IHasMediaSources.cs" />
<Compile Include="Entities\IHasMetascore.cs" />
<Compile Include="Entities\IHasOriginalTitle.cs" />
@ -154,7 +154,6 @@
<Compile Include="Entities\IHasSpecialFeatures.cs" />
<Compile Include="Entities\IHasStartDate.cs" />
<Compile Include="Entities\IHasTaglines.cs" />
<Compile Include="Entities\IHasTags.cs" />
<Compile Include="Entities\IHasThemeMedia.cs" />
<Compile Include="Entities\IHasTrailers.cs" />
<Compile Include="Entities\IHasUserData.cs" />
@ -177,6 +176,7 @@
<Compile Include="Entities\PhotoAlbum.cs" />
<Compile Include="Entities\Share.cs" />
<Compile Include="Entities\SourceType.cs" />
<Compile Include="Entities\TagExtensions.cs" />
<Compile Include="Entities\UserView.cs" />
<Compile Include="Entities\UserViewBuilder.cs" />
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
@ -218,7 +218,9 @@
<Compile Include="LiveTv\ProgramInfo.cs" />
<Compile Include="LiveTv\RecordingInfo.cs" />
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
<Compile Include="LiveTv\TimerEventInfo.cs" />
<Compile Include="LiveTv\TimerInfo.cs" />
<Compile Include="LiveTv\TunerChannelMapping.cs" />
<Compile Include="Localization\ILocalizationManager.cs" />
<Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" />
<Compile Include="MediaEncoding\EncodingJobOptions.cs" />
@ -290,21 +292,17 @@
<Compile Include="Providers\IImageFileSaver.cs" />
<Compile Include="Providers\IImageProvider.cs" />
<Compile Include="Providers\IImageSaver.cs" />
<Compile Include="Providers\IItemIdentityConverter.cs" />
<Compile Include="Providers\IItemIdentityProvider.cs" />
<Compile Include="Providers\ILocalImageFileProvider.cs" />
<Compile Include="Providers\ILocalMetadataProvider.cs" />
<Compile Include="Providers\ImageRefreshMode.cs" />
<Compile Include="Providers\ImageRefreshOptions.cs" />
<Compile Include="Providers\IPreRefreshProvider.cs" />
<Compile Include="Providers\IProviderRepository.cs" />
<Compile Include="Providers\IRemoteImageProvider.cs" />
<Compile Include="Providers\ILocalImageProvider.cs" />
<Compile Include="Providers\IMetadataProvider.cs" />
<Compile Include="Providers\IMetadataService.cs" />
<Compile Include="Providers\IRemoteMetadataProvider.cs" />
<Compile Include="Providers\IRemoteSearchProvider.cs" />
<Compile Include="Providers\ISeriesOrderProvider.cs" />
<Compile Include="Providers\ItemInfo.cs" />
<Compile Include="Providers\LiveTvProgramLookupInfo.cs" />
<Compile Include="Providers\LocalImageInfo.cs" />
@ -330,12 +328,8 @@
<Compile Include="Sorting\SortHelper.cs" />
<Compile Include="Subtitles\ISubtitleManager.cs" />
<Compile Include="Subtitles\ISubtitleProvider.cs" />
<Compile Include="Providers\ItemIdentifier.cs" />
<Compile Include="Providers\ItemIdentities.cs" />
<Compile Include="Providers\ItemLookupInfo.cs" />
<Compile Include="Providers\MetadataRefreshOptions.cs" />
<Compile Include="Providers\MetadataStatus.cs" />
<Compile Include="Providers\ISeriesOrderManager.cs" />
<Compile Include="Session\ISessionManager.cs" />
<Compile Include="Entities\AggregateFolder.cs" />
<Compile Include="Entities\Audio\Audio.cs" />

View File

@ -1,4 +1,5 @@
using MediaBrowser.Model.Dlna;
using System.Linq;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Controller.MediaEncoding
{
@ -74,7 +75,7 @@ namespace MediaBrowser.Controller.MediaEncoding
Level = info.VideoLevel;
ItemId = info.ItemId;
MediaSourceId = info.MediaSourceId;
AudioCodec = info.AudioCodec;
AudioCodec = info.TargetAudioCodec;
MaxAudioChannels = info.MaxAudioChannels;
AudioBitRate = info.AudioBitrate;
AudioSampleRate = info.TargetAudioSampleRate;

View File

@ -13,18 +13,14 @@ namespace MediaBrowser.Controller.MediaEncoding
/// </summary>
public interface IMediaEncoder : ITranscoderSupport
{
string EncoderLocationType { get; }
/// <summary>
/// Gets the encoder path.
/// </summary>
/// <value>The encoder path.</value>
string EncoderPath { get; }
/// <summary>
/// Gets the version.
/// </summary>
/// <value>The version.</value>
string Version { get; }
/// <summary>
/// Supportses the decoder.
/// </summary>
@ -66,12 +62,12 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="maxWidth">The maximum width.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task ExtractVideoImagesOnInterval(string[] inputFiles,
MediaProtocol protocol,
Video3DFormat? threedFormat,
TimeSpan interval,
string targetDirectory,
string filenamePrefix,
Task ExtractVideoImagesOnInterval(string[] inputFiles,
MediaProtocol protocol,
Video3DFormat? threedFormat,
TimeSpan interval,
string targetDirectory,
string filenamePrefix,
int? maxWidth,
CancellationToken cancellationToken);
@ -134,5 +130,9 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="path">The path.</param>
/// <returns>System.String.</returns>
string EscapeSubtitleFilterPath(string path);
Task Init();
Task UpdateEncoderPath(string path, string pathType);
}
}

View File

@ -10,13 +10,6 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Gets the subtitles.
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <param name="mediaSourceId">The media source identifier.</param>
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
/// <param name="outputFormat">The output format.</param>
/// <param name="startTimeTicks">The start time ticks.</param>
/// <param name="endTimeTicks">The end time ticks.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Stream}.</returns>
Task<Stream> GetSubtitles(string itemId,
string mediaSourceId,
@ -24,6 +17,7 @@ namespace MediaBrowser.Controller.MediaEncoding
string outputFormat,
long startTimeTicks,
long? endTimeTicks,
bool preserveOriginalTimestamps,
CancellationToken cancellationToken);
/// <summary>

View File

@ -80,7 +80,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="responseHeaders">The response headers.</param>
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
/// <returns>System.Object.</returns>
object GetStaticResult(IRequest requestContext,
Task<object> GetStaticResult(IRequest requestContext,
Guid cacheKey,
DateTime? lastDateModified,
TimeSpan? cacheDuration,
@ -94,7 +94,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestContext">The request context.</param>
/// <param name="options">The options.</param>
/// <returns>System.Object.</returns>
object GetStaticResult(IRequest requestContext, StaticResultOptions options);
Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options);
/// <summary>
/// Gets the static file result.
@ -103,7 +103,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="path">The path.</param>
/// <param name="fileShare">The file share.</param>
/// <returns>System.Object.</returns>
object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read);
Task<object> GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read);
/// <summary>
/// Gets the static file result.
@ -111,7 +111,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestContext">The request context.</param>
/// <param name="options">The options.</param>
/// <returns>System.Object.</returns>
object GetStaticFileResult(IRequest requestContext,
Task<object> GetStaticFileResult(IRequest requestContext,
StaticFileResultOptions options);
}
}

View File

@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Persistence
@ -81,7 +82,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="chapters">The chapters.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken);
Task SaveChapters(Guid id, List<ChapterInfo> chapters, CancellationToken cancellationToken);
/// <summary>
/// Gets the media streams.
@ -97,7 +98,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="streams">The streams.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken);
/// <summary>
/// Gets the item ids.
@ -153,7 +154,7 @@ namespace MediaBrowser.Controller.Persistence
/// </summary>
/// <param name="query">The query.</param>
/// <returns>List&lt;BaseItem&gt;.</returns>
IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
List<BaseItem> GetItemList(InternalItemsQuery query);
/// <summary>
/// Updates the inherited values.
@ -161,6 +162,13 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task UpdateInheritedValues(CancellationToken cancellationToken);
QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
}
}

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