fixes #762 - Marking unwatched doesn't update display

pull/702/head
Luke Pulverenti 10 years ago
parent 59dc591f66
commit 7fa9b14f56

@ -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,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);

@ -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,
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
}
}

@ -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>

@ -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>

@ -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);
}
}
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;

@ -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…
Cancel
Save