mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 03:26:07 +02:00
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
This commit is contained in:
commit
6470c62c50
74 changed files with 1352 additions and 1133 deletions
|
@ -1,59 +0,0 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Server.Implementations.HttpServer;
|
|
||||||
using ServiceStack.ServiceHost;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Javascript
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class GetJavascriptApiClient
|
|
||||||
/// </summary>
|
|
||||||
[Route("/JsApiClient.js", "GET")]
|
|
||||||
[ServiceStack.ServiceHost.Api(("Gets an api wrapper written in Javascript"))]
|
|
||||||
public class GetJavascriptApiClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Version identifier for caching
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The v.</value>
|
|
||||||
public string V { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class JavascriptApiClientService
|
|
||||||
/// </summary>
|
|
||||||
public class JavascriptApiClientService : BaseRestService
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the specified request.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">The request.</param>
|
|
||||||
/// <returns>System.Object.</returns>
|
|
||||||
public object Get(GetJavascriptApiClient request)
|
|
||||||
{
|
|
||||||
TimeSpan? cacheDuration = null;
|
|
||||||
|
|
||||||
// If there's a version number in the query string we can cache this unconditionally
|
|
||||||
if (!string.IsNullOrEmpty(request.V))
|
|
||||||
{
|
|
||||||
cacheDuration = TimeSpan.FromDays(365);
|
|
||||||
}
|
|
||||||
|
|
||||||
var assembly = GetType().Assembly.GetName();
|
|
||||||
|
|
||||||
return ToStaticResult(assembly.Version.ToString().GetMD5(), null, cacheDuration, MimeTypes.GetMimeType("script.js"), GetStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Stream.</returns>
|
|
||||||
private Task<Stream> GetStream()
|
|
||||||
{
|
|
||||||
return Task.FromResult(GetType().Assembly.GetManifestResourceStream("MediaBrowser.Api.Javascript.ApiClient.js"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Server.Implementations.HttpServer;
|
using MediaBrowser.Server.Implementations.HttpServer;
|
||||||
using ServiceStack.ServiceHost;
|
using ServiceStack.ServiceHost;
|
||||||
using System;
|
using System;
|
||||||
|
|
|
@ -85,7 +85,6 @@
|
||||||
<Compile Include="Images\ImageRequest.cs" />
|
<Compile Include="Images\ImageRequest.cs" />
|
||||||
<Compile Include="Images\ImageService.cs" />
|
<Compile Include="Images\ImageService.cs" />
|
||||||
<Compile Include="Images\ImageWriter.cs" />
|
<Compile Include="Images\ImageWriter.cs" />
|
||||||
<Compile Include="Javascript\JavascriptApiClientService.cs" />
|
|
||||||
<Compile Include="Library\LibraryHelpers.cs" />
|
<Compile Include="Library\LibraryHelpers.cs" />
|
||||||
<Compile Include="Library\LibraryService.cs" />
|
<Compile Include="Library\LibraryService.cs" />
|
||||||
<Compile Include="Library\LibraryStructureService.cs" />
|
<Compile Include="Library\LibraryStructureService.cs" />
|
||||||
|
@ -107,6 +106,7 @@
|
||||||
<Compile Include="ApiEntryPoint.cs" />
|
<Compile Include="ApiEntryPoint.cs" />
|
||||||
<Compile Include="SystemService.cs" />
|
<Compile Include="SystemService.cs" />
|
||||||
<Compile Include="UserLibrary\BaseItemsByNameService.cs" />
|
<Compile Include="UserLibrary\BaseItemsByNameService.cs" />
|
||||||
|
<Compile Include="UserLibrary\BaseItemsRequest.cs" />
|
||||||
<Compile Include="UserLibrary\GenresService.cs" />
|
<Compile Include="UserLibrary\GenresService.cs" />
|
||||||
<Compile Include="UserLibrary\ItemsService.cs" />
|
<Compile Include="UserLibrary\ItemsService.cs" />
|
||||||
<Compile Include="UserLibrary\PersonsService.cs" />
|
<Compile Include="UserLibrary\PersonsService.cs" />
|
||||||
|
@ -141,7 +141,6 @@
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Javascript\ApiClient.js" />
|
|
||||||
<Content Include="options.xml" />
|
<Content Include="options.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
|
|
|
@ -6,6 +6,7 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Server.Implementations.HttpServer;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
@ -14,7 +15,6 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Server.Implementations.HttpServer;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
|
@ -650,10 +650,8 @@ namespace MediaBrowser.Api.Playback
|
||||||
state.VideoStream = GetMediaStream(media.MediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video, true);
|
state.VideoStream = GetMediaStream(media.MediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video, true);
|
||||||
state.SubtitleStream = GetMediaStream(media.MediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
|
state.SubtitleStream = GetMediaStream(media.MediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
state.AudioStream = GetMediaStream(media.MediaStreams, null, MediaStreamType.Audio, true);
|
||||||
state.AudioStream = GetMediaStream(media.MediaStreams, null, MediaStreamType.Audio, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Audio/{Id}/segments/{SegmentId}.mp3", "GET")]
|
[Route("/Audio/{Id}/segments/{SegmentId}/stream.mp3", "GET")]
|
||||||
[Route("/Audio/{Id}/segments/{SegmentId}.aac", "GET")]
|
[Route("/Audio/{Id}/segments/{SegmentId}/stream.aac", "GET")]
|
||||||
[ServiceStack.ServiceHost.Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
|
[ServiceStack.ServiceHost.Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
|
||||||
public class GetHlsAudioSegment
|
public class GetHlsAudioSegment
|
||||||
{
|
{
|
||||||
|
|
|
@ -127,7 +127,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
// The segement paths within the playlist are phsyical, so strip that out to make it relative
|
// The segement paths within the playlist are phsyical, so strip that out to make it relative
|
||||||
fileText = fileText.Replace(Path.GetDirectoryName(playlist) + Path.DirectorySeparatorChar, string.Empty);
|
fileText = fileText.Replace(Path.GetDirectoryName(playlist) + Path.DirectorySeparatorChar, string.Empty);
|
||||||
|
|
||||||
fileText = fileText.Replace(SegmentFilePrefix, "segments/");
|
fileText = fileText.Replace(SegmentFilePrefix, "segments/").Replace(".ts", "/stream.ts").Replace(".aac", "/stream.aac").Replace(".mp3", "/stream.mp3");
|
||||||
|
|
||||||
// Even though we specify target duration of 9, ffmpeg seems unable to keep all segments under that amount
|
// Even though we specify target duration of 9, ffmpeg seems unable to keep all segments under that amount
|
||||||
fileText = fileText.Replace("#EXT-X-TARGETDURATION:9", "#EXT-X-TARGETDURATION:10");
|
fileText = fileText.Replace("#EXT-X-TARGETDURATION:9", "#EXT-X-TARGETDURATION:10");
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Videos/{Id}/segments/{SegmentId}.ts", "GET")]
|
[Route("/Videos/{Id}/segments/{SegmentId}/stream.ts", "GET")]
|
||||||
[ServiceStack.ServiceHost.Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
|
[ServiceStack.ServiceHost.Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
|
||||||
public class GetHlsVideoSegment
|
public class GetHlsVideoSegment
|
||||||
{
|
{
|
||||||
|
|
|
@ -135,11 +135,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
|
ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ProgressiveStreamWriter
|
return new ProgressiveStreamWriter(outputPath, state, Logger);
|
||||||
{
|
|
||||||
Path = outputPath,
|
|
||||||
State = state
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -9,9 +9,22 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
{
|
{
|
||||||
public class ProgressiveStreamWriter : IStreamWriter
|
public class ProgressiveStreamWriter : IStreamWriter
|
||||||
{
|
{
|
||||||
public string Path { get; set; }
|
private string Path { get; set; }
|
||||||
public StreamState State { get; set; }
|
private StreamState State { get; set; }
|
||||||
public ILogger Logger { get; set; }
|
private ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProgressiveStreamWriter" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
/// <param name="state">The state.</param>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
|
public ProgressiveStreamWriter(string path, StreamState state, ILogger logger)
|
||||||
|
{
|
||||||
|
Path = path;
|
||||||
|
State = state;
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes to.
|
/// Writes to.
|
||||||
|
@ -38,6 +51,8 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.ErrorException("Error streaming media", ex);
|
Logger.ErrorException("Error streaming media", ex);
|
||||||
|
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
[Route("/Videos/{Id}/stream.mkv", "GET")]
|
[Route("/Videos/{Id}/stream.mkv", "GET")]
|
||||||
[Route("/Videos/{Id}/stream.mpeg", "GET")]
|
[Route("/Videos/{Id}/stream.mpeg", "GET")]
|
||||||
[Route("/Videos/{Id}/stream.avi", "GET")]
|
[Route("/Videos/{Id}/stream.avi", "GET")]
|
||||||
|
[Route("/Videos/{Id}/stream.m2ts", "GET")]
|
||||||
[Route("/Videos/{Id}/stream", "GET")]
|
[Route("/Videos/{Id}/stream", "GET")]
|
||||||
[ServiceStack.ServiceHost.Api(Description = "Gets a video stream")]
|
[ServiceStack.ServiceHost.Api(Description = "Gets a video stream")]
|
||||||
public class GetVideoStream : VideoStreamRequest
|
public class GetVideoStream : VideoStreamRequest
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Server.Implementations.HttpServer;
|
using MediaBrowser.Server.Implementations.HttpServer;
|
||||||
using ServiceStack.ServiceHost;
|
using ServiceStack.ServiceHost;
|
||||||
using System;
|
using System;
|
||||||
|
@ -23,12 +23,16 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
/// The _user manager
|
/// The _user manager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly IUserManager UserManager;
|
protected readonly IUserManager UserManager;
|
||||||
|
/// <summary>
|
||||||
|
/// The library manager
|
||||||
|
/// </summary>
|
||||||
protected readonly ILibraryManager LibraryManager;
|
protected readonly ILibraryManager LibraryManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
|
/// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userManager">The user manager.</param>
|
/// <param name="userManager">The user manager.</param>
|
||||||
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager)
|
protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
UserManager = userManager;
|
UserManager = userManager;
|
||||||
|
@ -44,7 +48,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
{
|
{
|
||||||
var user = UserManager.GetUserById(request.UserId);
|
var user = UserManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, UserManager, LibraryManager, user.Id);
|
var item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, UserManager, LibraryManager, user.Id);
|
||||||
|
|
||||||
IEnumerable<BaseItem> items;
|
IEnumerable<BaseItem> items;
|
||||||
|
|
||||||
|
@ -157,54 +161,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetItemsByName
|
/// Class GetItemsByName
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GetItemsByName : IReturn<ItemsResult>
|
public class GetItemsByName : BaseItemsRequest, IReturn<ItemsResult>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the user id.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The user id.</value>
|
|
||||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
|
||||||
public Guid UserId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the start index.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The start index.</value>
|
|
||||||
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
|
||||||
public int? StartIndex { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the size of the page.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The size of the page.</value>
|
|
||||||
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
|
||||||
public int? Limit { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether this <see cref="GetItemsByName" /> is recursive.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if recursive; otherwise, <c>false</c>.</value>
|
|
||||||
[ApiMember(Name = "Recursive", Description = "When searching within folders, this determines whether or not the search will be recursive. true/false", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
|
||||||
public bool Recursive { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the sort order.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The sort order.</value>
|
|
||||||
[ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
|
||||||
public SortOrder? SortOrder { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If specified the search will be localized within a specific item or folder
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The item id.</value>
|
|
||||||
[ApiMember(Name = "Id", Description = "If specified the search will be localized within a specific item or folder", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fields to return within the items, in addition to basic information
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The fields.</value>
|
|
||||||
public string Fields { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
58
MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
Normal file
58
MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using ServiceStack.ServiceHost;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.UserLibrary
|
||||||
|
{
|
||||||
|
public abstract class BaseItemsRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the user id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The user id.</value>
|
||||||
|
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Skips over a given number of items within the results. Use for paging.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The start index.</value>
|
||||||
|
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? StartIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of items to return
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The limit.</value>
|
||||||
|
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? Limit { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not to perform the query recursively
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if recursive; otherwise, <c>false</c>.</value>
|
||||||
|
[ApiMember(Name = "Recursive", Description = "When searching within folders, this determines whether or not the search will be recursive. true/false", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||||
|
public bool Recursive { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the sort order.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The sort order.</value>
|
||||||
|
[ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
public SortOrder? SortOrder { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specify this to localize the search to a specific item or folder. Omit to use the root.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The parent id.</value>
|
||||||
|
[ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
public string ParentId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fields to return within the items, in addition to basic information
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The fields.</value>
|
||||||
|
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: AudioInfo, Chapters, DateCreated, DisplayMediaType, DisplayPreferences, Genres, ItemCounts, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, SeriesInfo, SortName, Studios, Taglines, TrailerUrls, UserData", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
|
public string Fields { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,7 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Server.Implementations.HttpServer;
|
using MediaBrowser.Server.Implementations.HttpServer;
|
||||||
using ServiceStack.ServiceHost;
|
using ServiceStack.ServiceHost;
|
||||||
using System;
|
using System;
|
||||||
|
@ -17,43 +16,8 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users/{UserId}/Items", "GET")]
|
[Route("/Users/{UserId}/Items", "GET")]
|
||||||
[ServiceStack.ServiceHost.Api(Description = "Gets items based on a query.")]
|
[ServiceStack.ServiceHost.Api(Description = "Gets items based on a query.")]
|
||||||
public class GetItems : IReturn<ItemsResult>
|
public class GetItems : BaseItemsRequest, IReturn<ItemsResult>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the user id.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The user id.</value>
|
|
||||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
|
||||||
public Guid UserId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specify this to localize the search to a specific item or folder. Omit to use the root.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The parent id.</value>
|
|
||||||
[ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
|
||||||
public string ParentId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Skips over a given number of items within the results. Use for paging.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The start index.</value>
|
|
||||||
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
|
||||||
public int? StartIndex { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The maximum number of items to return
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The limit.</value>
|
|
||||||
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
|
||||||
public int? Limit { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether or not to perform the query recursively
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if recursive; otherwise, <c>false</c>.</value>
|
|
||||||
[ApiMember(Name = "Recursive", Description = "When searching within folders, this determines whether or not the search will be recursive. true/false", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
|
||||||
public bool Recursive { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Limit results to items containing a specific person
|
/// Limit results to items containing a specific person
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -81,40 +45,20 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
/// <value>The index by.</value>
|
/// <value>The index by.</value>
|
||||||
public string IndexBy { get; set; }
|
public string IndexBy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The dynamic, localized sort function name
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The dynamic sort by.</value>
|
|
||||||
public string DynamicSortBy { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// What to sort the results by
|
/// What to sort the results by
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The sort by.</value>
|
/// <value>The sort by.</value>
|
||||||
[ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album,AlbumArtist,Artist,DateCreated,DatePlayed,PremiereDate,SortName,Random", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
[ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, CommunityRating, DateCreated, DatePlayed, PremiereDate, ProductionYear, SortName, Random, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
public string SortBy { get; set; }
|
public string SortBy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The sort order to return results with
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The sort order.</value>
|
|
||||||
[ApiMember(Name = "SortOrder", Description = "Optional. Ascending / Descending sort order", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
|
||||||
public string SortOrder { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters to apply to the results
|
/// Filters to apply to the results
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The filters.</value>
|
/// <value>The filters.</value>
|
||||||
[ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder,IsNotFolder,IsUnplayed,IsPlayed,IsFavorite,IsResumable", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
[ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsRecentlyAdded, IsResumable", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
public string Filters { get; set; }
|
public string Filters { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fields to return within the items, in addition to basic information
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The fields.</value>
|
|
||||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: AudioInfo, Chapters, DateCreated, DisplayMediaType, DisplayPreferences, Genres, ItemCounts, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, SeriesInfo, SortName, Studios, Taglines, TrailerUrls, UserData", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
|
||||||
public string Fields { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Limit results to items containing specific genres
|
/// Limit results to items containing specific genres
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -254,7 +198,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
return ((Folder)item).GetRecursiveChildren(user);
|
return ((Folder)item).GetRecursiveChildren(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((Folder)item).GetChildren(user, request.IndexBy, request.DynamicSortBy, GetSortOrder(request));
|
return ((Folder)item).GetChildren(user, request.IndexBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -266,58 +210,9 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
private IEnumerable<BaseItem> ApplySortOrder(GetItems request, IEnumerable<BaseItem> items, User user)
|
private IEnumerable<BaseItem> ApplySortOrder(GetItems request, IEnumerable<BaseItem> items, User user)
|
||||||
{
|
{
|
||||||
var isFirst = true;
|
var orderBy = GetOrderBy(request).ToArray();
|
||||||
var descending = (GetSortOrder(request) ?? SortOrder.Ascending) == SortOrder.Descending;
|
|
||||||
|
|
||||||
IOrderedEnumerable<BaseItem> orderedItems = null;
|
return orderBy.Length == 0 ? items : _libraryManager.Sort(items, user, orderBy, request.SortOrder ?? SortOrder.Ascending);
|
||||||
|
|
||||||
foreach (var orderBy in GetOrderBy(request).Select(o => GetComparer(o, user)))
|
|
||||||
{
|
|
||||||
if (isFirst)
|
|
||||||
{
|
|
||||||
orderedItems = descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
orderedItems = descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy);
|
|
||||||
}
|
|
||||||
|
|
||||||
isFirst = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return orderedItems ?? items;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the comparer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sortBy">The sort by.</param>
|
|
||||||
/// <param name="user">The user.</param>
|
|
||||||
/// <returns>IComparer{BaseItem}.</returns>
|
|
||||||
/// <exception cref="System.ArgumentException"></exception>
|
|
||||||
private IComparer<BaseItem> GetComparer(ItemSortBy sortBy, User user)
|
|
||||||
{
|
|
||||||
switch (sortBy)
|
|
||||||
{
|
|
||||||
case ItemSortBy.Album:
|
|
||||||
return new AlbumComparer();
|
|
||||||
case ItemSortBy.AlbumArtist:
|
|
||||||
return new AlbumArtistComparer();
|
|
||||||
case ItemSortBy.Artist:
|
|
||||||
return new ArtistComparer();
|
|
||||||
case ItemSortBy.Random:
|
|
||||||
return new RandomComparer();
|
|
||||||
case ItemSortBy.DateCreated:
|
|
||||||
return new DateCreatedComparer();
|
|
||||||
case ItemSortBy.SortName:
|
|
||||||
return new SortNameComparer();
|
|
||||||
case ItemSortBy.PremiereDate:
|
|
||||||
return new PremiereDateComparer();
|
|
||||||
case ItemSortBy.DatePlayed:
|
|
||||||
return new DatePlayedComparer { User = user };
|
|
||||||
default:
|
|
||||||
throw new ArgumentException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -465,7 +360,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
return item.ScreenshotImagePaths != null && item.ScreenshotImagePaths.Count > 0;
|
return item.ScreenshotImagePaths != null && item.ScreenshotImagePaths.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageType == ImageType.ChapterImage)
|
if (imageType == ImageType.Chapter)
|
||||||
{
|
{
|
||||||
var video = item as Video;
|
var video = item as Video;
|
||||||
|
|
||||||
|
@ -521,21 +416,6 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the sort order.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">The request.</param>
|
|
||||||
/// <returns>System.Nullable{SortOrder}.</returns>
|
|
||||||
private SortOrder? GetSortOrder(GetItems request)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(request.SortOrder))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (SortOrder)Enum.Parse(typeof(SortOrder), request.SortOrder, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the filters.
|
/// Gets the filters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -575,16 +455,16 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <returns>IEnumerable{ItemSortBy}.</returns>
|
/// <returns>IEnumerable{ItemSortBy}.</returns>
|
||||||
private IEnumerable<ItemSortBy> GetOrderBy(GetItems request)
|
private IEnumerable<string> GetOrderBy(GetItems request)
|
||||||
{
|
{
|
||||||
var val = request.SortBy;
|
var val = request.SortBy;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(val))
|
if (string.IsNullOrEmpty(val))
|
||||||
{
|
{
|
||||||
return new ItemSortBy[] { };
|
return new string[] { };
|
||||||
}
|
}
|
||||||
|
|
||||||
return val.Split(',').Select(v => (ItemSortBy)Enum.Parse(typeof(ItemSortBy), v, true));
|
return val.Split(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -621,201 +501,4 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
return x.DateCreated.CompareTo(y.DateCreated);
|
return x.DateCreated.CompareTo(y.DateCreated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class RandomComparer
|
|
||||||
/// </summary>
|
|
||||||
public class RandomComparer : IComparer<BaseItem>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compares the specified x.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <param name="y">The y.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
public int Compare(BaseItem x, BaseItem y)
|
|
||||||
{
|
|
||||||
return Guid.NewGuid().CompareTo(Guid.NewGuid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class SortNameComparer
|
|
||||||
/// </summary>
|
|
||||||
public class SortNameComparer : IComparer<BaseItem>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compares the specified x.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <param name="y">The y.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
public int Compare(BaseItem x, BaseItem y)
|
|
||||||
{
|
|
||||||
return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class AlbumArtistComparer
|
|
||||||
/// </summary>
|
|
||||||
public class AlbumArtistComparer : IComparer<BaseItem>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compares the specified x.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <param name="y">The y.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
public int Compare(BaseItem x, BaseItem y)
|
|
||||||
{
|
|
||||||
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
private string GetValue(BaseItem x)
|
|
||||||
{
|
|
||||||
var audio = x as Audio;
|
|
||||||
|
|
||||||
return audio == null ? string.Empty : audio.AlbumArtist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class AlbumComparer
|
|
||||||
/// </summary>
|
|
||||||
public class AlbumComparer : IComparer<BaseItem>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compares the specified x.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <param name="y">The y.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
public int Compare(BaseItem x, BaseItem y)
|
|
||||||
{
|
|
||||||
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
private string GetValue(BaseItem x)
|
|
||||||
{
|
|
||||||
var audio = x as Audio;
|
|
||||||
|
|
||||||
return audio == null ? string.Empty : audio.Album;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class ArtistComparer
|
|
||||||
/// </summary>
|
|
||||||
public class ArtistComparer : IComparer<BaseItem>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compares the specified x.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <param name="y">The y.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
public int Compare(BaseItem x, BaseItem y)
|
|
||||||
{
|
|
||||||
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
private string GetValue(BaseItem x)
|
|
||||||
{
|
|
||||||
var audio = x as Audio;
|
|
||||||
|
|
||||||
return audio == null ? string.Empty : audio.Artist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class PremiereDateComparer
|
|
||||||
/// </summary>
|
|
||||||
public class PremiereDateComparer : IComparer<BaseItem>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Compares the specified x.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <param name="y">The y.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
public int Compare(BaseItem x, BaseItem y)
|
|
||||||
{
|
|
||||||
return GetDate(x).CompareTo(GetDate(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the date.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <returns>DateTime.</returns>
|
|
||||||
private DateTime GetDate(BaseItem x)
|
|
||||||
{
|
|
||||||
if (x.PremiereDate.HasValue)
|
|
||||||
{
|
|
||||||
return x.PremiereDate.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.ProductionYear.HasValue)
|
|
||||||
{
|
|
||||||
return new DateTime(x.ProductionYear.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
||||||
}
|
|
||||||
return DateTime.MaxValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class DatePlayedComparer
|
|
||||||
/// </summary>
|
|
||||||
public class DatePlayedComparer : IComparer<BaseItem>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the user.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The user.</value>
|
|
||||||
public User User { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compares the specified x.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <param name="y">The y.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
public int Compare(BaseItem x, BaseItem y)
|
|
||||||
{
|
|
||||||
return GetDate(x).CompareTo(GetDate(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the date.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <returns>DateTime.</returns>
|
|
||||||
private DateTime GetDate(BaseItem x)
|
|
||||||
{
|
|
||||||
var userdata = x.GetUserData(User, false);
|
|
||||||
|
|
||||||
if (userdata != null && userdata.LastPlayedDate.HasValue)
|
|
||||||
{
|
|
||||||
return userdata.LastPlayedDate.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DateTime.MinValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Connectivity;
|
using MediaBrowser.Model.Connectivity;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Server.Implementations.HttpServer;
|
using MediaBrowser.Server.Implementations.HttpServer;
|
||||||
using ServiceStack.ServiceHost;
|
using ServiceStack.ServiceHost;
|
||||||
using ServiceStack.Text.Controller;
|
using ServiceStack.Text.Controller;
|
||||||
|
|
|
@ -13,7 +13,6 @@ using MediaBrowser.Common.Security;
|
||||||
using MediaBrowser.Common.Updates;
|
using MediaBrowser.Common.Updates;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using MediaBrowser.Model.System;
|
|
||||||
using MediaBrowser.Model.Updates;
|
using MediaBrowser.Model.Updates;
|
||||||
using SimpleInjector;
|
using SimpleInjector;
|
||||||
using System;
|
using System;
|
||||||
|
@ -26,6 +25,10 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Implementations
|
namespace MediaBrowser.Common.Implementations
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class BaseApplicationHost
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TApplicationPathsType">The type of the T application paths type.</typeparam>
|
||||||
public abstract class BaseApplicationHost<TApplicationPathsType> : IApplicationHost
|
public abstract class BaseApplicationHost<TApplicationPathsType> : IApplicationHost
|
||||||
where TApplicationPathsType : class, IApplicationPaths, new()
|
where TApplicationPathsType : class, IApplicationPaths, new()
|
||||||
{
|
{
|
||||||
|
@ -87,6 +90,7 @@ namespace MediaBrowser.Common.Implementations
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets assemblies that failed to load
|
/// Gets assemblies that failed to load
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <value>The failed assemblies.</value>
|
||||||
public List<string> FailedAssemblies { get; protected set; }
|
public List<string> FailedAssemblies { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -148,11 +152,31 @@ namespace MediaBrowser.Common.Implementations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The kernel.</value>
|
/// <value>The kernel.</value>
|
||||||
protected ITaskManager TaskManager { get; private set; }
|
protected ITaskManager TaskManager { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the security manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The security manager.</value>
|
||||||
protected ISecurityManager SecurityManager { get; private set; }
|
protected ISecurityManager SecurityManager { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the package manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The package manager.</value>
|
||||||
protected IPackageManager PackageManager { get; private set; }
|
protected IPackageManager PackageManager { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the HTTP client.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The HTTP client.</value>
|
||||||
protected IHttpClient HttpClient { get; private set; }
|
protected IHttpClient HttpClient { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the network manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The network manager.</value>
|
||||||
protected INetworkManager NetworkManager { get; private set; }
|
protected INetworkManager NetworkManager { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configuration manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration manager.</value>
|
||||||
protected IConfigurationManager ConfigurationManager { get; private set; }
|
protected IConfigurationManager ConfigurationManager { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -187,7 +211,21 @@ namespace MediaBrowser.Common.Implementations
|
||||||
|
|
||||||
FindParts();
|
FindParts();
|
||||||
|
|
||||||
Task.Run(() => ConfigureAutoRunAtStartup());
|
await RunStartupTasks().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the startup tasks.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
protected virtual Task RunStartupTasks()
|
||||||
|
{
|
||||||
|
return Task.Run(() =>
|
||||||
|
{
|
||||||
|
Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
|
||||||
|
|
||||||
|
Task.Run(() => ConfigureAutoRunAtStartup());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -202,6 +240,10 @@ namespace MediaBrowser.Common.Implementations
|
||||||
/// <value>The name of the log file prefix.</value>
|
/// <value>The name of the log file prefix.</value>
|
||||||
protected abstract string LogFilePrefixName { get; }
|
protected abstract string LogFilePrefixName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configuration manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>IConfigurationManager.</returns>
|
||||||
protected abstract IConfigurationManager GetConfigurationManager();
|
protected abstract IConfigurationManager GetConfigurationManager();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -210,8 +252,6 @@ namespace MediaBrowser.Common.Implementations
|
||||||
protected virtual void FindParts()
|
protected virtual void FindParts()
|
||||||
{
|
{
|
||||||
Plugins = GetExports<IPlugin>();
|
Plugins = GetExports<IPlugin>();
|
||||||
|
|
||||||
Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -236,6 +276,7 @@ namespace MediaBrowser.Common.Implementations
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers resources that classes will depend on
|
/// Registers resources that classes will depend on
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
protected virtual Task RegisterResources()
|
protected virtual Task RegisterResources()
|
||||||
{
|
{
|
||||||
return Task.Run(() =>
|
return Task.Run(() =>
|
||||||
|
@ -509,10 +550,23 @@ namespace MediaBrowser.Common.Implementations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restarts this instance.
|
||||||
|
/// </summary>
|
||||||
public abstract void Restart();
|
public abstract void Restart();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this instance can self update.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
|
||||||
public abstract bool CanSelfUpdate { get; }
|
public abstract bool CanSelfUpdate { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for update.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <param name="progress">The progress.</param>
|
||||||
|
/// <returns>Task{CheckForUpdateResult}.</returns>
|
||||||
public abstract Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress);
|
public abstract Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -529,6 +583,9 @@ namespace MediaBrowser.Common.Implementations
|
||||||
EventHelper.QueueEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs<Version> { Argument = package.version }, Logger);
|
EventHelper.QueueEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs<Version> { Argument = package.version }, Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shuts down.
|
||||||
|
/// </summary>
|
||||||
public abstract void Shutdown();
|
public abstract void Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,7 +356,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||||
return item.ScreenshotImagePaths[imageIndex];
|
return item.ScreenshotImagePaths[imageIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageType == ImageType.ChapterImage)
|
if (imageType == ImageType.Chapter)
|
||||||
{
|
{
|
||||||
var video = (Video)item;
|
var video = (Video)item;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SortOrder = MediaBrowser.Controller.Sorting.SortOrder;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
|
@ -177,63 +176,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Sorting
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _sort by options
|
|
||||||
/// </summary>
|
|
||||||
private Dictionary<string, IComparer<BaseItem>> _sortByOptions;
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary of sort options - consists of a display value (localized) and an IComparer of BaseItem
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The sort by options.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public Dictionary<string, IComparer<BaseItem>> SortByOptions
|
|
||||||
{
|
|
||||||
get { return _sortByOptions ?? (_sortByOptions = GetSortByOptions()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the valid set of sort by options for this folder type.
|
|
||||||
/// Override or extend to modify.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Dictionary{System.StringIComparer{BaseItem}}.</returns>
|
|
||||||
protected virtual Dictionary<string, IComparer<BaseItem>> GetSortByOptions()
|
|
||||||
{
|
|
||||||
return new Dictionary<string, IComparer<BaseItem>> {
|
|
||||||
{LocalizedStrings.Instance.GetString("NameDispPref"), new BaseItemComparer(SortOrder.Name, Logger)},
|
|
||||||
{LocalizedStrings.Instance.GetString("DateDispPref"), new BaseItemComparer(SortOrder.Date, Logger)},
|
|
||||||
{LocalizedStrings.Instance.GetString("RatingDispPref"), new BaseItemComparer(SortOrder.Rating, Logger)},
|
|
||||||
{LocalizedStrings.Instance.GetString("RuntimeDispPref"), new BaseItemComparer(SortOrder.Runtime, Logger)},
|
|
||||||
{LocalizedStrings.Instance.GetString("YearDispPref"), new BaseItemComparer(SortOrder.Year, Logger)}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a sorting comparer by name
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name.</param>
|
|
||||||
/// <returns>IComparer{BaseItem}.</returns>
|
|
||||||
private IComparer<BaseItem> GetSortingFunction(string name)
|
|
||||||
{
|
|
||||||
IComparer<BaseItem> sorting;
|
|
||||||
SortByOptions.TryGetValue(name ?? "", out sorting);
|
|
||||||
return sorting ?? new BaseItemComparer(SortOrder.Name, Logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the list of sort by choices for this folder (localized).
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The sort by option strings.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public IEnumerable<string> SortByOptionStrings
|
|
||||||
{
|
|
||||||
get { return SortByOptions.Keys; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Indexing
|
#region Indexing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -877,11 +819,9 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
/// <param name="indexBy">The index by.</param>
|
/// <param name="indexBy">The index by.</param>
|
||||||
/// <param name="sortBy">The sort by.</param>
|
|
||||||
/// <param name="sortOrder">The sort order.</param>
|
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException"></exception>
|
/// <exception cref="System.ArgumentNullException"></exception>
|
||||||
public virtual IEnumerable<BaseItem> GetChildren(User user, string indexBy = null, string sortBy = null, Model.Entities.SortOrder? sortOrder = null)
|
public virtual IEnumerable<BaseItem> GetChildren(User user, string indexBy = null)
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
|
@ -889,7 +829,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
|
|
||||||
//the true root should return our users root folder children
|
//the true root should return our users root folder children
|
||||||
if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, indexBy, sortBy, sortOrder);
|
if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, indexBy);
|
||||||
|
|
||||||
IEnumerable<BaseItem> result = null;
|
IEnumerable<BaseItem> result = null;
|
||||||
|
|
||||||
|
@ -904,14 +844,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
result = ActualChildren.Where(c => c.IsVisible(user));
|
result = ActualChildren.Where(c => c.IsVisible(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(sortBy))
|
return result;
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sortOrder.HasValue && sortOrder.Value == Model.Entities.SortOrder.Descending
|
|
||||||
? result.OrderByDescending(i => i, GetSortingFunction(sortBy))
|
|
||||||
: result.OrderBy(i => i, GetSortingFunction(sortBy));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -11,6 +11,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Library
|
namespace MediaBrowser.Controller.Library
|
||||||
{
|
{
|
||||||
|
@ -160,8 +161,6 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <param name="fields">The fields.</param>
|
/// <param name="fields">The fields.</param>
|
||||||
private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields)
|
private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields)
|
||||||
{
|
{
|
||||||
dto.IsNew = item.IsRecentlyAdded(user);
|
|
||||||
|
|
||||||
if (fields.Contains(ItemFields.UserData))
|
if (fields.Contains(ItemFields.UserData))
|
||||||
{
|
{
|
||||||
var userData = item.GetUserData(user, false);
|
var userData = item.GetUserData(user, false);
|
||||||
|
@ -366,18 +365,10 @@ namespace MediaBrowser.Controller.Library
|
||||||
{
|
{
|
||||||
var folder = (Folder)item;
|
var folder = (Folder)item;
|
||||||
|
|
||||||
dto.IsRoot = folder.IsRoot;
|
|
||||||
dto.IsVirtualFolder = folder.IsVirtualFolder;
|
|
||||||
|
|
||||||
if (fields.Contains(ItemFields.IndexOptions))
|
if (fields.Contains(ItemFields.IndexOptions))
|
||||||
{
|
{
|
||||||
dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
|
dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fields.Contains(ItemFields.SortOptions))
|
|
||||||
{
|
|
||||||
dto.SortOptions = folder.SortByOptionStrings.ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add audio info
|
// Add audio info
|
||||||
|
@ -678,7 +669,7 @@ namespace MediaBrowser.Controller.Library
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(chapterInfo.ImagePath))
|
if (!string.IsNullOrEmpty(chapterInfo.ImagePath))
|
||||||
{
|
{
|
||||||
dto.ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.ChapterImage, chapterInfo.ImagePath);
|
dto.ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Chapter, chapterInfo.ImagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dto;
|
return dto;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.IO;
|
using MediaBrowser.Controller.IO;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -158,7 +159,19 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <param name="pluginFolders">The plugin folders.</param>
|
/// <param name="pluginFolders">The plugin folders.</param>
|
||||||
/// <param name="resolvers">The resolvers.</param>
|
/// <param name="resolvers">The resolvers.</param>
|
||||||
/// <param name="introProviders">The intro providers.</param>
|
/// <param name="introProviders">The intro providers.</param>
|
||||||
|
/// <param name="itemComparers">The item comparers.</param>
|
||||||
void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders,
|
void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders,
|
||||||
IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders);
|
IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders, IEnumerable<IBaseItemComparer> itemComparers);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sorts the specified items.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <param name="sortBy">The sort by.</param>
|
||||||
|
/// <param name="sortOrder">The sort order.</param>
|
||||||
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
|
IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy,
|
||||||
|
SortOrder sortOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -185,8 +185,8 @@
|
||||||
<Compile Include="Providers\FolderProviderFromXml.cs" />
|
<Compile Include="Providers\FolderProviderFromXml.cs" />
|
||||||
<Compile Include="Providers\ImageFromMediaLocationProvider.cs" />
|
<Compile Include="Providers\ImageFromMediaLocationProvider.cs" />
|
||||||
<Compile Include="Providers\MediaInfo\FFProbeVideoInfoProvider.cs" />
|
<Compile Include="Providers\MediaInfo\FFProbeVideoInfoProvider.cs" />
|
||||||
<Compile Include="Sorting\BaseItemComparer.cs" />
|
<Compile Include="Sorting\IBaseItemComparer.cs" />
|
||||||
<Compile Include="Sorting\SortOrder.cs" />
|
<Compile Include="Sorting\IUserBaseItemComparer.cs" />
|
||||||
<Compile Include="Updates\IInstallationManager.cs" />
|
<Compile Include="Updates\IInstallationManager.cs" />
|
||||||
<Compile Include="Weather\IWeatherProvider.cs" />
|
<Compile Include="Weather\IWeatherProvider.cs" />
|
||||||
<Compile Include="Providers\BaseItemXmlParser.cs" />
|
<Compile Include="Providers\BaseItemXmlParser.cs" />
|
||||||
|
@ -202,7 +202,7 @@
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="MediaInfo\ffmpeg20130209.zip" />
|
<EmbeddedResource Include="MediaInfo\ffmpeg20130310.zip" />
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
985770c0d2633a13719be2e5cf19554262415f62
|
|
|
@ -0,0 +1 @@
|
||||||
|
a005e50576665b191cbd02b42d6260bffb764690
|
|
@ -1,248 +0,0 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Sorting {
|
|
||||||
/// <summary>
|
|
||||||
/// Class BaseItemComparer
|
|
||||||
/// </summary>
|
|
||||||
public class BaseItemComparer : IComparer<BaseItem> {
|
|
||||||
/// <summary>
|
|
||||||
/// The _order
|
|
||||||
/// </summary>
|
|
||||||
private readonly SortOrder _order;
|
|
||||||
/// <summary>
|
|
||||||
/// The _property name
|
|
||||||
/// </summary>
|
|
||||||
private readonly string _propertyName;
|
|
||||||
/// <summary>
|
|
||||||
/// The _compare culture
|
|
||||||
/// </summary>
|
|
||||||
private readonly StringComparison _compareCulture = StringComparison.CurrentCultureIgnoreCase;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the logger.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The logger.</value>
|
|
||||||
private ILogger Logger { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseItemComparer" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="order">The order.</param>
|
|
||||||
/// <param name="logger">The logger.</param>
|
|
||||||
public BaseItemComparer(SortOrder order, ILogger logger) {
|
|
||||||
_order = order;
|
|
||||||
Logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseItemComparer" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="order">The order.</param>
|
|
||||||
/// <param name="compare">The compare.</param>
|
|
||||||
/// <param name="logger">The logger.</param>
|
|
||||||
public BaseItemComparer(SortOrder order, StringComparison compare, ILogger logger)
|
|
||||||
{
|
|
||||||
_order = order;
|
|
||||||
_compareCulture = compare;
|
|
||||||
Logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseItemComparer" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="property">The property.</param>
|
|
||||||
/// <param name="logger">The logger.</param>
|
|
||||||
public BaseItemComparer(string property, ILogger logger)
|
|
||||||
{
|
|
||||||
_order = SortOrder.Custom;
|
|
||||||
_propertyName = property;
|
|
||||||
Logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseItemComparer" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="property">The property.</param>
|
|
||||||
/// <param name="compare">The compare.</param>
|
|
||||||
/// <param name="logger">The logger.</param>
|
|
||||||
public BaseItemComparer(string property, StringComparison compare, ILogger logger)
|
|
||||||
{
|
|
||||||
_order = SortOrder.Custom;
|
|
||||||
_propertyName = property;
|
|
||||||
_compareCulture = compare;
|
|
||||||
Logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region IComparer<BaseItem> Members
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compares the specified x.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The x.</param>
|
|
||||||
/// <param name="y">The y.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
public int Compare(BaseItem x, BaseItem y) {
|
|
||||||
int compare = 0;
|
|
||||||
|
|
||||||
switch (_order) {
|
|
||||||
|
|
||||||
case SortOrder.Date:
|
|
||||||
compare = -x.DateCreated.CompareTo(y.DateCreated);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SortOrder.Year:
|
|
||||||
|
|
||||||
var xProductionYear = x.ProductionYear ?? 0;
|
|
||||||
var yProductionYear = y.ProductionYear ?? 0;
|
|
||||||
|
|
||||||
|
|
||||||
compare = yProductionYear.CompareTo(xProductionYear);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SortOrder.Rating:
|
|
||||||
|
|
||||||
var xRating = x.CommunityRating ?? 0;
|
|
||||||
var yRating = y.CommunityRating ?? 0;
|
|
||||||
|
|
||||||
compare = yRating.CompareTo(xRating);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SortOrder.Runtime:
|
|
||||||
var xRuntime = x.RunTimeTicks ?? 0;
|
|
||||||
var yRuntime = y.RunTimeTicks ?? 0;
|
|
||||||
|
|
||||||
compare = xRuntime.CompareTo(yRuntime);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SortOrder.Custom:
|
|
||||||
|
|
||||||
Logger.Debug("Sorting on custom field " + _propertyName);
|
|
||||||
var yProp = y.GetType().GetProperty(_propertyName);
|
|
||||||
var xProp = x.GetType().GetProperty(_propertyName);
|
|
||||||
if (yProp == null || xProp == null) break;
|
|
||||||
var yVal = yProp.GetValue(y, null);
|
|
||||||
var xVal = xProp.GetValue(x,null);
|
|
||||||
if (yVal == null && xVal == null) break;
|
|
||||||
if (yVal == null) return 1;
|
|
||||||
if (xVal == null) return -1;
|
|
||||||
compare = String.Compare(xVal.ToString(), yVal.ToString(),_compareCulture);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
compare = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compare == 0) {
|
|
||||||
|
|
||||||
var name1 = x.SortName ?? x.Name ?? "";
|
|
||||||
var name2 = y.SortName ?? y.Name ?? "";
|
|
||||||
|
|
||||||
//if (Config.Instance.EnableAlphanumericSorting)
|
|
||||||
compare = AlphaNumericCompare(name1, name2,_compareCulture);
|
|
||||||
//else
|
|
||||||
// compare = String.Compare(name1,name2,_compareCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
return compare;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Alphas the numeric compare.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s1">The s1.</param>
|
|
||||||
/// <param name="s2">The s2.</param>
|
|
||||||
/// <param name="compareCulture">The compare culture.</param>
|
|
||||||
/// <returns>System.Int32.</returns>
|
|
||||||
private int AlphaNumericCompare(string s1, string s2, StringComparison compareCulture) {
|
|
||||||
// http://dotnetperls.com/Content/Alphanumeric-Sorting.aspx
|
|
||||||
|
|
||||||
int len1 = s1.Length;
|
|
||||||
int len2 = s2.Length;
|
|
||||||
int marker1 = 0;
|
|
||||||
int marker2 = 0;
|
|
||||||
|
|
||||||
// Walk through two the strings with two markers.
|
|
||||||
while (marker1 < len1 && marker2 < len2) {
|
|
||||||
char ch1 = s1[marker1];
|
|
||||||
char ch2 = s2[marker2];
|
|
||||||
|
|
||||||
// Some buffers we can build up characters in for each chunk.
|
|
||||||
var space1 = new char[len1];
|
|
||||||
var loc1 = 0;
|
|
||||||
var space2 = new char[len2];
|
|
||||||
var loc2 = 0;
|
|
||||||
|
|
||||||
// Walk through all following characters that are digits or
|
|
||||||
// characters in BOTH strings starting at the appropriate marker.
|
|
||||||
// Collect char arrays.
|
|
||||||
do {
|
|
||||||
space1[loc1++] = ch1;
|
|
||||||
marker1++;
|
|
||||||
|
|
||||||
if (marker1 < len1) {
|
|
||||||
ch1 = s1[marker1];
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
|
|
||||||
|
|
||||||
do {
|
|
||||||
space2[loc2++] = ch2;
|
|
||||||
marker2++;
|
|
||||||
|
|
||||||
if (marker2 < len2) {
|
|
||||||
ch2 = s2[marker2];
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
|
|
||||||
|
|
||||||
// If we have collected numbers, compare them numerically.
|
|
||||||
// Otherwise, if we have strings, compare them alphabetically.
|
|
||||||
var str1 = new string(space1);
|
|
||||||
var str2 = new string(space2);
|
|
||||||
|
|
||||||
var result = 0;
|
|
||||||
|
|
||||||
//biggest int - 2147483647
|
|
||||||
if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]) /*&& str1.Length < 10 && str2.Length < 10*/) //this assumed the entire string was a number...
|
|
||||||
{
|
|
||||||
int thisNumericChunk;
|
|
||||||
var isValid = false;
|
|
||||||
|
|
||||||
if (int.TryParse(str1.Substring(0, str1.Length > 9 ? 10 : str1.Length), out thisNumericChunk))
|
|
||||||
{
|
|
||||||
int thatNumericChunk;
|
|
||||||
|
|
||||||
if (int.TryParse(str2.Substring(0, str2.Length > 9 ? 10 : str2.Length), out thatNumericChunk))
|
|
||||||
{
|
|
||||||
isValid = true;
|
|
||||||
result = thisNumericChunk.CompareTo(thatNumericChunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isValid)
|
|
||||||
{
|
|
||||||
Logger.Error("Error comparing numeric strings: " + str1 + "/" + str2);
|
|
||||||
result = String.Compare(str1, str2, compareCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
result = String.Compare(str1,str2,compareCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len1 - len2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
17
MediaBrowser.Controller/Sorting/IBaseItemComparer.cs
Normal file
17
MediaBrowser.Controller/Sorting/IBaseItemComparer.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IBaseItemComparer
|
||||||
|
/// </summary>
|
||||||
|
public interface IBaseItemComparer : IComparer<BaseItem>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
string Name { get; }
|
||||||
|
}
|
||||||
|
}
|
16
MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs
Normal file
16
MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a BaseItem comparer that requires a User to perform it's comparison
|
||||||
|
/// </summary>
|
||||||
|
public interface IUserBaseItemComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the user.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The user.</value>
|
||||||
|
User User { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Sorting {
|
|
||||||
/// <summary>
|
|
||||||
/// Enum SortOrder
|
|
||||||
/// </summary>
|
|
||||||
public enum SortOrder {
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sort by name
|
|
||||||
/// </summary>
|
|
||||||
Name,
|
|
||||||
/// <summary>
|
|
||||||
/// Sort by date added to the library
|
|
||||||
/// </summary>
|
|
||||||
Date,
|
|
||||||
/// <summary>
|
|
||||||
/// Sort by community rating
|
|
||||||
/// </summary>
|
|
||||||
Rating,
|
|
||||||
/// <summary>
|
|
||||||
/// Sort by runtime
|
|
||||||
/// </summary>
|
|
||||||
Runtime,
|
|
||||||
/// <summary>
|
|
||||||
/// Sort by year
|
|
||||||
/// </summary>
|
|
||||||
Year,
|
|
||||||
/// <summary>
|
|
||||||
/// Custom sort order added by plugins
|
|
||||||
/// </summary>
|
|
||||||
Custom
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,4 @@
|
||||||
using System;
|
using System.Windows;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Data;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Installer
|
namespace MediaBrowser.Installer
|
||||||
{
|
{
|
||||||
|
|
|
@ -87,15 +87,11 @@
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Configuration" />
|
<Reference Include="System.Configuration" />
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Web" />
|
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="System.Xaml">
|
<Reference Include="System.Xaml">
|
||||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
|
@ -154,20 +154,6 @@ namespace MediaBrowser.Model.Dto
|
||||||
[ProtoMember(25)]
|
[ProtoMember(25)]
|
||||||
public bool IsFolder { get; set; }
|
public bool IsFolder { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If the item is a Folder this will determine if it's the Root or not
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>null</c> if [is root] contains no value, <c>true</c> if [is root]; otherwise, <c>false</c>.</value>
|
|
||||||
[ProtoMember(26)]
|
|
||||||
public bool? IsRoot { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If the item is a Folder this will determine if it's a VF or not
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>null</c> if [is virtual folder] contains no value, <c>true</c> if [is virtual folder]; otherwise, <c>false</c>.</value>
|
|
||||||
[ProtoMember(27)]
|
|
||||||
public bool? IsVirtualFolder { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the parent id.
|
/// Gets or sets the parent id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -231,13 +217,6 @@ namespace MediaBrowser.Model.Dto
|
||||||
[ProtoMember(36)]
|
[ProtoMember(36)]
|
||||||
public UserItemDataDto UserData { get; set; }
|
public UserItemDataDto UserData { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether this instance is new.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if this instance is new; otherwise, <c>false</c>.</value>
|
|
||||||
[ProtoMember(37)]
|
|
||||||
public bool IsNew { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the recently added item count.
|
/// Gets or sets the recently added item count.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -315,13 +294,6 @@ namespace MediaBrowser.Model.Dto
|
||||||
[ProtoMember(52)]
|
[ProtoMember(52)]
|
||||||
public List<DayOfWeek> AirDays { get; set; }
|
public List<DayOfWeek> AirDays { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the sort options.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The sort options.</value>
|
|
||||||
[ProtoMember(53)]
|
|
||||||
public string[] SortOptions { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the index options.
|
/// Gets or sets the index options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -398,26 +370,6 @@ namespace MediaBrowser.Model.Dto
|
||||||
return Type.Equals(type, StringComparison.OrdinalIgnoreCase);
|
return Type.Equals(type, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this instance can resume.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if this instance can resume; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public bool CanResume
|
|
||||||
{
|
|
||||||
get { return UserData != null && UserData.PlaybackPositionTicks > 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the resume position ticks.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The resume position ticks.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public long ResumePositionTicks
|
|
||||||
{
|
|
||||||
get { return UserData == null ? 0 : UserData.PlaybackPositionTicks; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the image tags.
|
/// Gets or sets the image tags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -474,6 +426,26 @@ namespace MediaBrowser.Model.Dto
|
||||||
[ProtoMember(69)]
|
[ProtoMember(69)]
|
||||||
public string MediaType { get; set; }
|
public string MediaType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance can resume.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance can resume; otherwise, <c>false</c>.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public bool CanResume
|
||||||
|
{
|
||||||
|
get { return UserData != null && UserData.PlaybackPositionTicks > 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the resume position ticks.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The resume position ticks.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public long ResumePositionTicks
|
||||||
|
{
|
||||||
|
get { return UserData == null ? 0 : UserData.PlaybackPositionTicks; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the backdrop count.
|
/// Gets the backdrop count.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -604,12 +576,26 @@ namespace MediaBrowser.Model.Dto
|
||||||
get { return string.Equals(MediaType, Entities.MediaType.Game, StringComparison.OrdinalIgnoreCase); }
|
get { return string.Equals(MediaType, Entities.MediaType.Game, StringComparison.OrdinalIgnoreCase); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance is person.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance is person; otherwise, <c>false</c>.</value>
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public bool IsPerson
|
public bool IsPerson
|
||||||
{
|
{
|
||||||
get { return string.Equals(Type, "Person", StringComparison.OrdinalIgnoreCase); }
|
get { return string.Equals(Type, "Person", StringComparison.OrdinalIgnoreCase); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance is root.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public bool IsRoot
|
||||||
|
{
|
||||||
|
get { return string.Equals(Type, "AggregateFolder", StringComparison.OrdinalIgnoreCase); }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when [property changed].
|
/// Occurs when [property changed].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Enum ItemSortBy
|
|
||||||
/// </summary>
|
|
||||||
public enum ItemSortBy
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The album
|
|
||||||
/// </summary>
|
|
||||||
Album,
|
|
||||||
/// <summary>
|
|
||||||
/// The album artist
|
|
||||||
/// </summary>
|
|
||||||
AlbumArtist,
|
|
||||||
/// <summary>
|
|
||||||
/// The artist
|
|
||||||
/// </summary>
|
|
||||||
Artist,
|
|
||||||
/// <summary>
|
|
||||||
/// The date created
|
|
||||||
/// </summary>
|
|
||||||
DateCreated,
|
|
||||||
/// <summary>
|
|
||||||
/// The date played
|
|
||||||
/// </summary>
|
|
||||||
DatePlayed,
|
|
||||||
/// <summary>
|
|
||||||
/// The premiere date
|
|
||||||
/// </summary>
|
|
||||||
PremiereDate,
|
|
||||||
/// <summary>
|
|
||||||
/// The sort name
|
|
||||||
/// </summary>
|
|
||||||
SortName,
|
|
||||||
/// <summary>
|
|
||||||
/// The random
|
|
||||||
/// </summary>
|
|
||||||
Random
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Enum MediaType
|
|
||||||
/// </summary>
|
|
||||||
public enum MediaType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The audio
|
|
||||||
/// </summary>
|
|
||||||
Audio,
|
|
||||||
/// <summary>
|
|
||||||
/// The game
|
|
||||||
/// </summary>
|
|
||||||
Game,
|
|
||||||
/// <summary>
|
|
||||||
/// The video
|
|
||||||
/// </summary>
|
|
||||||
Video
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -49,6 +49,6 @@ namespace MediaBrowser.Model.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The chapter image
|
/// The chapter image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ChapterImage
|
Chapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,7 @@
|
||||||
<Compile Include="Dto\BaseItemPerson.cs" />
|
<Compile Include="Dto\BaseItemPerson.cs" />
|
||||||
<Compile Include="Dto\ChapterInfoDto.cs" />
|
<Compile Include="Dto\ChapterInfoDto.cs" />
|
||||||
<Compile Include="Dto\IItemDto.cs" />
|
<Compile Include="Dto\IItemDto.cs" />
|
||||||
<Compile Include="Dto\ItemsByNameQuery.cs" />
|
<Compile Include="Querying\ItemsByNameQuery.cs" />
|
||||||
<Compile Include="Dto\MediaType.cs" />
|
|
||||||
<Compile Include="Entities\BaseItemInfo.cs" />
|
<Compile Include="Entities\BaseItemInfo.cs" />
|
||||||
<Compile Include="Connectivity\ClientConnectionInfo.cs" />
|
<Compile Include="Connectivity\ClientConnectionInfo.cs" />
|
||||||
<Compile Include="Connectivity\ClientType.cs" />
|
<Compile Include="Connectivity\ClientType.cs" />
|
||||||
|
@ -63,8 +62,8 @@
|
||||||
<Compile Include="Globalization\CultureDto.cs" />
|
<Compile Include="Globalization\CultureDto.cs" />
|
||||||
<Compile Include="IO\FileSystemEntryInfo.cs" />
|
<Compile Include="IO\FileSystemEntryInfo.cs" />
|
||||||
<Compile Include="Dto\ImageOptions.cs" />
|
<Compile Include="Dto\ImageOptions.cs" />
|
||||||
<Compile Include="Dto\ItemFilter.cs" />
|
<Compile Include="Querying\ItemFilter.cs" />
|
||||||
<Compile Include="Dto\ItemQuery.cs" />
|
<Compile Include="Querying\ItemQuery.cs" />
|
||||||
<Compile Include="Entities\LibraryUpdateInfo.cs" />
|
<Compile Include="Entities\LibraryUpdateInfo.cs" />
|
||||||
<Compile Include="Entities\ParentalRating.cs" />
|
<Compile Include="Entities\ParentalRating.cs" />
|
||||||
<Compile Include="Dto\StreamOptions.cs" />
|
<Compile Include="Dto\StreamOptions.cs" />
|
||||||
|
@ -90,11 +89,11 @@
|
||||||
<Compile Include="Configuration\UserConfiguration.cs" />
|
<Compile Include="Configuration\UserConfiguration.cs" />
|
||||||
<Compile Include="Drawing\DrawingUtils.cs" />
|
<Compile Include="Drawing\DrawingUtils.cs" />
|
||||||
<Compile Include="Dto\UserItemDataDto.cs" />
|
<Compile Include="Dto\UserItemDataDto.cs" />
|
||||||
<Compile Include="Dto\ItemFields.cs" />
|
<Compile Include="Querying\ItemFields.cs" />
|
||||||
<Compile Include="Dto\ItemSortBy.cs" />
|
<Compile Include="Querying\ItemSortBy.cs" />
|
||||||
<Compile Include="Dto\BaseItemDto.cs" />
|
<Compile Include="Dto\BaseItemDto.cs" />
|
||||||
<Compile Include="Dto\UserDto.cs" />
|
<Compile Include="Dto\UserDto.cs" />
|
||||||
<Compile Include="Dto\ItemsResult.cs" />
|
<Compile Include="Querying\ItemsResult.cs" />
|
||||||
<Compile Include="Entities\DisplayPreferences.cs" />
|
<Compile Include="Entities\DisplayPreferences.cs" />
|
||||||
<Compile Include="Entities\ImageType.cs" />
|
<Compile Include="Entities\ImageType.cs" />
|
||||||
<Compile Include="Entities\IHasProviderIds.cs" />
|
<Compile Include="Entities\IHasProviderIds.cs" />
|
||||||
|
|
54
MediaBrowser.Model/PropertyChanged.xml
Normal file
54
MediaBrowser.Model/PropertyChanged.xml
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<doc>
|
||||||
|
<assembly>
|
||||||
|
<name>PropertyChanged</name>
|
||||||
|
</assembly>
|
||||||
|
<members>
|
||||||
|
<member name="T:PropertyChanged.AlsoNotifyForAttribute">
|
||||||
|
<summary>
|
||||||
|
Injects this property to be notified when a dependant property is set.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:PropertyChanged.AlsoNotifyForAttribute.#ctor(System.String)">
|
||||||
|
<summary>
|
||||||
|
Initializes a new instance of <see cref="T:PropertyChanged.DependsOnAttribute"/>.
|
||||||
|
</summary>
|
||||||
|
<param name="property">A property that will be notified for.</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:PropertyChanged.AlsoNotifyForAttribute.#ctor(System.String,System.String[])">
|
||||||
|
<summary>
|
||||||
|
Initializes a new instance of <see cref="T:PropertyChanged.DependsOnAttribute"/>.
|
||||||
|
</summary>
|
||||||
|
<param name="property">A property that will be notified for.</param>
|
||||||
|
<param name="otherProperties">The properties that will be notified for.</param>
|
||||||
|
</member>
|
||||||
|
<member name="T:PropertyChanged.DependsOnAttribute">
|
||||||
|
<summary>
|
||||||
|
Injects this property to be notified when a dependant property is set.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:PropertyChanged.DependsOnAttribute.#ctor(System.String)">
|
||||||
|
<summary>
|
||||||
|
Initializes a new instance of <see cref="T:PropertyChanged.DependsOnAttribute"/>.
|
||||||
|
</summary>
|
||||||
|
<param name="dependency">A property that the assigned property depends on.</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:PropertyChanged.DependsOnAttribute.#ctor(System.String,System.String[])">
|
||||||
|
<summary>
|
||||||
|
Initializes a new instance of <see cref="T:PropertyChanged.DependsOnAttribute"/>.
|
||||||
|
</summary>
|
||||||
|
<param name="dependency">A property that the assigned property depends on.</param>
|
||||||
|
<param name="otherDependencies">The properties that the assigned property depends on.</param>
|
||||||
|
</member>
|
||||||
|
<member name="T:PropertyChanged.DoNotNotifyAttribute">
|
||||||
|
<summary>
|
||||||
|
Exclude a <see cref="T:System.Type"/> or property from notification.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:PropertyChanged.DoNotSetChangedAttribute">
|
||||||
|
<summary>
|
||||||
|
Exclude a <see cref="T:System.Type"/> or property from IsChanged flagging.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
|
</doc>
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
namespace MediaBrowser.Model.Querying
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to control the data that gets attached to DtoBaseItems
|
/// Used to control the data that gets attached to DtoBaseItems
|
||||||
|
@ -86,11 +86,6 @@ namespace MediaBrowser.Model.Dto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
SortName,
|
SortName,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The fields that the server supports sorting on
|
|
||||||
/// </summary>
|
|
||||||
SortOptions,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The studios of the item
|
/// The studios of the item
|
||||||
/// </summary>
|
/// </summary>
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
namespace MediaBrowser.Model.Querying
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enum ItemFilter
|
/// Enum ItemFilter
|
|
@ -1,7 +1,8 @@
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
namespace MediaBrowser.Model.Querying
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains all the possible parameters that can be used to query for items
|
/// Contains all the possible parameters that can be used to query for items
|
||||||
|
@ -36,7 +37,7 @@ namespace MediaBrowser.Model.Dto
|
||||||
/// What to sort the results by
|
/// What to sort the results by
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The sort by.</value>
|
/// <value>The sort by.</value>
|
||||||
public ItemSortBy[] SortBy { get; set; }
|
public string[] SortBy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sort order to return results with
|
/// The sort order to return results with
|
||||||
|
@ -116,12 +117,6 @@ namespace MediaBrowser.Model.Dto
|
||||||
/// <value>The index by.</value>
|
/// <value>The index by.</value>
|
||||||
public string IndexBy { get; set; }
|
public string IndexBy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The dynamic, localized sort function name
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The dynamic sort by.</value>
|
|
||||||
public string DynamicSortBy { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the image types.
|
/// Gets or sets the image types.
|
||||||
/// </summary>
|
/// </summary>
|
54
MediaBrowser.Model/Querying/ItemSortBy.cs
Normal file
54
MediaBrowser.Model/Querying/ItemSortBy.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Querying
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// These represent sort orders that are known by the core
|
||||||
|
/// </summary>
|
||||||
|
public static class ItemSortBy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The album
|
||||||
|
/// </summary>
|
||||||
|
public const string Album = "Album";
|
||||||
|
/// <summary>
|
||||||
|
/// The album artist
|
||||||
|
/// </summary>
|
||||||
|
public const string AlbumArtist = "AlbumArtist";
|
||||||
|
/// <summary>
|
||||||
|
/// The artist
|
||||||
|
/// </summary>
|
||||||
|
public const string Artist = "Artist";
|
||||||
|
/// <summary>
|
||||||
|
/// The date created
|
||||||
|
/// </summary>
|
||||||
|
public const string DateCreated = "DateCreated";
|
||||||
|
/// <summary>
|
||||||
|
/// The date played
|
||||||
|
/// </summary>
|
||||||
|
public const string DatePlayed = "DatePlayed";
|
||||||
|
/// <summary>
|
||||||
|
/// The premiere date
|
||||||
|
/// </summary>
|
||||||
|
public const string PremiereDate = "PremiereDate";
|
||||||
|
/// <summary>
|
||||||
|
/// The sort name
|
||||||
|
/// </summary>
|
||||||
|
public const string SortName = "SortName";
|
||||||
|
/// <summary>
|
||||||
|
/// The random
|
||||||
|
/// </summary>
|
||||||
|
public const string Random = "Random";
|
||||||
|
/// <summary>
|
||||||
|
/// The runtime
|
||||||
|
/// </summary>
|
||||||
|
public const string Runtime = "Runtime";
|
||||||
|
/// <summary>
|
||||||
|
/// The community rating
|
||||||
|
/// </summary>
|
||||||
|
public const string CommunityRating = "CommunityRating";
|
||||||
|
/// <summary>
|
||||||
|
/// The production year
|
||||||
|
/// </summary>
|
||||||
|
public const string ProductionYear = "ProductionYear";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
namespace MediaBrowser.Model.Querying
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class ItemsByNameQuery
|
/// Class ItemsByNameQuery
|
||||||
|
@ -34,10 +34,10 @@ namespace MediaBrowser.Model.Dto
|
||||||
/// <value>The sort order.</value>
|
/// <value>The sort order.</value>
|
||||||
public SortOrder? SortOrder { get; set; }
|
public SortOrder? SortOrder { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If specified the search will be localized within a specific item or folder
|
/// Gets or sets the parent id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The item id.</value>
|
/// <value>The parent id.</value>
|
||||||
public string ItemId { get; set; }
|
public string ParentId { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fields to return within the items, in addition to basic information
|
/// Fields to return within the items, in addition to basic information
|
||||||
/// </summary>
|
/// </summary>
|
|
@ -1,6 +1,7 @@
|
||||||
using ProtoBuf;
|
using MediaBrowser.Model.Dto;
|
||||||
|
using ProtoBuf;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dto
|
namespace MediaBrowser.Model.Querying
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the result of a query for items
|
/// Represents the result of a query for items
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
using System.Net;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
@ -257,7 +258,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
|
|
||||||
var stream = await factoryFn().ConfigureAwait(false);
|
var stream = await factoryFn().ConfigureAwait(false);
|
||||||
|
|
||||||
return new StreamWriter(stream);
|
var httpListenerResponse = (HttpListenerResponse) Response.OriginalResponse;
|
||||||
|
httpListenerResponse.SendChunked = false;
|
||||||
|
|
||||||
|
if (IsRangeRequest)
|
||||||
|
{
|
||||||
|
return new RangeRequestWriter(Request.Headers, httpListenerResponse, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpListenerResponse.ContentLength64 = stream.Length;
|
||||||
|
return new StreamWriter(stream, Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
string content;
|
string content;
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
using ServiceStack.Service;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
|
{
|
||||||
|
public class RangeRequestWriter : IStreamWriter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the source stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The source stream.</value>
|
||||||
|
public Stream SourceStream { get; set; }
|
||||||
|
public HttpListenerResponse Response { get; set; }
|
||||||
|
public NameValueCollection RequestHeaders { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestHeaders">The request headers.</param>
|
||||||
|
/// <param name="response">The response.</param>
|
||||||
|
/// <param name="source">The source.</param>
|
||||||
|
public RangeRequestWriter(NameValueCollection requestHeaders, HttpListenerResponse response, Stream source)
|
||||||
|
{
|
||||||
|
RequestHeaders = requestHeaders;
|
||||||
|
Response = response;
|
||||||
|
SourceStream = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The _requested ranges
|
||||||
|
/// </summary>
|
||||||
|
private List<KeyValuePair<long, long?>> _requestedRanges;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the requested ranges.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The requested ranges.</value>
|
||||||
|
protected IEnumerable<KeyValuePair<long, long?>> RequestedRanges
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_requestedRanges == null)
|
||||||
|
{
|
||||||
|
_requestedRanges = new List<KeyValuePair<long, long?>>();
|
||||||
|
|
||||||
|
// Example: bytes=0-,32-63
|
||||||
|
var ranges = RequestHeaders["Range"].Split('=')[1].Split(',');
|
||||||
|
|
||||||
|
foreach (var range in ranges)
|
||||||
|
{
|
||||||
|
var vals = range.Split('-');
|
||||||
|
|
||||||
|
long start = 0;
|
||||||
|
long? end = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(vals[0]))
|
||||||
|
{
|
||||||
|
start = long.Parse(vals[0]);
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(vals[1]))
|
||||||
|
{
|
||||||
|
end = long.Parse(vals[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_requestedRanges.Add(new KeyValuePair<long, long?>(start, end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _requestedRanges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes to.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="responseStream">The response stream.</param>
|
||||||
|
public void WriteTo(Stream responseStream)
|
||||||
|
{
|
||||||
|
Response.Headers["Accept-Ranges"] = "bytes";
|
||||||
|
Response.StatusCode = 206;
|
||||||
|
|
||||||
|
var task = WriteToAsync(responseStream);
|
||||||
|
|
||||||
|
Task.WaitAll(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes to async.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="responseStream">The response stream.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
private async Task WriteToAsync(Stream responseStream)
|
||||||
|
{
|
||||||
|
using (var source = SourceStream)
|
||||||
|
{
|
||||||
|
var requestedRange = RequestedRanges.First();
|
||||||
|
|
||||||
|
var totalLength = SourceStream.Length;
|
||||||
|
|
||||||
|
// If the requested range is "0-", we can optimize by just doing a stream copy
|
||||||
|
if (!requestedRange.Value.HasValue)
|
||||||
|
{
|
||||||
|
await ServeCompleteRangeRequest(source, requestedRange, responseStream, totalLength).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will have to buffer a portion of the content into memory
|
||||||
|
await ServePartialRangeRequest(source, requestedRange.Key, requestedRange.Value.Value, responseStream, totalLength).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles a range request of "bytes=0-"
|
||||||
|
/// This will serve the complete content and add the content-range header
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceStream">The source stream.</param>
|
||||||
|
/// <param name="requestedRange">The requested range.</param>
|
||||||
|
/// <param name="responseStream">The response stream.</param>
|
||||||
|
/// <param name="totalContentLength">Total length of the content.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
private Task ServeCompleteRangeRequest(Stream sourceStream, KeyValuePair<long, long?> requestedRange, Stream responseStream, long totalContentLength)
|
||||||
|
{
|
||||||
|
var rangeStart = requestedRange.Key;
|
||||||
|
var rangeEnd = totalContentLength - 1;
|
||||||
|
var rangeLength = 1 + rangeEnd - rangeStart;
|
||||||
|
|
||||||
|
// Content-Length is the length of what we're serving, not the original content
|
||||||
|
Response.ContentLength64 = rangeLength;
|
||||||
|
Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength);
|
||||||
|
|
||||||
|
if (rangeStart > 0)
|
||||||
|
{
|
||||||
|
sourceStream.Position = rangeStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceStream.CopyToAsync(responseStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serves a partial range request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceStream">The source stream.</param>
|
||||||
|
/// <param name="rangeStart">The range start.</param>
|
||||||
|
/// <param name="rangeEnd">The range end.</param>
|
||||||
|
/// <param name="responseStream">The response stream.</param>
|
||||||
|
/// <param name="totalContentLength">Total length of the content.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
private async Task ServePartialRangeRequest(Stream sourceStream, long rangeStart, long rangeEnd, Stream responseStream, long totalContentLength)
|
||||||
|
{
|
||||||
|
var rangeLength = 1 + rangeEnd - rangeStart;
|
||||||
|
|
||||||
|
// Content-Length is the length of what we're serving, not the original content
|
||||||
|
Response.ContentLength64 = rangeLength;
|
||||||
|
Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength);
|
||||||
|
|
||||||
|
sourceStream.Position = rangeStart;
|
||||||
|
|
||||||
|
// Fast track to just copy the stream to the end
|
||||||
|
if (rangeEnd == totalContentLength - 1)
|
||||||
|
{
|
||||||
|
await sourceStream.CopyToAsync(responseStream).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Read the bytes we need
|
||||||
|
var buffer = new byte[Convert.ToInt32(rangeLength)];
|
||||||
|
await sourceStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await responseStream.WriteAsync(buffer, 0, Convert.ToInt32(rangeLength)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
using ServiceStack.Service;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using ServiceStack.Service;
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -9,6 +11,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StreamWriter : IStreamWriter
|
public class StreamWriter : IStreamWriter
|
||||||
{
|
{
|
||||||
|
private ILogger Logger { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the source stream.
|
/// Gets or sets the source stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -19,9 +23,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
|
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">The source.</param>
|
/// <param name="source">The source.</param>
|
||||||
public StreamWriter(Stream source)
|
/// <param name="logger">The logger.</param>
|
||||||
|
public StreamWriter(Stream source, ILogger logger)
|
||||||
{
|
{
|
||||||
SourceStream = source;
|
SourceStream = source;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -42,9 +48,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
private async Task WriteToAsync(Stream responseStream)
|
private async Task WriteToAsync(Stream responseStream)
|
||||||
{
|
{
|
||||||
using (var src = SourceStream)
|
try
|
||||||
{
|
{
|
||||||
await src.CopyToAsync(responseStream).ConfigureAwait(false);
|
using (var src = SourceStream)
|
||||||
|
{
|
||||||
|
await src.CopyToAsync(responseStream).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("Error streaming media", ex);
|
||||||
|
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ using MediaBrowser.Controller.IO;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
using MediaBrowser.Controller.ScheduledTasks;
|
using MediaBrowser.Controller.ScheduledTasks;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Server.Implementations.Library.Resolvers;
|
using MediaBrowser.Server.Implementations.Library.Resolvers;
|
||||||
|
@ -22,6 +23,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Library
|
namespace MediaBrowser.Server.Implementations.Library
|
||||||
{
|
{
|
||||||
|
@ -54,6 +56,12 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
/// <value>The entity resolvers enumerable.</value>
|
/// <value>The entity resolvers enumerable.</value>
|
||||||
private IEnumerable<IItemResolver> EntityResolvers { get; set; }
|
private IEnumerable<IItemResolver> EntityResolvers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the comparers.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The comparers.</value>
|
||||||
|
private IEnumerable<IBaseItemComparer> Comparers { get; set; }
|
||||||
|
|
||||||
#region LibraryChanged Event
|
#region LibraryChanged Event
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fires whenever any validation routine adds or removes items. The added and removed items are properties of the args.
|
/// Fires whenever any validation routine adds or removes items. The added and removed items are properties of the args.
|
||||||
|
@ -124,12 +132,14 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
/// <param name="pluginFolders">The plugin folders.</param>
|
/// <param name="pluginFolders">The plugin folders.</param>
|
||||||
/// <param name="resolvers">The resolvers.</param>
|
/// <param name="resolvers">The resolvers.</param>
|
||||||
/// <param name="introProviders">The intro providers.</param>
|
/// <param name="introProviders">The intro providers.</param>
|
||||||
public void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders, IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders)
|
/// <param name="itemComparers">The item comparers.</param>
|
||||||
|
public void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders, IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders, IEnumerable<IBaseItemComparer> itemComparers)
|
||||||
{
|
{
|
||||||
EntityResolutionIgnoreRules = rules;
|
EntityResolutionIgnoreRules = rules;
|
||||||
PluginFolderCreators = pluginFolders;
|
PluginFolderCreators = pluginFolders;
|
||||||
EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
|
EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
|
||||||
IntroProviders = introProviders;
|
IntroProviders = introProviders;
|
||||||
|
Comparers = itemComparers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -702,5 +712,62 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
{
|
{
|
||||||
return IntroProviders.SelectMany(i => i.GetIntros(item, user));
|
return IntroProviders.SelectMany(i => i.GetIntros(item, user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sorts the specified sort by.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <param name="sortBy">The sort by.</param>
|
||||||
|
/// <param name="sortOrder">The sort order.</param>
|
||||||
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
|
public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy, SortOrder sortOrder)
|
||||||
|
{
|
||||||
|
var isFirst = true;
|
||||||
|
|
||||||
|
IOrderedEnumerable<BaseItem> orderedItems = null;
|
||||||
|
|
||||||
|
foreach (var orderBy in sortBy.Select(o => GetComparer(o, user)).Where(c => c != null))
|
||||||
|
{
|
||||||
|
if (isFirst)
|
||||||
|
{
|
||||||
|
orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
orderedItems = sortOrder == SortOrder.Descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
isFirst = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return orderedItems ?? items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the comparer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <returns>IBaseItemComparer.</returns>
|
||||||
|
private IBaseItemComparer GetComparer(string name, User user)
|
||||||
|
{
|
||||||
|
var comparer = Comparers.FirstOrDefault(c => string.Equals(name, c.Name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (comparer != null)
|
||||||
|
{
|
||||||
|
// If it requires a user, create a new one, and assign the user
|
||||||
|
if (comparer is IUserBaseItemComparer)
|
||||||
|
{
|
||||||
|
var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType());
|
||||||
|
|
||||||
|
userComparer.User = user;
|
||||||
|
|
||||||
|
return userComparer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return comparer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
<Compile Include="HttpServer\HttpResultFactory.cs" />
|
<Compile Include="HttpServer\HttpResultFactory.cs" />
|
||||||
<Compile Include="HttpServer\HttpServer.cs" />
|
<Compile Include="HttpServer\HttpServer.cs" />
|
||||||
<Compile Include="HttpServer\NativeWebSocket.cs" />
|
<Compile Include="HttpServer\NativeWebSocket.cs" />
|
||||||
|
<Compile Include="HttpServer\RangeRequestWriter.cs" />
|
||||||
<Compile Include="HttpServer\ServerFactory.cs" />
|
<Compile Include="HttpServer\ServerFactory.cs" />
|
||||||
<Compile Include="HttpServer\StreamWriter.cs" />
|
<Compile Include="HttpServer\StreamWriter.cs" />
|
||||||
<Compile Include="HttpServer\SwaggerService.cs" />
|
<Compile Include="HttpServer\SwaggerService.cs" />
|
||||||
|
@ -139,6 +140,17 @@
|
||||||
<Compile Include="ServerApplicationPaths.cs" />
|
<Compile Include="ServerApplicationPaths.cs" />
|
||||||
<Compile Include="ServerManager\ServerManager.cs" />
|
<Compile Include="ServerManager\ServerManager.cs" />
|
||||||
<Compile Include="ServerManager\WebSocketConnection.cs" />
|
<Compile Include="ServerManager\WebSocketConnection.cs" />
|
||||||
|
<Compile Include="Sorting\AlbumArtistComparer.cs" />
|
||||||
|
<Compile Include="Sorting\AlbumComparer.cs" />
|
||||||
|
<Compile Include="Sorting\ArtistComparer.cs" />
|
||||||
|
<Compile Include="Sorting\CommunityRatingComparer.cs" />
|
||||||
|
<Compile Include="Sorting\DateCreatedComparer.cs" />
|
||||||
|
<Compile Include="Sorting\DatePlayedComparer.cs" />
|
||||||
|
<Compile Include="Sorting\PremiereDateComparer.cs" />
|
||||||
|
<Compile Include="Sorting\ProductionYearComparer.cs" />
|
||||||
|
<Compile Include="Sorting\RandomComparer.cs" />
|
||||||
|
<Compile Include="Sorting\RuntimeComparer.cs" />
|
||||||
|
<Compile Include="Sorting\SortNameComparer.cs" />
|
||||||
<Compile Include="Sqlite\SQLiteDisplayPreferencesRepository.cs" />
|
<Compile Include="Sqlite\SQLiteDisplayPreferencesRepository.cs" />
|
||||||
<Compile Include="Sqlite\SQLiteExtensions.cs" />
|
<Compile Include="Sqlite\SQLiteExtensions.cs" />
|
||||||
<Compile Include="Sqlite\SQLiteItemRepository.cs" />
|
<Compile Include="Sqlite\SQLiteItemRepository.cs" />
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class AlbumArtistComparer
|
||||||
|
/// </summary>
|
||||||
|
public class AlbumArtistComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
private string GetValue(BaseItem x)
|
||||||
|
{
|
||||||
|
var audio = x as Audio;
|
||||||
|
|
||||||
|
return audio == null ? string.Empty : audio.AlbumArtist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.AlbumArtist; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs
Normal file
46
MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class AlbumComparer
|
||||||
|
/// </summary>
|
||||||
|
public class AlbumComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
private string GetValue(BaseItem x)
|
||||||
|
{
|
||||||
|
var audio = x as Audio;
|
||||||
|
|
||||||
|
return audio == null ? string.Empty : audio.Album;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.Album; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class ArtistComparer
|
||||||
|
/// </summary>
|
||||||
|
public class ArtistComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
private string GetValue(BaseItem x)
|
||||||
|
{
|
||||||
|
var audio = x as Audio;
|
||||||
|
|
||||||
|
return audio == null ? string.Empty : audio.Artist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.Artist; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
public class CommunityRatingComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return (x.CommunityRating ?? 0).CompareTo(y.CommunityRating ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.CommunityRating; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class DateCreatedComparer
|
||||||
|
/// </summary>
|
||||||
|
public class DateCreatedComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return DateTime.Compare(x.DateCreated, y.DateCreated);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.DateCreated; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class DatePlayedComparer
|
||||||
|
/// </summary>
|
||||||
|
public class DatePlayedComparer : IUserBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the user.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The user.</value>
|
||||||
|
public User User { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return GetDate(x).CompareTo(GetDate(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the date.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <returns>DateTime.</returns>
|
||||||
|
private DateTime GetDate(BaseItem x)
|
||||||
|
{
|
||||||
|
var userdata = x.GetUserData(User, false);
|
||||||
|
|
||||||
|
if (userdata != null && userdata.LastPlayedDate.HasValue)
|
||||||
|
{
|
||||||
|
return userdata.LastPlayedDate.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DateTime.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.DatePlayed; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class PremiereDateComparer
|
||||||
|
/// </summary>
|
||||||
|
public class PremiereDateComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return GetDate(x).CompareTo(GetDate(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the date.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <returns>DateTime.</returns>
|
||||||
|
private DateTime GetDate(BaseItem x)
|
||||||
|
{
|
||||||
|
if (x.PremiereDate.HasValue)
|
||||||
|
{
|
||||||
|
return x.PremiereDate.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.ProductionYear.HasValue)
|
||||||
|
{
|
||||||
|
return new DateTime(x.ProductionYear.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
return DateTime.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.PremiereDate; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class ProductionYearComparer
|
||||||
|
/// </summary>
|
||||||
|
public class ProductionYearComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return GetValue(x).CompareTo(GetValue(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the date.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <returns>DateTime.</returns>
|
||||||
|
private int GetValue(BaseItem x)
|
||||||
|
{
|
||||||
|
if (x.ProductionYear.HasValue)
|
||||||
|
{
|
||||||
|
return x.ProductionYear.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.PremiereDate.HasValue)
|
||||||
|
{
|
||||||
|
return x.PremiereDate.Value.Year;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.ProductionYear; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class RandomComparer
|
||||||
|
/// </summary>
|
||||||
|
public class RandomComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return Guid.NewGuid().CompareTo(Guid.NewGuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.Random; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class RuntimeComparer
|
||||||
|
/// </summary>
|
||||||
|
public class RuntimeComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return (x.RunTimeTicks ?? 0).CompareTo(y.RunTimeTicks ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.Runtime; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Sorting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class SortNameComparer
|
||||||
|
/// </summary>
|
||||||
|
public class SortNameComparer : IBaseItemComparer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the specified x.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x.</param>
|
||||||
|
/// <param name="y">The y.</param>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
public int Compare(BaseItem x, BaseItem y)
|
||||||
|
{
|
||||||
|
return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return ItemSortBy.SortName; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -127,7 +127,10 @@ namespace MediaBrowser.Server.Implementations.Udp
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
_udpClient.Close();
|
if (_udpClient != null)
|
||||||
|
{
|
||||||
|
_udpClient.Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -18,6 +18,7 @@ using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
|
using MediaBrowser.Controller.Sorting;
|
||||||
using MediaBrowser.Controller.Updates;
|
using MediaBrowser.Controller.Updates;
|
||||||
using MediaBrowser.Controller.Weather;
|
using MediaBrowser.Controller.Weather;
|
||||||
using MediaBrowser.IsoMounter;
|
using MediaBrowser.IsoMounter;
|
||||||
|
@ -126,23 +127,21 @@ namespace MediaBrowser.ServerApplication
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The HTTP server.</value>
|
/// <value>The HTTP server.</value>
|
||||||
private IHttpServer HttpServer { get; set; }
|
private IHttpServer HttpServer { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inits this instance.
|
/// Runs the startup tasks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public override async Task Init()
|
protected override async Task RunStartupTasks()
|
||||||
{
|
{
|
||||||
await base.Init().ConfigureAwait(false);
|
// Do these before allowing the base method to run, which will invoke startup scheduled tasks
|
||||||
|
await ServerKernel.LoadRepositories(ServerConfigurationManager).ConfigureAwait(false);
|
||||||
|
|
||||||
Task.Run(async () =>
|
await base.RunStartupTasks().ConfigureAwait(false);
|
||||||
{
|
|
||||||
await ServerKernel.LoadRepositories(ServerConfigurationManager).ConfigureAwait(false);
|
|
||||||
|
|
||||||
DirectoryWatchers.Start();
|
DirectoryWatchers.Start();
|
||||||
|
|
||||||
Parallel.ForEach(GetExports<IServerEntryPoint>(), entryPoint => entryPoint.Run());
|
Parallel.ForEach(GetExports<IServerEntryPoint>(), entryPoint => entryPoint.Run());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -205,13 +204,15 @@ namespace MediaBrowser.ServerApplication
|
||||||
ServerKernel.FFMpegManager = new FFMpegManager(ServerKernel, ZipClient, JsonSerializer, ProtobufSerializer, LogManager, ApplicationPaths);
|
ServerKernel.FFMpegManager = new FFMpegManager(ServerKernel, ZipClient, JsonSerializer, ProtobufSerializer, LogManager, ApplicationPaths);
|
||||||
ServerKernel.ImageManager = new ImageManager(ServerKernel, ProtobufSerializer, LogManager.GetLogger("ImageManager"), ApplicationPaths);
|
ServerKernel.ImageManager = new ImageManager(ServerKernel, ProtobufSerializer, LogManager.GetLogger("ImageManager"), ApplicationPaths);
|
||||||
|
|
||||||
ServerKernel.UserDataRepositories = GetExports<IUserDataRepository>();
|
Parallel.Invoke(
|
||||||
ServerKernel.UserRepositories = GetExports<IUserRepository>();
|
() => ServerKernel.UserDataRepositories = GetExports<IUserDataRepository>(),
|
||||||
ServerKernel.DisplayPreferencesRepositories = GetExports<IDisplayPreferencesRepository>();
|
() => ServerKernel.UserRepositories = GetExports<IUserRepository>(),
|
||||||
ServerKernel.ItemRepositories = GetExports<IItemRepository>();
|
() => ServerKernel.DisplayPreferencesRepositories = GetExports<IDisplayPreferencesRepository>(),
|
||||||
ServerKernel.WeatherProviders = GetExports<IWeatherProvider>();
|
() => ServerKernel.ItemRepositories = GetExports<IItemRepository>(),
|
||||||
ServerKernel.ImageEnhancers = GetExports<IImageEnhancer>().OrderBy(e => e.Priority).ToArray();
|
() => ServerKernel.WeatherProviders = GetExports<IWeatherProvider>(),
|
||||||
ServerKernel.StringFiles = GetExports<LocalizedStringData>();
|
() => ServerKernel.ImageEnhancers = GetExports<IImageEnhancer>().OrderBy(e => e.Priority).ToArray(),
|
||||||
|
() => ServerKernel.StringFiles = GetExports<LocalizedStringData>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -237,14 +238,20 @@ namespace MediaBrowser.ServerApplication
|
||||||
{
|
{
|
||||||
base.FindParts();
|
base.FindParts();
|
||||||
|
|
||||||
HttpServer.Init(GetExports<IRestfulService>(false));
|
Parallel.Invoke(
|
||||||
|
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
HttpServer.Init(GetExports<IRestfulService>(false));
|
||||||
|
|
||||||
ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false));
|
ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false));
|
||||||
ServerManager.Start();
|
ServerManager.Start();
|
||||||
|
},
|
||||||
|
|
||||||
LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(), GetExports<IVirtualFolderCreator>(), GetExports<IItemResolver>(), GetExports<IIntroProvider>());
|
() => LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(), GetExports<IVirtualFolderCreator>(), GetExports<IItemResolver>(), GetExports<IIntroProvider>(), GetExports<IBaseItemComparer>()),
|
||||||
|
|
||||||
ProviderManager.AddMetadataProviders(GetExports<BaseMetadataProvider>().OrderBy(e => e.Priority).ToArray());
|
() => ProviderManager.AddMetadataProviders(GetExports<BaseMetadataProvider>().OrderBy(e => e.Priority).ToArray())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -4,8 +4,10 @@ using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Localization;
|
using MediaBrowser.Controller.Localization;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -78,7 +80,8 @@ namespace MediaBrowser.ServerApplication
|
||||||
Cursor = Cursors.Wait;
|
Cursor = Cursors.Wait;
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
IEnumerable<BaseItem> children = CurrentUser.Name == "Physical" ? _libraryManager.RootFolder.Children.OrderBy(i => i.SortName) : _libraryManager.RootFolder.GetChildren(CurrentUser, sortBy: LocalizedStrings.Instance.GetString("NameDispPref"));
|
IEnumerable<BaseItem> children = CurrentUser.Name == "Physical" ? _libraryManager.RootFolder.Children : _libraryManager.RootFolder.GetChildren(CurrentUser);
|
||||||
|
children = OrderByName(children, CurrentUser);
|
||||||
|
|
||||||
foreach (Folder folder in children)
|
foreach (Folder folder in children)
|
||||||
{
|
{
|
||||||
|
@ -86,9 +89,12 @@ namespace MediaBrowser.ServerApplication
|
||||||
var currentFolder = folder;
|
var currentFolder = folder;
|
||||||
Task.Factory.StartNew(() =>
|
Task.Factory.StartNew(() =>
|
||||||
{
|
{
|
||||||
var prefs = ddlProfile.SelectedItem != null ? currentFolder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")} : new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")};
|
var prefs = ddlProfile.SelectedItem != null ? currentFolder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false) ?? new DisplayPreferences {SortBy = ItemSortBy.SortName} : new DisplayPreferences {SortBy = ItemSortBy.SortName};
|
||||||
var node = new TreeViewItem { Tag = currentFolder };
|
var node = new TreeViewItem { Tag = currentFolder };
|
||||||
AddChildren(node, currentFolder.GetChildren(CurrentUser, prefs.IndexBy, prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")), CurrentUser);
|
|
||||||
|
var subChildren = currentFolder.GetChildren(CurrentUser, prefs.IndexBy);
|
||||||
|
subChildren = OrderByName(subChildren, CurrentUser);
|
||||||
|
AddChildren(node, subChildren, CurrentUser);
|
||||||
node.Header = currentFolder.Name + " (" +
|
node.Header = currentFolder.Name + " (" +
|
||||||
node.Items.Count + ")";
|
node.Items.Count + ")";
|
||||||
tvwLibrary.Items.Add(node);
|
tvwLibrary.Items.Add(node);
|
||||||
|
@ -100,6 +106,28 @@ namespace MediaBrowser.ServerApplication
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Orders the name of the by.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
|
private IEnumerable<BaseItem> OrderByName(IEnumerable<BaseItem> items, User user)
|
||||||
|
{
|
||||||
|
return OrderBy(items, user, ItemSortBy.SortName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Orders the name of the by.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
|
private IEnumerable<BaseItem> OrderBy(IEnumerable<BaseItem> items, User user, string order)
|
||||||
|
{
|
||||||
|
return _libraryManager.Sort(items, user, new[] { order }, SortOrder.Ascending);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the children.
|
/// Adds the children.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -115,7 +143,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
if (subFolder != null)
|
if (subFolder != null)
|
||||||
{
|
{
|
||||||
var prefs = subFolder.GetDisplayPrefs(user, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")};
|
var prefs = subFolder.GetDisplayPrefs(user, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")};
|
||||||
AddChildren(node, subFolder.GetChildren(user, sortBy: prefs.SortBy), user);
|
AddChildren(node, OrderBy(subFolder.GetChildren(user), user, prefs.SortBy), user);
|
||||||
node.Header = item.Name + " (" + node.Items.Count + ")";
|
node.Header = item.Name + " (" + node.Items.Count + ")";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -152,14 +180,29 @@ namespace MediaBrowser.ServerApplication
|
||||||
{
|
{
|
||||||
lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Visible;
|
lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Visible;
|
||||||
ddlIndexBy.ItemsSource = folder.IndexByOptionStrings;
|
ddlIndexBy.ItemsSource = folder.IndexByOptionStrings;
|
||||||
ddlSortBy.ItemsSource = folder.SortByOptionStrings;
|
|
||||||
|
ddlSortBy.ItemsSource = new []
|
||||||
|
{
|
||||||
|
ItemSortBy.SortName,
|
||||||
|
ItemSortBy.Album,
|
||||||
|
ItemSortBy.AlbumArtist,
|
||||||
|
ItemSortBy.Artist,
|
||||||
|
ItemSortBy.CommunityRating,
|
||||||
|
ItemSortBy.DateCreated,
|
||||||
|
ItemSortBy.DatePlayed,
|
||||||
|
ItemSortBy.PremiereDate,
|
||||||
|
ItemSortBy.ProductionYear,
|
||||||
|
ItemSortBy.Random,
|
||||||
|
ItemSortBy.Runtime
|
||||||
|
};
|
||||||
|
|
||||||
var prefs = folder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false);
|
var prefs = folder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false);
|
||||||
ddlIndexBy.SelectedItem = prefs != null
|
ddlIndexBy.SelectedItem = prefs != null
|
||||||
? prefs.IndexBy ?? LocalizedStrings.Instance.GetString("NoneDispPref")
|
? prefs.IndexBy ?? LocalizedStrings.Instance.GetString("NoneDispPref")
|
||||||
: LocalizedStrings.Instance.GetString("NoneDispPref");
|
: LocalizedStrings.Instance.GetString("NoneDispPref");
|
||||||
ddlSortBy.SelectedItem = prefs != null
|
ddlSortBy.SelectedItem = prefs != null
|
||||||
? prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")
|
? prefs.SortBy ?? ItemSortBy.SortName
|
||||||
: LocalizedStrings.Instance.GetString("NameDispPref");
|
: ItemSortBy.SortName;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -311,7 +354,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
var folder = treeItem != null
|
var folder = treeItem != null
|
||||||
? treeItem.Tag as Folder
|
? treeItem.Tag as Folder
|
||||||
: null;
|
: null;
|
||||||
var prefs = folder != null ? folder.GetDisplayPrefs(CurrentUser, true) : new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")};
|
var prefs = folder != null ? folder.GetDisplayPrefs(CurrentUser, true) : new DisplayPreferences {SortBy = ItemSortBy.SortName};
|
||||||
if (folder != null && prefs.IndexBy != ddlIndexBy.SelectedItem as string)
|
if (folder != null && prefs.IndexBy != ddlIndexBy.SelectedItem as string)
|
||||||
{
|
{
|
||||||
//grab UI context so we can update within the below task
|
//grab UI context so we can update within the below task
|
||||||
|
@ -326,7 +369,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
//re-build the current item's children as an index
|
//re-build the current item's children as an index
|
||||||
prefs.IndexBy = ddlIndexBy.SelectedItem as string;
|
prefs.IndexBy = ddlIndexBy.SelectedItem as string;
|
||||||
treeItem.Items.Clear();
|
treeItem.Items.Clear();
|
||||||
AddChildren(treeItem,folder.GetChildren(CurrentUser, prefs.IndexBy, prefs.SortBy), CurrentUser);
|
AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, prefs.IndexBy), CurrentUser, prefs.SortBy), CurrentUser);
|
||||||
treeItem.Header = folder.Name + "(" +
|
treeItem.Header = folder.Name + "(" +
|
||||||
treeItem.Items.Count + ")";
|
treeItem.Items.Count + ")";
|
||||||
Cursor = Cursors.Arrow;
|
Cursor = Cursors.Arrow;
|
||||||
|
@ -367,7 +410,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
//re-sort
|
//re-sort
|
||||||
prefs.SortBy = ddlSortBy.SelectedItem as string;
|
prefs.SortBy = ddlSortBy.SelectedItem as string;
|
||||||
treeItem.Items.Clear();
|
treeItem.Items.Clear();
|
||||||
AddChildren(treeItem,folder.GetChildren(CurrentUser,prefs.IndexBy, prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")), CurrentUser);
|
AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, prefs.IndexBy), CurrentUser, prefs.SortBy ?? ItemSortBy.SortName), CurrentUser);
|
||||||
treeItem.Header = folder.Name + "(" +
|
treeItem.Header = folder.Name + "(" +
|
||||||
treeItem.Items.Count + ")";
|
treeItem.Items.Count + ")";
|
||||||
Cursor = Cursors.Arrow;
|
Cursor = Cursors.Arrow;
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
</ManifestKeyFile>
|
</ManifestKeyFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<GenerateManifests>true</GenerateManifests>
|
<GenerateManifests>false</GenerateManifests>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SignManifests>false</SignManifests>
|
<SignManifests>false</SignManifests>
|
||||||
|
@ -112,6 +112,9 @@
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetZone>LocalIntranet</TargetZone>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Hardcodet.Wpf.TaskbarNotification">
|
<Reference Include="Hardcodet.Wpf.TaskbarNotification">
|
||||||
<HintPath>..\packages\Hardcodet.Wpf.TaskbarNotification.1.0.4.0\lib\net40\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
|
<HintPath>..\packages\Hardcodet.Wpf.TaskbarNotification.1.0.4.0\lib\net40\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
|
||||||
|
|
Binary file not shown.
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
using System.Reflection;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Common.ScheduledTasks;
|
using MediaBrowser.Common.ScheduledTasks;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
|
@ -391,7 +392,6 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
{
|
{
|
||||||
"http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js",
|
"http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js",
|
||||||
"http://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.js",
|
"http://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.js",
|
||||||
"../jsapiclient.js" + versionString,
|
|
||||||
"scripts/all.js" + versionString
|
"scripts/all.js" + versionString
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -447,20 +447,27 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
|
var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
|
||||||
|
|
||||||
|
await AppendResource(assembly, memoryStream, "MediaBrowser.WebDashboard.ApiClient.js", newLineBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (var file in scriptFiles)
|
foreach (var file in scriptFiles)
|
||||||
{
|
{
|
||||||
using (var stream = assembly.GetManifestResourceStream(resourcePrefix + file))
|
await AppendResource(assembly, memoryStream, resourcePrefix + file, newLineBytes).ConfigureAwait(false);
|
||||||
{
|
|
||||||
await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
return memoryStream;
|
return memoryStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task AppendResource(Assembly assembly, Stream outputStream, string path, byte[] newLineBytes)
|
||||||
|
{
|
||||||
|
using (var stream = assembly.GetManifestResourceStream(path))
|
||||||
|
{
|
||||||
|
await stream.CopyToAsync(outputStream).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await outputStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,10 @@
|
||||||
<label>Disable internet providers for:</label>
|
<label>Disable internet providers for:</label>
|
||||||
<div id="divItemTypes"></div>
|
<div id="divItemTypes"></div>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li style="display: none;">
|
||||||
<button type="submit" data-theme="b">
|
<button class="btnSubmit" type="submit" data-theme="b">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
<button type="button" onclick="Dashboard.navigate('dashboard.html');">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -18,32 +18,29 @@
|
||||||
<form id="metadataConfigurationForm">
|
<form id="metadataConfigurationForm">
|
||||||
<ul data-role="listview" class="ulForm">
|
<ul data-role="listview" class="ulForm">
|
||||||
<li>
|
<li>
|
||||||
<input type="checkbox" id="chkEnableInternetProviders" name="chkEnableInternetProviders" />
|
<input type="checkbox" id="chkEnableInternetProviders" name="chkEnableInternetProviders" onchange="MetadataConfigurationPage.submit();" />
|
||||||
<label for="chkEnableInternetProviders">Download metadata from the internet </label>
|
<label for="chkEnableInternetProviders">Download metadata from the internet </label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="checkbox" id="chkSaveLocal" name="chkSaveLocal" />
|
<input type="checkbox" id="chkSaveLocal" name="chkSaveLocal onchange="MetadataConfigurationPage.submit();" />
|
||||||
<label for="chkSaveLocal">Save metadata within media folders </label>
|
<label for="chkSaveLocal">Save metadata within media folders </label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="txtRefreshDays">Metadata refresh period (days): </label>
|
<label for="txtRefreshDays">Metadata refresh period (days): </label>
|
||||||
<input type="number" id="txtRefreshDays" name="txtRefreshDays" pattern="[0-9]*" required="required" min="1" />
|
<input type="number" id="txtRefreshDays" name="txtRefreshDays" pattern="[0-9]*" required="required" min="1" onchange="MetadataConfigurationPage.submit();" />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="selectLanguage">Preferred language: </label>
|
<label for="selectLanguage">Preferred language: </label>
|
||||||
<select name="selectLanguage" id="selectLanguage"></select>
|
<select name="selectLanguage" id="selectLanguage" onchange="MetadataConfigurationPage.submit();"></select>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="selectCountry">Country: </label>
|
<label for="selectCountry">Country: </label>
|
||||||
<select name="selectCountry" id="selectCountry"></select>
|
<select name="selectCountry" id="selectCountry" onchange="MetadataConfigurationPage.submit();"></select>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li style="display: none;">
|
||||||
<button type="submit" data-theme="b">
|
<button class="btnSubmit" type="submit" data-theme="b">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
<button type="button" onclick="Dashboard.navigate('dashboard.html');">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<form id="metadataImagesConfigurationForm">
|
<form id="metadataImagesConfigurationForm">
|
||||||
<ul data-role="listview" class="ulForm">
|
<ul data-role="listview" class="ulForm">
|
||||||
<li>
|
<li>
|
||||||
<input type="checkbox" id="chkRefreshItemImages" name="chkRefreshItemImages" />
|
<input type="checkbox" id="chkRefreshItemImages" name="chkRefreshItemImages" onchange="MetadataImagesPage.submit();" />
|
||||||
<label for="chkRefreshItemImages">Refresh existing images </label>
|
<label for="chkRefreshItemImages">Refresh existing images </label>
|
||||||
<div class="fieldDescription">
|
<div class="fieldDescription">
|
||||||
When enabled, images will be refreshed periodically
|
When enabled, images will be refreshed periodically
|
||||||
|
@ -26,100 +26,100 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="txtNumbackdrops">Max number of backdrops per item: </label>
|
<label for="txtNumbackdrops">Max number of backdrops per item: </label>
|
||||||
<input type="number" id="txtNumbackdrops" name="txtNumbackdrops" pattern="[0-9]*" required="required" min="1" />
|
<input type="number" id="txtNumbackdrops" name="txtNumbackdrops" pattern="[0-9]*" required="required" min="1" onchange="MetadataImagesPage.submit();" />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label>Enable additional image downloading:</label>
|
<label>Enable additional image downloading:</label>
|
||||||
|
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>Movies</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieArt" name="chkDownloadMovieArt" />
|
|
||||||
<label for="chkDownloadMovieArt">Movie Art</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieBanner" name="chkDownloadMovieBanner" />
|
<div data-role="collapsible">
|
||||||
<label for="chkDownloadMovieBanner">Movie Banner</label>
|
<h3>Movies</h3>
|
||||||
|
<div data-role="controlgroup">
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadMovieArt" name="chkDownloadMovieArt" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadMovieArt">Movie Art</label>
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieDisc" name="chkDownloadMovieDisc" />
|
<input type="checkbox" data-mini="true" id="chkDownloadMovieBanner" name="chkDownloadMovieBanner" onchange="MetadataImagesPage.submit();" />
|
||||||
<label for="chkDownloadMovieDisc">Movie Disc</label>
|
<label for="chkDownloadMovieBanner">Movie Banner</label>
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieLogo" name="chkDownloadMovieLogo" />
|
<input type="checkbox" data-mini="true" id="chkDownloadMovieDisc" name="chkDownloadMovieDisc" onchange="MetadataImagesPage.submit();" />
|
||||||
<label for="chkDownloadMovieLogo">Movie Logo</label>
|
<label for="chkDownloadMovieDisc">Movie Disc</label>
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadMovieThumb" name="chkDownloadMovieThumb" />
|
<input type="checkbox" data-mini="true" id="chkDownloadMovieLogo" name="chkDownloadMovieLogo" onchange="MetadataImagesPage.submit();" />
|
||||||
<label for="chkDownloadMovieThumb">Movie Thumb</label>
|
<label for="chkDownloadMovieLogo">Movie Logo</label>
|
||||||
|
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadMovieThumb" name="chkDownloadMovieThumb" onchange="MetadataImagesPage.submit();" />
|
||||||
</div>
|
<label for="chkDownloadMovieThumb">Movie Thumb</label>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>TV Series</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chKDownloadTVArt" name="chKDownloadTVArt" />
|
|
||||||
<label for="chKDownloadTVArt">TV Series Art</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadTVBanner" name="chkDownloadTVBanner" />
|
|
||||||
<label for="chkDownloadTVBanner">TV Series Banner</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadTVLogo" name="chkDownloadTVLogo" />
|
|
||||||
<label for="chkDownloadTVLogo">TV Series Logo</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadTVThumb" name="chkDownloadTVThumb" />
|
|
||||||
<label for="chkDownloadTVThumb">TV Series Thumb</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>TV Seasons</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadSeasonBackdrops" name="chkDownloadSeasonBackdrops" />
|
|
||||||
<label for="chkDownloadSeasonBackdrops">TV Season Backdrops</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadSeasonBanner" name="chkDownloadSeasonBanner" />
|
|
||||||
<label for="chkDownloadSeasonBanner">TV Season Banner</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadSeasonThumb" name="chkDownloadSeasonThumb" />
|
|
||||||
<label for="chkDownloadSeasonThumb">TV Season Thumb</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div data-role="collapsible">
|
<div data-role="collapsible">
|
||||||
<h3>Music Artists</h3>
|
<h3>TV Series</h3>
|
||||||
<div data-role="controlgroup">
|
<div data-role="controlgroup">
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadArtistThumb" name="chkDownloadArtistThumb" />
|
<input type="checkbox" data-mini="true" id="chKDownloadTVArt" name="chKDownloadTVArt" onchange="MetadataImagesPage.submit();" />
|
||||||
<label for="chkDownloadArtistThumb">Music Artist Thumb (primary image)</label>
|
<label for="chKDownloadTVArt">TV Series Art</label>
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadArtistBackdrops" name="chkDownloadArtistBackdrops" />
|
<input type="checkbox" data-mini="true" id="chkDownloadTVBanner" name="chkDownloadTVBanner" onchange="MetadataImagesPage.submit();" />
|
||||||
<label for="chkDownloadArtistBackdrops">Music Artist Backdrops</label>
|
<label for="chkDownloadTVBanner">TV Series Banner</label>
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadArtistLogo" name="chkDownloadArtistLogo" />
|
<input type="checkbox" data-mini="true" id="chkDownloadTVLogo" name="chkDownloadTVLogo" onchange="MetadataImagesPage.submit();" />
|
||||||
<label for="chkDownloadArtistLogo">Music Artist Logo</label>
|
<label for="chkDownloadTVLogo">TV Series Logo</label>
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadArtistBanner" name="chkDownloadArtistBanner" />
|
|
||||||
<label for="chkDownloadArtistBanner">Music Artist Banner</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadTVThumb" name="chkDownloadTVThumb" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadTVThumb">TV Series Thumb</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div data-role="collapsible">
|
|
||||||
<h3>Music Albums</h3>
|
|
||||||
<div data-role="controlgroup">
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadAlbumPrimary" name="chkDownloadAlbumPrimary" />
|
|
||||||
<label for="chkDownloadAlbumPrimary">Music Album Cover</label>
|
|
||||||
|
|
||||||
<input type="checkbox" data-mini="true" id="chkDownloadAlbumBackdrops" name="chkDownloadAlbumBackdrops" />
|
|
||||||
<label for="chkDownloadAlbumBackdrops">Music Album Backdrops</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div data-role="collapsible">
|
||||||
|
<h3>TV Seasons</h3>
|
||||||
|
<div data-role="controlgroup">
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadSeasonBackdrops" name="chkDownloadSeasonBackdrops" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadSeasonBackdrops">TV Season Backdrops</label>
|
||||||
|
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadSeasonBanner" name="chkDownloadSeasonBanner" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadSeasonBanner">TV Season Banner</label>
|
||||||
|
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadSeasonThumb" name="chkDownloadSeasonThumb" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadSeasonThumb">TV Season Thumb</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-role="collapsible">
|
||||||
|
<h3>Music Artists</h3>
|
||||||
|
<div data-role="controlgroup">
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadArtistThumb" name="chkDownloadArtistThumb" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadArtistThumb">Music Artist Thumb (primary image)</label>
|
||||||
|
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadArtistBackdrops" name="chkDownloadArtistBackdrops" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadArtistBackdrops">Music Artist Backdrops</label>
|
||||||
|
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadArtistLogo" name="chkDownloadArtistLogo" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadArtistLogo">Music Artist Logo</label>
|
||||||
|
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadArtistBanner" name="chkDownloadArtistBanner" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadArtistBanner">Music Artist Banner</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-role="collapsible">
|
||||||
|
<h3>Music Albums</h3>
|
||||||
|
<div data-role="controlgroup">
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadAlbumPrimary" name="chkDownloadAlbumPrimary" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadAlbumPrimary">Music Album Cover</label>
|
||||||
|
|
||||||
|
<input type="checkbox" data-mini="true" id="chkDownloadAlbumBackdrops" name="chkDownloadAlbumBackdrops" onchange="MetadataImagesPage.submit();" />
|
||||||
|
<label for="chkDownloadAlbumBackdrops">Music Album Backdrops</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="selectTmdbPosterDownloadSize">Tmdb poster download size: </label>
|
<label for="selectTmdbPosterDownloadSize">Tmdb poster download size: </label>
|
||||||
<select id="selectTmdbPosterDownloadSize" name="selectTmdbPosterDownloadSize">
|
<select id="selectTmdbPosterDownloadSize" name="selectTmdbPosterDownloadSize" onchange="MetadataImagesPage.submit();">
|
||||||
<option value="original">original</option>
|
<option value="original">original</option>
|
||||||
<option value="w92">w92</option>
|
<option value="w92">w92</option>
|
||||||
<option value="w154">w154</option>
|
<option value="w154">w154</option>
|
||||||
|
@ -130,7 +130,7 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="selectTmdbBackdropDownloadSize">Tmdb backdrop download size: </label>
|
<label for="selectTmdbBackdropDownloadSize">Tmdb backdrop download size: </label>
|
||||||
<select id="selectTmdbBackdropDownloadSize" name="selectTmdbBackdropDownloadSize">
|
<select id="selectTmdbBackdropDownloadSize" name="selectTmdbBackdropDownloadSize" onchange="MetadataImagesPage.submit();">
|
||||||
<option value="original">original</option>
|
<option value="original">original</option>
|
||||||
<option value="w380">w380</option>
|
<option value="w380">w380</option>
|
||||||
<option value="w780">w780</option>
|
<option value="w780">w780</option>
|
||||||
|
@ -139,20 +139,17 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="selectTmdbPersonImageDownloadSize">Tmdb person image download size: </label>
|
<label for="selectTmdbPersonImageDownloadSize">Tmdb person image download size: </label>
|
||||||
<select id="selectTmdbPersonImageDownloadSize" name="selectTmdbPersonImageDownloadSize">
|
<select id="selectTmdbPersonImageDownloadSize" name="selectTmdbPersonImageDownloadSize" onchange="MetadataImagesPage.submit();">
|
||||||
<option value="original">original</option>
|
<option value="original">original</option>
|
||||||
<option value="w45">w45</option>
|
<option value="w45">w45</option>
|
||||||
<option value="w185">w185</option>
|
<option value="w185">w185</option>
|
||||||
<option value="h632">h632</option>
|
<option value="h632">h632</option>
|
||||||
</select>
|
</select>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li style="display: none;">
|
||||||
<button type="submit" data-theme="b">
|
<button class="btnSubmit" type="submit" data-theme="b">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
<button type="button" onclick="Dashboard.navigate('dashboard.html');">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
var checkedAttribute = configuration.InternetProviderExcludeTypes.indexOf(type) != -1 ? ' checked="checked"' : '';
|
var checkedAttribute = configuration.InternetProviderExcludeTypes.indexOf(type) != -1 ? ' checked="checked"' : '';
|
||||||
|
|
||||||
html += '<input' + checkedAttribute + ' class="chkItemType" data-itemtype="' + type + '" type="checkbox" name="' + id + '" id="' + id + '" />';
|
html += '<input' + checkedAttribute + ' class="chkItemType" data-itemtype="' + type + '" type="checkbox" name="' + id + '" id="' + id + '" onchange="AdvancedMetadataConfigurationPage.submit();" />';
|
||||||
html += '<label for="' + id + '">' + type + '</label>';
|
html += '<label for="' + id + '">' + type + '</label>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,12 @@
|
||||||
$('#divItemTypes', page).html(html).trigger("create");
|
$('#divItemTypes', page).html(html).trigger("create");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
submit: function () {
|
||||||
|
|
||||||
|
$('.btnSubmit', $.mobile.activePage)[0].click();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
onSubmit: function () {
|
onSubmit: function () {
|
||||||
Dashboard.showLoadingMsg();
|
Dashboard.showLoadingMsg();
|
||||||
|
|
||||||
|
@ -54,7 +60,7 @@
|
||||||
return currentCheckbox.getAttribute('data-itemtype');
|
return currentCheckbox.getAttribute('data-itemtype');
|
||||||
});
|
});
|
||||||
|
|
||||||
ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult);
|
ApiClient.updateServerConfiguration(config);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Disable default form submission
|
// Disable default form submission
|
||||||
|
|
|
@ -79,6 +79,12 @@
|
||||||
$('#selectLanguage', '#metadataConfigurationPage').html(html).selectmenu("refresh");
|
$('#selectLanguage', '#metadataConfigurationPage').html(html).selectmenu("refresh");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
submit: function () {
|
||||||
|
|
||||||
|
$('.btnSubmit', $.mobile.activePage)[0].click();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
onSubmit: function () {
|
onSubmit: function () {
|
||||||
Dashboard.showLoadingMsg();
|
Dashboard.showLoadingMsg();
|
||||||
|
|
||||||
|
@ -92,7 +98,7 @@
|
||||||
config.PreferredMetadataLanguage = $('#selectLanguage', form).val();
|
config.PreferredMetadataLanguage = $('#selectLanguage', form).val();
|
||||||
config.MetadataCountryCode = $('#selectCountry', form).val();
|
config.MetadataCountryCode = $('#selectCountry', form).val();
|
||||||
|
|
||||||
ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult);
|
ApiClient.updateServerConfiguration(config);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Disable default form submission
|
// Disable default form submission
|
||||||
|
|
|
@ -42,6 +42,12 @@
|
||||||
Dashboard.hideLoadingMsg();
|
Dashboard.hideLoadingMsg();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
submit: function () {
|
||||||
|
|
||||||
|
$('.btnSubmit', $.mobile.activePage)[0].click();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
onSubmit: function () {
|
onSubmit: function () {
|
||||||
Dashboard.showLoadingMsg();
|
Dashboard.showLoadingMsg();
|
||||||
|
|
||||||
|
@ -75,7 +81,7 @@
|
||||||
config.DownloadMusicAlbumImages.Primary = $('#chkDownloadAlbumPrimary', form).checked();
|
config.DownloadMusicAlbumImages.Primary = $('#chkDownloadAlbumPrimary', form).checked();
|
||||||
config.DownloadMusicAlbumImages.Backdrops = $('#chkDownloadAlbumBackdrops', form).checked();
|
config.DownloadMusicAlbumImages.Backdrops = $('#chkDownloadAlbumBackdrops', form).checked();
|
||||||
|
|
||||||
ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult);
|
ApiClient.updateServerConfiguration(config);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Disable default form submission
|
// Disable default form submission
|
||||||
|
|
|
@ -403,6 +403,7 @@
|
||||||
<EmbeddedResource Include="Html\css\images\mblogotextblack.png" />
|
<EmbeddedResource Include="Html\css\images\mblogotextblack.png" />
|
||||||
<EmbeddedResource Include="Html\css\images\mblogotextwhite.png" />
|
<EmbeddedResource Include="Html\css\images\mblogotextwhite.png" />
|
||||||
<EmbeddedResource Include="Html\css\images\clients\dlna.png" />
|
<EmbeddedResource Include="Html\css\images\clients\dlna.png" />
|
||||||
|
<EmbeddedResource Include="ApiClient.js" />
|
||||||
<Content Include="Html\css\images\stars.png" />
|
<Content Include="Html\css\images\stars.png" />
|
||||||
<EmbeddedResource Include="Html\scripts\MediaPlayer.js" />
|
<EmbeddedResource Include="Html\scripts\MediaPlayer.js" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.40" targetFramework="net45" />
|
||||||
<package id="ServiceStack" version="3.9.38" targetFramework="net45" />
|
<package id="ServiceStack" version="3.9.38" targetFramework="net45" />
|
||||||
<package id="ServiceStack.Common" version="3.9.38" targetFramework="net45" />
|
<package id="ServiceStack.Common" version="3.9.38" targetFramework="net45" />
|
||||||
<package id="ServiceStack.OrmLite.SqlServer" version="3.9.39" targetFramework="net45" />
|
<package id="ServiceStack.OrmLite.SqlServer" version="3.9.39" targetFramework="net45" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.40</version>
|
<version>3.0.43</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description>
|
<description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.40" />
|
<dependency id="MediaBrowser.Common" version="3.0.43" />
|
||||||
<dependency id="NLog" version="2.0.0.2000" />
|
<dependency id="NLog" version="2.0.0.2000" />
|
||||||
<dependency id="ServiceStack.Text" version="3.9.38" />
|
<dependency id="ServiceStack.Text" version="3.9.38" />
|
||||||
<dependency id="protobuf-net" version="2.0.0.621" />
|
<dependency id="protobuf-net" version="2.0.0.621" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.40</version>
|
<version>3.0.43</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.40</version>
|
<version>3.0.43</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.40" />
|
<dependency id="MediaBrowser.Common" version="3.0.43" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
|
Loading…
Reference in a new issue