aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Reed <ebr@mediabrowser3.com>2013-03-11 11:03:41 -0400
committerEric Reed <ebr@mediabrowser3.com>2013-03-11 11:03:41 -0400
commit6470c62c5048dd22caff3a2f4cb296e7e0e5937a (patch)
treea566b28ca659291da99bdded88b4b366cc2572e1
parent889bd32e9e798fe816f4ae1d0051e755c30eac5e (diff)
parent39020714f75b1bd1fe41355d4e9dadc9620ed8a1 (diff)
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
-rw-r--r--MediaBrowser.Api/Javascript/JavascriptApiClientService.cs59
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs1
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj3
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs8
-rw-r--r--MediaBrowser.Api/Playback/Hls/AudioHlsService.cs4
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs6
-rw-r--r--MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs21
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs1
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs57
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs58
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs339
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs1
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs65
-rw-r--r--MediaBrowser.Controller/Drawing/ImageManager.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs73
-rw-r--r--MediaBrowser.Controller/Library/DtoBuilder.cs13
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs15
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj6
-rw-r--r--MediaBrowser.Controller/MediaInfo/ffmpeg20130209.zip.REMOVED.git-id1
-rw-r--r--MediaBrowser.Controller/MediaInfo/ffmpeg20130310.zip.REMOVED.git-id1
-rw-r--r--MediaBrowser.Controller/Sorting/BaseItemComparer.cs248
-rw-r--r--MediaBrowser.Controller/Sorting/IBaseItemComparer.cs17
-rw-r--r--MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs16
-rw-r--r--MediaBrowser.Controller/Sorting/SortOrder.cs33
-rw-r--r--MediaBrowser.Installer/App.xaml.cs8
-rw-r--r--MediaBrowser.Installer/MediaBrowser.Installer.csproj4
-rw-r--r--MediaBrowser.Model/DTO/BaseItemDto.cs82
-rw-r--r--MediaBrowser.Model/DTO/ItemSortBy.cs42
-rw-r--r--MediaBrowser.Model/DTO/MediaType.cs22
-rw-r--r--MediaBrowser.Model/Entities/ImageType.cs2
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj13
-rw-r--r--MediaBrowser.Model/PropertyChanged.xml54
-rw-r--r--MediaBrowser.Model/Querying/ItemFields.cs (renamed from MediaBrowser.Model/DTO/ItemFields.cs)7
-rw-r--r--MediaBrowser.Model/Querying/ItemFilter.cs (renamed from MediaBrowser.Model/DTO/ItemFilter.cs)2
-rw-r--r--MediaBrowser.Model/Querying/ItemQuery.cs (renamed from MediaBrowser.Model/DTO/ItemQuery.cs)13
-rw-r--r--MediaBrowser.Model/Querying/ItemSortBy.cs54
-rw-r--r--MediaBrowser.Model/Querying/ItemsByNameQuery.cs (renamed from MediaBrowser.Model/Dto/ItemsByNameQuery.cs)8
-rw-r--r--MediaBrowser.Model/Querying/ItemsResult.cs (renamed from MediaBrowser.Model/DTO/ItemsResult.cs)5
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs14
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs177
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs23
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs69
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj12
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs46
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs46
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs46
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs29
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs56
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs52
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs52
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs32
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Udp/UdpServer.cs5
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs51
-rw-r--r--MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs63
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj5
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfxbin1676 -> 0 bytes
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs23
-rw-r--r--MediaBrowser.WebDashboard/ApiClient.js (renamed from MediaBrowser.Api/Javascript/ApiClient.js)0
-rw-r--r--MediaBrowser.WebDashboard/Html/advancedMetadata.html7
-rw-r--r--MediaBrowser.WebDashboard/Html/metadata.html17
-rw-r--r--MediaBrowser.WebDashboard/Html/metadataImages.html137
-rw-r--r--MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js10
-rw-r--r--MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js8
-rw-r--r--MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js8
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj1
-rw-r--r--MediaBrowser.WebDashboard/packages.config1
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
74 files changed, 1343 insertions, 1124 deletions
diff --git a/MediaBrowser.Api/Javascript/JavascriptApiClientService.cs b/MediaBrowser.Api/Javascript/JavascriptApiClientService.cs
deleted file mode 100644
index 5ea6f3ebe..000000000
--- a/MediaBrowser.Api/Javascript/JavascriptApiClientService.cs
+++ /dev/null
@@ -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"));
- }
- }
-}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index ae15500df..f0633c4b6 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Server.Implementations.HttpServer;
using ServiceStack.ServiceHost;
using System;
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 8444dc46c..fc02410cc 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -85,7 +85,6 @@
<Compile Include="Images\ImageRequest.cs" />
<Compile Include="Images\ImageService.cs" />
<Compile Include="Images\ImageWriter.cs" />
- <Compile Include="Javascript\JavascriptApiClientService.cs" />
<Compile Include="Library\LibraryHelpers.cs" />
<Compile Include="Library\LibraryService.cs" />
<Compile Include="Library\LibraryStructureService.cs" />
@@ -107,6 +106,7 @@
<Compile Include="ApiEntryPoint.cs" />
<Compile Include="SystemService.cs" />
<Compile Include="UserLibrary\BaseItemsByNameService.cs" />
+ <Compile Include="UserLibrary\BaseItemsRequest.cs" />
<Compile Include="UserLibrary\GenresService.cs" />
<Compile Include="UserLibrary\ItemsService.cs" />
<Compile Include="UserLibrary\PersonsService.cs" />
@@ -141,7 +141,6 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
- <EmbeddedResource Include="Javascript\ApiClient.js" />
<Content Include="options.xml" />
</ItemGroup>
<ItemGroup />
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index f22a9e09b..570c6eea0 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Server.Implementations.HttpServer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -14,7 +15,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Server.Implementations.HttpServer;
namespace MediaBrowser.Api.Playback
{
@@ -650,10 +650,8 @@ namespace MediaBrowser.Api.Playback
state.VideoStream = GetMediaStream(media.MediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video, true);
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;
}
diff --git a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
index ecdab94b3..98033c057 100644
--- a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
@@ -18,8 +18,8 @@ namespace MediaBrowser.Api.Playback.Hls
}
- [Route("/Audio/{Id}/segments/{SegmentId}.mp3", "GET")]
- [Route("/Audio/{Id}/segments/{SegmentId}.aac", "GET")]
+ [Route("/Audio/{Id}/segments/{SegmentId}/stream.mp3", "GET")]
+ [Route("/Audio/{Id}/segments/{SegmentId}/stream.aac", "GET")]
[ServiceStack.ServiceHost.Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
public class GetHlsAudioSegment
{
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 1fb8a504f..c27219bbf 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -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
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
fileText = fileText.Replace("#EXT-X-TARGETDURATION:9", "#EXT-X-TARGETDURATION:10");
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index dfbed538f..578eb93ac 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -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.")]
public class GetHlsVideoSegment
{
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 251cd4bd6..a4acc2845 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -135,11 +135,7 @@ namespace MediaBrowser.Api.Playback.Progressive
ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
}
- return new ProgressiveStreamWriter
- {
- Path = outputPath,
- State = state
- };
+ return new ProgressiveStreamWriter(outputPath, state, Logger);
}
/// <summary>
diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
index e9e134002..efab3bbc6 100644
--- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
+++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
@@ -9,9 +9,22 @@ namespace MediaBrowser.Api.Playback.Progressive
{
public class ProgressiveStreamWriter : IStreamWriter
{
- public string Path { get; set; }
- public StreamState State { get; set; }
- public ILogger Logger { get; set; }
+ private string Path { get; set; }
+ private StreamState State { 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>
/// Writes to.
@@ -38,6 +51,8 @@ namespace MediaBrowser.Api.Playback.Progressive
catch (Exception ex)
{
Logger.ErrorException("Error streaming media", ex);
+
+ throw;
}
finally
{
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index d8ffa61fd..10455c028 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -20,6 +20,7 @@ namespace MediaBrowser.Api.Playback.Progressive
[Route("/Videos/{Id}/stream.mkv", "GET")]
[Route("/Videos/{Id}/stream.mpeg", "GET")]
[Route("/Videos/{Id}/stream.avi", "GET")]
+ [Route("/Videos/{Id}/stream.m2ts", "GET")]
[Route("/Videos/{Id}/stream", "GET")]
[ServiceStack.ServiceHost.Api(Description = "Gets a video stream")]
public class GetVideoStream : VideoStreamRequest
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 975f8bdfe..5fb2097cd 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -1,7 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Server.Implementations.HttpServer;
using ServiceStack.ServiceHost;
using System;
@@ -23,12 +23,16 @@ namespace MediaBrowser.Api.UserLibrary
/// The _user manager
/// </summary>
protected readonly IUserManager UserManager;
+ /// <summary>
+ /// The library manager
+ /// </summary>
protected readonly ILibraryManager LibraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
/// </summary>
/// <param name="userManager">The user manager.</param>
+ /// <param name="libraryManager">The library manager.</param>
protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager)
{
UserManager = userManager;
@@ -44,7 +48,7 @@ namespace MediaBrowser.Api.UserLibrary
{
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;
@@ -157,54 +161,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetItemsByName
/// </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; }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
new file mode 100644
index 000000000..ed1beab6f
--- /dev/null
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -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; }
+ }
+}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 92f267a21..ff062c183 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -1,8 +1,7 @@
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Server.Implementations.HttpServer;
using ServiceStack.ServiceHost;
using System;
@@ -17,44 +16,9 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
[Route("/Users/{UserId}/Items", "GET")]
[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>
/// Limit results to items containing a specific person
/// </summary>
/// <value>The person.</value>
@@ -82,40 +46,20 @@ namespace MediaBrowser.Api.UserLibrary
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>
/// What to sort the results by
/// </summary>
/// <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; }
/// <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>
/// Filters to apply to the results
/// </summary>
/// <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; }
/// <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>
/// Limit results to items containing specific genres
/// </summary>
/// <value>The genres.</value>
@@ -254,7 +198,7 @@ namespace MediaBrowser.Api.UserLibrary
return ((Folder)item).GetRecursiveChildren(user);
}
- return ((Folder)item).GetChildren(user, request.IndexBy, request.DynamicSortBy, GetSortOrder(request));
+ return ((Folder)item).GetChildren(user, request.IndexBy);
}
/// <summary>
@@ -266,58 +210,9 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<BaseItem> ApplySortOrder(GetItems request, IEnumerable<BaseItem> items, User user)
{
- var isFirst = true;
- var descending = (GetSortOrder(request) ?? SortOrder.Ascending) == SortOrder.Descending;
-
- IOrderedEnumerable<BaseItem> orderedItems = null;
+ var orderBy = GetOrderBy(request).ToArray();
- 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();
- }
+ return orderBy.Length == 0 ? items : _libraryManager.Sort(items, user, orderBy, request.SortOrder ?? SortOrder.Ascending);
}
/// <summary>
@@ -465,7 +360,7 @@ namespace MediaBrowser.Api.UserLibrary
return item.ScreenshotImagePaths != null && item.ScreenshotImagePaths.Count > 0;
}
- if (imageType == ImageType.ChapterImage)
+ if (imageType == ImageType.Chapter)
{
var video = item as Video;
@@ -522,21 +417,6 @@ namespace MediaBrowser.Api.UserLibrary
}
/// <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>
/// Gets the filters.
/// </summary>
/// <param name="request">The request.</param>
@@ -575,16 +455,16 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <returns>IEnumerable{ItemSortBy}.</returns>
- private IEnumerable<ItemSortBy> GetOrderBy(GetItems request)
+ private IEnumerable<string> GetOrderBy(GetItems request)
{
var val = request.SortBy;
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>
@@ -621,201 +501,4 @@ namespace MediaBrowser.Api.UserLibrary
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;
- }
- }
}
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 1182dbb05..88b7dc57c 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Connectivity;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Server.Implementations.HttpServer;
using ServiceStack.ServiceHost;
using ServiceStack.Text.Controller;
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index a9c73d0e9..1950c1428 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -13,7 +13,6 @@ using MediaBrowser.Common.Security;
using MediaBrowser.Common.Updates;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.System;
using MediaBrowser.Model.Updates;
using SimpleInjector;
using System;
@@ -26,6 +25,10 @@ using System.Threading.Tasks;
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
where TApplicationPathsType : class, IApplicationPaths, new()
{
@@ -87,6 +90,7 @@ namespace MediaBrowser.Common.Implementations
/// <summary>
/// Gets assemblies that failed to load
/// </summary>
+ /// <value>The failed assemblies.</value>
public List<string> FailedAssemblies { get; protected set; }
/// <summary>
@@ -148,11 +152,31 @@ namespace MediaBrowser.Common.Implementations
/// </summary>
/// <value>The kernel.</value>
protected ITaskManager TaskManager { get; private set; }
+ /// <summary>
+ /// Gets the security manager.
+ /// </summary>
+ /// <value>The security manager.</value>
protected ISecurityManager SecurityManager { get; private set; }
+ /// <summary>
+ /// Gets the package manager.
+ /// </summary>
+ /// <value>The package manager.</value>
protected IPackageManager PackageManager { get; private set; }
+ /// <summary>
+ /// Gets the HTTP client.
+ /// </summary>
+ /// <value>The HTTP client.</value>
protected IHttpClient HttpClient { get; private set; }
+ /// <summary>
+ /// Gets the network manager.
+ /// </summary>
+ /// <value>The network manager.</value>
protected INetworkManager NetworkManager { get; private set; }
+ /// <summary>
+ /// Gets the configuration manager.
+ /// </summary>
+ /// <value>The configuration manager.</value>
protected IConfigurationManager ConfigurationManager { get; private set; }
/// <summary>
@@ -187,7 +211,21 @@ namespace MediaBrowser.Common.Implementations
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>
@@ -202,6 +240,10 @@ namespace MediaBrowser.Common.Implementations
/// <value>The name of the log file prefix.</value>
protected abstract string LogFilePrefixName { get; }
+ /// <summary>
+ /// Gets the configuration manager.
+ /// </summary>
+ /// <returns>IConfigurationManager.</returns>
protected abstract IConfigurationManager GetConfigurationManager();
/// <summary>
@@ -210,8 +252,6 @@ namespace MediaBrowser.Common.Implementations
protected virtual void FindParts()
{
Plugins = GetExports<IPlugin>();
-
- Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
}
/// <summary>
@@ -236,6 +276,7 @@ namespace MediaBrowser.Common.Implementations
/// <summary>
/// Registers resources that classes will depend on
/// </summary>
+ /// <returns>Task.</returns>
protected virtual Task RegisterResources()
{
return Task.Run(() =>
@@ -509,10 +550,23 @@ namespace MediaBrowser.Common.Implementations
}
}
+ /// <summary>
+ /// Restarts this instance.
+ /// </summary>
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; }
+ /// <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);
/// <summary>
@@ -529,6 +583,9 @@ namespace MediaBrowser.Common.Implementations
EventHelper.QueueEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs<Version> { Argument = package.version }, Logger);
}
+ /// <summary>
+ /// Shuts down.
+ /// </summary>
public abstract void Shutdown();
}
}
diff --git a/MediaBrowser.Controller/Drawing/ImageManager.cs b/MediaBrowser.Controller/Drawing/ImageManager.cs
index d95f72df7..3c6f845e5 100644
--- a/MediaBrowser.Controller/Drawing/ImageManager.cs
+++ b/MediaBrowser.Controller/Drawing/ImageManager.cs
@@ -356,7 +356,7 @@ namespace MediaBrowser.Controller.Drawing
return item.ScreenshotImagePaths[imageIndex];
}
- if (imageType == ImageType.ChapterImage)
+ if (imageType == ImageType.Chapter)
{
var video = (Video)item;
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index c6f479029..ef34742df 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -13,7 +13,6 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
-using SortOrder = MediaBrowser.Controller.Sorting.SortOrder;
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
/// <summary>
@@ -877,11 +819,9 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="user">The user.</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>
/// <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)
{
@@ -889,7 +829,7 @@ namespace MediaBrowser.Controller.Entities
}
//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;
@@ -904,14 +844,7 @@ namespace MediaBrowser.Controller.Entities
result = ActualChildren.Where(c => c.IsVisible(user));
}
- if (string.IsNullOrEmpty(sortBy))
- {
- return result;
- }
-
- return sortOrder.HasValue && sortOrder.Value == Model.Entities.SortOrder.Descending
- ? result.OrderByDescending(i => i, GetSortingFunction(sortBy))
- : result.OrderBy(i => i, GetSortingFunction(sortBy));
+ return result;
}
/// <summary>
diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs
index b8e775e97..fcd3e68aa 100644
--- a/MediaBrowser.Controller/Library/DtoBuilder.cs
+++ b/MediaBrowser.Controller/Library/DtoBuilder.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Library
{
@@ -160,8 +161,6 @@ namespace MediaBrowser.Controller.Library
/// <param name="fields">The fields.</param>
private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields)
{
- dto.IsNew = item.IsRecentlyAdded(user);
-
if (fields.Contains(ItemFields.UserData))
{
var userData = item.GetUserData(user, false);
@@ -366,18 +365,10 @@ namespace MediaBrowser.Controller.Library
{
var folder = (Folder)item;
- dto.IsRoot = folder.IsRoot;
- dto.IsVirtualFolder = folder.IsVirtualFolder;
-
if (fields.Contains(ItemFields.IndexOptions))
{
dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
}
-
- if (fields.Contains(ItemFields.SortOptions))
- {
- dto.SortOptions = folder.SortByOptionStrings.ToArray();
- }
}
// Add audio info
@@ -678,7 +669,7 @@ namespace MediaBrowser.Controller.Library
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;
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 3f1930209..40131b6d2 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
@@ -158,7 +159,19 @@ namespace MediaBrowser.Controller.Library
/// <param name="pluginFolders">The plugin folders.</param>
/// <param name="resolvers">The resolvers.</param>
/// <param name="introProviders">The intro providers.</param>
+ /// <param name="itemComparers">The item comparers.</param>
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);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 5ae6cccac..89353b2ef 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -185,8 +185,8 @@
<Compile Include="Providers\FolderProviderFromXml.cs" />
<Compile Include="Providers\ImageFromMediaLocationProvider.cs" />
<Compile Include="Providers\MediaInfo\FFProbeVideoInfoProvider.cs" />
- <Compile Include="Sorting\BaseItemComparer.cs" />
- <Compile Include="Sorting\SortOrder.cs" />
+ <Compile Include="Sorting\IBaseItemComparer.cs" />
+ <Compile Include="Sorting\IUserBaseItemComparer.cs" />
<Compile Include="Updates\IInstallationManager.cs" />
<Compile Include="Weather\IWeatherProvider.cs" />
<Compile Include="Providers\BaseItemXmlParser.cs" />
@@ -202,7 +202,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <EmbeddedResource Include="MediaInfo\ffmpeg20130209.zip" />
+ <EmbeddedResource Include="MediaInfo\ffmpeg20130310.zip" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
diff --git a/MediaBrowser.Controller/MediaInfo/ffmpeg20130209.zip.REMOVED.git-id b/MediaBrowser.Controller/MediaInfo/ffmpeg20130209.zip.REMOVED.git-id
deleted file mode 100644
index 307afc51c..000000000
--- a/MediaBrowser.Controller/MediaInfo/ffmpeg20130209.zip.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-985770c0d2633a13719be2e5cf19554262415f62 \ No newline at end of file
diff --git a/MediaBrowser.Controller/MediaInfo/ffmpeg20130310.zip.REMOVED.git-id b/MediaBrowser.Controller/MediaInfo/ffmpeg20130310.zip.REMOVED.git-id
new file mode 100644
index 000000000..830011a04
--- /dev/null
+++ b/MediaBrowser.Controller/MediaInfo/ffmpeg20130310.zip.REMOVED.git-id
@@ -0,0 +1 @@
+a005e50576665b191cbd02b42d6260bffb764690 \ No newline at end of file
diff --git a/MediaBrowser.Controller/Sorting/BaseItemComparer.cs b/MediaBrowser.Controller/Sorting/BaseItemComparer.cs
deleted file mode 100644
index 94c16775d..000000000
--- a/MediaBrowser.Controller/Sorting/BaseItemComparer.cs
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs
new file mode 100644
index 000000000..6d0b95bcb
--- /dev/null
+++ b/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs
@@ -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; }
+ }
+}
diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs
new file mode 100644
index 000000000..b9da1f6a6
--- /dev/null
+++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs
@@ -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; }
+ }
+}
diff --git a/MediaBrowser.Controller/Sorting/SortOrder.cs b/MediaBrowser.Controller/Sorting/SortOrder.cs
deleted file mode 100644
index 3152ac67e..000000000
--- a/MediaBrowser.Controller/Sorting/SortOrder.cs
+++ /dev/null
@@ -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
- }
-}
diff --git a/MediaBrowser.Installer/App.xaml.cs b/MediaBrowser.Installer/App.xaml.cs
index a7c1681e8..3e1230d44 100644
--- a/MediaBrowser.Installer/App.xaml.cs
+++ b/MediaBrowser.Installer/App.xaml.cs
@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Configuration;
-using System.Data;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Windows;
+using System.Windows;
namespace MediaBrowser.Installer
{
diff --git a/MediaBrowser.Installer/MediaBrowser.Installer.csproj b/MediaBrowser.Installer/MediaBrowser.Installer.csproj
index 473e8d37a..470a18463 100644
--- a/MediaBrowser.Installer/MediaBrowser.Installer.csproj
+++ b/MediaBrowser.Installer/MediaBrowser.Installer.csproj
@@ -87,15 +87,11 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
- <Reference Include="System.Data" />
<Reference Include="System.Drawing" />
- <Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
- <Reference Include="System.Xml.Linq" />
- <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
diff --git a/MediaBrowser.Model/DTO/BaseItemDto.cs b/MediaBrowser.Model/DTO/BaseItemDto.cs
index 971b0bde7..5b63f588c 100644
--- a/MediaBrowser.Model/DTO/BaseItemDto.cs
+++ b/MediaBrowser.Model/DTO/BaseItemDto.cs
@@ -155,20 +155,6 @@ namespace MediaBrowser.Model.Dto
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>
/// Gets or sets the parent id.
/// </summary>
/// <value>The parent id.</value>
@@ -232,13 +218,6 @@ namespace MediaBrowser.Model.Dto
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>
/// Gets or sets the recently added item count.
/// </summary>
/// <value>The recently added item count.</value>
@@ -316,13 +295,6 @@ namespace MediaBrowser.Model.Dto
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>
/// Gets or sets the index options.
/// </summary>
/// <value>The index options.</value>
@@ -399,26 +371,6 @@ namespace MediaBrowser.Model.Dto
}
/// <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>
/// Gets or sets the image tags.
/// </summary>
/// <value>The image tags.</value>
@@ -475,6 +427,26 @@ namespace MediaBrowser.Model.Dto
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>
/// Gets the backdrop count.
/// </summary>
/// <value>The backdrop count.</value>
@@ -604,6 +576,10 @@ namespace MediaBrowser.Model.Dto
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]
public bool IsPerson
{
@@ -611,6 +587,16 @@ namespace MediaBrowser.Model.Dto
}
/// <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>
/// Occurs when [property changed].
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
diff --git a/MediaBrowser.Model/DTO/ItemSortBy.cs b/MediaBrowser.Model/DTO/ItemSortBy.cs
deleted file mode 100644
index 30cd1c3a4..000000000
--- a/MediaBrowser.Model/DTO/ItemSortBy.cs
+++ /dev/null
@@ -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
- }
-}
diff --git a/MediaBrowser.Model/DTO/MediaType.cs b/MediaBrowser.Model/DTO/MediaType.cs
deleted file mode 100644
index eae97e616..000000000
--- a/MediaBrowser.Model/DTO/MediaType.cs
+++ /dev/null
@@ -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
- }
-}
diff --git a/MediaBrowser.Model/Entities/ImageType.cs b/MediaBrowser.Model/Entities/ImageType.cs
index aaae8dda3..8ad1090b8 100644
--- a/MediaBrowser.Model/Entities/ImageType.cs
+++ b/MediaBrowser.Model/Entities/ImageType.cs
@@ -49,6 +49,6 @@ namespace MediaBrowser.Model.Entities
/// <summary>
/// The chapter image
/// </summary>
- ChapterImage
+ Chapter
}
}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 6c2a62f91..36f585e5c 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -45,8 +45,7 @@
<Compile Include="Dto\BaseItemPerson.cs" />
<Compile Include="Dto\ChapterInfoDto.cs" />
<Compile Include="Dto\IItemDto.cs" />
- <Compile Include="Dto\ItemsByNameQuery.cs" />
- <Compile Include="Dto\MediaType.cs" />
+ <Compile Include="Querying\ItemsByNameQuery.cs" />
<Compile Include="Entities\BaseItemInfo.cs" />
<Compile Include="Connectivity\ClientConnectionInfo.cs" />
<Compile Include="Connectivity\ClientType.cs" />
@@ -63,8 +62,8 @@
<Compile Include="Globalization\CultureDto.cs" />
<Compile Include="IO\FileSystemEntryInfo.cs" />
<Compile Include="Dto\ImageOptions.cs" />
- <Compile Include="Dto\ItemFilter.cs" />
- <Compile Include="Dto\ItemQuery.cs" />
+ <Compile Include="Querying\ItemFilter.cs" />
+ <Compile Include="Querying\ItemQuery.cs" />
<Compile Include="Entities\LibraryUpdateInfo.cs" />
<Compile Include="Entities\ParentalRating.cs" />
<Compile Include="Dto\StreamOptions.cs" />
@@ -90,11 +89,11 @@
<Compile Include="Configuration\UserConfiguration.cs" />
<Compile Include="Drawing\DrawingUtils.cs" />
<Compile Include="Dto\UserItemDataDto.cs" />
- <Compile Include="Dto\ItemFields.cs" />
- <Compile Include="Dto\ItemSortBy.cs" />
+ <Compile Include="Querying\ItemFields.cs" />
+ <Compile Include="Querying\ItemSortBy.cs" />
<Compile Include="Dto\BaseItemDto.cs" />
<Compile Include="Dto\UserDto.cs" />
- <Compile Include="Dto\ItemsResult.cs" />
+ <Compile Include="Querying\ItemsResult.cs" />
<Compile Include="Entities\DisplayPreferences.cs" />
<Compile Include="Entities\ImageType.cs" />
<Compile Include="Entities\IHasProviderIds.cs" />
diff --git a/MediaBrowser.Model/PropertyChanged.xml b/MediaBrowser.Model/PropertyChanged.xml
new file mode 100644
index 000000000..e69755cf4
--- /dev/null
+++ b/MediaBrowser.Model/PropertyChanged.xml
@@ -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>
diff --git a/MediaBrowser.Model/DTO/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs
index a24c8a8f0..8cf9796c0 100644
--- a/MediaBrowser.Model/DTO/ItemFields.cs
+++ b/MediaBrowser.Model/Querying/ItemFields.cs
@@ -1,5 +1,5 @@

-namespace MediaBrowser.Model.Dto
+namespace MediaBrowser.Model.Querying
{
/// <summary>
/// Used to control the data that gets attached to DtoBaseItems
@@ -87,11 +87,6 @@ namespace MediaBrowser.Model.Dto
SortName,
/// <summary>
- /// The fields that the server supports sorting on
- /// </summary>
- SortOptions,
-
- /// <summary>
/// The studios of the item
/// </summary>
Studios,
diff --git a/MediaBrowser.Model/DTO/ItemFilter.cs b/MediaBrowser.Model/Querying/ItemFilter.cs
index 038acc587..9c7f139a8 100644
--- a/MediaBrowser.Model/DTO/ItemFilter.cs
+++ b/MediaBrowser.Model/Querying/ItemFilter.cs
@@ -1,5 +1,5 @@

-namespace MediaBrowser.Model.Dto
+namespace MediaBrowser.Model.Querying
{
/// <summary>
/// Enum ItemFilter
diff --git a/MediaBrowser.Model/DTO/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs
index 6d64a093b..3b320a011 100644
--- a/MediaBrowser.Model/DTO/ItemQuery.cs
+++ b/MediaBrowser.Model/Querying/ItemQuery.cs
@@ -1,7 +1,8 @@
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
using System;
-namespace MediaBrowser.Model.Dto
+namespace MediaBrowser.Model.Querying
{
/// <summary>
/// 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
/// </summary>
/// <value>The sort by.</value>
- public ItemSortBy[] SortBy { get; set; }
+ public string[] SortBy { get; set; }
/// <summary>
/// The sort order to return results with
@@ -117,12 +118,6 @@ namespace MediaBrowser.Model.Dto
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>
/// Gets or sets the image types.
/// </summary>
/// <value>The image types.</value>
diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs
new file mode 100644
index 000000000..9599e2aac
--- /dev/null
+++ b/MediaBrowser.Model/Querying/ItemSortBy.cs
@@ -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";
+ }
+}
diff --git a/MediaBrowser.Model/Dto/ItemsByNameQuery.cs b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs
index a10b29012..35964aea3 100644
--- a/MediaBrowser.Model/Dto/ItemsByNameQuery.cs
+++ b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs
@@ -1,7 +1,7 @@
using MediaBrowser.Model.Entities;
using System;
-namespace MediaBrowser.Model.Dto
+namespace MediaBrowser.Model.Querying
{
/// <summary>
/// Class ItemsByNameQuery
@@ -34,10 +34,10 @@ namespace MediaBrowser.Model.Dto
/// <value>The sort order.</value>
public SortOrder? SortOrder { get; set; }
/// <summary>
- /// If specified the search will be localized within a specific item or folder
+ /// Gets or sets the parent id.
/// </summary>
- /// <value>The item id.</value>
- public string ItemId { get; set; }
+ /// <value>The parent id.</value>
+ public string ParentId { get; set; }
/// <summary>
/// Fields to return within the items, in addition to basic information
/// </summary>
diff --git a/MediaBrowser.Model/DTO/ItemsResult.cs b/MediaBrowser.Model/Querying/ItemsResult.cs
index 623e04fdd..f8393b7fc 100644
--- a/MediaBrowser.Model/DTO/ItemsResult.cs
+++ b/MediaBrowser.Model/Querying/ItemsResult.cs
@@ -1,6 +1,7 @@
-using ProtoBuf;
+using MediaBrowser.Model.Dto;
+using ProtoBuf;
-namespace MediaBrowser.Model.Dto
+namespace MediaBrowser.Model.Querying
{
/// <summary>
/// Represents the result of a query for items
diff --git a/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs b/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs
index cdb6adbe7..0445cd863 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Extensions;
+using System.Net;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Logging;
@@ -257,7 +258,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer
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;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
new file mode 100644
index 000000000..e5c4c9796
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -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);
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
index ab178b6ea..6f5d6e25f 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
@@ -1,4 +1,6 @@
-using ServiceStack.Service;
+using MediaBrowser.Model.Logging;
+using ServiceStack.Service;
+using System;
using System.IO;
using System.Threading.Tasks;
@@ -9,6 +11,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// </summary>
public class StreamWriter : IStreamWriter
{
+ private ILogger Logger { get; set; }
+
/// <summary>
/// Gets or sets the source stream.
/// </summary>
@@ -19,9 +23,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
/// </summary>
/// <param name="source">The source.</param>
- public StreamWriter(Stream source)
+ /// <param name="logger">The logger.</param>
+ public StreamWriter(Stream source, ILogger logger)
{
SourceStream = source;
+ Logger = logger;
}
/// <summary>
@@ -42,9 +48,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <returns>Task.</returns>
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;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 78ada1431..6cd46a310 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.ScheduledTasks;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Implementations.Library.Resolvers;
@@ -22,6 +23,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using SortOrder = MediaBrowser.Model.Entities.SortOrder;
namespace MediaBrowser.Server.Implementations.Library
{
@@ -54,6 +56,12 @@ namespace MediaBrowser.Server.Implementations.Library
/// <value>The entity resolvers enumerable.</value>
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
/// <summary>
/// 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="resolvers">The resolvers.</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;
PluginFolderCreators = pluginFolders;
EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
IntroProviders = introProviders;
+ Comparers = itemComparers;
}
/// <summary>
@@ -702,5 +712,62 @@ namespace MediaBrowser.Server.Implementations.Library
{
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;
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 0b9f7c7e1..2bb75a18d 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -109,6 +109,7 @@
<Compile Include="HttpServer\HttpResultFactory.cs" />
<Compile Include="HttpServer\HttpServer.cs" />
<Compile Include="HttpServer\NativeWebSocket.cs" />
+ <Compile Include="HttpServer\RangeRequestWriter.cs" />
<Compile Include="HttpServer\ServerFactory.cs" />
<Compile Include="HttpServer\StreamWriter.cs" />
<Compile Include="HttpServer\SwaggerService.cs" />
@@ -139,6 +140,17 @@
<Compile Include="ServerApplicationPaths.cs" />
<Compile Include="ServerManager\ServerManager.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\SQLiteExtensions.cs" />
<Compile Include="Sqlite\SQLiteItemRepository.cs" />
diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs
new file mode 100644
index 000000000..2493c0fc6
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs
new file mode 100644
index 000000000..f455d5c2b
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.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 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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs
new file mode 100644
index 000000000..c34f096a2
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.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 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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs
new file mode 100644
index 000000000..bdd18a648
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs
@@ -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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs
new file mode 100644
index 000000000..9862f0a8a
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs
@@ -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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
new file mode 100644
index 000000000..db7e455c7
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
@@ -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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs
new file mode 100644
index 000000000..fcbc58987
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs
@@ -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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs
new file mode 100644
index 000000000..16d531334
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs
@@ -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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs
new file mode 100644
index 000000000..b1677331a
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs
@@ -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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs
new file mode 100644
index 000000000..793cb265e
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs
@@ -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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs
new file mode 100644
index 000000000..873753a2b
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs
@@ -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; }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs
index c6869c12d..8315b2000 100644
--- a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs
+++ b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs
@@ -127,7 +127,10 @@ namespace MediaBrowser.Server.Implementations.Udp
/// </summary>
public void Stop()
{
- _udpClient.Close();
+ if (_udpClient != null)
+ {
+ _udpClient.Close();
+ }
}
/// <summary>
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index c822aae84..d5a505792 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -18,6 +18,7 @@ using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Updates;
using MediaBrowser.Controller.Weather;
using MediaBrowser.IsoMounter;
@@ -126,23 +127,21 @@ namespace MediaBrowser.ServerApplication
/// </summary>
/// <value>The HTTP server.</value>
private IHttpServer HttpServer { get; set; }
-
+
/// <summary>
- /// Inits this instance.
+ /// Runs the startup tasks.
/// </summary>
/// <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 ServerKernel.LoadRepositories(ServerConfigurationManager).ConfigureAwait(false);
+ await base.RunStartupTasks().ConfigureAwait(false);
- DirectoryWatchers.Start();
+ DirectoryWatchers.Start();
- Parallel.ForEach(GetExports<IServerEntryPoint>(), entryPoint => entryPoint.Run());
- });
+ Parallel.ForEach(GetExports<IServerEntryPoint>(), entryPoint => entryPoint.Run());
}
/// <summary>
@@ -205,13 +204,15 @@ namespace MediaBrowser.ServerApplication
ServerKernel.FFMpegManager = new FFMpegManager(ServerKernel, ZipClient, JsonSerializer, ProtobufSerializer, LogManager, ApplicationPaths);
ServerKernel.ImageManager = new ImageManager(ServerKernel, ProtobufSerializer, LogManager.GetLogger("ImageManager"), ApplicationPaths);
- ServerKernel.UserDataRepositories = GetExports<IUserDataRepository>();
- ServerKernel.UserRepositories = GetExports<IUserRepository>();
- ServerKernel.DisplayPreferencesRepositories = GetExports<IDisplayPreferencesRepository>();
- ServerKernel.ItemRepositories = GetExports<IItemRepository>();
- ServerKernel.WeatherProviders = GetExports<IWeatherProvider>();
- ServerKernel.ImageEnhancers = GetExports<IImageEnhancer>().OrderBy(e => e.Priority).ToArray();
- ServerKernel.StringFiles = GetExports<LocalizedStringData>();
+ Parallel.Invoke(
+ () => ServerKernel.UserDataRepositories = GetExports<IUserDataRepository>(),
+ () => ServerKernel.UserRepositories = GetExports<IUserRepository>(),
+ () => ServerKernel.DisplayPreferencesRepositories = GetExports<IDisplayPreferencesRepository>(),
+ () => ServerKernel.ItemRepositories = GetExports<IItemRepository>(),
+ () => ServerKernel.WeatherProviders = GetExports<IWeatherProvider>(),
+ () => ServerKernel.ImageEnhancers = GetExports<IImageEnhancer>().OrderBy(e => e.Priority).ToArray(),
+ () => ServerKernel.StringFiles = GetExports<LocalizedStringData>()
+ );
}
/// <summary>
@@ -237,14 +238,20 @@ namespace MediaBrowser.ServerApplication
{
base.FindParts();
- HttpServer.Init(GetExports<IRestfulService>(false));
+ Parallel.Invoke(
+
+ () =>
+ {
+ HttpServer.Init(GetExports<IRestfulService>(false));
- ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false));
- ServerManager.Start();
+ ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false));
+ 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>
diff --git a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
index d567a9fd8..1968bbc7d 100644
--- a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
+++ b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
@@ -4,8 +4,10 @@ using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
@@ -78,7 +80,8 @@ namespace MediaBrowser.ServerApplication
Cursor = Cursors.Wait;
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)
{
@@ -86,9 +89,12 @@ namespace MediaBrowser.ServerApplication
var currentFolder = folder;
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 };
- 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.Items.Count + ")";
tvwLibrary.Items.Add(node);
@@ -101,6 +107,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>
/// Adds the children.
/// </summary>
/// <param name="parent">The parent.</param>
@@ -115,7 +143,7 @@ namespace MediaBrowser.ServerApplication
if (subFolder != null)
{
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 + ")";
}
else
@@ -152,14 +180,29 @@ namespace MediaBrowser.ServerApplication
{
lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Visible;
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);
ddlIndexBy.SelectedItem = prefs != null
? prefs.IndexBy ?? LocalizedStrings.Instance.GetString("NoneDispPref")
: LocalizedStrings.Instance.GetString("NoneDispPref");
ddlSortBy.SelectedItem = prefs != null
- ? prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")
- : LocalizedStrings.Instance.GetString("NameDispPref");
+ ? prefs.SortBy ?? ItemSortBy.SortName
+ : ItemSortBy.SortName;
}
else
{
@@ -311,7 +354,7 @@ namespace MediaBrowser.ServerApplication
var folder = treeItem != null
? treeItem.Tag as Folder
: 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)
{
//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
prefs.IndexBy = ddlIndexBy.SelectedItem as string;
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.Items.Count + ")";
Cursor = Cursors.Arrow;
@@ -367,7 +410,7 @@ namespace MediaBrowser.ServerApplication
//re-sort
prefs.SortBy = ddlSortBy.SelectedItem as string;
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.Items.Count + ")";
Cursor = Cursors.Arrow;
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index ec3137d83..88ef97950 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -76,7 +76,7 @@
</ManifestKeyFile>
</PropertyGroup>
<PropertyGroup>
- <GenerateManifests>true</GenerateManifests>
+ <GenerateManifests>false</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<SignManifests>false</SignManifests>
@@ -112,6 +112,9 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
+ <PropertyGroup>
+ <TargetZone>LocalIntranet</TargetZone>
+ </PropertyGroup>
<ItemGroup>
<Reference Include="Hardcodet.Wpf.TaskbarNotification">
<HintPath>..\packages\Hardcodet.Wpf.TaskbarNotification.1.0.4.0\lib\net40\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx
deleted file mode 100644
index 64676b054..000000000
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx
+++ /dev/null
Binary files differ
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 86e4c10ea..4c861c61b 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Extensions;
+using System.Reflection;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks;
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://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.js",
- "../jsapiclient.js" + versionString,
"scripts/all.js" + versionString
};
@@ -447,20 +447,27 @@ namespace MediaBrowser.WebDashboard.Api
var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
+ await AppendResource(assembly, memoryStream, "MediaBrowser.WebDashboard.ApiClient.js", newLineBytes).ConfigureAwait(false);
+
foreach (var file in scriptFiles)
{
- using (var stream = assembly.GetManifestResourceStream(resourcePrefix + file))
- {
- await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
- await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
- }
+ await AppendResource(assembly, memoryStream, resourcePrefix + file, newLineBytes).ConfigureAwait(false);
}
memoryStream.Position = 0;
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);
+ }
+ }
+
}
}
diff --git a/MediaBrowser.Api/Javascript/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js
index 31022de38..31022de38 100644
--- a/MediaBrowser.Api/Javascript/ApiClient.js
+++ b/MediaBrowser.WebDashboard/ApiClient.js
diff --git a/MediaBrowser.WebDashboard/Html/advancedMetadata.html b/MediaBrowser.WebDashboard/Html/advancedMetadata.html
index 60e02ba3c..6ea3d7e74 100644
--- a/MediaBrowser.WebDashboard/Html/advancedMetadata.html
+++ b/MediaBrowser.WebDashboard/Html/advancedMetadata.html
@@ -21,13 +21,10 @@
<label>Disable internet providers for:</label>
<div id="divItemTypes"></div>
</li>
- <li>
- <button type="submit" data-theme="b">
+ <li style="display: none;">
+ <button class="btnSubmit" type="submit" data-theme="b">
Save
</button>
- <button type="button" onclick="Dashboard.navigate('dashboard.html');">
- Cancel
- </button>
</li>
</ul>
</form>
diff --git a/MediaBrowser.WebDashboard/Html/metadata.html b/MediaBrowser.WebDashboard/Html/metadata.html
index 4618dd4bd..28fd7dedd 100644
--- a/MediaBrowser.WebDashboard/Html/metadata.html
+++ b/MediaBrowser.WebDashboard/Html/metadata.html
@@ -18,32 +18,29 @@
<form id="metadataConfigurationForm">
<ul data-role="listview" class="ulForm">
<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>
</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>
</li>
<li>
<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>
<label for="selectLanguage">Preferred language: </label>
- <select name="selectLanguage" id="selectLanguage"></select>
+ <select name="selectLanguage" id="selectLanguage" onchange="MetadataConfigurationPage.submit();"></select>
</li>
<li>
<label for="selectCountry">Country: </label>
- <select name="selectCountry" id="selectCountry"></select>
+ <select name="selectCountry" id="selectCountry" onchange="MetadataConfigurationPage.submit();"></select>
</li>
- <li>
- <button type="submit" data-theme="b">
+ <li style="display: none;">
+ <button class="btnSubmit" type="submit" data-theme="b">
Save
</button>
- <button type="button" onclick="Dashboard.navigate('dashboard.html');">
- Cancel
- </button>
</li>
</ul>
</form>
diff --git a/MediaBrowser.WebDashboard/Html/metadataImages.html b/MediaBrowser.WebDashboard/Html/metadataImages.html
index b06a3205b..0197af43d 100644
--- a/MediaBrowser.WebDashboard/Html/metadataImages.html
+++ b/MediaBrowser.WebDashboard/Html/metadataImages.html
@@ -18,7 +18,7 @@
<form id="metadataImagesConfigurationForm">
<ul data-role="listview" class="ulForm">
<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>
<div class="fieldDescription">
When enabled, images will be refreshed periodically
@@ -26,100 +26,100 @@
</li>
<li>
<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>
<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" />
- <label for="chkDownloadMovieBanner">Movie Banner</label>
+ <div data-role="collapsible">
+ <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" />
- <label for="chkDownloadMovieDisc">Movie Disc</label>
+ <input type="checkbox" data-mini="true" id="chkDownloadMovieBanner" name="chkDownloadMovieBanner" onchange="MetadataImagesPage.submit();" />
+ <label for="chkDownloadMovieBanner">Movie Banner</label>
- <input type="checkbox" data-mini="true" id="chkDownloadMovieLogo" name="chkDownloadMovieLogo" />
- <label for="chkDownloadMovieLogo">Movie Logo</label>
+ <input type="checkbox" data-mini="true" id="chkDownloadMovieDisc" name="chkDownloadMovieDisc" onchange="MetadataImagesPage.submit();" />
+ <label for="chkDownloadMovieDisc">Movie Disc</label>
+
+ <input type="checkbox" data-mini="true" id="chkDownloadMovieLogo" name="chkDownloadMovieLogo" onchange="MetadataImagesPage.submit();" />
+ <label for="chkDownloadMovieLogo">Movie Logo</label>
+
+ <input type="checkbox" data-mini="true" id="chkDownloadMovieThumb" name="chkDownloadMovieThumb" onchange="MetadataImagesPage.submit();" />
+ <label for="chkDownloadMovieThumb">Movie Thumb</label>
- <input type="checkbox" data-mini="true" id="chkDownloadMovieThumb" name="chkDownloadMovieThumb" />
- <label for="chkDownloadMovieThumb">Movie Thumb</label>
-
- </div>
</div>
+ </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>
+ <div data-role="collapsible">
+ <h3>TV Series</h3>
+ <div data-role="controlgroup">
+ <input type="checkbox" data-mini="true" id="chKDownloadTVArt" name="chKDownloadTVArt" onchange="MetadataImagesPage.submit();" />
+ <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="chkDownloadTVBanner" name="chkDownloadTVBanner" onchange="MetadataImagesPage.submit();" />
+ <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="chkDownloadTVLogo" name="chkDownloadTVLogo" onchange="MetadataImagesPage.submit();" />
+ <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>
+ <input type="checkbox" data-mini="true" id="chkDownloadTVThumb" name="chkDownloadTVThumb" onchange="MetadataImagesPage.submit();" />
+ <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>
+ <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="chkDownloadSeasonThumb" name="chkDownloadSeasonThumb" />
- <label for="chkDownloadSeasonThumb">TV Season Thumb</label>
- </div>
+ <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 data-role="collapsible">
- <h3>Music Artists</h3>
- <div data-role="controlgroup">
- <input type="checkbox" data-mini="true" id="chkDownloadArtistThumb" name="chkDownloadArtistThumb" />
- <label for="chkDownloadArtistThumb">Music Artist Thumb (primary image)</label>
+ </div>
- <input type="checkbox" data-mini="true" id="chkDownloadArtistBackdrops" name="chkDownloadArtistBackdrops" />
- <label for="chkDownloadArtistBackdrops">Music Artist Backdrops</label>
+ <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="chkDownloadArtistLogo" name="chkDownloadArtistLogo" />
- <label for="chkDownloadArtistLogo">Music Artist Logo</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="chkDownloadArtistBanner" name="chkDownloadArtistBanner" />
- <label for="chkDownloadArtistBanner">Music Artist Banner</label>
- </div>
+ <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 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>
+
+ <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>
<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="w92">w92</option>
<option value="w154">w154</option>
@@ -130,7 +130,7 @@
</li>
<li>
<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="w380">w380</option>
<option value="w780">w780</option>
@@ -139,20 +139,17 @@
</li>
<li>
<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="w45">w45</option>
<option value="w185">w185</option>
<option value="h632">h632</option>
</select>
</li>
- <li>
- <button type="submit" data-theme="b">
+ <li style="display: none;">
+ <button class="btnSubmit" type="submit" data-theme="b">
Save
</button>
- <button type="button" onclick="Dashboard.navigate('dashboard.html');">
- Cancel
- </button>
</li>
</ul>
</form>
diff --git a/MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js b/MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js
index 73ed3f431..8b89add10 100644
--- a/MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js
+++ b/MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js
@@ -33,7 +33,7 @@
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>';
}
@@ -42,6 +42,12 @@
$('#divItemTypes', page).html(html).trigger("create");
},
+ submit: function () {
+
+ $('.btnSubmit', $.mobile.activePage)[0].click();
+
+ },
+
onSubmit: function () {
Dashboard.showLoadingMsg();
@@ -54,7 +60,7 @@
return currentCheckbox.getAttribute('data-itemtype');
});
- ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult);
+ ApiClient.updateServerConfiguration(config);
});
// Disable default form submission
diff --git a/MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js b/MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js
index e68940b83..f7a9ba07b 100644
--- a/MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js
+++ b/MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js
@@ -79,6 +79,12 @@
$('#selectLanguage', '#metadataConfigurationPage').html(html).selectmenu("refresh");
},
+ submit: function () {
+
+ $('.btnSubmit', $.mobile.activePage)[0].click();
+
+ },
+
onSubmit: function () {
Dashboard.showLoadingMsg();
@@ -92,7 +98,7 @@
config.PreferredMetadataLanguage = $('#selectLanguage', form).val();
config.MetadataCountryCode = $('#selectCountry', form).val();
- ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult);
+ ApiClient.updateServerConfiguration(config);
});
// Disable default form submission
diff --git a/MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js b/MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js
index 0dff46c39..e09172d36 100644
--- a/MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js
+++ b/MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js
@@ -42,6 +42,12 @@
Dashboard.hideLoadingMsg();
},
+ submit: function () {
+
+ $('.btnSubmit', $.mobile.activePage)[0].click();
+
+ },
+
onSubmit: function () {
Dashboard.showLoadingMsg();
@@ -75,7 +81,7 @@
config.DownloadMusicAlbumImages.Primary = $('#chkDownloadAlbumPrimary', form).checked();
config.DownloadMusicAlbumImages.Backdrops = $('#chkDownloadAlbumBackdrops', form).checked();
- ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult);
+ ApiClient.updateServerConfiguration(config);
});
// Disable default form submission
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 188c18722..07992b1e3 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -403,6 +403,7 @@
<EmbeddedResource Include="Html\css\images\mblogotextblack.png" />
<EmbeddedResource Include="Html\css\images\mblogotextwhite.png" />
<EmbeddedResource Include="Html\css\images\clients\dlna.png" />
+ <EmbeddedResource Include="ApiClient.js" />
<Content Include="Html\css\images\stars.png" />
<EmbeddedResource Include="Html\scripts\MediaPlayer.js" />
</ItemGroup>
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index 629487c79..fb7a49ef6 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="MediaBrowser.ApiClient.Javascript" version="3.0.40" targetFramework="net45" />
<package id="ServiceStack" 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" />
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index f1ac09af5..4ba290fac 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
- <version>3.0.40</version>
+ <version>3.0.43</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<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>
<copyright>Copyright © Media Browser 2013</copyright>
<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="ServiceStack.Text" version="3.9.38" />
<dependency id="protobuf-net" version="2.0.0.621" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 8b22d0886..36e8ce994 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.40</version>
+ <version>3.0.43</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index a97d2fc03..5193e4480 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.40</version>
+ <version>3.0.43</version>
<title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.40" />
+ <dependency id="MediaBrowser.Common" version="3.0.43" />
</dependencies>
</metadata>
<files>