commit
cd8642a4bc
|
@ -2622,6 +2622,11 @@ namespace Emby.Server.Implementations.Data
|
||||||
groups.Add("PresentationUniqueKey");
|
groups.Add("PresentationUniqueKey");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (query.GroupBySeriesPresentationUniqueKey)
|
||||||
|
{
|
||||||
|
groups.Add("SeriesPresentationUniqueKey");
|
||||||
|
}
|
||||||
|
|
||||||
if (groups.Count > 0)
|
if (groups.Count > 0)
|
||||||
{
|
{
|
||||||
return " Group by " + string.Join(",", groups.ToArray());
|
return " Group by " + string.Join(",", groups.ToArray());
|
||||||
|
@ -2934,6 +2939,10 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
commandText += " select count (distinct PresentationUniqueKey)" + GetFromText();
|
commandText += " select count (distinct PresentationUniqueKey)" + GetFromText();
|
||||||
}
|
}
|
||||||
|
else if (query.GroupBySeriesPresentationUniqueKey)
|
||||||
|
{
|
||||||
|
commandText += " select count (distinct SeriesPresentationUniqueKey)" + GetFromText();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
commandText += " select count (guid)" + GetFromText();
|
commandText += " select count (guid)" + GetFromText();
|
||||||
|
@ -3079,6 +3088,11 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
if (string.Equals(name, ItemSortBy.DatePlayed, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(name, ItemSortBy.DatePlayed, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
if (query.GroupBySeriesPresentationUniqueKey)
|
||||||
|
{
|
||||||
|
return new Tuple<string, bool>("MAX(LastPlayedDate)", false);
|
||||||
|
}
|
||||||
|
|
||||||
return new Tuple<string, bool>("LastPlayedDate", false);
|
return new Tuple<string, bool>("LastPlayedDate", false);
|
||||||
}
|
}
|
||||||
if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase))
|
||||||
|
@ -3353,6 +3367,10 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
commandText += " select count (distinct PresentationUniqueKey)" + GetFromText();
|
commandText += " select count (distinct PresentationUniqueKey)" + GetFromText();
|
||||||
}
|
}
|
||||||
|
else if (query.GroupBySeriesPresentationUniqueKey)
|
||||||
|
{
|
||||||
|
commandText += " select count (distinct SeriesPresentationUniqueKey)" + GetFromText();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
commandText += " select count (guid)" + GetFromText();
|
commandText += " select count (guid)" + GetFromText();
|
||||||
|
@ -4640,6 +4658,11 @@ namespace Emby.Server.Implementations.Data
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (query.GroupBySeriesPresentationUniqueKey)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey))
|
if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -6,19 +6,16 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Emby.Server.Implementations.HttpServer;
|
|
||||||
using Emby.Server.Implementations.Services;
|
using Emby.Server.Implementations.Services;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Services;
|
using MediaBrowser.Model.Services;
|
||||||
using IRequest = MediaBrowser.Model.Services.IRequest;
|
using IRequest = MediaBrowser.Model.Services.IRequest;
|
||||||
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
|
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
|
||||||
using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.HttpServer
|
namespace Emby.Server.Implementations.HttpServer
|
||||||
{
|
{
|
||||||
|
@ -193,48 +190,35 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public object ToOptimizedResult<T>(IRequest request, T dto)
|
public object ToOptimizedResult<T>(IRequest request, T dto)
|
||||||
{
|
{
|
||||||
var compressionType = GetCompressionType(request);
|
var contentType = request.ResponseContentType;
|
||||||
if (compressionType == null)
|
|
||||||
|
switch (GetRealContentType(contentType))
|
||||||
{
|
{
|
||||||
var contentType = request.ResponseContentType;
|
case "application/xml":
|
||||||
|
case "text/xml":
|
||||||
|
case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
|
||||||
|
return SerializeToXmlString(dto);
|
||||||
|
|
||||||
switch (GetRealContentType(contentType))
|
case "application/json":
|
||||||
{
|
case "text/json":
|
||||||
case "application/xml":
|
return _jsonSerializer.SerializeToString(dto);
|
||||||
case "text/xml":
|
default:
|
||||||
case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
|
{
|
||||||
return SerializeToXmlString(dto);
|
var ms = new MemoryStream();
|
||||||
|
var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
|
||||||
|
|
||||||
case "application/json":
|
writerFn(dto, ms);
|
||||||
case "text/json":
|
|
||||||
return _jsonSerializer.SerializeToString(dto);
|
ms.Position = 0;
|
||||||
}
|
|
||||||
|
if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return GetHttpResult(new byte[] { }, contentType, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetHttpResult(ms, contentType, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not use the memoryStreamFactory here, they don't place nice with compression
|
|
||||||
using (var ms = new MemoryStream())
|
|
||||||
{
|
|
||||||
var contentType = request.ResponseContentType;
|
|
||||||
var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
|
|
||||||
|
|
||||||
writerFn(dto, ms);
|
|
||||||
|
|
||||||
ms.Position = 0;
|
|
||||||
|
|
||||||
var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Stream GetCompressionStream(Stream outputStream, string compressionType)
|
|
||||||
{
|
|
||||||
if (compressionType == "deflate")
|
|
||||||
return new DeflateStream(outputStream, CompressionMode.Compress, true);
|
|
||||||
if (compressionType == "gzip")
|
|
||||||
return new GZipStream(outputStream, CompressionMode.Compress, true);
|
|
||||||
|
|
||||||
throw new NotSupportedException(compressionType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetRealContentType(string contentType)
|
public static string GetRealContentType(string contentType)
|
||||||
|
@ -568,123 +552,47 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
var contentType = options.ContentType;
|
var contentType = options.ContentType;
|
||||||
var responseHeaders = options.ResponseHeaders;
|
var responseHeaders = options.ResponseHeaders;
|
||||||
|
|
||||||
var requestedCompressionType = GetCompressionType(requestContext);
|
//var requestedCompressionType = GetCompressionType(requestContext);
|
||||||
|
|
||||||
if (!compress || string.IsNullOrEmpty(requestedCompressionType))
|
var rangeHeader = requestContext.Headers.Get("Range");
|
||||||
|
|
||||||
|
if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
|
||||||
{
|
{
|
||||||
var rangeHeader = requestContext.Headers.Get("Range");
|
return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
|
||||||
|
|
||||||
if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
|
|
||||||
{
|
{
|
||||||
return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
|
OnComplete = options.OnComplete,
|
||||||
{
|
OnError = options.OnError,
|
||||||
OnComplete = options.OnComplete,
|
FileShare = options.FileShare
|
||||||
OnError = options.OnError,
|
};
|
||||||
FileShare = options.FileShare
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(rangeHeader))
|
|
||||||
{
|
|
||||||
var stream = await factoryFn().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
|
|
||||||
{
|
|
||||||
OnComplete = options.OnComplete
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var stream = await factoryFn().ConfigureAwait(false);
|
|
||||||
|
|
||||||
responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
|
|
||||||
|
|
||||||
if (isHeadRequest)
|
|
||||||
{
|
|
||||||
stream.Dispose();
|
|
||||||
|
|
||||||
return GetHttpResult(new byte[] { }, contentType, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new StreamWriter(stream, contentType, _logger)
|
|
||||||
{
|
|
||||||
OnComplete = options.OnComplete,
|
|
||||||
OnError = options.OnError
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var stream = await factoryFn().ConfigureAwait(false))
|
if (!string.IsNullOrWhiteSpace(rangeHeader))
|
||||||
{
|
{
|
||||||
return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false);
|
var stream = await factoryFn().ConfigureAwait(false);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IHasHeaders> GetCompressedResult(Stream stream,
|
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
|
||||||
string requestedCompressionType,
|
|
||||||
IDictionary<string, string> responseHeaders,
|
|
||||||
bool isHeadRequest,
|
|
||||||
string contentType)
|
|
||||||
{
|
|
||||||
using (var reader = new MemoryStream())
|
|
||||||
{
|
|
||||||
await stream.CopyToAsync(reader).ConfigureAwait(false);
|
|
||||||
|
|
||||||
reader.Position = 0;
|
|
||||||
var content = reader.ToArray();
|
|
||||||
|
|
||||||
if (content.Length >= 1024)
|
|
||||||
{
|
{
|
||||||
content = Compress(content, requestedCompressionType);
|
OnComplete = options.OnComplete
|
||||||
responseHeaders["Content-Encoding"] = requestedCompressionType;
|
};
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var stream = await factoryFn().ConfigureAwait(false);
|
||||||
|
|
||||||
responseHeaders["Vary"] = "Accept-Encoding";
|
responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
|
||||||
responseHeaders["Content-Length"] = content.Length.ToString(UsCulture);
|
|
||||||
|
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
{
|
{
|
||||||
|
stream.Dispose();
|
||||||
|
|
||||||
return GetHttpResult(new byte[] { }, contentType, true);
|
return GetHttpResult(new byte[] { }, contentType, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetHttpResult(content, contentType, true, responseHeaders);
|
return new StreamWriter(stream, contentType, _logger)
|
||||||
}
|
{
|
||||||
}
|
OnComplete = options.OnComplete,
|
||||||
|
OnError = options.OnError
|
||||||
private byte[] Compress(byte[] bytes, string compressionType)
|
};
|
||||||
{
|
|
||||||
if (compressionType == "deflate")
|
|
||||||
return Deflate(bytes);
|
|
||||||
|
|
||||||
if (compressionType == "gzip")
|
|
||||||
return GZip(bytes);
|
|
||||||
|
|
||||||
throw new NotSupportedException(compressionType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] Deflate(byte[] bytes)
|
|
||||||
{
|
|
||||||
// In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream
|
|
||||||
// Which means we must use MemoryStream since you have to use ToArray() on a closed Stream
|
|
||||||
using (var ms = new MemoryStream())
|
|
||||||
using (var zipStream = new DeflateStream(ms, CompressionMode.Compress))
|
|
||||||
{
|
|
||||||
zipStream.Write(bytes, 0, bytes.Length);
|
|
||||||
zipStream.Dispose();
|
|
||||||
|
|
||||||
return ms.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] GZip(byte[] buffer)
|
|
||||||
{
|
|
||||||
using (var ms = new MemoryStream())
|
|
||||||
using (var zipStream = new GZipStream(ms, CompressionMode.Compress))
|
|
||||||
{
|
|
||||||
zipStream.Write(buffer, 0, buffer.Length);
|
|
||||||
zipStream.Dispose();
|
|
||||||
|
|
||||||
return ms.ToArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,7 +269,41 @@ namespace Emby.Server.Implementations.Library
|
||||||
return new List<BaseItem>();
|
return new List<BaseItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var excludeItemTypes = includeItemTypes.Length == 0 ? new[]
|
var mediaTypes = new List<string>();
|
||||||
|
|
||||||
|
if (includeItemTypes.Length == 0)
|
||||||
|
{
|
||||||
|
foreach (var parent in parents.OfType<ICollectionFolder>())
|
||||||
|
{
|
||||||
|
switch (parent.CollectionType)
|
||||||
|
{
|
||||||
|
case CollectionType.Books:
|
||||||
|
mediaTypes.Add(MediaType.Book);
|
||||||
|
break;
|
||||||
|
case CollectionType.Games:
|
||||||
|
mediaTypes.Add(MediaType.Game);
|
||||||
|
break;
|
||||||
|
case CollectionType.Music:
|
||||||
|
mediaTypes.Add(MediaType.Audio);
|
||||||
|
break;
|
||||||
|
case CollectionType.Photos:
|
||||||
|
mediaTypes.Add(MediaType.Photo);
|
||||||
|
mediaTypes.Add(MediaType.Video);
|
||||||
|
break;
|
||||||
|
case CollectionType.HomeVideos:
|
||||||
|
mediaTypes.Add(MediaType.Photo);
|
||||||
|
mediaTypes.Add(MediaType.Video);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mediaTypes.Add(MediaType.Video);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaTypes = mediaTypes.Distinct().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 ? new[]
|
||||||
{
|
{
|
||||||
typeof(Person).Name,
|
typeof(Person).Name,
|
||||||
typeof(Studio).Name,
|
typeof(Studio).Name,
|
||||||
|
@ -290,7 +324,8 @@ namespace Emby.Server.Implementations.Library
|
||||||
IsVirtualItem = false,
|
IsVirtualItem = false,
|
||||||
Limit = limit * 5,
|
Limit = limit * 5,
|
||||||
IsPlayed = isPlayed,
|
IsPlayed = isPlayed,
|
||||||
DtoOptions = options
|
DtoOptions = options,
|
||||||
|
MediaTypes = mediaTypes.ToArray()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (parents.Count == 0)
|
if (parents.Count == 0)
|
||||||
|
|
|
@ -1632,7 +1632,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var episodesToDelete = (librarySeries.GetItems(new InternalItemsQuery
|
var episodesToDelete = (librarySeries.GetItemList(new InternalItemsQuery
|
||||||
{
|
{
|
||||||
SortBy = new[] { ItemSortBy.DateCreated },
|
SortBy = new[] { ItemSortBy.DateCreated },
|
||||||
SortOrder = SortOrder.Descending,
|
SortOrder = SortOrder.Descending,
|
||||||
|
@ -1642,7 +1642,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
DtoOptions = new DtoOptions(true)
|
DtoOptions = new DtoOptions(true)
|
||||||
|
|
||||||
}))
|
}))
|
||||||
.Items
|
|
||||||
.Where(i => i.LocationType == LocationType.FileSystem && _fileSystem.FileExists(i.Path))
|
.Where(i => i.LocationType == LocationType.FileSystem && _fileSystem.FileExists(i.Path))
|
||||||
.Skip(seriesTimer.KeepUpTo - 1)
|
.Skip(seriesTimer.KeepUpTo - 1)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
|
@ -1845,6 +1845,9 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, List<ItemFields> fields, User user = null)
|
public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, List<ItemFields> fields, User user = null)
|
||||||
{
|
{
|
||||||
var programTuples = new List<Tuple<BaseItemDto, string, string, string>>();
|
var programTuples = new List<Tuple<BaseItemDto, string, string, string>>();
|
||||||
|
var hasChannelImage = fields.Contains(ItemFields.ChannelImage);
|
||||||
|
var hasChannelInfo = fields.Contains(ItemFields.ChannelInfo);
|
||||||
|
var hasServiceName = fields.Contains(ItemFields.ServiceName);
|
||||||
|
|
||||||
foreach (var tuple in tuples)
|
foreach (var tuple in tuples)
|
||||||
{
|
{
|
||||||
|
@ -1887,7 +1890,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
dto.IsPremiere = program.IsPremiere;
|
dto.IsPremiere = program.IsPremiere;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fields.Contains(ItemFields.ChannelInfo))
|
if (hasChannelInfo || hasChannelImage)
|
||||||
{
|
{
|
||||||
var channel = GetInternalChannel(program.ChannelId);
|
var channel = GetInternalChannel(program.ChannelId);
|
||||||
|
|
||||||
|
@ -1897,7 +1900,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
dto.MediaType = channel.MediaType;
|
dto.MediaType = channel.MediaType;
|
||||||
dto.ChannelNumber = channel.Number;
|
dto.ChannelNumber = channel.Number;
|
||||||
|
|
||||||
if (channel.HasImage(ImageType.Primary))
|
if (hasChannelImage && channel.HasImage(ImageType.Primary))
|
||||||
{
|
{
|
||||||
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
|
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
|
||||||
}
|
}
|
||||||
|
@ -1906,7 +1909,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
|
|
||||||
var serviceName = program.ServiceName;
|
var serviceName = program.ServiceName;
|
||||||
|
|
||||||
if (fields.Contains(ItemFields.ServiceName))
|
if (hasServiceName)
|
||||||
{
|
{
|
||||||
dto.ServiceName = serviceName;
|
dto.ServiceName = serviceName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1089,7 +1089,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
{
|
{
|
||||||
var folder = (Folder)item;
|
var folder = (Folder)item;
|
||||||
|
|
||||||
var itemsResult = folder.GetItems(new InternalItemsQuery(user)
|
var itemsResult = folder.GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
IsFolder = false,
|
IsFolder = false,
|
||||||
|
@ -1104,7 +1104,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return FilterToSingleMediaType(itemsResult.Items)
|
return FilterToSingleMediaType(itemsResult)
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.TV
|
||||||
int? limit = null;
|
int? limit = null;
|
||||||
if (!string.IsNullOrWhiteSpace(request.SeriesId))
|
if (!string.IsNullOrWhiteSpace(request.SeriesId))
|
||||||
{
|
{
|
||||||
var series = _libraryManager.GetItemById(request.SeriesId);
|
var series = _libraryManager.GetItemById(request.SeriesId) as Series;
|
||||||
|
|
||||||
if (series != null)
|
if (series != null)
|
||||||
{
|
{
|
||||||
|
@ -51,17 +51,22 @@ namespace Emby.Server.Implementations.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(presentationUniqueKey) && limit.HasValue)
|
if (!string.IsNullOrWhiteSpace(presentationUniqueKey))
|
||||||
|
{
|
||||||
|
return GetResult(GetNextUpEpisodes(request, user, new[] { presentationUniqueKey }, dtoOptions), request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (limit.HasValue)
|
||||||
{
|
{
|
||||||
limit = limit.Value + 10;
|
limit = limit.Value + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
IncludeItemTypes = new[] { typeof(Series).Name },
|
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||||
SortBy = new[] { ItemSortBy.SeriesDatePlayed },
|
SortBy = new[] { ItemSortBy.DatePlayed },
|
||||||
SortOrder = SortOrder.Descending,
|
SortOrder = SortOrder.Descending,
|
||||||
PresentationUniqueKey = presentationUniqueKey,
|
SeriesPresentationUniqueKey = presentationUniqueKey,
|
||||||
Limit = limit,
|
Limit = limit,
|
||||||
ParentId = parentIdGuid,
|
ParentId = parentIdGuid,
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
|
@ -69,11 +74,12 @@ namespace Emby.Server.Implementations.TV
|
||||||
{
|
{
|
||||||
Fields = new List<ItemFields>
|
Fields = new List<ItemFields>
|
||||||
{
|
{
|
||||||
ItemFields.PresentationUniqueKey
|
ItemFields.SeriesPresentationUniqueKey
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
GroupBySeriesPresentationUniqueKey = true
|
||||||
|
|
||||||
}).Cast<Series>().Select(GetUniqueSeriesKey);
|
}).Cast<Episode>().Select(GetUniqueSeriesKey);
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
// Avoid implicitly captured closure
|
||||||
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
|
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
|
||||||
|
@ -94,7 +100,7 @@ namespace Emby.Server.Implementations.TV
|
||||||
int? limit = null;
|
int? limit = null;
|
||||||
if (!string.IsNullOrWhiteSpace(request.SeriesId))
|
if (!string.IsNullOrWhiteSpace(request.SeriesId))
|
||||||
{
|
{
|
||||||
var series = _libraryManager.GetItemById(request.SeriesId);
|
var series = _libraryManager.GetItemById(request.SeriesId) as Series;
|
||||||
|
|
||||||
if (series != null)
|
if (series != null)
|
||||||
{
|
{
|
||||||
|
@ -103,28 +109,34 @@ namespace Emby.Server.Implementations.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(presentationUniqueKey) && limit.HasValue)
|
if (!string.IsNullOrWhiteSpace(presentationUniqueKey))
|
||||||
|
{
|
||||||
|
return GetResult(GetNextUpEpisodes(request, user, new [] { presentationUniqueKey }, dtoOptions), request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (limit.HasValue)
|
||||||
{
|
{
|
||||||
limit = limit.Value + 10;
|
limit = limit.Value + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
IncludeItemTypes = new[] { typeof(Series).Name },
|
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||||
SortBy = new[] { ItemSortBy.SeriesDatePlayed },
|
SortBy = new[] { ItemSortBy.DatePlayed },
|
||||||
SortOrder = SortOrder.Descending,
|
SortOrder = SortOrder.Descending,
|
||||||
PresentationUniqueKey = presentationUniqueKey,
|
SeriesPresentationUniqueKey = presentationUniqueKey,
|
||||||
Limit = limit,
|
Limit = limit,
|
||||||
DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
|
DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
|
||||||
{
|
{
|
||||||
Fields = new List<ItemFields>
|
Fields = new List<ItemFields>
|
||||||
{
|
{
|
||||||
ItemFields.PresentationUniqueKey
|
ItemFields.SeriesPresentationUniqueKey
|
||||||
},
|
},
|
||||||
EnableImages = false
|
EnableImages = false
|
||||||
}
|
},
|
||||||
|
GroupBySeriesPresentationUniqueKey = true
|
||||||
|
|
||||||
}, parentsFolders.Cast<BaseItem>().ToList()).Cast<Series>().Select(GetUniqueSeriesKey);
|
}, parentsFolders.Cast<BaseItem>().ToList()).Cast<Episode>().Select(GetUniqueSeriesKey);
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
// Avoid implicitly captured closure
|
||||||
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
|
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
|
||||||
|
@ -167,7 +179,12 @@ namespace Emby.Server.Implementations.TV
|
||||||
.Where(i => i != null);
|
.Where(i => i != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetUniqueSeriesKey(BaseItem series)
|
private string GetUniqueSeriesKey(Episode episode)
|
||||||
|
{
|
||||||
|
return episode.SeriesPresentationUniqueKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetUniqueSeriesKey(Series series)
|
||||||
{
|
{
|
||||||
return series.GetPresentationUniqueKey();
|
return series.GetPresentationUniqueKey();
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.UserViews
|
||||||
|
|
||||||
var recursive = !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
var recursive = !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var result = view.GetItems(new InternalItemsQuery
|
var result = view.GetItemList(new InternalItemsQuery
|
||||||
{
|
{
|
||||||
CollapseBoxSetItems = false,
|
CollapseBoxSetItems = false,
|
||||||
Recursive = recursive,
|
Recursive = recursive,
|
||||||
|
@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.UserViews
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var items = result.Items.Select(i =>
|
var items = result.Select(i =>
|
||||||
{
|
{
|
||||||
var episode = i as Episode;
|
var episode = i as Episode;
|
||||||
if (episode != null)
|
if (episode != null)
|
||||||
|
|
|
@ -70,19 +70,19 @@ namespace Emby.Server.Implementations.UserViews
|
||||||
if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(view.ViewType, SpecialFolder.TvGenre, StringComparison.OrdinalIgnoreCase))
|
string.Equals(view.ViewType, SpecialFolder.TvGenre, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var userItemsResult = view.GetItems(new InternalItemsQuery
|
var userItemsResult = view.GetItemList(new InternalItemsQuery
|
||||||
{
|
{
|
||||||
CollapseBoxSetItems = false,
|
CollapseBoxSetItems = false,
|
||||||
DtoOptions = new DtoOptions(false)
|
DtoOptions = new DtoOptions(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
return userItemsResult.Items.ToList();
|
return userItemsResult.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
var isUsingCollectionStrip = IsUsingCollectionStrip(view);
|
var isUsingCollectionStrip = IsUsingCollectionStrip(view);
|
||||||
var recursive = isUsingCollectionStrip && !new[] { CollectionType.Channels, CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
var recursive = isUsingCollectionStrip && !new[] { CollectionType.Channels, CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var result = view.GetItems(new InternalItemsQuery
|
var result = view.GetItemList(new InternalItemsQuery
|
||||||
{
|
{
|
||||||
User = view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null,
|
User = view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null,
|
||||||
CollapseBoxSetItems = false,
|
CollapseBoxSetItems = false,
|
||||||
|
@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.UserViews
|
||||||
DtoOptions = new DtoOptions(false)
|
DtoOptions = new DtoOptions(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
var items = result.Items.Select(i =>
|
var items = result.Select(i =>
|
||||||
{
|
{
|
||||||
var episode = i as Episode;
|
var episode = i as Episode;
|
||||||
if (episode != null)
|
if (episode != null)
|
||||||
|
|
|
@ -61,9 +61,9 @@ namespace MediaBrowser.Api
|
||||||
user == null ? _libraryManager.RootFolder : user.RootFolder :
|
user == null ? _libraryManager.RootFolder : user.RootFolder :
|
||||||
parentItem;
|
parentItem;
|
||||||
|
|
||||||
var result = ((Folder)item).GetItems(GetItemsQuery(request, user));
|
var result = ((Folder)item).GetItemList(GetItemsQuery(request, user));
|
||||||
|
|
||||||
return ToOptimizedResult(GetFilters(result.Items));
|
return ToOptimizedResult(GetFilters(result.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryFilters GetFilters(BaseItem[] items)
|
private QueryFilters GetFilters(BaseItem[] items)
|
||||||
|
|
|
@ -438,14 +438,14 @@ namespace MediaBrowser.Api
|
||||||
throw new ResourceNotFoundException("Series not found");
|
throw new ResourceNotFoundException("Series not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
var seasons = (series.GetItems(new InternalItemsQuery(user)
|
var seasons = (series.GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
IsMissing = request.IsMissing,
|
IsMissing = request.IsMissing,
|
||||||
IsVirtualUnaired = request.IsVirtualUnaired,
|
IsVirtualUnaired = request.IsVirtualUnaired,
|
||||||
IsSpecialSeason = request.IsSpecialSeason,
|
IsSpecialSeason = request.IsSpecialSeason,
|
||||||
AdjacentTo = request.AdjacentTo
|
AdjacentTo = request.AdjacentTo
|
||||||
|
|
||||||
})).Items.OfType<Season>();
|
})).OfType<Season>();
|
||||||
|
|
||||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||||
|
|
||||||
|
|
|
@ -970,6 +970,27 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return GetItemsInternal(query);
|
return GetItemsInternal(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
|
||||||
|
{
|
||||||
|
query.EnableTotalRecordCount = false;
|
||||||
|
|
||||||
|
if (query.ItemIds.Length > 0)
|
||||||
|
{
|
||||||
|
var result = LibraryManager.GetItemList(query);
|
||||||
|
|
||||||
|
if (query.SortBy.Length == 0)
|
||||||
|
{
|
||||||
|
var ids = query.ItemIds.ToList();
|
||||||
|
|
||||||
|
// Try to preserve order
|
||||||
|
result = result.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetItemsInternal(query).Items;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
|
protected virtual QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (SourceType == SourceType.Channel)
|
if (SourceType == SourceType.Channel)
|
||||||
|
@ -1375,10 +1396,10 @@ namespace MediaBrowser.Controller.Entities
|
||||||
query.IsVirtualItem = false;
|
query.IsVirtualItem = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemsResult = GetItems(query);
|
var itemsResult = GetItemList(query);
|
||||||
|
|
||||||
// Sweep through recursively and update status
|
// Sweep through recursively and update status
|
||||||
var tasks = itemsResult.Items.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
|
var tasks = itemsResult.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -1390,7 +1411,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public override async Task MarkUnplayed(User user)
|
public override async Task MarkUnplayed(User user)
|
||||||
{
|
{
|
||||||
var itemsResult = GetItems(new InternalItemsQuery
|
var itemsResult = GetItemList(new InternalItemsQuery
|
||||||
{
|
{
|
||||||
User = user,
|
User = user,
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
|
@ -1400,14 +1421,14 @@ namespace MediaBrowser.Controller.Entities
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sweep through recursively and update status
|
// Sweep through recursively and update status
|
||||||
var tasks = itemsResult.Items.Select(c => c.MarkUnplayed(user));
|
var tasks = itemsResult.Select(c => c.MarkUnplayed(user));
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsPlayed(User user)
|
public override bool IsPlayed(User user)
|
||||||
{
|
{
|
||||||
var itemsResult = GetItems(new InternalItemsQuery(user)
|
var itemsResult = GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
IsFolder = false,
|
IsFolder = false,
|
||||||
|
@ -1416,7 +1437,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return itemsResult.Items
|
return itemsResult
|
||||||
.All(i => i.IsPlayed(user));
|
.All(i => i.IsPlayed(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
public string SeriesPresentationUniqueKey { get; set; }
|
public string SeriesPresentationUniqueKey { get; set; }
|
||||||
|
|
||||||
public bool GroupByPresentationUniqueKey { get; set; }
|
public bool GroupByPresentationUniqueKey { get; set; }
|
||||||
|
public bool GroupBySeriesPresentationUniqueKey { get; set; }
|
||||||
public bool EnableTotalRecordCount { get; set; }
|
public bool EnableTotalRecordCount { get; set; }
|
||||||
public bool ForceDirect { get; set; }
|
public bool ForceDirect { get; set; }
|
||||||
public Dictionary<string, string> ExcludeProviderIds { get; set; }
|
public Dictionary<string, string> ExcludeProviderIds { get; set; }
|
||||||
|
|
|
@ -193,7 +193,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
|
|
||||||
if (query.IncludeItemTypes.Length == 0)
|
if (query.IncludeItemTypes.Length == 0)
|
||||||
{
|
{
|
||||||
query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
|
query.IncludeItemTypes = new[] { typeof(Episode).Name };
|
||||||
}
|
}
|
||||||
query.IsVirtualItem = false;
|
query.IsVirtualItem = false;
|
||||||
query.Limit = 0;
|
query.Limit = 0;
|
||||||
|
|
|
@ -82,7 +82,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
|
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
|
||||||
{
|
{
|
||||||
var result = GetItems(new InternalItemsQuery
|
var result = GetItemList(new InternalItemsQuery
|
||||||
{
|
{
|
||||||
User = user,
|
User = user,
|
||||||
EnableTotalRecordCount = false,
|
EnableTotalRecordCount = false,
|
||||||
|
@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return result.Items;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanDelete()
|
public override bool CanDelete()
|
||||||
|
@ -105,7 +105,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
|
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
var result = GetItems(new InternalItemsQuery
|
var result = GetItemList(new InternalItemsQuery
|
||||||
{
|
{
|
||||||
User = user,
|
User = user,
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
|
@ -117,7 +117,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return result.Items.Where(i => UserViewBuilder.FilterItem(i, query));
|
return result.Where(i => UserViewBuilder.FilterItem(i, query));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||||
|
|
|
@ -182,10 +182,7 @@ namespace MediaBrowser.Controller.Playlists
|
||||||
DtoOptions = options
|
DtoOptions = options
|
||||||
};
|
};
|
||||||
|
|
||||||
var itemsResult = folder.GetItems(query);
|
return folder.GetItemList(query);
|
||||||
var items = itemsResult.Items;
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { item };
|
return new[] { item };
|
||||||
|
|
|
@ -224,6 +224,7 @@
|
||||||
SeriesPresentationUniqueKey,
|
SeriesPresentationUniqueKey,
|
||||||
DateLastRefreshed,
|
DateLastRefreshed,
|
||||||
DateLastSaved,
|
DateLastSaved,
|
||||||
RefreshState
|
RefreshState,
|
||||||
|
ChannelImage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ namespace MediaBrowser.Server.Mono
|
||||||
private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, StartupOptions options)
|
private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, StartupOptions options)
|
||||||
{
|
{
|
||||||
// Allow all https requests
|
// Allow all https requests
|
||||||
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
|
//ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
|
||||||
|
|
||||||
var environmentInfo = GetEnvironmentInfo();
|
var environmentInfo = GetEnvironmentInfo();
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("3.2.26.10")]
|
[assembly: AssemblyVersion("3.2.26.11")]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user