mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-04-23 21:47:14 -04:00
fixes #762 - Marking unwatched doesn't update display
This commit is contained in:
parent
59dc591f66
commit
7fa9b14f56
55 changed files with 706 additions and 438 deletions
28
MediaBrowser.Api/BrandingService.cs
Normal file
28
MediaBrowser.Api/BrandingService.cs
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,13 +11,64 @@ 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}/Subtitles/{Index}", "DELETE", Summary = "Deletes an external subtitle file")]
|
||||
[Authenticated]
|
||||
public class DeleteSubtitle
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "DELETE")]
|
||||
public int Index { get; set; }
|
||||
}
|
||||
|
||||
[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")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "Language", Description = "Language", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Language { get; set; }
|
||||
}
|
||||
|
||||
[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")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[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")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "SubtitleId", Description = "SubtitleId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string SubtitleId { get; set; }
|
||||
}
|
||||
|
||||
[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; }
|
||||
}
|
||||
|
||||
[Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format (vtt).")]
|
||||
public class GetSubtitle
|
||||
{
|
||||
|
@ -39,55 +92,6 @@ namespace MediaBrowser.Api.Library
|
|||
public long StartPositionTicks { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Videos/{Id}/Subtitles/{Index}", "DELETE", Summary = "Deletes an external subtitle file")]
|
||||
public class DeleteSubtitle
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "DELETE")]
|
||||
public int Index { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{Id}/RemoteSearch/Subtitles/{Language}", "GET")]
|
||||
public class SearchRemoteSubtitles : IReturn<List<RemoteSubtitleInfo>>
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "Language", Description = "Language", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Language { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{Id}/RemoteSearch/Subtitles/Providers", "GET")]
|
||||
public class GetSubtitleProviders : IReturn<List<SubtitleProviderInfo>>
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{Id}/RemoteSearch/Subtitles/{SubtitleId}", "POST")]
|
||||
public class DownloadRemoteSubtitles : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "SubtitleId", Description = "SubtitleId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string SubtitleId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Providers/Subtitles/Subtitles/{Id}", "GET")]
|
||||
public class GetRemoteSubtitles : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
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);
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -25,13 +25,6 @@ namespace MediaBrowser.Controller.Dto
|
|||
/// <returns>System.String.</returns>
|
||||
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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -769,6 +770,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
/// <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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,10 +8,24 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
{
|
||||
get
|
||||
{
|
||||
return FindParent<Season>();
|
||||
return Season;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
||||
/// <summary>
|
||||
/// No providers will be executed
|
||||
/// </summary>
|
||||
None = 1,
|
||||
|
||||
/// <summary>
|
||||
/// All providers will be executed to search for new metadata
|
||||
/// </summary>
|
||||
FullRefresh = 2,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The validation only
|
||||
/// </summary>
|
||||
ValidationOnly = 3
|
||||
ValidationOnly = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Providers will be executed based on default rules
|
||||
/// </summary>
|
||||
Default = 2,
|
||||
|
||||
/// <summary>
|
||||
/// All providers will be executed to search for new metadata
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
12
MediaBrowser.Model/Branding/BrandingOptions.cs
Normal file
12
MediaBrowser.Model/Branding/BrandingOptions.cs
Normal file
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Model.Dto
|
||||
{
|
||||
|
@ -15,6 +15,18 @@ namespace MediaBrowser.Model.Dto
|
|||
/// <value>The rating.</value>
|
||||
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>
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using MediaBrowser.Model.Configuration;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.Notifications
|
||||
|
|
|
@ -1,32 +1,20 @@
|
|||
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
|
||||
{
|
||||
[DebuggerDisplay("Client = {Client}, Username = {UserName}")]
|
||||
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.
|
||||
|
@ -118,12 +94,6 @@ namespace MediaBrowser.Model.Session
|
|||
/// <value>The now playing item.</value>
|
||||
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>
|
||||
|
|
31
MediaBrowser.Model/System/LogFile.cs
Normal file
31
MediaBrowser.Model/System/LogFile.cs
Normal file
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
dto.UserData.Played = dto.PlayedPercentage.HasValue && dto.PlayedPercentage.Value >= 100;
|
||||
dto.UserData.PlayedPercentage = dto.PlayedPercentage;
|
||||
dto.UserData.UnplayedItemCount = dto.RecursiveUnplayedItemCount;
|
||||
}
|
||||
|
||||
var userData = _userDataRepository.GetUserData(user.Id, item.GetUserDataKey());
|
||||
|
||||
dto.UserData = GetUserItemDataDto(userData);
|
||||
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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."
|
||||
}
|
|
@ -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" />
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -86,18 +86,6 @@ namespace MediaBrowser.ServerApplication.Native
|
|||
appHost.WebApplicationName + "/swagger-ui/index.html", logger);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
|
@ -1748,11 +1748,6 @@
|
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="dashboard-ui\appsweather.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="dashboard-ui\useredit.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
@ -1814,11 +1809,6 @@
|
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue