aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-07-03 22:22:57 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-07-03 22:22:57 -0400
commit7fa9b14f56eabbb06e38726879b3cddc47b8e8fb (patch)
tree68c33977dc4f71cb3decae62c071887b9f914fc1
parent59dc591f66c20b6417aa2baa9503a154585386f9 (diff)
fixes #762 - Marking unwatched doesn't update display
-rw-r--r--MediaBrowser.Api/BrandingService.cs28
-rw-r--r--MediaBrowser.Api/ConfigurationService.cs7
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs7
-rw-r--r--MediaBrowser.Api/ItemRefreshService.cs22
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs2
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj4
-rw-r--r--MediaBrowser.Api/NotificationsService.cs2
-rw-r--r--MediaBrowser.Api/SessionsService.cs12
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs (renamed from MediaBrowser.Api/Library/SubtitleService.cs)83
-rw-r--r--MediaBrowser.Api/SystemService.cs70
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs10
-rw-r--r--MediaBrowser.Api/UserService.cs4
-rw-r--r--MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs149
-rw-r--r--MediaBrowser.Common/Net/MimeTypes.cs4
-rw-r--r--MediaBrowser.Controller/Dto/IDtoService.cs7
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs15
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs80
-rw-r--r--MediaBrowser.Controller/Entities/IHasUserData.cs18
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs2
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs6
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs2
-rw-r--r--MediaBrowser.Controller/Library/IUserDataManager.cs9
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs4
-rw-r--r--MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs39
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs8
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj6
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj6
-rw-r--r--MediaBrowser.Model/Branding/BrandingOptions.cs12
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs3
-rw-r--r--MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs3
-rw-r--r--MediaBrowser.Model/Dto/UserItemDataDto.cs16
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj2
-rw-r--r--MediaBrowser.Model/Notifications/NotificationRequest.cs3
-rw-r--r--MediaBrowser.Model/Session/SessionInfoDto.cs32
-rw-r--r--MediaBrowser.Model/System/LogFile.cs31
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs28
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Branding/BrandingConfigurationFactory.cs21
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs52
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs45
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs26
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserDataManager.cs37
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs11
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/server.json17
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj1
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs27
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs33
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs2
-rw-r--r--MediaBrowser.ServerApplication/Native/BrowserLauncher.cs12
-rw-r--r--MediaBrowser.ServerApplication/ServerNotifyIcon.cs15
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs3
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj22
55 files changed, 676 insertions, 408 deletions
diff --git a/MediaBrowser.Api/BrandingService.cs b/MediaBrowser.Api/BrandingService.cs
new file mode 100644
index 000000000..4b49b411a
--- /dev/null
+++ b/MediaBrowser.Api/BrandingService.cs
@@ -0,0 +1,28 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Branding;
+using ServiceStack;
+
+namespace MediaBrowser.Api
+{
+ [Route("/Branding/Configuration", "GET", Summary = "Gets branding configuration")]
+ public class GetBrandingOptions : IReturn<BrandingOptions>
+ {
+ }
+
+ public class BrandingService : BaseApiService
+ {
+ private readonly IConfigurationManager _config;
+
+ public BrandingService(IConfigurationManager config)
+ {
+ _config = config;
+ }
+
+ public object Get(GetBrandingOptions request)
+ {
+ var result = _config.GetConfiguration<BrandingOptions>("branding");
+
+ return ToOptimizedResult(result);
+ }
+ }
+}
diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs
index 39fcc50d8..291deb3b0 100644
--- a/MediaBrowser.Api/ConfigurationService.cs
+++ b/MediaBrowser.Api/ConfigurationService.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Serialization;
@@ -27,6 +28,7 @@ namespace MediaBrowser.Api
}
[Route("/System/Configuration/{Key}", "GET", Summary = "Gets a named configuration")]
+ [Authenticated]
public class GetNamedConfiguration
{
[ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@@ -37,11 +39,13 @@ namespace MediaBrowser.Api
/// Class UpdateConfiguration
/// </summary>
[Route("/System/Configuration", "POST", Summary = "Updates application configuration")]
+ [Authenticated]
public class UpdateConfiguration : ServerConfiguration, IReturnVoid
{
}
[Route("/System/Configuration/{Key}", "POST", Summary = "Updates named configuration")]
+ [Authenticated]
public class UpdateNamedConfiguration : IReturnVoid, IRequiresRequestStream
{
[ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@@ -51,18 +55,21 @@ namespace MediaBrowser.Api
}
[Route("/System/Configuration/MetadataOptions/Default", "GET", Summary = "Gets a default MetadataOptions object")]
+ [Authenticated]
public class GetDefaultMetadataOptions : IReturn<MetadataOptions>
{
}
[Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")]
+ [Authenticated]
public class GetMetadataPlugins : IReturn<List<MetadataPluginSummary>>
{
}
[Route("/System/Configuration/VideoImageExtraction", "POST", Summary = "Updates image extraction for all types")]
+ [Authenticated]
public class UpdateVideoImageExtraction : IReturnVoid
{
public bool Enabled { get; set; }
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 4f8c348bb..deaefe019 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
@@ -26,6 +27,7 @@ namespace MediaBrowser.Api.Images
/// </summary>
[Route("/Items/{Id}/Images", "GET")]
[Api(Description = "Gets information about an item's images")]
+ [Authenticated]
public class GetItemImageInfos : IReturn<List<ImageInfo>>
{
/// <summary>
@@ -56,6 +58,7 @@ namespace MediaBrowser.Api.Images
/// </summary>
[Route("/Items/{Id}/Images/{Type}/{Index}/Index", "POST")]
[Api(Description = "Updates the index for an item image")]
+ [Authenticated]
public class UpdateItemImageIndex : IReturnVoid
{
/// <summary>
@@ -137,6 +140,7 @@ namespace MediaBrowser.Api.Images
[Route("/Items/{Id}/Images/{Type}", "DELETE")]
[Route("/Items/{Id}/Images/{Type}/{Index}", "DELETE")]
[Api(Description = "Deletes an item image")]
+ [Authenticated]
public class DeleteItemImage : DeleteImageRequest, IReturnVoid
{
/// <summary>
@@ -153,6 +157,7 @@ namespace MediaBrowser.Api.Images
[Route("/Users/{Id}/Images/{Type}", "DELETE")]
[Route("/Users/{Id}/Images/{Type}/{Index}", "DELETE")]
[Api(Description = "Deletes a user image")]
+ [Authenticated]
public class DeleteUserImage : DeleteImageRequest, IReturnVoid
{
/// <summary>
@@ -169,6 +174,7 @@ namespace MediaBrowser.Api.Images
[Route("/Users/{Id}/Images/{Type}", "POST")]
[Route("/Users/{Id}/Images/{Type}/{Index}", "POST")]
[Api(Description = "Posts a user image")]
+ [Authenticated]
public class PostUserImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
{
/// <summary>
@@ -191,6 +197,7 @@ namespace MediaBrowser.Api.Images
[Route("/Items/{Id}/Images/{Type}", "POST")]
[Route("/Items/{Id}/Images/{Type}/{Index}", "POST")]
[Api(Description = "Posts an item image")]
+ [Authenticated]
public class PostItemImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
{
/// <summary>
diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs
index b95e18a0d..993b69601 100644
--- a/MediaBrowser.Api/ItemRefreshService.cs
+++ b/MediaBrowser.Api/ItemRefreshService.cs
@@ -13,10 +13,16 @@ namespace MediaBrowser.Api
{
public class BaseRefreshRequest : IReturnVoid
{
- [ApiMember(Name = "Forced", Description = "Indicates if a normal or forced refresh should occur.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public bool Forced { get; set; }
+ [ApiMember(Name = "MetadataRefreshMode", Description = "Specifies the metadata refresh mode", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
+ public MetadataRefreshMode MetadataRefreshMode { get; set; }
- [ApiMember(Name = "ReplaceAllImages", Description = "Determines if images should be replaced during the refresh.", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
+ [ApiMember(Name = "ImageRefreshMode", Description = "Specifies the image refresh mode", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
+ public ImageRefreshMode ImageRefreshMode { get; set; }
+
+ [ApiMember(Name = "ReplaceAllMetadata", Description = "Determines if metadata should be replaced. Only applicable if mode is FullRefresh", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
+ public bool ReplaceAllMetadata { get; set; }
+
+ [ApiMember(Name = "ReplaceAllImages", Description = "Determines if images should be replaced. Only applicable if mode is FullRefresh", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
public bool ReplaceAllImages { get; set; }
}
@@ -93,7 +99,7 @@ namespace MediaBrowser.Api
private async Task RefreshItem(RefreshItem request, BaseItem item)
{
var options = GetRefreshOptions(request);
-
+
try
{
await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
@@ -148,10 +154,10 @@ namespace MediaBrowser.Api
{
return new MetadataRefreshOptions
{
- MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
- ImageRefreshMode = ImageRefreshMode.FullRefresh,
- ReplaceAllMetadata = request.Forced,
- ReplaceAllImages = request.ReplaceAllImages
+ MetadataRefreshMode = request.MetadataRefreshMode,
+ ImageRefreshMode = request.ImageRefreshMode,
+ ReplaceAllImages = request.ReplaceAllImages,
+ ReplaceAllMetadata = request.ReplaceAllMetadata
};
}
}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 77a714755..10aa23126 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dto;
@@ -226,6 +227,7 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Class LibraryService
/// </summary>
+ [Authenticated]
public class LibraryService : BaseApiService
{
/// <summary>
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index a68966b33..ca2887d19 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -65,11 +65,12 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
+ <Compile Include="BrandingService.cs" />
<Compile Include="ChannelService.cs" />
<Compile Include="Dlna\DlnaServerService.cs" />
<Compile Include="Dlna\DlnaService.cs" />
<Compile Include="Library\ChapterService.cs" />
- <Compile Include="Library\SubtitleService.cs" />
+ <Compile Include="Subtitles\SubtitleService.cs" />
<Compile Include="Movies\CollectionService.cs" />
<Compile Include="Music\AlbumsService.cs" />
<Compile Include="AppThemeService.cs" />
@@ -139,7 +140,6 @@
<Compile Include="UserService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VideosService.cs" />
- <Compile Include="WebSocket\LogFileWebSocketListener.cs" />
<Compile Include="WebSocket\SessionInfoWebSocketListener.cs" />
<Compile Include="WebSocket\SystemInfoWebSocketListener.cs" />
</ItemGroup>
diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs
index 28edb61dd..51a080106 100644
--- a/MediaBrowser.Api/NotificationsService.cs
+++ b/MediaBrowser.Api/NotificationsService.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Notifications;
using MediaBrowser.Model.Notifications;
using ServiceStack;
@@ -82,6 +83,7 @@ namespace MediaBrowser.Api
public string Ids { get; set; }
}
+ [Authenticated]
public class NotificationsService : BaseApiService
{
private readonly INotificationsRepository _notificationsRepo;
diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs
index 00c307a18..f4651601b 100644
--- a/MediaBrowser.Api/SessionsService.cs
+++ b/MediaBrowser.Api/SessionsService.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Session;
using ServiceStack;
@@ -14,6 +15,7 @@ namespace MediaBrowser.Api
/// Class GetSessions
/// </summary>
[Route("/Sessions", "GET", Summary = "Gets a list of sessions")]
+ [Authenticated]
public class GetSessions : IReturn<List<SessionInfoDto>>
{
[ApiMember(Name = "ControllableByUserId", Description = "Optional. Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
@@ -27,6 +29,7 @@ namespace MediaBrowser.Api
/// Class DisplayContent
/// </summary>
[Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")]
+ [Authenticated]
public class DisplayContent : IReturnVoid
{
/// <summary>
@@ -59,6 +62,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/{Id}/Playing", "POST", Summary = "Instructs a session to play an item")]
+ [Authenticated]
public class Play : IReturnVoid
{
/// <summary>
@@ -91,6 +95,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/{Id}/Playing/{Command}", "POST", Summary = "Issues a playstate command to a client")]
+ [Authenticated]
public class SendPlaystateCommand : IReturnVoid
{
/// <summary>
@@ -115,6 +120,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/{Id}/System/{Command}", "POST", Summary = "Issues a system command to a client")]
+ [Authenticated]
public class SendSystemCommand : IReturnVoid
{
/// <summary>
@@ -133,6 +139,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/{Id}/Command/{Command}", "POST", Summary = "Issues a system command to a client")]
+ [Authenticated]
public class SendGeneralCommand : IReturnVoid
{
/// <summary>
@@ -151,6 +158,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/{Id}/Command", "POST", Summary = "Issues a system command to a client")]
+ [Authenticated]
public class SendFullGeneralCommand : GeneralCommand, IReturnVoid
{
/// <summary>
@@ -162,6 +170,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/{Id}/Message", "POST", Summary = "Issues a command to a client to display a message to the user")]
+ [Authenticated]
public class SendMessageCommand : IReturnVoid
{
/// <summary>
@@ -182,6 +191,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/{Id}/Users/{UserId}", "POST", Summary = "Adds an additional user to a session")]
+ [Authenticated]
public class AddUserToSession : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@@ -192,6 +202,7 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/{Id}/Users/{UserId}", "DELETE", Summary = "Removes an additional user from a session")]
+ [Authenticated]
public class RemoveUserFromSession : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@@ -202,7 +213,6 @@ namespace MediaBrowser.Api
}
[Route("/Sessions/Capabilities", "POST", Summary = "Updates capabilities for a device")]
- [Route("/Sessions/{Id}/Capabilities", "POST", Summary = "Updates capabilities for a device")]
public class PostCapabilities : IReturnVoid
{
/// <summary>
diff --git a/MediaBrowser.Api/Library/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 4fc3e00c0..3e692cb22 100644
--- a/MediaBrowser.Api/Library/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Controller.Entities;
+using System.IO;
+using System.Linq;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
@@ -9,37 +11,13 @@ using MediaBrowser.Model.Providers;
using ServiceStack;
using System;
using System.Collections.Generic;
-using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-namespace MediaBrowser.Api.Library
+namespace MediaBrowser.Api.Subtitles
{
- [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format (vtt).")]
- public class GetSubtitle
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
-
- [ApiMember(Name = "MediaSourceId", Description = "MediaSourceId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string MediaSourceId { get; set; }
-
- [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
- public int Index { get; set; }
-
- [ApiMember(Name = "Format", Description = "Format", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Format { get; set; }
-
- [ApiMember(Name = "StartPositionTicks", Description = "StartPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public long StartPositionTicks { get; set; }
- }
-
[Route("/Videos/{Id}/Subtitles/{Index}", "DELETE", Summary = "Deletes an external subtitle file")]
+ [Authenticated]
public class DeleteSubtitle
{
/// <summary>
@@ -54,6 +32,7 @@ namespace MediaBrowser.Api.Library
}
[Route("/Items/{Id}/RemoteSearch/Subtitles/{Language}", "GET")]
+ [Authenticated]
public class SearchRemoteSubtitles : IReturn<List<RemoteSubtitleInfo>>
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@@ -64,6 +43,7 @@ namespace MediaBrowser.Api.Library
}
[Route("/Items/{Id}/RemoteSearch/Subtitles/Providers", "GET")]
+ [Authenticated]
public class GetSubtitleProviders : IReturn<List<SubtitleProviderInfo>>
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@@ -71,6 +51,7 @@ namespace MediaBrowser.Api.Library
}
[Route("/Items/{Id}/RemoteSearch/Subtitles/{SubtitleId}", "POST")]
+ [Authenticated]
public class DownloadRemoteSubtitles : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@@ -81,13 +62,36 @@ namespace MediaBrowser.Api.Library
}
[Route("/Providers/Subtitles/Subtitles/{Id}", "GET")]
+ [Authenticated]
public class GetRemoteSubtitles : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
- [Authenticated]
+ [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format (vtt).")]
+ public class GetSubtitle
+ {
+ /// <summary>
+ /// Gets or sets the id.
+ /// </summary>
+ /// <value>The id.</value>
+ [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Id { get; set; }
+
+ [ApiMember(Name = "MediaSourceId", Description = "MediaSourceId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string MediaSourceId { get; set; }
+
+ [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
+ public int Index { get; set; }
+
+ [ApiMember(Name = "Format", Description = "Format", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Format { get; set; }
+
+ [ApiMember(Name = "StartPositionTicks", Description = "StartPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public long StartPositionTicks { get; set; }
+ }
+
public class SubtitleService : BaseApiService
{
private readonly ILibraryManager _libraryManager;
@@ -101,14 +105,6 @@ namespace MediaBrowser.Api.Library
_subtitleEncoder = subtitleEncoder;
}
- public object Get(SearchRemoteSubtitles request)
- {
- var video = (Video)_libraryManager.GetItemById(request.Id);
-
- var response = _subtitleManager.SearchSubtitles(video, request.Language, CancellationToken.None).Result;
-
- return ToOptimizedResult(response);
- }
public object Get(GetSubtitle request)
{
if (string.IsNullOrEmpty(request.Format))
@@ -131,14 +127,23 @@ namespace MediaBrowser.Api.Library
private async Task<Stream> GetSubtitles(GetSubtitle request)
{
- return await _subtitleEncoder.GetSubtitles(request.Id,
- request.MediaSourceId,
- request.Index,
+ return await _subtitleEncoder.GetSubtitles(request.Id,
+ request.MediaSourceId,
+ request.Index,
request.Format,
request.StartPositionTicks,
CancellationToken.None).ConfigureAwait(false);
}
+ public object Get(SearchRemoteSubtitles request)
+ {
+ var video = (Video)_libraryManager.GetItemById(request.Id);
+
+ var response = _subtitleManager.SearchSubtitles(video, request.Language, CancellationToken.None).Result;
+
+ return ToOptimizedResult(response);
+ }
+
public void Delete(DeleteSubtitle request)
{
var task = _subtitleManager.DeleteSubtitles(request.Id, request.Index);
diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs
index 2f0741434..6f2e83a79 100644
--- a/MediaBrowser.Api/SystemService.cs
+++ b/MediaBrowser.Api/SystemService.cs
@@ -1,6 +1,12 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.System;
using ServiceStack;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.Api
@@ -18,15 +24,30 @@ namespace MediaBrowser.Api
/// Class RestartApplication
/// </summary>
[Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")]
+ [Authenticated]
public class RestartApplication
{
}
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
+ [Authenticated]
public class ShutdownApplication
{
}
+ [Route("/System/Logs", "GET", Summary = "Gets a list of available server log files")]
+ [Authenticated]
+ public class GetServerLogs : IReturn<List<LogFile>>
+ {
+ }
+
+ [Route("/System/Logs/Log", "GET", Summary = "Gets a log file")]
+ public class GetLogFile
+ {
+ [ApiMember(Name = "Name", Description = "The log file name.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string Name { get; set; }
+ }
+
/// <summary>
/// Class SystemInfoService
/// </summary>
@@ -36,16 +57,59 @@ namespace MediaBrowser.Api
/// The _app host
/// </summary>
private readonly IServerApplicationHost _appHost;
-
+ private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="SystemService" /> class.
/// </summary>
/// <param name="appHost">The app host.</param>
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
- public SystemService(IServerApplicationHost appHost)
+ public SystemService(IServerApplicationHost appHost, IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appHost = appHost;
+ _appPaths = appPaths;
+ _fileSystem = fileSystem;
+ }
+
+ public object Get(GetServerLogs request)
+ {
+ List<FileInfo> files;
+
+ try
+ {
+ files = new DirectoryInfo(_appPaths.LogDirectoryPath)
+ .EnumerateFiles("*", SearchOption.AllDirectories)
+ .Where(i => string.Equals(i.Extension, ".txt", System.StringComparison.OrdinalIgnoreCase))
+ .ToList();
+ }
+ catch (DirectoryNotFoundException)
+ {
+ files = new List<FileInfo>();
+ }
+
+ var result = files.Select(i => new LogFile
+ {
+ DateCreated = _fileSystem.GetCreationTimeUtc(i),
+ DateModified = _fileSystem.GetLastWriteTimeUtc(i),
+ Name = i.Name,
+ Size = i.Length
+
+ }).OrderByDescending(i => i.DateModified)
+ .ThenByDescending(i => i.DateCreated)
+ .ThenBy(i => i.Name)
+ .ToList();
+
+ return ToOptimizedResult(result);
+ }
+
+ public object Get(GetLogFile request)
+ {
+ var file = new DirectoryInfo(_appPaths.LogDirectoryPath)
+ .EnumerateFiles("*", SearchOption.AllDirectories)
+ .First(i => string.Equals(i.Name, request.Name, System.StringComparison.OrdinalIgnoreCase));
+
+ return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShare.ReadWrite);
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index d1767e7fd..55cdc8681 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -717,9 +717,7 @@ namespace MediaBrowser.Api.UserLibrary
await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
- data = _userDataRepository.GetUserData(user.Id, key);
-
- return _dtoService.GetUserItemDataDto(data);
+ return _userDataRepository.GetUserDataDto(item, user);
}
/// <summary>
@@ -766,9 +764,7 @@ namespace MediaBrowser.Api.UserLibrary
await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
- data = _userDataRepository.GetUserData(user.Id, key);
-
- return _dtoService.GetUserItemDataDto(data);
+ return _userDataRepository.GetUserDataDto(item, user);
}
/// <summary>
@@ -936,7 +932,7 @@ namespace MediaBrowser.Api.UserLibrary
await item.MarkUnplayed(user, _userDataRepository).ConfigureAwait(false);
}
- return _dtoService.GetUserItemDataDto(_userDataRepository.GetUserData(user.Id, item.GetUserDataKey()));
+ return _userDataRepository.GetUserDataDto(item, user);
}
}
}
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 64d1fcb34..cda489c94 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -51,6 +51,7 @@ namespace MediaBrowser.Api
/// Class DeleteUser
/// </summary>
[Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")]
+ [Authenticated]
public class DeleteUser : IReturnVoid
{
/// <summary>
@@ -107,6 +108,7 @@ namespace MediaBrowser.Api
/// Class UpdateUserPassword
/// </summary>
[Route("/Users/{Id}/Password", "POST", Summary = "Updates a user's password")]
+ [Authenticated]
public class UpdateUserPassword : IReturnVoid
{
/// <summary>
@@ -138,6 +140,7 @@ namespace MediaBrowser.Api
/// Class UpdateUser
/// </summary>
[Route("/Users/{Id}", "POST", Summary = "Updates a user")]
+ [Authenticated]
public class UpdateUser : UserDto, IReturnVoid
{
}
@@ -146,6 +149,7 @@ namespace MediaBrowser.Api
/// Class CreateUser
/// </summary>
[Route("/Users", "POST", Summary = "Creates a user")]
+ [Authenticated]
public class CreateUser : UserDto, IReturn<UserDto>
{
}
diff --git a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs
deleted file mode 100644
index 46dabb042..000000000
--- a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Api.WebSocket
-{
- /// <summary>
- /// Class ScheduledTasksWebSocketListener
- /// </summary>
- public class LogFileWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<string>, LogFileWebSocketState>
- {
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- protected override string Name
- {
- get { return "LogFile"; }
- }
-
- /// <summary>
- /// The _kernel
- /// </summary>
- private readonly ILogManager _logManager;
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="LogFileWebSocketListener" /> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="logManager">The log manager.</param>
- public LogFileWebSocketListener(ILogger logger, ILogManager logManager, IFileSystem fileSystem)
- : base(logger)
- {
- _logManager = logManager;
- _fileSystem = fileSystem;
- _logManager.LoggerLoaded += kernel_LoggerLoaded;
- }
-
- /// <summary>
- /// Gets the data to send.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <returns>IEnumerable{System.String}.</returns>
- protected override async Task<IEnumerable<string>> GetDataToSend(LogFileWebSocketState state)
- {
- if (!string.Equals(_logManager.LogFilePath, state.LastLogFilePath))
- {
- state.LastLogFilePath = _logManager.LogFilePath;
- state.StartLine = 0;
- }
-
- var lines = await GetLogLines(state.LastLogFilePath, state.StartLine, _fileSystem).ConfigureAwait(false);
-
- state.StartLine += lines.Count;
-
- return lines;
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected override void Dispose(bool dispose)
- {
- if (dispose)
- {
- _logManager.LoggerLoaded -= kernel_LoggerLoaded;
- }
- base.Dispose(dispose);
- }
-
- /// <summary>
- /// Handles the LoggerLoaded event of the kernel control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- void kernel_LoggerLoaded(object sender, EventArgs e)
- {
- // Reset the startline for each connection whenever the logger reloads
- lock (ActiveConnections)
- {
- foreach (var connection in ActiveConnections)
- {
- connection.Item4.StartLine = 0;
- }
- }
- }
-
- /// <summary>
- /// Gets the log lines.
- /// </summary>
- /// <param name="logFilePath">The log file path.</param>
- /// <param name="startLine">The start line.</param>
- /// <returns>Task{IEnumerable{System.String}}.</returns>
- internal static async Task<List<string>> GetLogLines(string logFilePath, int startLine, IFileSystem fileSystem)
- {
- var lines = new List<string>();
-
- using (var fs = fileSystem.GetFileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
- {
- using (var reader = new StreamReader(fs))
- {
- while (!reader.EndOfStream)
- {
- var line = await reader.ReadLineAsync().ConfigureAwait(false);
-
- if (line.IndexOf("Info -", StringComparison.OrdinalIgnoreCase) != -1 ||
- line.IndexOf("Warn -", StringComparison.OrdinalIgnoreCase) != -1 ||
- line.IndexOf("Error -", StringComparison.OrdinalIgnoreCase) != -1)
- {
- lines.Add(line);
- }
- }
- }
- }
-
- if (startLine > 0)
- {
- lines = lines.Skip(startLine).ToList();
- }
-
- return lines;
- }
- }
-
- /// <summary>
- /// Class LogFileWebSocketState
- /// </summary>
- public class LogFileWebSocketState : WebSocketListenerState
- {
- /// <summary>
- /// Gets or sets the last log file path.
- /// </summary>
- /// <value>The last log file path.</value>
- public string LastLogFilePath { get; set; }
- /// <summary>
- /// Gets or sets the start line.
- /// </summary>
- /// <value>The start line.</value>
- public int StartLine { get; set; }
- }
-}
diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs
index 0cc4fc6b4..dcac5e7ba 100644
--- a/MediaBrowser.Common/Net/MimeTypes.cs
+++ b/MediaBrowser.Common/Net/MimeTypes.cs
@@ -199,6 +199,10 @@ namespace MediaBrowser.Common.Net
{
return "application/x-javascript";
}
+ if (ext.Equals(".map", StringComparison.OrdinalIgnoreCase))
+ {
+ return "application/x-javascript";
+ }
if (ext.Equals(".woff", StringComparison.OrdinalIgnoreCase))
{
diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs
index f9d7cc21a..0d0555dc0 100644
--- a/MediaBrowser.Controller/Dto/IDtoService.cs
+++ b/MediaBrowser.Controller/Dto/IDtoService.cs
@@ -26,13 +26,6 @@ namespace MediaBrowser.Controller.Dto
string GetDtoId(BaseItem item);
/// <summary>
- /// Gets the user item data dto.
- /// </summary>
- /// <param name="data">The data.</param>
- /// <returns>UserItemDataDto.</returns>
- UserItemDataDto GetUserItemDataDto(UserItemData data);
-
- /// <summary>
/// Attaches the primary image aspect ratio.
/// </summary>
/// <param name="dto">The dto.</param>
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 524d7097b..042834731 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Logging;
@@ -1571,5 +1572,19 @@ namespace MediaBrowser.Controller.Entities
return path;
}
+
+ public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
+ {
+ if (RunTimeTicks.HasValue)
+ {
+ double pct = RunTimeTicks.Value;
+
+ if (pct > 0)
+ {
+ pct = userData.PlaybackPositionTicks / pct;
+ dto.PlayedPercentage = 100 * pct;
+ }
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 584091b13..b886cef19 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MoreLinq;
using System;
@@ -770,6 +771,11 @@ namespace MediaBrowser.Controller.Entities
/// <exception cref="System.ArgumentNullException"></exception>
public virtual IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
+ return GetChildren(user, includeLinkedChildren, false);
+ }
+
+ internal IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren, bool includeHidden)
+ {
if (user == null)
{
throw new ArgumentNullException();
@@ -780,7 +786,7 @@ namespace MediaBrowser.Controller.Entities
var list = new List<BaseItem>();
- var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false);
+ var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, includeHidden, false);
return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list;
}
@@ -796,9 +802,10 @@ namespace MediaBrowser.Controller.Entities
/// <param name="user">The user.</param>
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
/// <param name="list">The list.</param>
+ /// <param name="includeHidden">if set to <c>true</c> [include hidden].</param>
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool AddChildrenToList(User user, bool includeLinkedChildren, List<BaseItem> list, bool recursive)
+ private bool AddChildrenToList(User user, bool includeLinkedChildren, List<BaseItem> list, bool includeHidden, bool recursive)
{
var hasLinkedChildren = false;
@@ -806,7 +813,7 @@ namespace MediaBrowser.Controller.Entities
{
if (child.IsVisible(user))
{
- if (!child.IsHiddenFromUser(user))
+ if (includeHidden || !child.IsHiddenFromUser(user))
{
list.Add(child);
}
@@ -815,7 +822,7 @@ namespace MediaBrowser.Controller.Entities
{
var folder = (Folder)child;
- if (folder.AddChildrenToList(user, includeLinkedChildren, list, true))
+ if (folder.AddChildrenToList(user, includeLinkedChildren, list, includeHidden, true))
{
hasLinkedChildren = true;
}
@@ -855,7 +862,7 @@ namespace MediaBrowser.Controller.Entities
var list = new List<BaseItem>();
- var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, true);
+ var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false, true);
return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list;
}
@@ -1069,5 +1076,68 @@ namespace MediaBrowser.Controller.Entities
return GetRecursiveChildren(user).Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual)
.All(i => i.IsUnplayed(user));
}
+
+ public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
+ {
+ var recursiveItemCount = 0;
+ var unplayed = 0;
+
+ double totalPercentPlayed = 0;
+
+ IEnumerable<BaseItem> children;
+ var folder = this;
+
+ var season = folder as Season;
+
+ if (season != null)
+ {
+ children = season.GetEpisodes(user).Where(i => i.LocationType != LocationType.Virtual);
+ }
+ else
+ {
+ children = folder.GetRecursiveChildren(user)
+ .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual);
+ }
+
+ // Loop through each recursive child
+ foreach (var child in children)
+ {
+ recursiveItemCount++;
+
+ var isUnplayed = true;
+
+ var itemUserData = UserDataManager.GetUserData(user.Id, child.GetUserDataKey());
+
+ // Incrememt totalPercentPlayed
+ if (itemUserData != null)
+ {
+ if (itemUserData.Played)
+ {
+ totalPercentPlayed += 100;
+
+ isUnplayed = false;
+ }
+ else if (itemUserData.PlaybackPositionTicks > 0 && child.RunTimeTicks.HasValue && child.RunTimeTicks.Value > 0)
+ {
+ double itemPercent = itemUserData.PlaybackPositionTicks;
+ itemPercent /= child.RunTimeTicks.Value;
+ totalPercentPlayed += itemPercent;
+ }
+ }
+
+ if (isUnplayed)
+ {
+ unplayed++;
+ }
+ }
+
+ dto.UnplayedItemCount = unplayed;
+
+ if (recursiveItemCount > 0)
+ {
+ dto.PlayedPercentage = totalPercentPlayed / recursiveItemCount;
+ dto.Played = dto.PlayedPercentage.Value >= 100;
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs
index 780181a61..d576d90c4 100644
--- a/MediaBrowser.Controller/Entities/IHasUserData.cs
+++ b/MediaBrowser.Controller/Entities/IHasUserData.cs
@@ -1,4 +1,6 @@
-
+using MediaBrowser.Model.Dto;
+using System;
+
namespace MediaBrowser.Controller.Entities
{
/// <summary>
@@ -7,9 +9,23 @@ namespace MediaBrowser.Controller.Entities
public interface IHasUserData
{
/// <summary>
+ /// Gets or sets the identifier.
+ /// </summary>
+ /// <value>The identifier.</value>
+ Guid Id { get; set; }
+
+ /// <summary>
/// Gets the user data key.
/// </summary>
/// <returns>System.String.</returns>
string GetUserDataKey();
+
+ /// <summary>
+ /// Fills the user data dto values.
+ /// </summary>
+ /// <param name="dto">The dto.</param>
+ /// <param name="userData">The user data.</param>
+ /// <param name="user">The user.</param>
+ void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user);
}
}
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index b9630a66f..847183fd0 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -91,7 +91,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
- return FindParent<Season>();
+ return Season;
}
}
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index e5a8135c2..6404e71ec 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Dto;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -51,5 +52,10 @@ namespace MediaBrowser.Controller.Entities
LibraryManager.RegisterItem(item);
}
}
+
+ public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
+ {
+ // Nothing meaninful here and will only waste resources
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 86099fdc0..619a497f5 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -44,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
return user.RootFolder
- .GetChildren(user, true)
+ .GetChildren(user, true, true)
.OfType<Folder>()
.Where(i => !excludeFolderIds.Contains(i.Id) && !IsExcludedFromGrouping(i));
}
diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs
index 2bec9e3de..9db91e7f2 100644
--- a/MediaBrowser.Controller/Library/IUserDataManager.cs
+++ b/MediaBrowser.Controller/Library/IUserDataManager.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using System;
using System.Threading;
@@ -34,5 +35,13 @@ namespace MediaBrowser.Controller.Library
/// <param name="key">The key.</param>
/// <returns>Task{UserItemData}.</returns>
UserItemData GetUserData(Guid userId, string key);
+
+ /// <summary>
+ /// Gets the user data dto.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="user">The user.</param>
+ /// <returns>UserItemDataDto.</returns>
+ UserItemDataDto GetUserDataDto(IHasUserData item, User user);
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
index 23610351e..ba1cb3043 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Controller.LiveTv
{
- public interface ILiveTvRecording : IHasImages, IHasMediaSources
+ public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData
{
string ServiceName { get; set; }
@@ -20,8 +20,6 @@ namespace MediaBrowser.Controller.LiveTv
string GetClientTypeName();
- string GetUserDataKey();
-
bool IsParentalAllowed(User user);
Task RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken);
diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
index 692d6db90..7f1ddbce9 100644
--- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
+++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
@@ -1,6 +1,6 @@
-using System;
+using MediaBrowser.Model.Entities;
+using System;
using System.Collections.Generic;
-using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Providers
{
@@ -18,6 +18,11 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
[Obsolete]
public bool ForceSave { get; set; }
+
+ public MetadataRefreshOptions()
+ {
+ MetadataRefreshMode = MetadataRefreshMode.Default;
+ }
}
public class ImageRefreshOptions
@@ -38,48 +43,54 @@ namespace MediaBrowser.Controller.Providers
public bool IsReplacingImage(ImageType type)
{
- return ReplaceAllImages || ReplaceImages.Contains(type);
+ return ImageRefreshMode == ImageRefreshMode.FullRefresh &&
+ (ReplaceAllImages || ReplaceImages.Contains(type));
}
}
public enum MetadataRefreshMode
{
/// <summary>
- /// Providers will be executed based on default rules
+ /// The none
/// </summary>
- EnsureMetadata = 0,
+ None = 0,
/// <summary>
- /// No providers will be executed
+ /// The validation only
/// </summary>
- None = 1,
+ ValidationOnly = 1,
/// <summary>
- /// All providers will be executed to search for new metadata
+ /// Providers will be executed based on default rules
/// </summary>
- FullRefresh = 2,
+ Default = 2,
/// <summary>
- /// The validation only
+ /// All providers will be executed to search for new metadata
/// </summary>
- ValidationOnly = 3
+ FullRefresh = 3
}
public enum ImageRefreshMode
{
/// <summary>
+ /// The none
+ /// </summary>
+ None = 0,
+
+ /// <summary>
/// The default
/// </summary>
- Default = 0,
+ Default = 1,
/// <summary>
/// Existing images will be validated
/// </summary>
- ValidationOnly = 1,
+ ValidationOnly = 2,
/// <summary>
/// All providers will be executed to search for new metadata
/// </summary>
- FullRefresh = 2
+ FullRefresh = 3
}
}
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 6d3a9d20c..7b2062182 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -219,7 +219,13 @@ namespace MediaBrowser.Controller.Session
/// <param name="deviceName">Name of the device.</param>
/// <param name="remoteEndPoint">The remote end point.</param>
/// <returns>Task{SessionInfo}.</returns>
- Task<AuthenticationResult> AuthenticateNewSession(string username, string password, string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint);
+ Task<AuthenticationResult> AuthenticateNewSession(string username,
+ string password,
+ string clientType,
+ string appVersion,
+ string deviceId,
+ string deviceName,
+ string remoteEndPoint);
/// <summary>
/// Reports the capabilities.
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index 0ed49d5f8..91c1508fc 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -77,6 +77,9 @@
<Compile Include="..\MediaBrowser.Model\ApiClient\SessionUpdatesEventArgs.cs">
<Link>ApiClient\SessionUpdatesEventArgs.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Branding\BrandingOptions.cs">
+ <Link>Branding\BrandingOptions.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Channels\ChannelFeatures.cs">
<Link>Channels\ChannelFeatures.cs</Link>
</Compile>
@@ -815,6 +818,9 @@
<Compile Include="..\MediaBrowser.Model\Session\UserDataChangeInfo.cs">
<Link>Session\UserDataChangeInfo.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\System\LogFile.cs">
+ <Link>System\LogFile.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\System\SystemInfo.cs">
<Link>System\SystemInfo.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 12c87ca97..782e8524d 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -64,6 +64,9 @@
<Compile Include="..\MediaBrowser.Model\ApiClient\SessionUpdatesEventArgs.cs">
<Link>ApiClient\SessionUpdatesEventArgs.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Branding\BrandingOptions.cs">
+ <Link>Branding\BrandingOptions.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Channels\ChannelFeatures.cs">
<Link>Channels\ChannelFeatures.cs</Link>
</Compile>
@@ -796,6 +799,9 @@
<Compile Include="..\MediaBrowser.Model\Session\UserDataChangeInfo.cs">
<Link>Session\UserDataChangeInfo.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\System\LogFile.cs">
+ <Link>System\LogFile.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\System\SystemInfo.cs">
<Link>System\SystemInfo.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/Branding/BrandingOptions.cs b/MediaBrowser.Model/Branding/BrandingOptions.cs
new file mode 100644
index 000000000..737cb5c48
--- /dev/null
+++ b/MediaBrowser.Model/Branding/BrandingOptions.cs
@@ -0,0 +1,12 @@
+
+namespace MediaBrowser.Model.Branding
+{
+ public class BrandingOptions
+ {
+ /// <summary>
+ /// Gets or sets the login disclaimer.
+ /// </summary>
+ /// <value>The login disclaimer.</value>
+ public string LoginDisclaimer { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 36c353479..49b731341 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -158,9 +158,6 @@ namespace MediaBrowser.Model.Configuration
public bool EnableTmdbUpdates { get; set; }
public bool EnableFanArtUpdates { get; set; }
- public bool RequireMobileManualLogin { get; set; }
- public bool RequireNonMobileManualLogin { get; set; }
-
/// <summary>
/// Gets or sets the image saving convention.
/// </summary>
diff --git a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
index db8b69951..86eb40b97 100644
--- a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
+++ b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
@@ -10,12 +10,15 @@ namespace MediaBrowser.Model.Configuration
public bool SaveImagePathsInNfo { get; set; }
public bool EnablePathSubstitution { get; set; }
+ public bool EnableExtraThumbsDuplication { get; set; }
+
public XbmcMetadataOptions()
{
ReleaseDateFormat = "yyyy-MM-dd";
SaveImagePathsInNfo = true;
EnablePathSubstitution = true;
+ EnableExtraThumbsDuplication = true;
}
}
}
diff --git a/MediaBrowser.Model/Dto/UserItemDataDto.cs b/MediaBrowser.Model/Dto/UserItemDataDto.cs
index 26b0e9d9e..6ee9f1916 100644
--- a/MediaBrowser.Model/Dto/UserItemDataDto.cs
+++ b/MediaBrowser.Model/Dto/UserItemDataDto.cs
@@ -1,6 +1,6 @@
-using System;
+using MediaBrowser.Model.Extensions;
+using System;
using System.ComponentModel;
-using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.Dto
{
@@ -16,6 +16,18 @@ namespace MediaBrowser.Model.Dto
public double? Rating { get; set; }
/// <summary>
+ /// Gets or sets the played percentage.
+ /// </summary>
+ /// <value>The played percentage.</value>
+ public double? PlayedPercentage { get; set; }
+
+ /// <summary>
+ /// Gets or sets the unplayed item count.
+ /// </summary>
+ /// <value>The unplayed item count.</value>
+ public int? UnplayedItemCount { get; set; }
+
+ /// <summary>
/// Gets or sets the playback position ticks.
/// </summary>
/// <value>The playback position ticks.</value>
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index d758f2f39..4d4ca8e20 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -65,6 +65,7 @@
<Compile Include="ApiClient\IServerEvents.cs" />
<Compile Include="ApiClient\GeneralCommandEventArgs.cs" />
<Compile Include="ApiClient\SessionUpdatesEventArgs.cs" />
+ <Compile Include="Branding\BrandingOptions.cs" />
<Compile Include="Channels\ChannelFeatures.cs" />
<Compile Include="Channels\ChannelInfo.cs" />
<Compile Include="Channels\ChannelItemQuery.cs" />
@@ -294,6 +295,7 @@
<Compile Include="Session\SessionInfoDto.cs" />
<Compile Include="Session\SessionUserInfo.cs" />
<Compile Include="Session\UserDataChangeInfo.cs" />
+ <Compile Include="System\LogFile.cs" />
<Compile Include="Themes\AppTheme.cs" />
<Compile Include="Themes\AppThemeInfo.cs" />
<Compile Include="Themes\ThemeImage.cs" />
diff --git a/MediaBrowser.Model/Notifications/NotificationRequest.cs b/MediaBrowser.Model/Notifications/NotificationRequest.cs
index f511d41a9..6e9368f44 100644
--- a/MediaBrowser.Model/Notifications/NotificationRequest.cs
+++ b/MediaBrowser.Model/Notifications/NotificationRequest.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Model.Configuration;
-using System;
+using System;
using System.Collections.Generic;
namespace MediaBrowser.Model.Notifications
diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs
index 40723eff8..98df3efe5 100644
--- a/MediaBrowser.Model/Session/SessionInfoDto.cs
+++ b/MediaBrowser.Model/Session/SessionInfoDto.cs
@@ -1,9 +1,9 @@
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
-using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.Session
{
@@ -11,22 +11,10 @@ namespace MediaBrowser.Model.Session
public class SessionInfoDto : IHasPropertyChangedEvent
{
/// <summary>
- /// Gets or sets a value indicating whether this instance can seek.
- /// </summary>
- /// <value><c>true</c> if this instance can seek; otherwise, <c>false</c>.</value>
- public bool CanSeek { get; set; }
-
- /// <summary>
/// Gets or sets the supported commands.
/// </summary>
/// <value>The supported commands.</value>
public List<string> SupportedCommands { get; set; }
-
- /// <summary>
- /// Gets or sets the remote end point.
- /// </summary>
- /// <value>The remote end point.</value>
- public string RemoteEndPoint { get; set; }
/// <summary>
/// Gets or sets the queueable media types.
@@ -99,18 +87,6 @@ namespace MediaBrowser.Model.Session
/// </summary>
/// <value>The name of the device.</value>
public string DeviceName { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance is paused.
- /// </summary>
- /// <value><c>true</c> if this instance is paused; otherwise, <c>false</c>.</value>
- public bool IsPaused { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance is muted.
- /// </summary>
- /// <value><c>true</c> if this instance is muted; otherwise, <c>false</c>.</value>
- public bool IsMuted { get; set; }
/// <summary>
/// Gets or sets the now playing item.
@@ -119,12 +95,6 @@ namespace MediaBrowser.Model.Session
public BaseItemInfo NowPlayingItem { get; set; }
/// <summary>
- /// Gets or sets the now playing position ticks.
- /// </summary>
- /// <value>The now playing position ticks.</value>
- public long? NowPlayingPositionTicks { get; set; }
-
- /// <summary>
/// Gets or sets the device id.
/// </summary>
/// <value>The device id.</value>
diff --git a/MediaBrowser.Model/System/LogFile.cs b/MediaBrowser.Model/System/LogFile.cs
new file mode 100644
index 000000000..ba409c542
--- /dev/null
+++ b/MediaBrowser.Model/System/LogFile.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace MediaBrowser.Model.System
+{
+ public class LogFile
+ {
+ /// <summary>
+ /// Gets or sets the date created.
+ /// </summary>
+ /// <value>The date created.</value>
+ public DateTime DateCreated { get; set; }
+
+ /// <summary>
+ /// Gets or sets the date modified.
+ /// </summary>
+ /// <value>The date modified.</value>
+ public DateTime DateModified { get; set; }
+
+ /// <summary>
+ /// Gets or sets the size.
+ /// </summary>
+ /// <value>The size.</value>
+ public long Size { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+ }
+}
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 12af93dbd..1b2e9fa6d 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -441,11 +442,16 @@ namespace MediaBrowser.Providers.Manager
var extraFanartFilename = GetBackdropSaveFilename(item.GetImages(ImageType.Backdrop), "fanart", "fanart", outputIndex);
- return new[]
- {
- Path.Combine(item.ContainingFolderPath, "extrafanart", extraFanartFilename + extension),
- Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension)
- };
+ var list = new List<string>
+ {
+ Path.Combine(item.ContainingFolderPath, "extrafanart", extraFanartFilename + extension)
+ };
+
+ if (EnableExtraThumbsDuplication)
+ {
+ list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension));
+ }
+ return list.ToArray();
}
if (type == ImageType.Primary)
@@ -528,6 +534,16 @@ namespace MediaBrowser.Providers.Manager
return new[] { GetStandardSavePath(item, type, imageIndex, mimeType, true) };
}
+ private bool EnableExtraThumbsDuplication
+ {
+ get
+ {
+ var config = _config.GetConfiguration<XbmcMetadataOptions>("xbmcmetadata");
+
+ return config.EnableExtraThumbsDuplication;
+ }
+ }
+
/// <summary>
/// Gets the save path for item in mixed folder.
/// </summary>
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 92b4616e7..57a40741f 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -234,7 +234,7 @@ namespace MediaBrowser.Providers.MediaInfo
await _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken).ConfigureAwait(false);
if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh ||
- options.MetadataRefreshMode == MetadataRefreshMode.EnsureMetadata)
+ options.MetadataRefreshMode == MetadataRefreshMode.Default)
{
try
{
@@ -460,7 +460,7 @@ namespace MediaBrowser.Providers.MediaInfo
var externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, currentStreams.Count, options.DirectoryService, false).ToList();
- var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.EnsureMetadata ||
+ var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.Default ||
options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh;
if (enableSubtitleDownloading && (_config.Configuration.SubtitleOptions.DownloadEpisodeSubtitles &&
diff --git a/MediaBrowser.Server.Implementations/Branding/BrandingConfigurationFactory.cs b/MediaBrowser.Server.Implementations/Branding/BrandingConfigurationFactory.cs
new file mode 100644
index 000000000..d6cd3424b
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Branding/BrandingConfigurationFactory.cs
@@ -0,0 +1,21 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Branding;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Server.Implementations.Branding
+{
+ public class BrandingConfigurationFactory : IConfigurationFactory
+ {
+ public IEnumerable<ConfigurationStore> GetConfigurations()
+ {
+ return new[]
+ {
+ new ConfigurationStore
+ {
+ ConfigurationType = typeof(BrandingOptions),
+ Key = "branding"
+ }
+ };
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index 73216ca33..62ff9f687 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -212,6 +212,12 @@ namespace MediaBrowser.Server.Implementations.Dto
{
if (item.IsFolder)
{
+ var userData = _userDataRepository.GetUserData(user.Id, item.GetUserDataKey());
+
+ // Skip the user data manager because we've already looped through the recursive tree and don't want to do it twice
+ // TODO: Improve in future
+ dto.UserData = GetUserItemDataDto(userData);
+
var folder = (Folder)item;
dto.ChildCount = GetChildCount(folder, user);
@@ -220,15 +226,15 @@ namespace MediaBrowser.Server.Implementations.Dto
{
SetSpecialCounts(folder, user, dto, fields);
}
- }
- var userData = _userDataRepository.GetUserData(user.Id, item.GetUserDataKey());
-
- dto.UserData = GetUserItemDataDto(userData);
+ dto.UserData.Played = dto.PlayedPercentage.HasValue && dto.PlayedPercentage.Value >= 100;
+ dto.UserData.PlayedPercentage = dto.PlayedPercentage;
+ dto.UserData.UnplayedItemCount = dto.RecursiveUnplayedItemCount;
+ }
- if (item.IsFolder)
+ else
{
- dto.UserData.Played = dto.PlayedPercentage.HasValue && dto.PlayedPercentage.Value >= 100;
+ dto.UserData = _userDataRepository.GetUserDataDto(item, user);
}
dto.PlayAccess = item.GetPlayAccess(user);
@@ -1110,16 +1116,17 @@ namespace MediaBrowser.Server.Implementations.Dto
if (episode != null)
{
- series = item.FindParent<Series>();
+ series = episode.Series;
- dto.SeriesId = GetDtoId(series);
- dto.SeriesName = series.Name;
- dto.AirTime = series.AirTime;
- dto.SeriesStudio = series.Studios.FirstOrDefault();
-
- dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb);
-
- dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary);
+ if (series != null)
+ {
+ dto.SeriesId = GetDtoId(series);
+ dto.SeriesName = series.Name;
+ dto.AirTime = series.AirTime;
+ dto.SeriesStudio = series.Studios.FirstOrDefault();
+ dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb);
+ dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary);
+ }
}
// Add SeasonInfo
@@ -1127,14 +1134,17 @@ namespace MediaBrowser.Server.Implementations.Dto
if (season != null)
{
- series = item.FindParent<Series>();
+ series = season.Series;
- dto.SeriesId = GetDtoId(series);
- dto.SeriesName = series.Name;
- dto.AirTime = series.AirTime;
- dto.SeriesStudio = series.Studios.FirstOrDefault();
+ if (series != null)
+ {
+ dto.SeriesId = GetDtoId(series);
+ dto.SeriesName = series.Name;
+ dto.AirTime = series.AirTime;
+ dto.SeriesStudio = series.Studios.FirstOrDefault();
- dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary);
+ dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary);
+ }
}
var game = item as Game;
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index d7186aa21..c31f46215 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -1,10 +1,11 @@
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
+using MoreLinq;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -17,21 +18,21 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
{
private readonly ISessionManager _sessionManager;
private readonly ILogger _logger;
- private readonly IDtoService _dtoService;
private readonly IUserDataManager _userDataManager;
+ private readonly IUserManager _userManager;
private readonly object _syncLock = new object();
private Timer UpdateTimer { get; set; }
private const int UpdateDuration = 500;
- private readonly Dictionary<Guid, List<string>> _changedKeys = new Dictionary<Guid, List<string>>();
+ private readonly Dictionary<Guid, List<IHasUserData>> _changedItems = new Dictionary<Guid, List<IHasUserData>>();
- public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, IDtoService dtoService, ILogger logger)
+ public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, ILogger logger, IUserManager userManager)
{
_userDataManager = userDataManager;
_sessionManager = sessionManager;
- _dtoService = dtoService;
_logger = logger;
+ _userManager = userManager;
}
public void Run()
@@ -58,15 +59,28 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
UpdateTimer.Change(UpdateDuration, Timeout.Infinite);
}
- List<string> keys;
+ List<IHasUserData> keys;
- if (!_changedKeys.TryGetValue(e.UserId, out keys))
+ if (!_changedItems.TryGetValue(e.UserId, out keys))
{
- keys = new List<string>();
- _changedKeys[e.UserId] = keys;
+ keys = new List<IHasUserData>();
+ _changedItems[e.UserId] = keys;
}
- keys.Add(e.Key);
+ keys.Add(e.Item);
+
+ var baseItem = e.Item as BaseItem;
+
+ // Go up one level for indicators
+ if (baseItem != null)
+ {
+ var parent = baseItem.Parent;
+
+ if (parent != null)
+ {
+ keys.Add(parent);
+ }
+ }
}
}
@@ -75,8 +89,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
lock (_syncLock)
{
// Remove dupes in case some were saved multiple times
- var changes = _changedKeys.ToList();
- _changedKeys.Clear();
+ var changes = _changedItems.ToList();
+ _changedItems.Clear();
SendNotifications(changes, CancellationToken.None);
@@ -88,7 +102,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
}
}
- private async Task SendNotifications(IEnumerable<KeyValuePair<Guid, List<string>>> changes, CancellationToken cancellationToken)
+ private async Task SendNotifications(IEnumerable<KeyValuePair<Guid, List<IHasUserData>>> changes, CancellationToken cancellationToken)
{
foreach (var pair in changes)
{
@@ -99,8 +113,11 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
if (userSessions.Count > 0)
{
+ var user = _userManager.GetUserById(userId);
+
var dtoList = pair.Value
- .Select(i => _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(userId, i)))
+ .DistinctBy(i => i.Id)
+ .Select(i => _userDataManager.GetUserDataDto(i, user))
.ToList();
var info = new UserDataChangeInfo
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 833dfc5e4..cfcbb077e 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -363,19 +363,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
try
{
- var errorResponse = new ErrorResponse
- {
- ResponseStatus = new ResponseStatus
- {
- ErrorCode = ex.GetType().GetOperationName(),
- Message = ex.Message,
- StackTrace = ex.StackTrace,
- }
- };
-
var operationName = context.Request.GetOperationName();
var httpReq = GetRequest(context, operationName);
var httpRes = httpReq.Response;
+
+ if (httpRes.IsClosed)
+ {
+ return;
+ }
+
var contentType = httpReq.ResponseContentType;
var serializer = HostContext.ContentTypes.GetResponseSerializer(contentType);
@@ -398,6 +394,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer
httpRes.ContentType = contentType;
+ var errorResponse = new ErrorResponse
+ {
+ ResponseStatus = new ResponseStatus
+ {
+ ErrorCode = ex.GetType().GetOperationName(),
+ Message = ex.Message,
+ StackTrace = ex.StackTrace,
+ }
+ };
+
serializer(httpReq, errorResponse, httpRes);
httpRes.Close();
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index 77343ab4e..94be37e95 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -36,6 +36,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
auth.TryGetValue("Version", out version);
}
+ var token = httpReq.Headers["X-MediaBrowser-Token"];
+
+ if (string.IsNullOrWhiteSpace(token))
+ {
+ token = httpReq.QueryString["api_key"];
+ }
+
return new AuthorizationInfo
{
Client = client,
@@ -43,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
DeviceId = deviceId,
UserId = userId,
Version = version,
- Token = httpReq.Headers["X-AUTH-TOKEN"]
+ Token = token
};
}
diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
index 79f126511..d3030f31f 100644
--- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
@@ -125,5 +126,41 @@ namespace MediaBrowser.Server.Implementations.Library
{
return userId + key;
}
+
+ public UserItemDataDto GetUserDataDto(IHasUserData item, User user)
+ {
+ var userData = GetUserData(user.Id, item.GetUserDataKey());
+ var dto = GetUserItemDataDto(userData);
+
+ item.FillUserDataDtoValues(dto, userData, user);
+
+ return dto;
+ }
+
+ /// <summary>
+ /// Converts a UserItemData to a DTOUserItemData
+ /// </summary>
+ /// <param name="data">The data.</param>
+ /// <returns>DtoUserItemData.</returns>
+ /// <exception cref="System.ArgumentNullException"></exception>
+ private UserItemDataDto GetUserItemDataDto(UserItemData data)
+ {
+ if (data == null)
+ {
+ throw new ArgumentNullException("data");
+ }
+
+ return new UserItemDataDto
+ {
+ IsFavorite = data.IsFavorite,
+ Likes = data.Likes,
+ PlaybackPositionTicks = data.PlaybackPositionTicks,
+ PlayCount = data.PlayCount,
+ Rating = data.Rating,
+ Played = data.Played,
+ LastPlayedDate = data.LastPlayedDate,
+ Key = data.Key
+ };
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 412b2e7bd..9c69e656d 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -4,7 +4,6 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
@@ -23,15 +22,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly IUserDataManager _userDataManager;
private readonly IDtoService _dtoService;
- private readonly IItemRepository _itemRepo;
- public LiveTvDtoService(IDtoService dtoService, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILogger logger, IItemRepository itemRepo)
+ public LiveTvDtoService(IDtoService dtoService, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILogger logger)
{
_dtoService = dtoService;
_userDataManager = userDataManager;
_imageProcessor = imageProcessor;
_logger = logger;
- _itemRepo = itemRepo;
}
public TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service, LiveTvProgram program, LiveTvChannel channel)
@@ -249,7 +246,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (user != null)
{
- dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, recording.GetUserDataKey()));
+ dto.UserData = _userDataManager.GetUserDataDto(recording, user);
dto.PlayAccess = recording.GetPlayAccess(user);
}
@@ -322,7 +319,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (user != null)
{
- dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, info.GetUserDataKey()));
+ dto.UserData = _userDataManager.GetUserDataDto(info, user);
dto.PlayAccess = info.GetPlayAccess(user);
}
@@ -401,7 +398,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (user != null)
{
- dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, item.GetUserDataKey()));
+ dto.UserData = _userDataManager.GetUserDataDto(item, user);
dto.PlayAccess = item.GetPlayAccess(user);
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index ad1ddba88..09793f4fc 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -40,7 +40,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly IUserDataManager _userDataManager;
private readonly ILibraryManager _libraryManager;
private readonly ITaskManager _taskManager;
- private readonly IJsonSerializer _json;
private readonly IDtoService _dtoService;
private readonly ILocalizationManager _localization;
@@ -58,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1);
- public LiveTvManager(IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, IJsonSerializer json, ILocalizationManager localization)
+ public LiveTvManager(IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization)
{
_config = config;
_fileSystem = fileSystem;
@@ -67,12 +66,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_userManager = userManager;
_libraryManager = libraryManager;
_taskManager = taskManager;
- _json = json;
_localization = localization;
_dtoService = dtoService;
_userDataManager = userDataManager;
- _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger, _itemRepo);
+ _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index 3bd0df0eb..d6d4bbc51 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -258,11 +258,11 @@
"LabelCachePath": "Cache path:",
"LabelCachePathHelp": "This folder contains server cache files, such as images.",
"LabelImagesByNamePath": "Images by name path:",
- "LabelImagesByNamePathHelp": "This folder contains actor, artist, genre and studio images.",
+ "LabelImagesByNamePathHelp": "This folder contains downloaded actor, artist, genre and studio images.",
"LabelMetadataPath": "Metadata path:",
"LabelMetadataPathHelp": "This location contains downloaded artwork and metadata that is not configured to be stored in media folders.",
"LabelTranscodingTempPath": "Transcoding temporary path:",
- "LabelTranscodingTempPathHelp": "This folder contains working files used by the transcoder.",
+ "LabelTranscodingTempPathHelp": "This folder contains working files used by the transcoder. Specify a custom path, or leave empty to use the default within the server's data folder.",
"TabBasics": "Basics",
"TabTV": "TV",
"TabGames": "Games",
@@ -284,7 +284,7 @@
"ButtonAutoScroll": "Auto-scroll",
"LabelImageSavingConvention": "Image saving convention:",
"LabelImageSavingConventionHelp": "Media Browser recognizes images from most major media applications. Choosing your downloading convention is useful if you also use other products.",
- "OptionImageSavingCompatible": "Compatible - Media Browser/Plex/Xbmc",
+ "OptionImageSavingCompatible": "Compatible - Media Browser/Xbmc/Plex",
"OptionImageSavingStandard": "Standard - MB2",
"ButtonSignIn": "Sign In",
"TitleSignIn": "Sign In",
@@ -849,5 +849,14 @@
"LabelXbmcMetadataEnablePathSubstitutionHelp2": "See path substitution.",
"LabelGroupChannelsIntoViews": "Display the following channels directly within my views:",
"LabelGroupChannelsIntoViewsHelp": "If enabled, these channels will be displayed directly alongside other views. If disabled, they'll be displayed within a separate Channels view.",
- "LabelDisplayCollectionsView": "Display a Collections view to show movie collections"
+ "LabelDisplayCollectionsView": "Display a Collections view to show movie collections",
+ "LabelXbmcMetadataEnableExtraThumbs": "Copy extrafanart into extrathumbs",
+ "LabelXbmcMetadataEnableExtraThumbsHelp": "When downloading images they can be saved into both extrafanart and extrathumbs for maximum Xbmc skin compatibility.",
+ "TabServices": "Services",
+ "TabLogs": "Logs",
+ "HeaderServerLogFiles": "Server log files:",
+ "TabBranding": "Branding",
+ "HeaderBrandingHelp": "Customize the appearance of Media Browser to fit the needs of your group or organization.",
+ "LabelLoginDisclaimer": "Login disclaimer:",
+ "LabelLoginDisclaimerHelp": "This will be displayed at the bottom of the login page."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index a909929ae..1d201e069 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -101,6 +101,7 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
+ <Compile Include="Branding\BrandingConfigurationFactory.cs" />
<Compile Include="Channels\ChannelConfigurations.cs" />
<Compile Include="Channels\ChannelDownloadScheduledTask.cs" />
<Compile Include="Channels\ChannelImageProvider.cs" />
diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
index 964e2cd24..b832f3a06 100644
--- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
@@ -4,7 +4,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Notifications;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Notifications;
using System;
@@ -93,7 +92,9 @@ namespace MediaBrowser.Server.Implementations.Notifications
if (options != null && !string.IsNullOrWhiteSpace(request.NotificationType))
{
- return _userManager.Users.Where(i => _config.Configuration.NotificationOptions.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Configuration))
+ var config = GetConfiguration();
+
+ return _userManager.Users.Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Configuration))
.Select(i => i.Id.ToString("N"));
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 2f6790a3e..2d85a3aa7 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Common.Events;
+using System.Security.Cryptography;
+using System.Text;
+using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@@ -1185,6 +1187,24 @@ namespace MediaBrowser.Server.Implementations.Session
};
}
+ private bool IsLocal(string remoteEndpoint)
+ {
+ if (string.IsNullOrWhiteSpace(remoteEndpoint))
+ {
+ throw new ArgumentNullException("remoteEndpoint");
+ }
+
+ // Private address space:
+ // http://en.wikipedia.org/wiki/Private_network
+
+ return remoteEndpoint.IndexOf("localhost", StringComparison.OrdinalIgnoreCase) != -1 ||
+ remoteEndpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
+ remoteEndpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) ||
+ remoteEndpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) ||
+ remoteEndpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
+ remoteEndpoint.StartsWith("::", StringComparison.OrdinalIgnoreCase);
+ }
+
/// <summary>
/// Reports the capabilities.
/// </summary>
@@ -1283,15 +1303,10 @@ namespace MediaBrowser.Server.Implementations.Session
DeviceName = session.DeviceName,
Id = session.Id,
LastActivityDate = session.LastActivityDate,
- NowPlayingPositionTicks = session.PlayState.PositionTicks,
- IsPaused = session.PlayState.IsPaused,
- IsMuted = session.PlayState.IsMuted,
NowViewingItem = session.NowViewingItem,
ApplicationVersion = session.ApplicationVersion,
- CanSeek = session.PlayState.CanSeek,
QueueableMediaTypes = session.QueueableMediaTypes,
PlayableMediaTypes = session.PlayableMediaTypes,
- RemoteEndPoint = session.RemoteEndPoint,
AdditionalUsers = session.AdditionalUsers,
SupportedCommands = session.SupportedCommands,
UserName = session.UserName,
diff --git a/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs
index 46c3df07b..7e6a252cd 100644
--- a/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs
@@ -26,13 +26,36 @@ namespace MediaBrowser.Server.Implementations.Sorting
/// <returns>System.String.</returns>
private DateTime GetValue(BaseItem x)
{
- var series = (x as Series) ?? x.FindParent<Series>();
+ var series = x as Series;
- DateTime result;
- if (series != null && DateTime.TryParse(series.AirTime, out result))
+ if (series == null)
{
- return result;
- }
+ var season = x as Season;
+
+ if (season != null)
+ {
+ series = season.Series;
+ }
+ else
+ {
+ var episode = x as Episode;
+
+ if (episode != null)
+ {
+ series = episode.Series;
+ }
+ }
+ }
+
+ if (series != null)
+ {
+ DateTime result;
+ if (DateTime.TryParse(series.AirTime, out result))
+ {
+ return result;
+ }
+ }
+
return DateTime.MinValue;
}
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 673a9f151..91e92e21c 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -654,7 +654,7 @@ namespace MediaBrowser.ServerApplication
var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);
RegisterSingleInstance<ICollectionManager>(collectionManager);
- LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, JsonSerializer, LocalizationManager);
+ LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager);
RegisterSingleInstance(LiveTvManager);
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, FileSystemManager, UserManager, ChannelManager, LiveTvManager);
diff --git a/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs b/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs
index 4ba98e9b6..c2c64ea4d 100644
--- a/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs
+++ b/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs
@@ -87,18 +87,6 @@ namespace MediaBrowser.ServerApplication.Native
}
/// <summary>
- /// Opens the standard API documentation.
- /// </summary>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="appHost">The app host.</param>
- /// <param name="logger">The logger.</param>
- public static void OpenStandardApiDocumentation(IServerConfigurationManager configurationManager, IServerApplicationHost appHost, ILogger logger)
- {
- OpenUrl("http://localhost:" + configurationManager.Configuration.HttpServerPortNumber + "/" +
- appHost.WebApplicationName + "/metadata", logger);
- }
-
- /// <summary>
/// Opens the URL.
/// </summary>
/// <param name="url">The URL.</param>
diff --git a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
index f5f9434e7..47a4be8e3 100644
--- a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
+++ b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
@@ -29,7 +29,6 @@ namespace MediaBrowser.ServerApplication
private System.Windows.Forms.ToolStripMenuItem cmdLogWindow;
private System.Windows.Forms.ToolStripMenuItem cmdCommunity;
private System.Windows.Forms.ToolStripMenuItem cmdApiDocs;
- private System.Windows.Forms.ToolStripMenuItem cmdStandardDocs;
private System.Windows.Forms.ToolStripMenuItem cmdSwagger;
private System.Windows.Forms.ToolStripMenuItem cmdGtihub;
@@ -90,7 +89,6 @@ namespace MediaBrowser.ServerApplication
cmdConfigure = new System.Windows.Forms.ToolStripMenuItem();
cmdBrowse = new System.Windows.Forms.ToolStripMenuItem();
cmdApiDocs = new System.Windows.Forms.ToolStripMenuItem();
- cmdStandardDocs = new System.Windows.Forms.ToolStripMenuItem();
cmdSwagger = new System.Windows.Forms.ToolStripMenuItem();
cmdGtihub = new System.Windows.Forms.ToolStripMenuItem();
@@ -169,17 +167,11 @@ namespace MediaBrowser.ServerApplication
// cmdApiDocs
//
cmdApiDocs.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
- cmdStandardDocs,
cmdSwagger,
cmdGtihub});
cmdApiDocs.Name = "cmdApiDocs";
cmdApiDocs.Size = new System.Drawing.Size(208, 22);
//
- // cmdStandardDocs
- //
- cmdStandardDocs.Name = "cmdStandardDocs";
- cmdStandardDocs.Size = new System.Drawing.Size(136, 22);
- //
// cmdSwagger
//
cmdSwagger.Name = "cmdSwagger";
@@ -199,7 +191,6 @@ namespace MediaBrowser.ServerApplication
cmdLibraryExplorer.Click += cmdLibraryExplorer_Click;
cmdSwagger.Click += cmdSwagger_Click;
- cmdStandardDocs.Click += cmdStandardDocs_Click;
cmdGtihub.Click += cmdGtihub_Click;
LoadLogWindow(null, EventArgs.Empty);
@@ -224,7 +215,6 @@ namespace MediaBrowser.ServerApplication
cmdCommunity.Text = _localization.GetLocalizedString("LabelVisitCommunity");
cmdGtihub.Text = _localization.GetLocalizedString("LabelGithubWiki");
cmdSwagger.Text = _localization.GetLocalizedString("LabelSwagger");
- cmdStandardDocs.Text = _localization.GetLocalizedString("LabelStandard");
cmdApiDocs.Text = _localization.GetLocalizedString("LabelViewApiDocumentation");
cmdBrowse.Text = _localization.GetLocalizedString("LabelBrowseLibrary");
cmdConfigure.Text = _localization.GetLocalizedString("LabelConfigureMediaBrowser");
@@ -346,11 +336,6 @@ namespace MediaBrowser.ServerApplication
BrowserLauncher.OpenGithub(_logger);
}
- void cmdStandardDocs_Click(object sender, EventArgs e)
- {
- BrowserLauncher.OpenStandardApiDocumentation(_configurationManager, _appHost, _logger);
- }
-
void cmdSwagger_Click(object sender, EventArgs e)
{
BrowserLauncher.OpenSwagger(_configurationManager, _appHost, _logger);
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 3ccf26c37..36adae71c 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -521,6 +521,7 @@ namespace MediaBrowser.WebDashboard.Api
"mediacontroller.js",
"chromecast.js",
"backdrops.js",
+ "branding.js",
"mediaplayer.js",
"mediaplayer-video.js",
@@ -529,7 +530,6 @@ namespace MediaBrowser.WebDashboard.Api
"ratingdialog.js",
"aboutpage.js",
- "allusersettings.js",
"alphapicker.js",
"addpluginpage.js",
"advancedconfigurationpage.js",
@@ -537,7 +537,6 @@ namespace MediaBrowser.WebDashboard.Api
"advancedserversettings.js",
"metadataadvanced.js",
"appsplayback.js",
- "appsweather.js",
"autoorganizetv.js",
"autoorganizelog.js",
"channels.js",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 8f85fcb51..0099daaf1 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -98,6 +98,9 @@
<Content Include="dashboard-ui\appsplayback.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\branding.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\channelitems.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -392,9 +395,6 @@
<Content Include="dashboard-ui\musicalbumartists.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\allusersettings.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\collections.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -617,6 +617,9 @@
<Content Include="dashboard-ui\scripts\backdrops.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\branding.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\channelitems.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1499,9 +1502,6 @@
<Content Include="dashboard-ui\musicvideos.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\allusersettings.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\alphapicker.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1749,11 +1749,6 @@
</Content>
</ItemGroup>
<ItemGroup>
- <Content Include="dashboard-ui\appsweather.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- </ItemGroup>
- <ItemGroup>
<Content Include="dashboard-ui\useredit.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1815,11 +1810,6 @@
</Content>
</ItemGroup>
<ItemGroup>
- <Content Include="dashboard-ui\scripts\appsweather.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- </ItemGroup>
- <ItemGroup>
<Content Include="dashboard-ui\scripts\pluginspage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>