mirror of https://github.com/jellyfin/jellyfin.git
Add GPL modules
This commit is contained in:
parent
9bac3ac616
commit
a86b71899e
|
@ -231,7 +231,7 @@ namespace Emby.Notifications
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasSeries = item as IHasSeriesName;
|
var hasSeries = item as IHasSeries;
|
||||||
|
|
||||||
if (hasSeries != null)
|
if (hasSeries != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -318,7 +318,6 @@ namespace Emby.Server.Implementations
|
||||||
private IMediaEncoder MediaEncoder { get; set; }
|
private IMediaEncoder MediaEncoder { get; set; }
|
||||||
private ISubtitleEncoder SubtitleEncoder { get; set; }
|
private ISubtitleEncoder SubtitleEncoder { get; set; }
|
||||||
|
|
||||||
private IConnectManager ConnectManager { get; set; }
|
|
||||||
private ISessionManager SessionManager { get; set; }
|
private ISessionManager SessionManager { get; set; }
|
||||||
|
|
||||||
private ILiveTvManager LiveTvManager { get; set; }
|
private ILiveTvManager LiveTvManager { get; set; }
|
||||||
|
@ -839,8 +838,6 @@ namespace Emby.Server.Implementations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract IConnectManager CreateConnectManager();
|
|
||||||
|
|
||||||
protected virtual IHttpClient CreateHttpClient()
|
protected virtual IHttpClient CreateHttpClient()
|
||||||
{
|
{
|
||||||
return new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, GetDefaultUserAgent);
|
return new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, GetDefaultUserAgent);
|
||||||
|
@ -947,7 +944,7 @@ namespace Emby.Server.Implementations
|
||||||
AuthenticationRepository = GetAuthenticationRepository();
|
AuthenticationRepository = GetAuthenticationRepository();
|
||||||
RegisterSingleInstance(AuthenticationRepository);
|
RegisterSingleInstance(AuthenticationRepository);
|
||||||
|
|
||||||
UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider);
|
UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, this, JsonSerializer, FileSystemManager, CryptographyProvider);
|
||||||
RegisterSingleInstance(UserManager);
|
RegisterSingleInstance(UserManager);
|
||||||
|
|
||||||
LibraryManager = new LibraryManager(this, Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
|
LibraryManager = new LibraryManager(this, Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
|
||||||
|
@ -986,9 +983,6 @@ namespace Emby.Server.Implementations
|
||||||
var encryptionManager = new EncryptionManager();
|
var encryptionManager = new EncryptionManager();
|
||||||
RegisterSingleInstance<IEncryptionManager>(encryptionManager);
|
RegisterSingleInstance<IEncryptionManager>(encryptionManager);
|
||||||
|
|
||||||
ConnectManager = CreateConnectManager();
|
|
||||||
RegisterSingleInstance(ConnectManager);
|
|
||||||
|
|
||||||
DeviceManager = new DeviceManager(AuthenticationRepository, JsonSerializer, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
|
DeviceManager = new DeviceManager(AuthenticationRepository, JsonSerializer, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
|
||||||
RegisterSingleInstance(DeviceManager);
|
RegisterSingleInstance(DeviceManager);
|
||||||
|
|
||||||
|
@ -1045,11 +1039,11 @@ namespace Emby.Server.Implementations
|
||||||
RegisterSingleInstance(activityLogRepo);
|
RegisterSingleInstance(activityLogRepo);
|
||||||
RegisterSingleInstance<IActivityManager>(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager));
|
RegisterSingleInstance<IActivityManager>(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager));
|
||||||
|
|
||||||
var authContext = new AuthorizationContext(AuthenticationRepository, ConnectManager, UserManager);
|
var authContext = new AuthorizationContext(AuthenticationRepository, UserManager);
|
||||||
RegisterSingleInstance<IAuthorizationContext>(authContext);
|
RegisterSingleInstance<IAuthorizationContext>(authContext);
|
||||||
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
|
RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
|
||||||
|
|
||||||
AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, NetworkManager);
|
AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, SessionManager, NetworkManager);
|
||||||
RegisterSingleInstance<IAuthService>(AuthService);
|
RegisterSingleInstance<IAuthService>(AuthService);
|
||||||
|
|
||||||
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory, TextEncoding);
|
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory, TextEncoding);
|
||||||
|
|
|
@ -1086,7 +1086,7 @@ namespace Emby.Server.Implementations.Channels
|
||||||
}
|
}
|
||||||
item.ParentId = parentFolderId;
|
item.ParentId = parentFolderId;
|
||||||
|
|
||||||
var hasSeries = item as IHasSeriesName;
|
var hasSeries = item as IHasSeries;
|
||||||
if (hasSeries != null)
|
if (hasSeries != null)
|
||||||
{
|
{
|
||||||
if (!string.Equals(hasSeries.SeriesName, info.SeriesName, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(hasSeries.SeriesName, info.SeriesName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
@ -1215,4 +1215,4 @@ namespace Emby.Server.Implementations.Channels
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -942,7 +942,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
saveItemStatement.TryBind("@Album", item.Album);
|
saveItemStatement.TryBind("@Album", item.Album);
|
||||||
saveItemStatement.TryBind("@IsVirtualItem", item.IsVirtualItem);
|
saveItemStatement.TryBind("@IsVirtualItem", item.IsVirtualItem);
|
||||||
|
|
||||||
var hasSeriesName = item as IHasSeriesName;
|
var hasSeriesName = item as IHasSeries;
|
||||||
if (hasSeriesName != null)
|
if (hasSeriesName != null)
|
||||||
{
|
{
|
||||||
saveItemStatement.TryBind("@SeriesName", hasSeriesName.SeriesName);
|
saveItemStatement.TryBind("@SeriesName", hasSeriesName.SeriesName);
|
||||||
|
@ -1757,7 +1757,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
var hasSeriesName = item as IHasSeriesName;
|
var hasSeriesName = item as IHasSeries;
|
||||||
if (hasSeriesName != null)
|
if (hasSeriesName != null)
|
||||||
{
|
{
|
||||||
if (!reader.IsDBNull(index))
|
if (!reader.IsDBNull(index))
|
||||||
|
@ -6441,4 +6441,4 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,19 +17,17 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
||||||
{
|
{
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
|
||||||
public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, IConnectManager connectManager, ISessionManager sessionManager, INetworkManager networkManager)
|
public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, ISessionManager sessionManager, INetworkManager networkManager)
|
||||||
{
|
{
|
||||||
AuthorizationContext = authorizationContext;
|
AuthorizationContext = authorizationContext;
|
||||||
_config = config;
|
_config = config;
|
||||||
SessionManager = sessionManager;
|
SessionManager = sessionManager;
|
||||||
ConnectManager = connectManager;
|
|
||||||
UserManager = userManager;
|
UserManager = userManager;
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IUserManager UserManager { get; private set; }
|
public IUserManager UserManager { get; private set; }
|
||||||
public IAuthorizationContext AuthorizationContext { get; private set; }
|
public IAuthorizationContext AuthorizationContext { get; private set; }
|
||||||
public IConnectManager ConnectManager { get; private set; }
|
|
||||||
public ISessionManager SessionManager { get; private set; }
|
public ISessionManager SessionManager { get; private set; }
|
||||||
public INetworkManager NetworkManager { get; private set; }
|
public INetworkManager NetworkManager { get; private set; }
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,11 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
||||||
public class AuthorizationContext : IAuthorizationContext
|
public class AuthorizationContext : IAuthorizationContext
|
||||||
{
|
{
|
||||||
private readonly IAuthenticationRepository _authRepo;
|
private readonly IAuthenticationRepository _authRepo;
|
||||||
private readonly IConnectManager _connectManager;
|
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
|
|
||||||
public AuthorizationContext(IAuthenticationRepository authRepo, IConnectManager connectManager, IUserManager userManager)
|
public AuthorizationContext(IAuthenticationRepository authRepo, IUserManager userManager)
|
||||||
{
|
{
|
||||||
_authRepo = authRepo;
|
_authRepo = authRepo;
|
||||||
_connectManager = connectManager;
|
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
using MediaBrowser.Common.Events;
|
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using MediaBrowser.Controller.Connect;
|
|
||||||
using MediaBrowser.Controller.Drawing;
|
|
||||||
using MediaBrowser.Controller.Dto;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using MediaBrowser.Controller.Net;
|
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Controller.Providers;
|
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Connect;
|
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.Events;
|
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using MediaBrowser.Model.Serialization;
|
|
||||||
using MediaBrowser.Model.Users;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MediaBrowser.Model.Cryptography;
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using MediaBrowser.Controller.Authentication;
|
|
||||||
using MediaBrowser.Controller.Security;
|
|
||||||
using MediaBrowser.Controller.Devices;
|
|
||||||
using MediaBrowser.Controller.Session;
|
|
||||||
using MediaBrowser.Controller.Plugins;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Library
|
|
||||||
{
|
|
||||||
public class ConnectManager : IConnectManager
|
|
||||||
{
|
|
||||||
public ConnectManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -74,7 +74,6 @@ namespace Emby.Server.Implementations.Library
|
||||||
|
|
||||||
private readonly Func<IImageProcessor> _imageProcessorFactory;
|
private readonly Func<IImageProcessor> _imageProcessorFactory;
|
||||||
private readonly Func<IDtoService> _dtoServiceFactory;
|
private readonly Func<IDtoService> _dtoServiceFactory;
|
||||||
private readonly Func<IConnectManager> _connectFactory;
|
|
||||||
private readonly IServerApplicationHost _appHost;
|
private readonly IServerApplicationHost _appHost;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly ICryptoProvider _cryptographyProvider;
|
private readonly ICryptoProvider _cryptographyProvider;
|
||||||
|
@ -82,7 +81,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
private IAuthenticationProvider[] _authenticationProviders;
|
private IAuthenticationProvider[] _authenticationProviders;
|
||||||
private DefaultAuthenticationProvider _defaultAuthenticationProvider;
|
private DefaultAuthenticationProvider _defaultAuthenticationProvider;
|
||||||
|
|
||||||
public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ICryptoProvider cryptographyProvider)
|
public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ICryptoProvider cryptographyProvider)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
UserRepository = userRepository;
|
UserRepository = userRepository;
|
||||||
|
@ -90,7 +89,6 @@ namespace Emby.Server.Implementations.Library
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_imageProcessorFactory = imageProcessorFactory;
|
_imageProcessorFactory = imageProcessorFactory;
|
||||||
_dtoServiceFactory = dtoServiceFactory;
|
_dtoServiceFactory = dtoServiceFactory;
|
||||||
_connectFactory = connectFactory;
|
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
|
|
@ -61,21 +61,6 @@ namespace MediaBrowser.Api
|
||||||
public bool? IsAppStoreEnabled { get; set; }
|
public bool? IsAppStoreEnabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class GetPackageVersionUpdates
|
|
||||||
/// </summary>
|
|
||||||
[Route("/Packages/Updates", "GET", Summary = "Gets available package updates for currently installed packages")]
|
|
||||||
[Authenticated(Roles = "Admin")]
|
|
||||||
public class GetPackageVersionUpdates : IReturn<PackageVersionInfo[]>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the name.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The name.</value>
|
|
||||||
[ApiMember(Name = "PackageType", Description = "Package type filter (System/UserInstalled)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
|
||||||
public string PackageType { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class InstallPackage
|
/// Class InstallPackage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -146,30 +131,7 @@ namespace MediaBrowser.Api
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public async Task<object> Get(GetPackageVersionUpdates request)
|
///
|
||||||
{
|
|
||||||
PackageVersionInfo[] result = null;
|
|
||||||
|
|
||||||
if (string.Equals(request.PackageType, "UserInstalled", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
result = (await _installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, false, CancellationToken.None).ConfigureAwait(false)).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string.Equals(request.PackageType, "System", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var updateCheckResult = await _appHost
|
|
||||||
.CheckForApplicationUpdate(CancellationToken.None, new SimpleProgress<double>()).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (updateCheckResult.IsUpdateAvailable)
|
|
||||||
{
|
|
||||||
result = new PackageVersionInfo[] { updateCheckResult.Package };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ToOptimizedResult(result ?? new PackageVersionInfo[] { });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the specified request.
|
/// Gets the specified request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -148,7 +148,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
DisposeTranscodingThrottler();
|
DisposeTranscodingThrottler();
|
||||||
DisposeLiveStream();
|
DisposeLiveStream();
|
||||||
DisposeLogStream();
|
DisposeLogStream();
|
||||||
DisposeIsoMount();
|
|
||||||
|
|
||||||
TranscodingJob = null;
|
TranscodingJob = null;
|
||||||
}
|
}
|
||||||
|
@ -251,9 +250,9 @@ namespace MediaBrowser.Api.Playback
|
||||||
public DeviceProfile DeviceProfile { get; set; }
|
public DeviceProfile DeviceProfile { get; set; }
|
||||||
|
|
||||||
public TranscodingJob TranscodingJob;
|
public TranscodingJob TranscodingJob;
|
||||||
public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
|
public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float framerate, double? percentComplete, long bytesTranscoded, int? bitRate)
|
||||||
{
|
{
|
||||||
ApiEntryPoint.Instance.ReportTranscodingProgress(TranscodingJob, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate);
|
ApiEntryPoint.Instance.ReportTranscodingProgress(TranscodingJob, this, transcodingPosition, 0, percentComplete, 0, bitRate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,7 +230,7 @@ namespace MediaBrowser.Api
|
||||||
result.StartDate = program.StartDate;
|
result.StartDate = program.StartDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasSeries = item as IHasSeriesName;
|
var hasSeries = item as IHasSeries;
|
||||||
if (hasSeries != null)
|
if (hasSeries != null)
|
||||||
{
|
{
|
||||||
result.Series = hasSeries.SeriesName;
|
result.Series = hasSeries.SeriesName;
|
||||||
|
|
|
@ -51,16 +51,14 @@ namespace MediaBrowser.Api
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly IServerApplicationHost _appHost;
|
private readonly IServerApplicationHost _appHost;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IConnectManager _connectManager;
|
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
|
|
||||||
public StartupWizardService(IServerConfigurationManager config, IHttpClient httpClient, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, IMediaEncoder mediaEncoder)
|
public StartupWizardService(IServerConfigurationManager config, IHttpClient httpClient, IServerApplicationHost appHost, IUserManager userManager, IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_connectManager = connectManager;
|
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Configuration
|
||||||
|
{
|
||||||
|
public class ConfigurationUpdateEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the key.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The key.</value>
|
||||||
|
public string Key { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the new configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The new configuration.</value>
|
||||||
|
public object NewConfiguration { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Configuration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IApplicationPaths
|
||||||
|
/// </summary>
|
||||||
|
public interface IApplicationPaths
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the program data folder
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The program data path.</value>
|
||||||
|
string ProgramDataPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the program system folder
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The program data path.</value>
|
||||||
|
string ProgramSystemPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the folder path to the data directory
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The data directory.</value>
|
||||||
|
string DataPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the image cache path.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The image cache path.</value>
|
||||||
|
string ImageCachePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the plugin directory
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The plugins path.</value>
|
||||||
|
string PluginsPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the plugin configurations directory
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The plugin configurations path.</value>
|
||||||
|
string PluginConfigurationsPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to where temporary update files will be stored
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The plugin configurations path.</value>
|
||||||
|
string TempUpdatePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the log directory
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The log directory path.</value>
|
||||||
|
string LogDirectoryPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the application configuration root directory
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration directory path.</value>
|
||||||
|
string ConfigurationDirectoryPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the system configuration file
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The system configuration file path.</value>
|
||||||
|
string SystemConfigurationFilePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the folder path to the cache directory
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The cache directory.</value>
|
||||||
|
string CachePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the folder path to the temp directory within the cache folder
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The temp directory.</value>
|
||||||
|
string TempDirectory { get; }
|
||||||
|
|
||||||
|
string VirtualDataPath { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Configuration
|
||||||
|
{
|
||||||
|
public interface IConfigurationFactory
|
||||||
|
{
|
||||||
|
IEnumerable<ConfigurationStore> GetConfigurations();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConfigurationStore
|
||||||
|
{
|
||||||
|
public string Key { get; set; }
|
||||||
|
|
||||||
|
public Type ConfigurationType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IValidatingConfiguration
|
||||||
|
{
|
||||||
|
void Validate(object oldConfig, object newConfig);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Configuration
|
||||||
|
{
|
||||||
|
public interface IConfigurationManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [configuration updating].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdating;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [configuration updated].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<EventArgs> ConfigurationUpdated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [named configuration updated].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the application paths.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The application paths.</value>
|
||||||
|
IApplicationPaths CommonApplicationPaths { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration.</value>
|
||||||
|
BaseApplicationConfiguration CommonConfiguration { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the configuration.
|
||||||
|
/// </summary>
|
||||||
|
void SaveConfiguration();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces the configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newConfiguration">The new configuration.</param>
|
||||||
|
void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key.</param>
|
||||||
|
/// <returns>System.Object.</returns>
|
||||||
|
object GetConfiguration(string key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of the configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key.</param>
|
||||||
|
/// <returns>Type.</returns>
|
||||||
|
Type GetConfigurationType(string key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key.</param>
|
||||||
|
/// <param name="configuration">The configuration.</param>
|
||||||
|
void SaveConfiguration(string key, object configuration);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the parts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="factories">The factories.</param>
|
||||||
|
void AddParts(IEnumerable<IConfigurationFactory> factories);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConfigurationManagerExtensions
|
||||||
|
{
|
||||||
|
public static T GetConfiguration<T>(this IConfigurationManager manager, string key)
|
||||||
|
{
|
||||||
|
return (T)manager.GetConfiguration(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class EventHelper
|
||||||
|
/// </summary>
|
||||||
|
public static class EventHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fires the event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <param name="sender">The sender.</param>
|
||||||
|
/// <param name="args">The <see cref="EventArgs" /> instance containing the event data.</param>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
|
public static void QueueEventIfNotNull(EventHandler handler, object sender, EventArgs args, ILogger logger)
|
||||||
|
{
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler(sender, args);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.ErrorException("Error in event handler", ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queues the event.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <param name="sender">The sender.</param>
|
||||||
|
/// <param name="args">The args.</param>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
|
public static void QueueEventIfNotNull<T>(EventHandler<T> handler, object sender, T args, ILogger logger)
|
||||||
|
{
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler(sender, args);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.ErrorException("Error in event handler", ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fires the event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <param name="sender">The sender.</param>
|
||||||
|
/// <param name="args">The <see cref="EventArgs" /> instance containing the event data.</param>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
|
public static void FireEventIfNotNull(EventHandler handler, object sender, EventArgs args, ILogger logger)
|
||||||
|
{
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler(sender, args);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.ErrorException("Error in event handler", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fires the event.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <param name="sender">The sender.</param>
|
||||||
|
/// <param name="args">The args.</param>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
|
public static void FireEventIfNotNull<T>(EventHandler<T> handler, object sender, T args, ILogger logger)
|
||||||
|
{
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler(sender, args);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.ErrorException("Error in event handler", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using MediaBrowser.Model.Cryptography;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class BaseExtensions
|
||||||
|
/// </summary>
|
||||||
|
public static class BaseExtensions
|
||||||
|
{
|
||||||
|
public static ICryptoProvider CryptographyProvider { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Strips the HTML.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="htmlString">The HTML string.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
public static string StripHtml(this string htmlString)
|
||||||
|
{
|
||||||
|
// http://stackoverflow.com/questions/1349023/how-can-i-strip-html-from-text-in-net
|
||||||
|
const string pattern = @"<(.|\n)*?>";
|
||||||
|
|
||||||
|
return Regex.Replace(htmlString, pattern, string.Empty).Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the M d5.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The STR.</param>
|
||||||
|
/// <returns>Guid.</returns>
|
||||||
|
public static Guid GetMD5(this string str)
|
||||||
|
{
|
||||||
|
return CryptographyProvider.GetMD5(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the MB id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The STR.</param>
|
||||||
|
/// <param name="type">The type.</param>
|
||||||
|
/// <returns>Guid.</returns>
|
||||||
|
/// <exception cref="System.ArgumentNullException">type</exception>
|
||||||
|
[Obsolete("Use LibraryManager.GetNewItemId")]
|
||||||
|
public static Guid GetMBId(this string str, Type type)
|
||||||
|
{
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("type");
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = type.FullName + str.ToLower();
|
||||||
|
|
||||||
|
return key.GetMD5();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class ResourceNotFoundException
|
||||||
|
/// </summary>
|
||||||
|
public class ResourceNotFoundException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ResourceNotFoundException" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public ResourceNotFoundException()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ResourceNotFoundException" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message.</param>
|
||||||
|
public ResourceNotFoundException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RemoteServiceUnavailableException : Exception
|
||||||
|
{
|
||||||
|
public RemoteServiceUnavailableException()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoteServiceUnavailableException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RateLimitExceededException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RateLimitExceededException" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public RateLimitExceededException()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RateLimitExceededException" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message.</param>
|
||||||
|
public RateLimitExceededException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
using MediaBrowser.Common.Plugins;
|
||||||
|
using MediaBrowser.Model.Events;
|
||||||
|
using MediaBrowser.Model.Updates;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An interface to be implemented by the applications hosting a kernel
|
||||||
|
/// </summary>
|
||||||
|
public interface IApplicationHost
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display name of the operating system.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The display name of the operating system.</value>
|
||||||
|
string OperatingSystemDisplayName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the device identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The device identifier.</value>
|
||||||
|
string SystemId { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [application updated].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<GenericEventArgs<PackageVersionInfo>> ApplicationUpdated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this instance has pending kernel reload.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance has pending kernel reload; otherwise, <c>false</c>.</value>
|
||||||
|
bool HasPendingRestart { get; }
|
||||||
|
|
||||||
|
bool IsShuttingDown { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance can self restart.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value>
|
||||||
|
bool CanSelfRestart { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [has pending restart changed].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler HasPendingRestartChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Notifies the pending restart.
|
||||||
|
/// </summary>
|
||||||
|
void NotifyPendingRestart();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restarts this instance.
|
||||||
|
/// </summary>
|
||||||
|
void Restart();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the application version.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The application version.</value>
|
||||||
|
Version ApplicationVersion { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this instance can self update.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
|
||||||
|
bool CanSelfUpdate { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the exports.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
|
||||||
|
/// <returns>IEnumerable{``0}.</returns>
|
||||||
|
IEnumerable<T> GetExports<T>(bool manageLiftime = true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for update.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Task{CheckForUpdateResult}.</returns>
|
||||||
|
Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the application.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress<double> progress);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolves this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns>``0.</returns>
|
||||||
|
T Resolve<T>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolves this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns>``0.</returns>
|
||||||
|
T TryResolve<T>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shuts down.
|
||||||
|
/// </summary>
|
||||||
|
Task Shutdown();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugins.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The plugins.</value>
|
||||||
|
IPlugin[] Plugins { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the plugin.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="plugin">The plugin.</param>
|
||||||
|
void RemovePlugin(IPlugin plugin);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inits this instance.
|
||||||
|
/// </summary>
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type.</param>
|
||||||
|
/// <returns>System.Object.</returns>
|
||||||
|
object CreateInstance(Type type);
|
||||||
|
|
||||||
|
PackageVersionClass SystemUpdateLevel { get; }
|
||||||
|
|
||||||
|
string GetValue(string name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\SharedVersion.cs"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,157 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class HttpRequestOptions
|
||||||
|
/// </summary>
|
||||||
|
public class HttpRequestOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the URL.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The URL.</value>
|
||||||
|
public string Url { get; set; }
|
||||||
|
|
||||||
|
public CompressionMethod? DecompressionMethod { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the accept header.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The accept header.</value>
|
||||||
|
public string AcceptHeader
|
||||||
|
{
|
||||||
|
get { return GetHeaderValue("Accept"); }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RequestHeaders["Accept"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the cancellation token.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The cancellation token.</value>
|
||||||
|
public CancellationToken CancellationToken { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the resource pool.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The resource pool.</value>
|
||||||
|
public SemaphoreSlim ResourcePool { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the user agent.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The user agent.</value>
|
||||||
|
public string UserAgent
|
||||||
|
{
|
||||||
|
get { return GetHeaderValue("User-Agent"); }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RequestHeaders["User-Agent"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the referrer.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The referrer.</value>
|
||||||
|
public string Referer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the host.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The host.</value>
|
||||||
|
public string Host { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the progress.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The progress.</value>
|
||||||
|
public IProgress<double> Progress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether [enable HTTP compression].
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if [enable HTTP compression]; otherwise, <c>false</c>.</value>
|
||||||
|
public bool EnableHttpCompression { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, string> RequestHeaders { get; private set; }
|
||||||
|
|
||||||
|
public string RequestContentType { get; set; }
|
||||||
|
|
||||||
|
public string RequestContent { get; set; }
|
||||||
|
public byte[] RequestContentBytes { get; set; }
|
||||||
|
|
||||||
|
public bool BufferContent { get; set; }
|
||||||
|
|
||||||
|
public bool LogRequest { get; set; }
|
||||||
|
public bool LogRequestAsDebug { get; set; }
|
||||||
|
public bool LogErrors { get; set; }
|
||||||
|
public bool LogResponse { get; set; }
|
||||||
|
public bool LogResponseHeaders { get; set; }
|
||||||
|
|
||||||
|
public bool LogErrorResponseBody { get; set; }
|
||||||
|
public bool EnableKeepAlive { get; set; }
|
||||||
|
|
||||||
|
public CacheMode CacheMode { get; set; }
|
||||||
|
public TimeSpan CacheLength { get; set; }
|
||||||
|
|
||||||
|
public int TimeoutMs { get; set; }
|
||||||
|
public bool EnableDefaultUserAgent { get; set; }
|
||||||
|
|
||||||
|
public bool AppendCharsetToMimeType { get; set; }
|
||||||
|
public string DownloadFilePath { get; set; }
|
||||||
|
|
||||||
|
private string GetHeaderValue(string name)
|
||||||
|
{
|
||||||
|
string value;
|
||||||
|
|
||||||
|
RequestHeaders.TryGetValue(name, out value);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HttpRequestOptions"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public HttpRequestOptions()
|
||||||
|
{
|
||||||
|
EnableHttpCompression = true;
|
||||||
|
|
||||||
|
RequestHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
LogRequest = true;
|
||||||
|
LogErrors = true;
|
||||||
|
CacheMode = CacheMode.None;
|
||||||
|
|
||||||
|
TimeoutMs = 20000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPostData(IDictionary<string,string> values)
|
||||||
|
{
|
||||||
|
var strings = values.Keys.Select(key => string.Format("{0}={1}", key, values[key]));
|
||||||
|
var postContent = string.Join("&", strings.ToArray());
|
||||||
|
|
||||||
|
RequestContent = postContent;
|
||||||
|
RequestContentType = "application/x-www-form-urlencoded";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CacheMode
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Unconditional = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CompressionMethod
|
||||||
|
{
|
||||||
|
Deflate,
|
||||||
|
Gzip
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class HttpResponseInfo
|
||||||
|
/// </summary>
|
||||||
|
public class HttpResponseInfo : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type of the content.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type of the content.</value>
|
||||||
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the response URL.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The response URL.</value>
|
||||||
|
public string ResponseUrl { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the content.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The content.</value>
|
||||||
|
public Stream Content { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the status code.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The status code.</value>
|
||||||
|
public HttpStatusCode StatusCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the temp file path.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The temp file path.</value>
|
||||||
|
public string TempFilePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the length of the content.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The length of the content.</value>
|
||||||
|
public long? ContentLength { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the headers.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The headers.</value>
|
||||||
|
public Dictionary<string,string> Headers { get; set; }
|
||||||
|
|
||||||
|
private readonly IDisposable _disposable;
|
||||||
|
|
||||||
|
public HttpResponseInfo(IDisposable disposable)
|
||||||
|
{
|
||||||
|
_disposable = disposable;
|
||||||
|
Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
public HttpResponseInfo()
|
||||||
|
{
|
||||||
|
Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposable != null)
|
||||||
|
{
|
||||||
|
_disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IHttpClient
|
||||||
|
/// </summary>
|
||||||
|
public interface IHttpClient
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the response.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <returns>Task{HttpResponseInfo}.</returns>
|
||||||
|
Task<HttpResponseInfo> GetResponse(HttpRequestOptions options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the specified options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <returns>Task{Stream}.</returns>
|
||||||
|
Task<Stream> Get(HttpRequestOptions options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the asynchronous.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <param name="httpMethod">The HTTP method.</param>
|
||||||
|
/// <returns>Task{HttpResponseInfo}.</returns>
|
||||||
|
Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Posts the specified options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <returns>Task{HttpResponseInfo}.</returns>
|
||||||
|
Task<HttpResponseInfo> Post(HttpRequestOptions options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Downloads the contents of a given url into a temporary location
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <returns>Task{System.String}.</returns>
|
||||||
|
/// <exception cref="System.ArgumentNullException">progress</exception>
|
||||||
|
/// <exception cref="MediaBrowser.Model.Net.HttpException"></exception>
|
||||||
|
Task<string> GetTempFile(HttpRequestOptions options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the temporary file response.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <returns>Task{HttpResponseInfo}.</returns>
|
||||||
|
Task<HttpResponseInfo> GetTempFileResponse(HttpRequestOptions options);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Net;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Net
|
||||||
|
{
|
||||||
|
public interface INetworkManager
|
||||||
|
{
|
||||||
|
event EventHandler NetworkChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a random port number that is currently available
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>System.Int32.</returns>
|
||||||
|
int GetRandomUnusedTcpPort();
|
||||||
|
|
||||||
|
int GetRandomUnusedUdpPort();
|
||||||
|
|
||||||
|
Func<string[]> LocalSubnetsFn { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns MAC Address from first Network Card in Computer
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>[string] MAC Address</returns>
|
||||||
|
List<string> GetMacAddresses();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether [is in private address space] [the specified endpoint].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="endpoint">The endpoint.</param>
|
||||||
|
/// <returns><c>true</c> if [is in private address space] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
||||||
|
bool IsInPrivateAddressSpace(string endpoint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the network shares.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
/// <returns>IEnumerable{NetworkShare}.</returns>
|
||||||
|
IEnumerable<NetworkShare> GetNetworkShares(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets available devices within the domain
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>PC's in the Domain</returns>
|
||||||
|
IEnumerable<FileSystemEntryInfo> GetNetworkDevices();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether [is in local network] [the specified endpoint].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="endpoint">The endpoint.</param>
|
||||||
|
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
||||||
|
bool IsInLocalNetwork(string endpoint);
|
||||||
|
|
||||||
|
IpAddressInfo[] GetLocalIpAddresses();
|
||||||
|
|
||||||
|
IpAddressInfo ParseIpAddress(string ipAddress);
|
||||||
|
|
||||||
|
bool TryParseIpAddress(string ipAddress, out IpAddressInfo ipAddressInfo);
|
||||||
|
|
||||||
|
Task<IpAddressInfo[]> GetHostAddressesAsync(string host);
|
||||||
|
|
||||||
|
bool IsAddressInSubnets(string addressString, string[] subnets);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,276 @@
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Model.Plugins;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Plugins
|
||||||
|
{
|
||||||
|
public abstract class BasePlugin : IPlugin, IPluginAssembly
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the plugin
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public abstract string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The description.</value>
|
||||||
|
public virtual string Description
|
||||||
|
{
|
||||||
|
get { return string.Empty; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the unique id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The unique id.</value>
|
||||||
|
public virtual Guid Id { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin version
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The version.</value>
|
||||||
|
public Version Version { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the assembly file
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The assembly file path.</value>
|
||||||
|
public string AssemblyFilePath { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin info.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>PluginInfo.</returns>
|
||||||
|
public virtual PluginInfo GetPluginInfo()
|
||||||
|
{
|
||||||
|
var info = new PluginInfo
|
||||||
|
{
|
||||||
|
Name = Name,
|
||||||
|
Version = Version.ToString(),
|
||||||
|
Description = Description,
|
||||||
|
Id = Id.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when just before the plugin is uninstalled from the server.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnUninstalling()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAttributes(string assemblyFilePath, string dataFolderPath, Version assemblyVersion)
|
||||||
|
{
|
||||||
|
AssemblyFilePath = assemblyFilePath;
|
||||||
|
DataFolderPath = dataFolderPath;
|
||||||
|
Version = assemblyVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetId(Guid assemblyId)
|
||||||
|
{
|
||||||
|
Id = assemblyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the full path to the data folder, where the plugin can store any miscellaneous files needed
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The data folder path.</value>
|
||||||
|
public string DataFolderPath { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a common base class for all plugins
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TConfigurationType">The type of the T configuration type.</typeparam>
|
||||||
|
public abstract class BasePlugin<TConfigurationType> : BasePlugin, IHasPluginConfiguration
|
||||||
|
where TConfigurationType : BasePluginConfiguration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the application paths.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The application paths.</value>
|
||||||
|
protected IApplicationPaths ApplicationPaths { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the XML serializer.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The XML serializer.</value>
|
||||||
|
protected IXmlSerializer XmlSerializer { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of configuration this plugin uses
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type of the configuration.</value>
|
||||||
|
public Type ConfigurationType
|
||||||
|
{
|
||||||
|
get { return typeof(TConfigurationType); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Action<string> _directoryCreateFn;
|
||||||
|
public void SetStartupInfo(Action<string> directoryCreateFn)
|
||||||
|
{
|
||||||
|
// hack alert, until the .net core transition is complete
|
||||||
|
_directoryCreateFn = directoryCreateFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name the assembly file
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name of the assembly file.</value>
|
||||||
|
protected string AssemblyFileName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Path.GetFileName(AssemblyFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The _configuration sync lock
|
||||||
|
/// </summary>
|
||||||
|
private readonly object _configurationSyncLock = new object();
|
||||||
|
/// <summary>
|
||||||
|
/// The _configuration
|
||||||
|
/// </summary>
|
||||||
|
private TConfigurationType _configuration;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin's configuration
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration.</value>
|
||||||
|
public TConfigurationType Configuration
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// Lazy load
|
||||||
|
if (_configuration == null)
|
||||||
|
{
|
||||||
|
lock (_configurationSyncLock)
|
||||||
|
{
|
||||||
|
if (_configuration == null)
|
||||||
|
{
|
||||||
|
_configuration = LoadConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _configuration;
|
||||||
|
}
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
_configuration = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TConfigurationType LoadConfiguration()
|
||||||
|
{
|
||||||
|
var path = ConfigurationFilePath;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (TConfigurationType)XmlSerializer.DeserializeFromFile(typeof(TConfigurationType), path);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the configuration file. Subclasses should override
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name of the configuration file.</value>
|
||||||
|
public virtual string ConfigurationFileName
|
||||||
|
{
|
||||||
|
get { return Path.ChangeExtension(AssemblyFileName, ".xml"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the full path to the configuration file
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration file path.</value>
|
||||||
|
public string ConfigurationFilePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Path.Combine(ApplicationPaths.PluginConfigurationsPath, ConfigurationFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BasePlugin{TConfigurationType}" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="applicationPaths">The application paths.</param>
|
||||||
|
/// <param name="xmlSerializer">The XML serializer.</param>
|
||||||
|
protected BasePlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||||
|
{
|
||||||
|
ApplicationPaths = applicationPaths;
|
||||||
|
XmlSerializer = xmlSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The _save lock
|
||||||
|
/// </summary>
|
||||||
|
private readonly object _configurationSaveLock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the current configuration to the file system
|
||||||
|
/// </summary>
|
||||||
|
public virtual void SaveConfiguration()
|
||||||
|
{
|
||||||
|
lock (_configurationSaveLock)
|
||||||
|
{
|
||||||
|
_directoryCreateFn(Path.GetDirectoryName(ConfigurationFilePath));
|
||||||
|
|
||||||
|
XmlSerializer.SerializeToFile(Configuration, ConfigurationFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Completely overwrites the current configuration with a new copy
|
||||||
|
/// Returns true or false indicating success or failure
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration">The configuration.</param>
|
||||||
|
/// <exception cref="System.ArgumentNullException">configuration</exception>
|
||||||
|
public virtual void UpdateConfiguration(BasePluginConfiguration configuration)
|
||||||
|
{
|
||||||
|
if (configuration == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("configuration");
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration = (TConfigurationType)configuration;
|
||||||
|
|
||||||
|
SaveConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin's configuration
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration.</value>
|
||||||
|
BasePluginConfiguration IHasPluginConfiguration.Configuration
|
||||||
|
{
|
||||||
|
get { return Configuration; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override PluginInfo GetPluginInfo()
|
||||||
|
{
|
||||||
|
var info = base.GetPluginInfo();
|
||||||
|
|
||||||
|
info.ConfigurationFileName = ConfigurationFileName;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IPluginAssembly
|
||||||
|
{
|
||||||
|
void SetAttributes(string assemblyFilePath, string dataFolderPath, Version assemblyVersion);
|
||||||
|
void SetId(Guid assemblyId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
using MediaBrowser.Model.Plugins;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Plugins
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IPlugin
|
||||||
|
/// </summary>
|
||||||
|
public interface IPlugin
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the plugin
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The description.</value>
|
||||||
|
string Description { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the unique id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The unique id.</value>
|
||||||
|
Guid Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin version
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The version.</value>
|
||||||
|
Version Version { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the assembly file
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The assembly file path.</value>
|
||||||
|
string AssemblyFilePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the full path to the data folder, where the plugin can store any miscellaneous files needed
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The data folder path.</value>
|
||||||
|
string DataFolderPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin info.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>PluginInfo.</returns>
|
||||||
|
PluginInfo GetPluginInfo();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when just before the plugin is uninstalled from the server.
|
||||||
|
/// </summary>
|
||||||
|
void OnUninstalling();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasPluginConfiguration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of configuration this plugin uses
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type of the configuration.</value>
|
||||||
|
Type ConfigurationType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Completely overwrites the current configuration with a new copy
|
||||||
|
/// Returns true or false indicating success or failure
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration">The configuration.</param>
|
||||||
|
/// <exception cref="System.ArgumentNullException">configuration</exception>
|
||||||
|
void UpdateConfiguration(BasePluginConfiguration configuration);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin's configuration
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration.</value>
|
||||||
|
BasePluginConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
void SetStartupInfo(Action<string> directoryCreateFn);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Progress
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class ActionableProgress
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public class ActionableProgress<T> : IProgress<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The _actions
|
||||||
|
/// </summary>
|
||||||
|
private Action<T> _action;
|
||||||
|
public event EventHandler<T> ProgressChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the action.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">The action.</param>
|
||||||
|
public void RegisterAction(Action<T> action)
|
||||||
|
{
|
||||||
|
_action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Report(T value)
|
||||||
|
{
|
||||||
|
if (ProgressChanged != null)
|
||||||
|
{
|
||||||
|
ProgressChanged(this, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var action = _action;
|
||||||
|
if (action != null)
|
||||||
|
{
|
||||||
|
action(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimpleProgress<T> : IProgress<T>
|
||||||
|
{
|
||||||
|
public event EventHandler<T> ProgressChanged;
|
||||||
|
|
||||||
|
public void Report(T value)
|
||||||
|
{
|
||||||
|
if (ProgressChanged != null)
|
||||||
|
{
|
||||||
|
ProgressChanged(this, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("MediaBrowser.Common")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("MediaBrowser.Common")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Security
|
||||||
|
{
|
||||||
|
public interface IRequiresRegistration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Load all registration information required for this entity.
|
||||||
|
/// Your class should re-load all MBRegistrationRecords when this is called even if they were
|
||||||
|
/// previously loaded.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task LoadRegistrationInfoAsync();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Security
|
||||||
|
{
|
||||||
|
public interface ISecurityManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance is MB supporter.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance is MB supporter; otherwise, <c>false</c>.</value>
|
||||||
|
Task<bool> IsSupporter();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the supporter key.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The supporter key.</value>
|
||||||
|
string SupporterKey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the registration status. Overload to support existing plug-ins.
|
||||||
|
/// </summary>
|
||||||
|
Task<MBRegistrationRecord> GetRegistrationStatus(string feature);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register and app store sale with our back-end
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameters">Json parameters to pass to admin server</param>
|
||||||
|
Task RegisterAppStoreSale(string parameters);
|
||||||
|
Task UpdateSupporterKey(string newValue);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Security
|
||||||
|
{
|
||||||
|
public class PaymentRequiredException : Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,278 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Model.Updates;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Updates
|
||||||
|
{
|
||||||
|
public class GithubUpdater
|
||||||
|
{
|
||||||
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
|
|
||||||
|
public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
_jsonSerializer = jsonSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CheckForUpdateResult> CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, TimeSpan cacheLength, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
|
||||||
|
|
||||||
|
var options = new HttpRequestOptions
|
||||||
|
{
|
||||||
|
Url = url,
|
||||||
|
EnableKeepAlive = false,
|
||||||
|
CancellationToken = cancellationToken,
|
||||||
|
UserAgent = "Emby/3.0",
|
||||||
|
BufferContent = false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cacheLength.Ticks > 0)
|
||||||
|
{
|
||||||
|
options.CacheMode = CacheMode.Unconditional;
|
||||||
|
options.CacheLength = cacheLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
using (var stream = response.Content)
|
||||||
|
{
|
||||||
|
var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);
|
||||||
|
|
||||||
|
return CheckForUpdateResult(obj, minVersion, updateLevel, assetFilename, packageName, targetFilename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CheckForUpdateResult CheckForUpdateResult(RootObject[] obj, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename)
|
||||||
|
{
|
||||||
|
if (updateLevel == PackageVersionClass.Release)
|
||||||
|
{
|
||||||
|
// Technically all we need to do is check that it's not pre-release
|
||||||
|
// But let's addititional checks for -beta and -dev to handle builds that might be temporarily tagged incorrectly.
|
||||||
|
obj = obj.Where(i => !i.prerelease && !i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) && !i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||||
|
}
|
||||||
|
else if (updateLevel == PackageVersionClass.Beta)
|
||||||
|
{
|
||||||
|
obj = obj.Where(i => i.prerelease && i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||||
|
}
|
||||||
|
else if (updateLevel == PackageVersionClass.Dev)
|
||||||
|
{
|
||||||
|
obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) || i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
var availableUpdate = obj
|
||||||
|
.Select(i => CheckForUpdateResult(i, minVersion, assetFilename, packageName, targetFilename))
|
||||||
|
.Where(i => i != null)
|
||||||
|
.OrderByDescending(i => Version.Parse(i.AvailableVersion))
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
return availableUpdate ?? new CheckForUpdateResult
|
||||||
|
{
|
||||||
|
IsUpdateAvailable = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MatchesUpdateLevel(RootObject i, PackageVersionClass updateLevel)
|
||||||
|
{
|
||||||
|
if (updateLevel == PackageVersionClass.Beta)
|
||||||
|
{
|
||||||
|
return i.prerelease && i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
if (updateLevel == PackageVersionClass.Dev)
|
||||||
|
{
|
||||||
|
return !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Technically all we need to do is check that it's not pre-release
|
||||||
|
// But let's addititional checks for -beta and -dev to handle builds that might be temporarily tagged incorrectly.
|
||||||
|
return !i.prerelease && !i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<RootObject>> GetLatestReleases(string organzation, string repository, string assetFilename, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var list = new List<RootObject>();
|
||||||
|
|
||||||
|
var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
|
||||||
|
|
||||||
|
var options = new HttpRequestOptions
|
||||||
|
{
|
||||||
|
Url = url,
|
||||||
|
EnableKeepAlive = false,
|
||||||
|
CancellationToken = cancellationToken,
|
||||||
|
UserAgent = "Emby/3.0",
|
||||||
|
BufferContent = false
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
using (var stream = response.Content)
|
||||||
|
{
|
||||||
|
var obj = _jsonSerializer.DeserializeFromStream<RootObject[]>(stream);
|
||||||
|
|
||||||
|
obj = obj.Where(i => (i.assets ?? new List<Asset>()).Any(a => IsAsset(a, assetFilename, i.tag_name))).ToArray();
|
||||||
|
|
||||||
|
list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Release)).OrderByDescending(GetVersion).Take(1));
|
||||||
|
list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Beta)).OrderByDescending(GetVersion).Take(1));
|
||||||
|
list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Dev)).OrderByDescending(GetVersion).Take(1));
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Version GetVersion(RootObject obj)
|
||||||
|
{
|
||||||
|
Version version;
|
||||||
|
if (!Version.TryParse(obj.tag_name, out version))
|
||||||
|
{
|
||||||
|
return new Version(1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CheckForUpdateResult CheckForUpdateResult(RootObject obj, Version minVersion, string assetFilename, string packageName, string targetFilename)
|
||||||
|
{
|
||||||
|
Version version;
|
||||||
|
var versionString = obj.tag_name;
|
||||||
|
if (!Version.TryParse(versionString, out version))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version < minVersion)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var asset = (obj.assets ?? new List<Asset>()).FirstOrDefault(i => IsAsset(i, assetFilename, versionString));
|
||||||
|
|
||||||
|
if (asset == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CheckForUpdateResult
|
||||||
|
{
|
||||||
|
AvailableVersion = version.ToString(),
|
||||||
|
IsUpdateAvailable = version > minVersion,
|
||||||
|
Package = new PackageVersionInfo
|
||||||
|
{
|
||||||
|
classification = obj.prerelease ?
|
||||||
|
(obj.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase) ? PackageVersionClass.Dev : PackageVersionClass.Beta) :
|
||||||
|
PackageVersionClass.Release,
|
||||||
|
name = packageName,
|
||||||
|
sourceUrl = asset.browser_download_url,
|
||||||
|
targetFilename = targetFilename,
|
||||||
|
versionStr = version.ToString(),
|
||||||
|
requiredVersionStr = "1.0.0",
|
||||||
|
description = obj.body,
|
||||||
|
infoUrl = obj.html_url
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAsset(Asset asset, string assetFilename, string version)
|
||||||
|
{
|
||||||
|
var downloadFilename = Path.GetFileName(asset.browser_download_url) ?? string.Empty;
|
||||||
|
|
||||||
|
assetFilename = assetFilename.Replace("{version}", version);
|
||||||
|
|
||||||
|
if (downloadFilename.IndexOf(assetFilename, StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Equals(assetFilename, downloadFilename, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Uploader
|
||||||
|
{
|
||||||
|
public string login { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
public string avatar_url { get; set; }
|
||||||
|
public string gravatar_id { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
public string html_url { get; set; }
|
||||||
|
public string followers_url { get; set; }
|
||||||
|
public string following_url { get; set; }
|
||||||
|
public string gists_url { get; set; }
|
||||||
|
public string starred_url { get; set; }
|
||||||
|
public string subscriptions_url { get; set; }
|
||||||
|
public string organizations_url { get; set; }
|
||||||
|
public string repos_url { get; set; }
|
||||||
|
public string events_url { get; set; }
|
||||||
|
public string received_events_url { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public bool site_admin { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Asset
|
||||||
|
{
|
||||||
|
public string url { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public object label { get; set; }
|
||||||
|
public Uploader uploader { get; set; }
|
||||||
|
public string content_type { get; set; }
|
||||||
|
public string state { get; set; }
|
||||||
|
public int size { get; set; }
|
||||||
|
public int download_count { get; set; }
|
||||||
|
public string created_at { get; set; }
|
||||||
|
public string updated_at { get; set; }
|
||||||
|
public string browser_download_url { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Author
|
||||||
|
{
|
||||||
|
public string login { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
public string avatar_url { get; set; }
|
||||||
|
public string gravatar_id { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
public string html_url { get; set; }
|
||||||
|
public string followers_url { get; set; }
|
||||||
|
public string following_url { get; set; }
|
||||||
|
public string gists_url { get; set; }
|
||||||
|
public string starred_url { get; set; }
|
||||||
|
public string subscriptions_url { get; set; }
|
||||||
|
public string organizations_url { get; set; }
|
||||||
|
public string repos_url { get; set; }
|
||||||
|
public string events_url { get; set; }
|
||||||
|
public string received_events_url { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public bool site_admin { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RootObject
|
||||||
|
{
|
||||||
|
public string url { get; set; }
|
||||||
|
public string assets_url { get; set; }
|
||||||
|
public string upload_url { get; set; }
|
||||||
|
public string html_url { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
public string tag_name { get; set; }
|
||||||
|
public string target_commitish { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public bool draft { get; set; }
|
||||||
|
public Author author { get; set; }
|
||||||
|
public bool prerelease { get; set; }
|
||||||
|
public string created_at { get; set; }
|
||||||
|
public string published_at { get; set; }
|
||||||
|
public List<Asset> assets { get; set; }
|
||||||
|
public string tarball_url { get; set; }
|
||||||
|
public string zipball_url { get; set; }
|
||||||
|
public string body { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
using MediaBrowser.Common.Plugins;
|
||||||
|
using MediaBrowser.Model.Events;
|
||||||
|
using MediaBrowser.Model.Updates;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Updates
|
||||||
|
{
|
||||||
|
public interface IInstallationManager : IDisposable
|
||||||
|
{
|
||||||
|
event EventHandler<InstallationEventArgs> PackageInstalling;
|
||||||
|
event EventHandler<InstallationEventArgs> PackageInstallationCompleted;
|
||||||
|
event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed;
|
||||||
|
event EventHandler<InstallationEventArgs> PackageInstallationCancelled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current installations
|
||||||
|
/// </summary>
|
||||||
|
List<Tuple<InstallationInfo, CancellationTokenSource>> CurrentInstallations { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The completed installations
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<InstallationInfo> CompletedInstallations { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [plugin uninstalled].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [plugin updated].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>>> PluginUpdated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [plugin updated].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all available packages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <param name="withRegistration">if set to <c>true</c> [with registration].</param>
|
||||||
|
/// <param name="packageType">Type of the package.</param>
|
||||||
|
/// <param name="applicationVersion">The application version.</param>
|
||||||
|
/// <returns>Task{List{PackageInfo}}.</returns>
|
||||||
|
Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
|
||||||
|
bool withRegistration = true,
|
||||||
|
string packageType = null,
|
||||||
|
Version applicationVersion = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all available packages from a static resource.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{List{PackageInfo}}.</returns>
|
||||||
|
Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the package.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name.</param>
|
||||||
|
/// <param name="guid">The assembly guid</param>
|
||||||
|
/// <param name="classification">The classification.</param>
|
||||||
|
/// <param name="version">The version.</param>
|
||||||
|
/// <returns>Task{PackageVersionInfo}.</returns>
|
||||||
|
Task<PackageVersionInfo> GetPackage(string name, string guid, PackageVersionClass classification, Version version);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the latest compatible version.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name.</param>
|
||||||
|
/// <param name="guid">The assembly guid</param>
|
||||||
|
/// <param name="currentServerVersion">The current server version.</param>
|
||||||
|
/// <param name="classification">The classification.</param>
|
||||||
|
/// <returns>Task{PackageVersionInfo}.</returns>
|
||||||
|
Task<PackageVersionInfo> GetLatestCompatibleVersion(string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the latest compatible version.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="availablePackages">The available packages.</param>
|
||||||
|
/// <param name="name">The name.</param>
|
||||||
|
/// <param name="guid">The assembly guid</param>
|
||||||
|
/// <param name="currentServerVersion">The current server version.</param>
|
||||||
|
/// <param name="classification">The classification.</param>
|
||||||
|
/// <returns>PackageVersionInfo.</returns>
|
||||||
|
PackageVersionInfo GetLatestCompatibleVersion(IEnumerable<PackageInfo> availablePackages, string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the available plugin updates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="applicationVersion">The current server version.</param>
|
||||||
|
/// <param name="withAutoUpdateEnabled">if set to <c>true</c> [with auto update enabled].</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns>
|
||||||
|
Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Installs the package.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="package">The package.</param>
|
||||||
|
/// <param name="isPlugin">if set to <c>true</c> [is plugin].</param>
|
||||||
|
/// <param name="progress">The progress.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
/// <exception cref="System.ArgumentNullException">package</exception>
|
||||||
|
Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uninstalls a plugin
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="plugin">The plugin.</param>
|
||||||
|
/// <exception cref="System.ArgumentException"></exception>
|
||||||
|
void UninstallPlugin(IPlugin plugin);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
using MediaBrowser.Model.Updates;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Updates
|
||||||
|
{
|
||||||
|
public class InstallationEventArgs
|
||||||
|
{
|
||||||
|
public InstallationInfo InstallationInfo { get; set; }
|
||||||
|
|
||||||
|
public PackageVersionInfo PackageVersionInfo { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Common.Updates
|
||||||
|
{
|
||||||
|
public class InstallationFailedEventArgs : InstallationEventArgs
|
||||||
|
{
|
||||||
|
public Exception Exception { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
using MediaBrowser.Controller.Session;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Authentication
|
||||||
|
{
|
||||||
|
public class AuthenticationResult
|
||||||
|
{
|
||||||
|
public UserDto User { get; set; }
|
||||||
|
public SessionInfo SessionInfo { get; set; }
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
public string ServerId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Authentication
|
||||||
|
{
|
||||||
|
public interface IAuthenticationProvider
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
bool IsEnabled { get; }
|
||||||
|
Task<ProviderAuthenticationResult> Authenticate(string username, string password);
|
||||||
|
Task<bool> HasPassword(User user);
|
||||||
|
Task ChangePassword(User user, string newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IRequiresResolvedUser
|
||||||
|
{
|
||||||
|
Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasNewUserPolicy
|
||||||
|
{
|
||||||
|
UserPolicy GetNewUserPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderAuthenticationResult
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Channels;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common.Progress;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public class Channel : Folder
|
||||||
|
{
|
||||||
|
public override bool IsVisible(User user)
|
||||||
|
{
|
||||||
|
if (user.Policy.BlockedChannels != null)
|
||||||
|
{
|
||||||
|
if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.IsVisible(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsInheritedParentImages
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override SourceType SourceType
|
||||||
|
{
|
||||||
|
get { return SourceType.Channel; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
query.Parent = this;
|
||||||
|
query.ChannelIds = new Guid[] { Id };
|
||||||
|
|
||||||
|
// Don't blow up here because it could cause parent screens with other content to fail
|
||||||
|
return ChannelManager.GetChannelItemsInternal(query, new SimpleProgress<double>(), CancellationToken.None).Result;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Already logged at lower levels
|
||||||
|
return new QueryResult<BaseItem>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string GetInternalMetadataPath(string basePath)
|
||||||
|
{
|
||||||
|
return GetInternalMetadataPath(basePath, Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetInternalMetadataPath(string basePath, Guid id)
|
||||||
|
{
|
||||||
|
return System.IO.Path.Combine(basePath, "channels", id.ToString("N"), "metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool IsAllowTagFilterEnforced()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsChannelVisible(BaseItem channelItem, User user)
|
||||||
|
{
|
||||||
|
var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString(""));
|
||||||
|
|
||||||
|
return channel.IsVisible(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Channels;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public class ChannelItemInfo : IHasProviderIds
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string SeriesName { get; set; }
|
||||||
|
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public DateTime DateModified { get; set; }
|
||||||
|
|
||||||
|
public ChannelItemType Type { get; set; }
|
||||||
|
|
||||||
|
public string OfficialRating { get; set; }
|
||||||
|
|
||||||
|
public string Overview { get; set; }
|
||||||
|
|
||||||
|
public List<string> Genres { get; set; }
|
||||||
|
public List<string> Studios { get; set; }
|
||||||
|
public List<string> Tags { get; set; }
|
||||||
|
|
||||||
|
public List<PersonInfo> People { get; set; }
|
||||||
|
|
||||||
|
public float? CommunityRating { get; set; }
|
||||||
|
|
||||||
|
public long? RunTimeTicks { get; set; }
|
||||||
|
|
||||||
|
public string ImageUrl { get; set; }
|
||||||
|
public string OriginalTitle { get; set; }
|
||||||
|
|
||||||
|
public ChannelMediaType MediaType { get; set; }
|
||||||
|
public ChannelFolderType FolderType { get; set; }
|
||||||
|
|
||||||
|
public ChannelMediaContentType ContentType { get; set; }
|
||||||
|
public ExtraType ExtraType { get; set; }
|
||||||
|
public List<TrailerType> TrailerTypes { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, string> ProviderIds { get; set; }
|
||||||
|
|
||||||
|
public DateTime? PremiereDate { get; set; }
|
||||||
|
public int? ProductionYear { get; set; }
|
||||||
|
|
||||||
|
public DateTime? DateCreated { get; set; }
|
||||||
|
|
||||||
|
public DateTime? StartDate { get; set; }
|
||||||
|
public DateTime? EndDate { get; set; }
|
||||||
|
|
||||||
|
public int? IndexNumber { get; set; }
|
||||||
|
public int? ParentIndexNumber { get; set; }
|
||||||
|
|
||||||
|
public List<MediaSourceInfo> MediaSources { get; set; }
|
||||||
|
|
||||||
|
public string HomePageUrl { get; set; }
|
||||||
|
|
||||||
|
public List<string> Artists { get; set; }
|
||||||
|
|
||||||
|
public List<string> AlbumArtists { get; set; }
|
||||||
|
public bool IsLiveStream { get; set; }
|
||||||
|
public string Etag { get; set; }
|
||||||
|
|
||||||
|
public ChannelItemInfo()
|
||||||
|
{
|
||||||
|
MediaSources = new List<MediaSourceInfo>();
|
||||||
|
TrailerTypes = new List<TrailerType>();
|
||||||
|
Genres = new List<string>();
|
||||||
|
Studios = new List<string>();
|
||||||
|
People = new List<PersonInfo>();
|
||||||
|
Tags = new List<string>();
|
||||||
|
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
Artists = new List<string>();
|
||||||
|
AlbumArtists = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public class ChannelItemResult
|
||||||
|
{
|
||||||
|
public List<ChannelItemInfo> Items { get; set; }
|
||||||
|
|
||||||
|
public int? TotalRecordCount { get; set; }
|
||||||
|
|
||||||
|
public ChannelItemResult()
|
||||||
|
{
|
||||||
|
Items = new List<ChannelItemInfo>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public enum ChannelItemType
|
||||||
|
{
|
||||||
|
Media = 0,
|
||||||
|
|
||||||
|
Folder = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public enum ChannelParentalRating
|
||||||
|
{
|
||||||
|
GeneralAudience = 0,
|
||||||
|
|
||||||
|
UsPG = 1,
|
||||||
|
|
||||||
|
UsPG13 = 2,
|
||||||
|
|
||||||
|
UsR = 3,
|
||||||
|
|
||||||
|
Adult = 4
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public class ChannelSearchInfo
|
||||||
|
{
|
||||||
|
public string SearchTerm { get; set; }
|
||||||
|
|
||||||
|
public string UserId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ChannelLatestMediaSearch
|
||||||
|
{
|
||||||
|
public string UserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public interface IChannel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The description.</value>
|
||||||
|
string Description { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data version.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The data version.</value>
|
||||||
|
string DataVersion { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the home page URL.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The home page URL.</value>
|
||||||
|
string HomePageUrl { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parental rating.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The parental rating.</value>
|
||||||
|
ChannelParentalRating ParentalRating { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel information.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>ChannelFeatures.</returns>
|
||||||
|
InternalChannelFeatures GetChannelFeatures();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether [is enabled for] [the specified user].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user identifier.</param>
|
||||||
|
/// <returns><c>true</c> if [is enabled for] [the specified user]; otherwise, <c>false</c>.</returns>
|
||||||
|
bool IsEnabledFor(string userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel items.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{ChannelItem}}.</returns>
|
||||||
|
Task<ChannelItemResult> GetChannelItems(InternalChannelItemQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel image.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{DynamicImageInfo}.</returns>
|
||||||
|
Task<DynamicImageResponse> GetChannelImage(ImageType type, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the supported channel images.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>IEnumerable{ImageType}.</returns>
|
||||||
|
IEnumerable<ImageType> GetSupportedChannelImages();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
using System;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Channels;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public interface IChannelManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the parts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channels">The channels.</param>
|
||||||
|
void AddParts(IEnumerable<IChannel> channels);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel features.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier.</param>
|
||||||
|
/// <returns>ChannelFeatures.</returns>
|
||||||
|
ChannelFeatures GetChannelFeatures(string id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all channel features.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>IEnumerable{ChannelFeatures}.</returns>
|
||||||
|
ChannelFeatures[] GetAllChannelFeatures();
|
||||||
|
|
||||||
|
bool EnableMediaSourceDisplay(BaseItem item);
|
||||||
|
bool CanDelete(BaseItem item);
|
||||||
|
|
||||||
|
Task DeleteItem(BaseItem item);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier.</param>
|
||||||
|
/// <returns>Channel.</returns>
|
||||||
|
Channel GetChannel(string id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channels internal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
QueryResult<Channel> GetChannelsInternal(ChannelQuery query);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
QueryResult<BaseItemDto> GetChannels(ChannelQuery query);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the latest media.
|
||||||
|
/// </summary>
|
||||||
|
Task<QueryResult<BaseItemDto>> GetLatestChannelItems(InternalItemsQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the latest media.
|
||||||
|
/// </summary>
|
||||||
|
Task<QueryResult<BaseItem>> GetLatestChannelItemsInternal(InternalItemsQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel items.
|
||||||
|
/// </summary>
|
||||||
|
Task<QueryResult<BaseItemDto>> GetChannelItems(InternalItemsQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel items internal.
|
||||||
|
/// </summary>
|
||||||
|
Task<QueryResult<BaseItem>> GetChannelItemsInternal(InternalItemsQuery query, IProgress<double> progress, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel item media sources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{MediaSourceInfo}}.</returns>
|
||||||
|
IEnumerable<MediaSourceInfo> GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
bool EnableMediaProbe(BaseItem item);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public interface IHasCacheKey
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the cache key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user identifier.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
string GetCacheKey(string userId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public interface IRequiresMediaInfoCallback
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel item media information.
|
||||||
|
/// </summary>
|
||||||
|
Task<IEnumerable<MediaSourceInfo>> GetChannelItemMediaInfo(string id, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public interface ISearchableChannel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the specified search term.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="searchInfo">The search information.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{ChannelItemInfo}}.</returns>
|
||||||
|
Task<IEnumerable<ChannelItemInfo>> Search(ChannelSearchInfo searchInfo, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISupportsLatestMedia
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the latest media.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{ChannelItemInfo}}.</returns>
|
||||||
|
Task<IEnumerable<ChannelItemInfo>> GetLatestMedia(ChannelLatestMediaSearch request, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISupportsDelete
|
||||||
|
{
|
||||||
|
bool CanDelete(BaseItem item);
|
||||||
|
Task DeleteItem(string id, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IDisableMediaSourceDisplay
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISupportsMediaProbe
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasFolderAttributes
|
||||||
|
{
|
||||||
|
string[] Attributes { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
using System;
|
||||||
|
using MediaBrowser.Model.Channels;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public class InternalChannelFeatures
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the media types.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The media types.</value>
|
||||||
|
public List<ChannelMediaType> MediaTypes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the content types.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The content types.</value>
|
||||||
|
public List<ChannelMediaContentType> ContentTypes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the maximum number of records the channel allows retrieving at a time
|
||||||
|
/// </summary>
|
||||||
|
public int? MaxPageSize { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default sort orders.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The default sort orders.</value>
|
||||||
|
public List<ChannelItemSortField> DefaultSortFields { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if a sort ascending/descending toggle is supported or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool SupportsSortOrderToggle { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the automatic refresh levels.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The automatic refresh levels.</value>
|
||||||
|
public int? AutoRefreshLevels { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the daily download limit.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The daily download limit.</value>
|
||||||
|
public int? DailyDownloadLimit { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether [supports downloading].
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if [supports downloading]; otherwise, <c>false</c>.</value>
|
||||||
|
public bool SupportsContentDownloading { get; set; }
|
||||||
|
|
||||||
|
public InternalChannelFeatures()
|
||||||
|
{
|
||||||
|
MediaTypes = new List<ChannelMediaType>();
|
||||||
|
ContentTypes = new List<ChannelMediaContentType>();
|
||||||
|
|
||||||
|
DefaultSortFields = new List<ChannelItemSortField>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using MediaBrowser.Model.Channels;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
{
|
||||||
|
public class InternalChannelItemQuery
|
||||||
|
{
|
||||||
|
public string FolderId { get; set; }
|
||||||
|
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
|
||||||
|
public int? StartIndex { get; set; }
|
||||||
|
|
||||||
|
public int? Limit { get; set; }
|
||||||
|
|
||||||
|
public ChannelItemSortField? SortBy { get; set; }
|
||||||
|
|
||||||
|
public bool SortDescending { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Chapters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IChapterManager
|
||||||
|
/// </summary>
|
||||||
|
public interface IChapterManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the chapters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="itemId">The item identifier.</param>
|
||||||
|
/// <returns>List{ChapterInfo}.</returns>
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the chapters.
|
||||||
|
/// </summary>
|
||||||
|
void SaveChapters(string itemId, List<ChapterInfo> chapters);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Collections
|
||||||
|
{
|
||||||
|
public class CollectionCreationOptions : IHasProviderIds
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public Guid? ParentId { get; set; }
|
||||||
|
|
||||||
|
public bool IsLocked { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, string> ProviderIds { get; set; }
|
||||||
|
|
||||||
|
public string[] ItemIdList { get; set; }
|
||||||
|
public Guid[] UserIds { get; set; }
|
||||||
|
|
||||||
|
public CollectionCreationOptions()
|
||||||
|
{
|
||||||
|
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
ItemIdList = new string[] {};
|
||||||
|
UserIds = new Guid[] {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Collections
|
||||||
|
{
|
||||||
|
public class CollectionCreatedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The collection.</value>
|
||||||
|
public BoxSet Collection { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the options.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The options.</value>
|
||||||
|
public CollectionCreationOptions Options { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CollectionModifiedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The collection.</value>
|
||||||
|
public BoxSet Collection { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the items changed.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The items changed.</value>
|
||||||
|
public List<BaseItem> ItemsChanged { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Collections
|
||||||
|
{
|
||||||
|
public interface ICollectionManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [collection created].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [items added to collection].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [items removed from collection].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
BoxSet CreateCollection(CollectionCreationOptions options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds to collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="collectionId">The collection identifier.</param>
|
||||||
|
/// <param name="itemIds">The item ids.</param>
|
||||||
|
void AddToCollection(Guid collectionId, IEnumerable<string> itemIds);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes from collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="collectionId">The collection identifier.</param>
|
||||||
|
/// <param name="itemIds">The item ids.</param>
|
||||||
|
void RemoveFromCollection(Guid collectionId, IEnumerable<string> itemIds);
|
||||||
|
|
||||||
|
void AddToCollection(Guid collectionId, IEnumerable<Guid> itemIds);
|
||||||
|
void RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collapses the items within box sets.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
|
IEnumerable<BaseItem> CollapseItemsWithinBoxSets(IEnumerable<BaseItem> items, User user);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Configuration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IServerConfigurationManager
|
||||||
|
/// </summary>
|
||||||
|
public interface IServerConfigurationManager : IConfigurationManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the application paths.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The application paths.</value>
|
||||||
|
IServerApplicationPaths ApplicationPaths { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration.</value>
|
||||||
|
ServerConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
bool SetOptimalValues();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Connect;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Connect
|
||||||
|
{
|
||||||
|
public interface IConnectManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the wan API address.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The wan API address.</value>
|
||||||
|
string WanApiAddress { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Links the user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user identifier.</param>
|
||||||
|
/// <param name="connectUsername">The connect username.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task<UserLinkResult> LinkUser(string userId, string connectUsername);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the link.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user identifier.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task RemoveConnect(string userId);
|
||||||
|
|
||||||
|
User GetUserFromExchangeToken(string token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Authenticates the specified username.
|
||||||
|
/// </summary>
|
||||||
|
Task<ConnectAuthenticationResult> Authenticate(string username, string password, string passwordMd5);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether [is authorization token valid] [the specified token].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">The token.</param>
|
||||||
|
/// <returns><c>true</c> if [is authorization token valid] [the specified token]; otherwise, <c>false</c>.</returns>
|
||||||
|
bool IsAuthorizationTokenValid(string token);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Connect
|
||||||
|
{
|
||||||
|
public class UserLinkResult
|
||||||
|
{
|
||||||
|
public bool IsPending { get; set; }
|
||||||
|
public bool IsNewUserInvitation { get; set; }
|
||||||
|
public string GuestDisplayName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using MediaBrowser.Model.Devices;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Devices
|
||||||
|
{
|
||||||
|
public class CameraImageUploadInfo
|
||||||
|
{
|
||||||
|
public LocalFileInfo FileInfo { get; set; }
|
||||||
|
public DeviceInfo Device { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
using MediaBrowser.Model.Devices;
|
||||||
|
using MediaBrowser.Model.Events;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using MediaBrowser.Model.Session;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Devices
|
||||||
|
{
|
||||||
|
public interface IDeviceManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [camera image uploaded].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reportedId">The reported identifier.</param>
|
||||||
|
/// <param name="capabilities">The capabilities.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
void SaveCapabilities(string reportedId, ClientCapabilities capabilities);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reportedId">The reported identifier.</param>
|
||||||
|
/// <returns>ClientCapabilities.</returns>
|
||||||
|
ClientCapabilities GetCapabilities(string reportedId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the device information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier.</param>
|
||||||
|
/// <returns>DeviceInfo.</returns>
|
||||||
|
DeviceInfo GetDevice(string id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the devices.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <returns>IEnumerable<DeviceInfo>.</returns>
|
||||||
|
QueryResult<DeviceInfo> GetDevices(DeviceQuery query);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the upload history.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="deviceId">The device identifier.</param>
|
||||||
|
/// <returns>ContentUploadHistory.</returns>
|
||||||
|
ContentUploadHistory GetCameraUploadHistory(string deviceId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Accepts the upload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="deviceId">The device identifier.</param>
|
||||||
|
/// <param name="stream">The stream.</param>
|
||||||
|
/// <param name="file">The file.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance [can access device] the specified user identifier.
|
||||||
|
/// </summary>
|
||||||
|
bool CanAccessDevice(User user, string deviceId);
|
||||||
|
|
||||||
|
void UpdateDeviceOptions(string deviceId, DeviceOptions options);
|
||||||
|
DeviceOptions GetDeviceOptions(string deviceId);
|
||||||
|
event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Dlna
|
||||||
|
{
|
||||||
|
public interface IDlnaManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the profile infos.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>IEnumerable{DeviceProfileInfo}.</returns>
|
||||||
|
IEnumerable<DeviceProfileInfo> GetProfileInfos();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="headers">The headers.</param>
|
||||||
|
/// <returns>DeviceProfile.</returns>
|
||||||
|
DeviceProfile GetProfile(IDictionary<string,string> headers);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>DeviceProfile.</returns>
|
||||||
|
DeviceProfile GetDefaultProfile();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profile">The profile.</param>
|
||||||
|
void CreateProfile(DeviceProfile profile);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profile">The profile.</param>
|
||||||
|
void UpdateProfile(DeviceProfile profile);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier.</param>
|
||||||
|
void DeleteProfile(string id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier.</param>
|
||||||
|
/// <returns>DeviceProfile.</returns>
|
||||||
|
DeviceProfile GetProfile(string id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="deviceInfo">The device information.</param>
|
||||||
|
/// <returns>DeviceProfile.</returns>
|
||||||
|
DeviceProfile GetProfile(DeviceIdentification deviceInfo);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the server description XML.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="headers">The headers.</param>
|
||||||
|
/// <param name="serverUuId">The server uu identifier.</param>
|
||||||
|
/// <param name="serverAddress">The server address.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId, string serverAddress);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the icon.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The filename.</param>
|
||||||
|
/// <returns>DlnaIconResponse.</returns>
|
||||||
|
ImageStream GetIcon(string filename);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
using System;
|
||||||
|
using MediaBrowser.Model.Drawing;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Drawing
|
||||||
|
{
|
||||||
|
public interface IImageEncoder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the supported input formats.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The supported input formats.</value>
|
||||||
|
string[] SupportedInputFormats { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the supported output formats.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The supported output formats.</value>
|
||||||
|
ImageFormat[] SupportedOutputFormats { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encodes the image.
|
||||||
|
/// </summary>
|
||||||
|
string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the image collage.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
void CreateImageCollage(ImageCollageOptions options);
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether [supports image collage creation].
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
|
||||||
|
bool SupportsImageCollageCreation { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether [supports image encoding].
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if [supports image encoding]; otherwise, <c>false</c>.</value>
|
||||||
|
bool SupportsImageEncoding { get; }
|
||||||
|
|
||||||
|
ImageSize GetImageSize(string path);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
using System;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Drawing;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Drawing
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IImageProcessor
|
||||||
|
/// </summary>
|
||||||
|
public interface IImageProcessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the supported input formats.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The supported input formats.</value>
|
||||||
|
string[] SupportedInputFormats { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the image enhancers.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The image enhancers.</value>
|
||||||
|
IImageEnhancer[] ImageEnhancers { get; }
|
||||||
|
|
||||||
|
ImageSize GetImageSize(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size of the image.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The information.</param>
|
||||||
|
/// <returns>ImageSize.</returns>
|
||||||
|
ImageSize GetImageSize(BaseItem item, ItemImageInfo info);
|
||||||
|
|
||||||
|
ImageSize GetImageSize(BaseItem item, ItemImageInfo info, bool allowSlowMethods, bool updateItem);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the parts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enhancers">The enhancers.</param>
|
||||||
|
void AddParts(IEnumerable<IImageEnhancer> enhancers);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the supported enhancers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="imageType">Type of the image.</param>
|
||||||
|
/// <returns>IEnumerable{IImageEnhancer}.</returns>
|
||||||
|
IImageEnhancer[] GetSupportedEnhancers(BaseItem item, ImageType imageType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the image cache tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="image">The image.</param>
|
||||||
|
/// <returns>Guid.</returns>
|
||||||
|
string GetImageCacheTag(BaseItem item, ItemImageInfo image);
|
||||||
|
string GetImageCacheTag(BaseItem item, ChapterInfo info);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the image cache tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="image">The image.</param>
|
||||||
|
/// <param name="imageEnhancers">The image enhancers.</param>
|
||||||
|
/// <returns>Guid.</returns>
|
||||||
|
string GetImageCacheTag(BaseItem item, ItemImageInfo image, IImageEnhancer[] imageEnhancers);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes the image.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <param name="toStream">To stream.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task ProcessImage(ImageProcessingOptions options, Stream toStream);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes the image.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task<Tuple<string, string, DateTime>> ProcessImage(ImageProcessingOptions options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the enhanced image.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="imageType">Type of the image.</param>
|
||||||
|
/// <param name="imageIndex">Index of the image.</param>
|
||||||
|
/// <returns>Task{System.String}.</returns>
|
||||||
|
Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the supported image output formats.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>ImageOutputFormat[].</returns>
|
||||||
|
ImageFormat[] GetSupportedImageOutputFormats();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the image collage.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
void CreateImageCollage(ImageCollageOptions options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether [supports image collage creation].
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
|
||||||
|
bool SupportsImageCollageCreation { get; }
|
||||||
|
|
||||||
|
IImageEncoder ImageEncoder { get; set; }
|
||||||
|
|
||||||
|
bool SupportsTransparency(string path);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Drawing
|
||||||
|
{
|
||||||
|
public class ImageCollageOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the input paths.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The input paths.</value>
|
||||||
|
public string[] InputPaths { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the output path.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The output path.</value>
|
||||||
|
public string OutputPath { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the width.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The width.</value>
|
||||||
|
public int Width { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the height.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The height.</value>
|
||||||
|
public int Height { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Drawing;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Drawing
|
||||||
|
{
|
||||||
|
public static class ImageHelper
|
||||||
|
{
|
||||||
|
public static ImageSize GetNewImageSize(ImageProcessingOptions options, ImageSize? originalImageSize)
|
||||||
|
{
|
||||||
|
if (originalImageSize.HasValue)
|
||||||
|
{
|
||||||
|
// Determine the output size based on incoming parameters
|
||||||
|
var newSize = DrawingUtils.Resize(originalImageSize.Value, options.Width ?? 0, options.Height ?? 0, options.MaxWidth ?? 0, options.MaxHeight ?? 0);
|
||||||
|
|
||||||
|
return newSize;
|
||||||
|
}
|
||||||
|
return GetSizeEstimate(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IImageProcessor ImageProcessor { get; set; }
|
||||||
|
|
||||||
|
private static ImageSize GetSizeEstimate(ImageProcessingOptions options)
|
||||||
|
{
|
||||||
|
if (options.Width.HasValue && options.Height.HasValue)
|
||||||
|
{
|
||||||
|
return new ImageSize(options.Width.Value, options.Height.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var aspect = GetEstimatedAspectRatio(options.Image.Type, options.Item);
|
||||||
|
|
||||||
|
var width = options.Width ?? options.MaxWidth;
|
||||||
|
|
||||||
|
if (width.HasValue)
|
||||||
|
{
|
||||||
|
var heightValue = width.Value / aspect;
|
||||||
|
return new ImageSize(width.Value, heightValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
var height = options.Height ?? options.MaxHeight ?? 200;
|
||||||
|
var widthValue = aspect * height;
|
||||||
|
return new ImageSize(widthValue, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double GetEstimatedAspectRatio(ImageType type, BaseItem item)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ImageType.Art:
|
||||||
|
case ImageType.Backdrop:
|
||||||
|
case ImageType.Chapter:
|
||||||
|
case ImageType.Screenshot:
|
||||||
|
case ImageType.Thumb:
|
||||||
|
return 1.78;
|
||||||
|
case ImageType.Banner:
|
||||||
|
return 5.4;
|
||||||
|
case ImageType.Box:
|
||||||
|
case ImageType.BoxRear:
|
||||||
|
case ImageType.Disc:
|
||||||
|
case ImageType.Menu:
|
||||||
|
return 1;
|
||||||
|
case ImageType.Logo:
|
||||||
|
return 2.58;
|
||||||
|
case ImageType.Primary:
|
||||||
|
return item.GetDefaultPrimaryImageAspectRatio();
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Drawing;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Drawing
|
||||||
|
{
|
||||||
|
public class ImageProcessingOptions
|
||||||
|
{
|
||||||
|
public ImageProcessingOptions()
|
||||||
|
{
|
||||||
|
RequiresAutoOrientation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid ItemId { get; set; }
|
||||||
|
public BaseItem Item { get; set; }
|
||||||
|
|
||||||
|
public ItemImageInfo Image { get; set; }
|
||||||
|
|
||||||
|
public int ImageIndex { get; set; }
|
||||||
|
|
||||||
|
public bool CropWhiteSpace { get; set; }
|
||||||
|
|
||||||
|
public int? Width { get; set; }
|
||||||
|
|
||||||
|
public int? Height { get; set; }
|
||||||
|
|
||||||
|
public int? MaxWidth { get; set; }
|
||||||
|
|
||||||
|
public int? MaxHeight { get; set; }
|
||||||
|
|
||||||
|
public int Quality { get; set; }
|
||||||
|
|
||||||
|
public IImageEnhancer[] Enhancers { get; set; }
|
||||||
|
|
||||||
|
public ImageFormat[] SupportedOutputFormats { get; set; }
|
||||||
|
|
||||||
|
public bool AddPlayedIndicator { get; set; }
|
||||||
|
|
||||||
|
public int? UnplayedCount { get; set; }
|
||||||
|
public int? Blur { get; set; }
|
||||||
|
|
||||||
|
public double PercentPlayed { get; set; }
|
||||||
|
|
||||||
|
public string BackgroundColor { get; set; }
|
||||||
|
public string ForegroundLayer { get; set; }
|
||||||
|
public bool RequiresAutoOrientation { get; set; }
|
||||||
|
|
||||||
|
private bool HasDefaultOptions(string originalImagePath)
|
||||||
|
{
|
||||||
|
return HasDefaultOptionsWithoutSize(originalImagePath) &&
|
||||||
|
!Width.HasValue &&
|
||||||
|
!Height.HasValue &&
|
||||||
|
!MaxWidth.HasValue &&
|
||||||
|
!MaxHeight.HasValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasDefaultOptions(string originalImagePath, ImageSize? size)
|
||||||
|
{
|
||||||
|
if (!size.HasValue)
|
||||||
|
{
|
||||||
|
return HasDefaultOptions(originalImagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HasDefaultOptionsWithoutSize(originalImagePath))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sizeValue = size.Value;
|
||||||
|
|
||||||
|
if (Width.HasValue && !sizeValue.Width.Equals(Width.Value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Height.HasValue && !sizeValue.Height.Equals(Height.Value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (MaxWidth.HasValue && sizeValue.Width > MaxWidth.Value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (MaxHeight.HasValue && sizeValue.Height > MaxHeight.Value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasDefaultOptionsWithoutSize(string originalImagePath)
|
||||||
|
{
|
||||||
|
return (Quality >= 90) &&
|
||||||
|
IsFormatSupported(originalImagePath) &&
|
||||||
|
!AddPlayedIndicator &&
|
||||||
|
PercentPlayed.Equals(0) &&
|
||||||
|
!UnplayedCount.HasValue &&
|
||||||
|
!Blur.HasValue &&
|
||||||
|
!CropWhiteSpace &&
|
||||||
|
string.IsNullOrEmpty(BackgroundColor) &&
|
||||||
|
string.IsNullOrEmpty(ForegroundLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsFormatSupported(string originalImagePath)
|
||||||
|
{
|
||||||
|
var ext = Path.GetExtension(originalImagePath);
|
||||||
|
return SupportedOutputFormats.Any(outputFormat => string.Equals(ext, "." + outputFormat, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Drawing
|
||||||
|
{
|
||||||
|
public static class ImageProcessorExtensions
|
||||||
|
{
|
||||||
|
public static string GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType)
|
||||||
|
{
|
||||||
|
return processor.GetImageCacheTag(item, imageType, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType, int imageIndex)
|
||||||
|
{
|
||||||
|
var imageInfo = item.GetImageInfo(imageType, imageIndex);
|
||||||
|
|
||||||
|
if (imageInfo == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return processor.GetImageCacheTag(item, imageInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using MediaBrowser.Model.Drawing;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Drawing
|
||||||
|
{
|
||||||
|
public class ImageStream : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The stream.</value>
|
||||||
|
public Stream Stream { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the format.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The format.</value>
|
||||||
|
public ImageFormat Format { get; set; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (Stream != null)
|
||||||
|
{
|
||||||
|
Stream.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Dto
|
||||||
|
{
|
||||||
|
public class DtoOptions
|
||||||
|
{
|
||||||
|
private static readonly ItemFields[] DefaultExcludedFields = new []
|
||||||
|
{
|
||||||
|
ItemFields.SeasonUserData,
|
||||||
|
ItemFields.RefreshState
|
||||||
|
};
|
||||||
|
|
||||||
|
public ItemFields[] Fields { get; set; }
|
||||||
|
public ImageType[] ImageTypes { get; set; }
|
||||||
|
public int ImageTypeLimit { get; set; }
|
||||||
|
public bool EnableImages { get; set; }
|
||||||
|
public bool AddProgramRecordingInfo { get; set; }
|
||||||
|
public bool EnableUserData { get; set; }
|
||||||
|
public bool AddCurrentProgram { get; set; }
|
||||||
|
|
||||||
|
public DtoOptions()
|
||||||
|
: this(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly ImageType[] AllImageTypes = Enum.GetNames(typeof(ImageType))
|
||||||
|
.Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
private static readonly ItemFields[] AllItemFields = Enum.GetNames(typeof(ItemFields))
|
||||||
|
.Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
|
||||||
|
.Except(DefaultExcludedFields)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
public bool ContainsField(ItemFields field)
|
||||||
|
{
|
||||||
|
return AllItemFields.Contains(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DtoOptions(bool allFields)
|
||||||
|
{
|
||||||
|
ImageTypeLimit = int.MaxValue;
|
||||||
|
EnableImages = true;
|
||||||
|
EnableUserData = true;
|
||||||
|
AddCurrentProgram = true;
|
||||||
|
|
||||||
|
if (allFields)
|
||||||
|
{
|
||||||
|
Fields = AllItemFields;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Fields = new ItemFields[] { };
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageTypes = AllImageTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetImageLimit(ImageType type)
|
||||||
|
{
|
||||||
|
if (EnableImages && ImageTypes.Contains(type))
|
||||||
|
{
|
||||||
|
return ImageTypeLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Controller.Sync;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Dto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IDtoService
|
||||||
|
/// </summary>
|
||||||
|
public interface IDtoService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the dto id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
string GetDtoId(BaseItem item);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attaches the primary image aspect ratio.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dto">The dto.</param>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the primary image aspect ratio.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <returns>System.Nullable<System.Double>.</returns>
|
||||||
|
double? GetPrimaryImageAspectRatio(BaseItem item);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the base item dto.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="fields">The fields.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <param name="owner">The owner.</param>
|
||||||
|
BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the base item dto.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <param name="owner">The owner.</param>
|
||||||
|
/// <returns>BaseItemDto.</returns>
|
||||||
|
BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the base item dtos.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <param name="owner">The owner.</param>
|
||||||
|
BaseItemDto[] GetBaseItemDtos(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null);
|
||||||
|
|
||||||
|
BaseItemDto[] GetBaseItemDtos(List<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the item by name dto.
|
||||||
|
/// </summary>
|
||||||
|
BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, User user = null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
using MediaBrowser.Controller.IO;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specialized folder that can have items added to it's children by external entities.
|
||||||
|
/// Used for our RootFolder so plug-ins can add items.
|
||||||
|
/// </summary>
|
||||||
|
public class AggregateFolder : Folder
|
||||||
|
{
|
||||||
|
public AggregateFolder()
|
||||||
|
{
|
||||||
|
PhysicalLocationsList = new string[] { };
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool IsPhysicalRoot
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The _virtual children
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentBag<BaseItem> _virtualChildren = new ConcurrentBag<BaseItem>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the virtual children.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The virtual children.</value>
|
||||||
|
public ConcurrentBag<BaseItem> VirtualChildren
|
||||||
|
{
|
||||||
|
get { return _virtualChildren; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string[] PhysicalLocations
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return PhysicalLocationsList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] PhysicalLocationsList { get; set; }
|
||||||
|
|
||||||
|
protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
|
||||||
|
{
|
||||||
|
return CreateResolveArgs(directoryService, true).FileSystemChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guid[] _childrenIds = null;
|
||||||
|
private readonly object _childIdsLock = new object();
|
||||||
|
protected override List<BaseItem> LoadChildren()
|
||||||
|
{
|
||||||
|
lock (_childIdsLock)
|
||||||
|
{
|
||||||
|
if (_childrenIds == null || _childrenIds.Length == 0)
|
||||||
|
{
|
||||||
|
var list = base.LoadChildren();
|
||||||
|
_childrenIds = list.Select(i => i.Id).ToArray();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _childrenIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearCache()
|
||||||
|
{
|
||||||
|
lock (_childIdsLock)
|
||||||
|
{
|
||||||
|
_childrenIds = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _requiresRefresh;
|
||||||
|
public override bool RequiresRefresh()
|
||||||
|
{
|
||||||
|
var changed = base.RequiresRefresh() || _requiresRefresh;
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
{
|
||||||
|
var locations = PhysicalLocations;
|
||||||
|
|
||||||
|
var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations;
|
||||||
|
|
||||||
|
if (!locations.SequenceEqual(newLocations))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
|
||||||
|
{
|
||||||
|
ClearCache();
|
||||||
|
|
||||||
|
var changed = base.BeforeMetadataRefresh(replaceAllMetdata) || _requiresRefresh;
|
||||||
|
_requiresRefresh = false;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations)
|
||||||
|
{
|
||||||
|
ClearCache();
|
||||||
|
|
||||||
|
var path = ContainingFolderPath;
|
||||||
|
|
||||||
|
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
|
||||||
|
{
|
||||||
|
FileInfo = FileSystem.GetDirectoryInfo(path),
|
||||||
|
Path = path
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gather child folder and files
|
||||||
|
if (args.IsDirectory)
|
||||||
|
{
|
||||||
|
// When resolving the root, we need it's grandchildren (children of user views)
|
||||||
|
var flattenFolderDepth = 2;
|
||||||
|
|
||||||
|
var files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, FileSystem, CollectionFolder.ApplicationHost, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: true);
|
||||||
|
|
||||||
|
// Need to remove subpaths that may have been resolved from shortcuts
|
||||||
|
// Example: if \\server\movies exists, then strip out \\server\movies\action
|
||||||
|
files = LibraryManager.NormalizeRootPathList(files).ToArray();
|
||||||
|
|
||||||
|
args.FileSystemChildren = files;
|
||||||
|
}
|
||||||
|
|
||||||
|
_requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations);
|
||||||
|
if (setPhysicalLocations)
|
||||||
|
{
|
||||||
|
PhysicalLocationsList = args.PhysicalLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService)
|
||||||
|
{
|
||||||
|
return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
|
||||||
|
{
|
||||||
|
ClearCache();
|
||||||
|
|
||||||
|
await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
ClearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the virtual child.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="child">The child.</param>
|
||||||
|
/// <exception cref="System.ArgumentNullException"></exception>
|
||||||
|
public void AddVirtualChild(BaseItem child)
|
||||||
|
{
|
||||||
|
if (child == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
}
|
||||||
|
|
||||||
|
_virtualChildren.Add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the virtual child.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The id.</param>
|
||||||
|
/// <returns>BaseItem.</returns>
|
||||||
|
/// <exception cref="System.ArgumentNullException">id</exception>
|
||||||
|
public BaseItem FindVirtualChild(Guid id)
|
||||||
|
{
|
||||||
|
if (id.Equals(Guid.Empty))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in _virtualChildren)
|
||||||
|
{
|
||||||
|
if (child.Id == id)
|
||||||
|
{
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,216 @@
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class Audio
|
||||||
|
/// </summary>
|
||||||
|
public class Audio : BaseItem,
|
||||||
|
IHasAlbumArtist,
|
||||||
|
IHasArtist,
|
||||||
|
IHasMusicGenres,
|
||||||
|
IHasLookupInfo<SongInfo>,
|
||||||
|
IHasMediaSources
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the artist.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The artist.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string[] Artists { get; set; }
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string[] AlbumArtists { get; set; }
|
||||||
|
|
||||||
|
public Audio()
|
||||||
|
{
|
||||||
|
Artists = new string[] {};
|
||||||
|
AlbumArtists = new string[] {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetDefaultPrimaryImageAspectRatio()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsAddingToPlaylist
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsInheritedParentImages
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
protected override bool SupportsOwnedItems
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override Folder LatestItemsIndexContainer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return AlbumEntity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDownload()
|
||||||
|
{
|
||||||
|
return IsFileProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string[] AllArtists
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var list = new string[AlbumArtists.Length + Artists.Length];
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (var artist in AlbumArtists)
|
||||||
|
{
|
||||||
|
list[index] = artist;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
foreach (var artist in Artists)
|
||||||
|
{
|
||||||
|
list[index] = artist;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public MusicAlbum AlbumEntity
|
||||||
|
{
|
||||||
|
get { return FindParent<MusicAlbum>(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of the media.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type of the media.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string MediaType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Model.Entities.MediaType.Audio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the name of the sort.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
protected override string CreateSortName()
|
||||||
|
{
|
||||||
|
return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("0000 - ") : "")
|
||||||
|
+ (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
var list = base.GetUserDataKeys();
|
||||||
|
|
||||||
|
var songKey = IndexNumber.HasValue ? IndexNumber.Value.ToString("0000") : string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
if (ParentIndexNumber.HasValue)
|
||||||
|
{
|
||||||
|
songKey = ParentIndexNumber.Value.ToString("0000") + "-" + songKey;
|
||||||
|
}
|
||||||
|
songKey += Name;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Album))
|
||||||
|
{
|
||||||
|
songKey = Album + "-" + songKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
var albumArtist = AlbumArtists.Length == 0 ? null : AlbumArtists[0];
|
||||||
|
if (!string.IsNullOrEmpty(albumArtist))
|
||||||
|
{
|
||||||
|
songKey = albumArtist + "-" + songKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Insert(0, songKey);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UnratedItem GetBlockUnratedType()
|
||||||
|
{
|
||||||
|
if (SourceType == SourceType.Library)
|
||||||
|
{
|
||||||
|
return UnratedItem.Music;
|
||||||
|
}
|
||||||
|
return base.GetBlockUnratedType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MediaStream> GetMediaStreams(MediaStreamType type)
|
||||||
|
{
|
||||||
|
return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
|
||||||
|
{
|
||||||
|
ItemId = Id,
|
||||||
|
Type = type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public SongInfo GetLookupInfo()
|
||||||
|
{
|
||||||
|
var info = GetItemLookupInfo<SongInfo>();
|
||||||
|
|
||||||
|
info.AlbumArtists = AlbumArtists;
|
||||||
|
info.Album = Album;
|
||||||
|
info.Artists = Artists;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override List<Tuple<BaseItem, MediaSourceType>> GetAllItemsForMediaSources()
|
||||||
|
{
|
||||||
|
var list = new List<Tuple<BaseItem, MediaSourceType>>();
|
||||||
|
list.Add(new Tuple<BaseItem, MediaSourceType>(this, MediaSourceType.Default));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
|
{
|
||||||
|
public interface IHasAlbumArtist
|
||||||
|
{
|
||||||
|
string[] AlbumArtists { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasArtist
|
||||||
|
{
|
||||||
|
string[] AllArtists { get; }
|
||||||
|
|
||||||
|
string[] Artists { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
|
{
|
||||||
|
public interface IHasMusicGenres
|
||||||
|
{
|
||||||
|
string[] Genres { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,272 @@
|
||||||
|
using System;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Dto;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class MusicAlbum
|
||||||
|
/// </summary>
|
||||||
|
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
|
||||||
|
{
|
||||||
|
public string[] AlbumArtists { get; set; }
|
||||||
|
public string[] Artists { get; set; }
|
||||||
|
|
||||||
|
public MusicAlbum()
|
||||||
|
{
|
||||||
|
Artists = new string[] {};
|
||||||
|
AlbumArtists = new string[] {};
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsAddingToPlaylist
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsInheritedParentImages
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public MusicArtist MusicArtist
|
||||||
|
{
|
||||||
|
get { return GetMusicArtist(new DtoOptions(true)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public MusicArtist GetMusicArtist(DtoOptions options)
|
||||||
|
{
|
||||||
|
var parents = GetParents();
|
||||||
|
foreach (var parent in parents)
|
||||||
|
{
|
||||||
|
var artist = parent as MusicArtist;
|
||||||
|
if (artist != null)
|
||||||
|
{
|
||||||
|
return artist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = AlbumArtist;
|
||||||
|
if (!string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
return LibraryManager.GetArtist(name, options);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsCumulativeRunTimeTicks
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string[] AllArtists
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var list = new string[AlbumArtists.Length + Artists.Length];
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
foreach (var artist in AlbumArtists)
|
||||||
|
{
|
||||||
|
list[index] = artist;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
foreach (var artist in Artists)
|
||||||
|
{
|
||||||
|
list[index] = artist;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string AlbumArtist
|
||||||
|
{
|
||||||
|
get { return AlbumArtists.Length == 0 ? null : AlbumArtists[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the tracks.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The tracks.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public IEnumerable<BaseItem> Tracks
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetRecursiveChildren(i => i is Audio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||||
|
{
|
||||||
|
return Tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetDefaultPrimaryImageAspectRatio()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
var list = base.GetUserDataKeys();
|
||||||
|
|
||||||
|
var albumArtist = AlbumArtist;
|
||||||
|
if (!string.IsNullOrEmpty(albumArtist))
|
||||||
|
{
|
||||||
|
list.Insert(0, albumArtist + "-" + Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = this.GetProviderId(MetadataProviders.MusicBrainzAlbum);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
list.Insert(0, "MusicAlbum-Musicbrainz-" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
list.Insert(0, "MusicAlbum-MusicBrainzReleaseGroup-" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||||
|
{
|
||||||
|
return config.BlockUnratedItems.Contains(UnratedItem.Music);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UnratedItem GetBlockUnratedType()
|
||||||
|
{
|
||||||
|
return UnratedItem.Music;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlbumInfo GetLookupInfo()
|
||||||
|
{
|
||||||
|
var id = GetItemLookupInfo<AlbumInfo>();
|
||||||
|
|
||||||
|
id.AlbumArtists = AlbumArtists;
|
||||||
|
|
||||||
|
var artist = GetMusicArtist(new DtoOptions(false));
|
||||||
|
|
||||||
|
if (artist != null)
|
||||||
|
{
|
||||||
|
id.ArtistProviderIds = artist.ProviderIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
id.SongInfos = GetRecursiveChildren(i => i is Audio)
|
||||||
|
.Cast<Audio>()
|
||||||
|
.Select(i => i.GetLookupInfo())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var album = id.SongInfos
|
||||||
|
.Select(i => i.Album)
|
||||||
|
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(album))
|
||||||
|
{
|
||||||
|
id.Name = album;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var items = GetRecursiveChildren();
|
||||||
|
|
||||||
|
var totalItems = items.Count;
|
||||||
|
var numComplete = 0;
|
||||||
|
|
||||||
|
var childUpdateType = ItemUpdateType.None;
|
||||||
|
|
||||||
|
// Refresh songs
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var updateType = await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
childUpdateType = childUpdateType | updateType;
|
||||||
|
|
||||||
|
numComplete++;
|
||||||
|
double percent = numComplete;
|
||||||
|
percent /= totalItems;
|
||||||
|
progress.Report(percent * 95);
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentRefreshOptions = refreshOptions;
|
||||||
|
if (childUpdateType > ItemUpdateType.None)
|
||||||
|
{
|
||||||
|
parentRefreshOptions = new MetadataRefreshOptions(refreshOptions);
|
||||||
|
parentRefreshOptions.MetadataRefreshMode = MetadataRefreshMode.FullRefresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh current item
|
||||||
|
await RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!refreshOptions.IsAutomated)
|
||||||
|
{
|
||||||
|
await RefreshArtists(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshArtists(MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var all = AllArtists;
|
||||||
|
foreach (var i in all)
|
||||||
|
{
|
||||||
|
// This should not be necessary but we're seeing some cases of it
|
||||||
|
if (string.IsNullOrEmpty(i))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var artist = LibraryManager.GetArtist(i);
|
||||||
|
|
||||||
|
if (!artist.IsAccessedByName)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await artist.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,275 @@
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Extensions;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class MusicArtist
|
||||||
|
/// </summary>
|
||||||
|
public class MusicArtist : Folder, IItemByName, IHasMusicGenres, IHasDualAccess, IHasLookupInfo<ArtistInfo>
|
||||||
|
{
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public bool IsAccessedByName
|
||||||
|
{
|
||||||
|
get { return ParentId.Equals(Guid.Empty); }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool IsFolder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return !IsAccessedByName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsInheritedParentImages
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsCumulativeRunTimeTicks
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool IsDisplayedAsFolder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsAddingToPlaylist
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetDefaultPrimaryImageAspectRatio()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return !IsAccessedByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
|
||||||
|
{
|
||||||
|
if (query.IncludeItemTypes.Length == 0)
|
||||||
|
{
|
||||||
|
query.IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicVideo).Name, typeof(MusicAlbum).Name };
|
||||||
|
query.ArtistIds = new[] { Id };
|
||||||
|
}
|
||||||
|
|
||||||
|
return LibraryManager.GetItemList(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override IEnumerable<BaseItem> Children
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (IsAccessedByName)
|
||||||
|
{
|
||||||
|
return new List<BaseItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.Children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetChildCount(User user)
|
||||||
|
{
|
||||||
|
if (IsAccessedByName)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return base.GetChildCount(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSaveLocalMetadataEnabled()
|
||||||
|
{
|
||||||
|
if (IsAccessedByName)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.IsSaveLocalMetadataEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Task _cachedTask = Task.FromResult(true);
|
||||||
|
protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
|
||||||
|
{
|
||||||
|
if (IsAccessedByName)
|
||||||
|
{
|
||||||
|
// Should never get in here anyway
|
||||||
|
return _cachedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
var list = base.GetUserDataKeys();
|
||||||
|
|
||||||
|
list.InsertRange(0, GetUserDataKeys(this));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the folder containing the item.
|
||||||
|
/// If the item is a folder, it returns the folder itself
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The containing folder path.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string ContainingFolderPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the user data key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
private static List<string> GetUserDataKeys(MusicArtist item)
|
||||||
|
{
|
||||||
|
var list = new List<string>();
|
||||||
|
var id = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
list.Add("Artist-Musicbrainz-" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Add("Artist-" + (item.Name ?? string.Empty).RemoveDiacritics());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
public override string CreatePresentationUniqueKey()
|
||||||
|
{
|
||||||
|
return "Artist-" + (Name ?? string.Empty).RemoveDiacritics();
|
||||||
|
}
|
||||||
|
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||||
|
{
|
||||||
|
return config.BlockUnratedItems.Contains(UnratedItem.Music);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UnratedItem GetBlockUnratedType()
|
||||||
|
{
|
||||||
|
return UnratedItem.Music;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArtistInfo GetLookupInfo()
|
||||||
|
{
|
||||||
|
var info = GetItemLookupInfo<ArtistInfo>();
|
||||||
|
|
||||||
|
info.SongInfos = GetRecursiveChildren(i => i is Audio)
|
||||||
|
.Cast<Audio>()
|
||||||
|
.Select(i => i.GetLookupInfo())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
|
{
|
||||||
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
|
var validName = normalizeName ?
|
||||||
|
FileSystem.GetValidFilename(name).Trim().TrimEnd('.') :
|
||||||
|
name;
|
||||||
|
|
||||||
|
return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.ArtistsPath, validName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRebasedPath()
|
||||||
|
{
|
||||||
|
return GetPath(System.IO.Path.GetFileName(Path), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool RequiresRefresh()
|
||||||
|
{
|
||||||
|
if (IsAccessedByName)
|
||||||
|
{
|
||||||
|
var newPath = GetRebasedPath();
|
||||||
|
if (!string.Equals(Path, newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base.RequiresRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is called before any metadata refresh and returns true or false indicating if changes were made
|
||||||
|
/// </summary>
|
||||||
|
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
|
||||||
|
{
|
||||||
|
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
|
||||||
|
|
||||||
|
if (IsAccessedByName)
|
||||||
|
{
|
||||||
|
var newPath = GetRebasedPath();
|
||||||
|
if (!string.Equals(Path, newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Path = newPath;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Extensions;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class MusicGenre
|
||||||
|
/// </summary>
|
||||||
|
public class MusicGenre : BaseItem, IItemByName
|
||||||
|
{
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
var list = base.GetUserDataKeys();
|
||||||
|
|
||||||
|
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
public override string CreatePresentationUniqueKey()
|
||||||
|
{
|
||||||
|
return GetUserDataKeys()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsAddingToPlaylist
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsAncestors
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool IsDisplayedAsFolder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the folder containing the item.
|
||||||
|
/// If the item is a folder, it returns the folder itself
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The containing folder path.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string ContainingFolderPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetDefaultPrimaryImageAspectRatio()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSaveLocalMetadataEnabled()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
|
||||||
|
{
|
||||||
|
query.GenreIds = new[] { Id };
|
||||||
|
query.IncludeItemTypes = new[] { typeof(MusicVideo).Name, typeof(Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name };
|
||||||
|
|
||||||
|
return LibraryManager.GetItemList(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
|
{
|
||||||
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
|
var validName = normalizeName ?
|
||||||
|
FileSystem.GetValidFilename(name).Trim().TrimEnd('.') :
|
||||||
|
name;
|
||||||
|
|
||||||
|
return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.MusicGenrePath, validName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRebasedPath()
|
||||||
|
{
|
||||||
|
return GetPath(System.IO.Path.GetFileName(Path), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool RequiresRefresh()
|
||||||
|
{
|
||||||
|
var newPath = GetRebasedPath();
|
||||||
|
if (!string.Equals(Path, newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return base.RequiresRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is called before any metadata refresh and returns true or false indicating if changes were made
|
||||||
|
/// </summary>
|
||||||
|
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
|
||||||
|
{
|
||||||
|
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
|
||||||
|
|
||||||
|
var newPath = GetRebasedPath();
|
||||||
|
if (!string.Equals(Path, newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Path = newPath;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
using System;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public class AudioBook : Audio.Audio, IHasSeries, IHasLookupInfo<SongInfo>
|
||||||
|
{
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPositionTicksResume
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string SeriesPresentationUniqueKey { get; set; }
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string SeriesName { get; set; }
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public Guid SeriesId { get; set; }
|
||||||
|
|
||||||
|
public string FindSeriesSortName()
|
||||||
|
{
|
||||||
|
return SeriesName;
|
||||||
|
}
|
||||||
|
public string FindSeriesName()
|
||||||
|
{
|
||||||
|
return SeriesName;
|
||||||
|
}
|
||||||
|
public string FindSeriesPresentationUniqueKey()
|
||||||
|
{
|
||||||
|
return SeriesPresentationUniqueKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetDefaultPrimaryImageAspectRatio()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid FindSeriesId()
|
||||||
|
{
|
||||||
|
return SeriesId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDownload()
|
||||||
|
{
|
||||||
|
return IsFileProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UnratedItem GetBlockUnratedType()
|
||||||
|
{
|
||||||
|
return UnratedItem.Book;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public static class BaseItemExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the image path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="imageType">Type of the image.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
public static string GetImagePath(this BaseItem item, ImageType imageType)
|
||||||
|
{
|
||||||
|
return item.GetImagePath(imageType, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasImage(this BaseItem item, ImageType imageType)
|
||||||
|
{
|
||||||
|
return item.HasImage(imageType, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the image path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="imageType">Type of the image.</param>
|
||||||
|
/// <param name="file">The file.</param>
|
||||||
|
public static void SetImagePath(this BaseItem item, ImageType imageType, FileSystemMetadata file)
|
||||||
|
{
|
||||||
|
item.SetImagePath(imageType, 0, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the image path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="imageType">Type of the image.</param>
|
||||||
|
/// <param name="file">The file.</param>
|
||||||
|
public static void SetImagePath(this BaseItem item, ImageType imageType, string file)
|
||||||
|
{
|
||||||
|
if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
item.SetImage(new ItemImageInfo
|
||||||
|
{
|
||||||
|
Path = file,
|
||||||
|
Type = imageType
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Plugins derive from and export this class to create a folder that will appear in the root along
|
||||||
|
/// with all the other actual physical folders in the system.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BasePluginFolder : Folder, ICollectionFolder
|
||||||
|
{
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public virtual string CollectionType
|
||||||
|
{
|
||||||
|
get { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSaveLocalMetadataEnabled()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsInheritedParentImages
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//public override double? GetDefaultPrimaryImageAspectRatio()
|
||||||
|
//{
|
||||||
|
// double value = 16;
|
||||||
|
// value /= 9;
|
||||||
|
|
||||||
|
// return value;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries
|
||||||
|
{
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string MediaType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Model.Entities.MediaType.Book;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string SeriesPresentationUniqueKey { get; set; }
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public string SeriesName { get; set; }
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public Guid SeriesId { get; set; }
|
||||||
|
|
||||||
|
public string FindSeriesSortName()
|
||||||
|
{
|
||||||
|
return SeriesName;
|
||||||
|
}
|
||||||
|
public string FindSeriesName()
|
||||||
|
{
|
||||||
|
return SeriesName;
|
||||||
|
}
|
||||||
|
public string FindSeriesPresentationUniqueKey()
|
||||||
|
{
|
||||||
|
return SeriesPresentationUniqueKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid FindSeriesId()
|
||||||
|
{
|
||||||
|
return SeriesId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDownload()
|
||||||
|
{
|
||||||
|
return IsFileProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UnratedItem GetBlockUnratedType()
|
||||||
|
{
|
||||||
|
return UnratedItem.Book;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BookInfo GetLookupInfo()
|
||||||
|
{
|
||||||
|
var info = GetItemLookupInfo<BookInfo>();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(SeriesName))
|
||||||
|
{
|
||||||
|
info.SeriesName = GetParents().Select(i => i.Name).FirstOrDefault();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info.SeriesName = SeriesName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,405 @@
|
||||||
|
using MediaBrowser.Controller.IO;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specialized Folder class that points to a subset of the physical folders in the system.
|
||||||
|
/// It is created from the user-specific folders within the system root
|
||||||
|
/// </summary>
|
||||||
|
public class CollectionFolder : Folder, ICollectionFolder
|
||||||
|
{
|
||||||
|
public static IXmlSerializer XmlSerializer { get; set; }
|
||||||
|
public static IJsonSerializer JsonSerializer { get; set; }
|
||||||
|
public static IServerApplicationHost ApplicationHost { get; set; }
|
||||||
|
|
||||||
|
public CollectionFolder()
|
||||||
|
{
|
||||||
|
PhysicalLocationsList = new string[] { };
|
||||||
|
PhysicalFolderIds = new Guid[] { };
|
||||||
|
}
|
||||||
|
|
||||||
|
//public override double? GetDefaultPrimaryImageAspectRatio()
|
||||||
|
//{
|
||||||
|
// double value = 16;
|
||||||
|
// value /= 9;
|
||||||
|
|
||||||
|
// return value;
|
||||||
|
//}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsInheritedParentImages
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CollectionType { get; set; }
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, LibraryOptions> LibraryOptions = new Dictionary<string, LibraryOptions>();
|
||||||
|
public LibraryOptions GetLibraryOptions()
|
||||||
|
{
|
||||||
|
return GetLibraryOptions(Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LibraryOptions LoadLibraryOptions(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return new LibraryOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var mediaPath in result.PathInfos)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(mediaPath.Path))
|
||||||
|
{
|
||||||
|
mediaPath.Path = ApplicationHost.ExpandVirtualPath(mediaPath.Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
return new LibraryOptions();
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
return new LibraryOptions();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("Error loading library options", ex);
|
||||||
|
|
||||||
|
return new LibraryOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetLibraryOptionsPath(string path)
|
||||||
|
{
|
||||||
|
return System.IO.Path.Combine(path, "options.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateLibraryOptions(LibraryOptions options)
|
||||||
|
{
|
||||||
|
SaveLibraryOptions(Path, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LibraryOptions GetLibraryOptions(string path)
|
||||||
|
{
|
||||||
|
lock (LibraryOptions)
|
||||||
|
{
|
||||||
|
LibraryOptions options;
|
||||||
|
if (!LibraryOptions.TryGetValue(path, out options))
|
||||||
|
{
|
||||||
|
options = LoadLibraryOptions(path);
|
||||||
|
LibraryOptions[path] = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveLibraryOptions(string path, LibraryOptions options)
|
||||||
|
{
|
||||||
|
lock (LibraryOptions)
|
||||||
|
{
|
||||||
|
LibraryOptions[path] = options;
|
||||||
|
|
||||||
|
var clone = JsonSerializer.DeserializeFromString<LibraryOptions>(JsonSerializer.SerializeToString(options));
|
||||||
|
foreach (var mediaPath in clone.PathInfos)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(mediaPath.Path))
|
||||||
|
{
|
||||||
|
mediaPath.Path = ApplicationHost.ReverseVirtualPath(mediaPath.Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlSerializer.SerializeToFile(clone, GetLibraryOptionsPath(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnCollectionFolderChange()
|
||||||
|
{
|
||||||
|
lock (LibraryOptions)
|
||||||
|
{
|
||||||
|
LibraryOptions.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allow different display preferences for each collection folder
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The display prefs id.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override Guid DisplayPreferencesId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string[] PhysicalLocations
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return PhysicalLocationsList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSaveLocalMetadataEnabled()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] PhysicalLocationsList { get; set; }
|
||||||
|
public Guid[] PhysicalFolderIds { get; set; }
|
||||||
|
|
||||||
|
protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
|
||||||
|
{
|
||||||
|
return CreateResolveArgs(directoryService, true).FileSystemChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _requiresRefresh;
|
||||||
|
public override bool RequiresRefresh()
|
||||||
|
{
|
||||||
|
var changed = base.RequiresRefresh() || _requiresRefresh;
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
{
|
||||||
|
var locations = PhysicalLocations;
|
||||||
|
|
||||||
|
var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations;
|
||||||
|
|
||||||
|
if (!locations.SequenceEqual(newLocations))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
{
|
||||||
|
var folderIds = PhysicalFolderIds;
|
||||||
|
|
||||||
|
var newFolderIds = GetPhysicalFolders(false).Select(i => i.Id).ToList();
|
||||||
|
|
||||||
|
if (!folderIds.SequenceEqual(newFolderIds))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
|
||||||
|
{
|
||||||
|
var changed = base.BeforeMetadataRefresh(replaceAllMetdata) || _requiresRefresh;
|
||||||
|
_requiresRefresh = false;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double? GetRefreshProgress()
|
||||||
|
{
|
||||||
|
var folders = GetPhysicalFolders(true).ToList();
|
||||||
|
double totalProgresses = 0;
|
||||||
|
var foldersWithProgress = 0;
|
||||||
|
|
||||||
|
foreach (var folder in folders)
|
||||||
|
{
|
||||||
|
var progress = ProviderManager.GetRefreshProgress(folder.Id);
|
||||||
|
if (progress.HasValue)
|
||||||
|
{
|
||||||
|
totalProgresses += progress.Value;
|
||||||
|
foldersWithProgress++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foldersWithProgress == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (totalProgresses / foldersWithProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
|
||||||
|
{
|
||||||
|
return RefreshLinkedChildrenInternal(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RefreshLinkedChildrenInternal(bool setFolders)
|
||||||
|
{
|
||||||
|
var physicalFolders = GetPhysicalFolders(false)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var linkedChildren = physicalFolders
|
||||||
|
.SelectMany(c => c.LinkedChildren)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer(FileSystem));
|
||||||
|
|
||||||
|
LinkedChildren = linkedChildren.ToArray(linkedChildren.Count);
|
||||||
|
|
||||||
|
var folderIds = PhysicalFolderIds;
|
||||||
|
var newFolderIds = physicalFolders.Select(i => i.Id).ToArray();
|
||||||
|
|
||||||
|
if (!folderIds.SequenceEqual(newFolderIds))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
if (setFolders)
|
||||||
|
{
|
||||||
|
PhysicalFolderIds = newFolderIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations)
|
||||||
|
{
|
||||||
|
var path = ContainingFolderPath;
|
||||||
|
|
||||||
|
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
|
||||||
|
{
|
||||||
|
FileInfo = FileSystem.GetDirectoryInfo(path),
|
||||||
|
Path = path,
|
||||||
|
Parent = GetParent() as Folder,
|
||||||
|
CollectionType = CollectionType
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gather child folder and files
|
||||||
|
if (args.IsDirectory)
|
||||||
|
{
|
||||||
|
var flattenFolderDepth = 0;
|
||||||
|
|
||||||
|
var files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, FileSystem, ApplicationHost, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: true);
|
||||||
|
|
||||||
|
args.FileSystemChildren = files;
|
||||||
|
}
|
||||||
|
|
||||||
|
_requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations);
|
||||||
|
|
||||||
|
if (setPhysicalLocations)
|
||||||
|
{
|
||||||
|
PhysicalLocationsList = args.PhysicalLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes
|
||||||
|
/// ***Currently does not contain logic to maintain items that are unavailable in the file system***
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="progress">The progress.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
|
||||||
|
/// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
|
||||||
|
/// <param name="refreshOptions">The refresh options.</param>
|
||||||
|
/// <param name="directoryService">The directory service.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
|
||||||
|
{
|
||||||
|
return Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Our children are actually just references to the ones in the physical root...
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The actual children.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override IEnumerable<BaseItem> Children
|
||||||
|
{
|
||||||
|
get { return GetActualChildren(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<BaseItem> GetActualChildren()
|
||||||
|
{
|
||||||
|
return GetPhysicalFolders(true).SelectMany(c => c.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Folder> GetPhysicalFolders()
|
||||||
|
{
|
||||||
|
return GetPhysicalFolders(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Folder> GetPhysicalFolders(bool enableCache)
|
||||||
|
{
|
||||||
|
if (enableCache)
|
||||||
|
{
|
||||||
|
return PhysicalFolderIds.Select(i => LibraryManager.GetItemById(i)).OfType<Folder>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootChildren = LibraryManager.RootFolder.Children
|
||||||
|
.OfType<Folder>()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return PhysicalLocations.Where(i => !FileSystem.AreEqual(i, Path)).SelectMany(i => GetPhysicalParents(i, rootChildren)).DistinctBy(i => i.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Folder> GetPhysicalParents(string path, List<Folder> rootChildren)
|
||||||
|
{
|
||||||
|
var result = rootChildren
|
||||||
|
.Where(i => FileSystem.AreEqual(i.Path, path))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (result.Count == 0)
|
||||||
|
{
|
||||||
|
var folder = LibraryManager.FindByPath(path, true) as Folder;
|
||||||
|
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
|
result.Add(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public static class DayOfWeekHelper
|
||||||
|
{
|
||||||
|
public static List<DayOfWeek> GetDaysOfWeek(DynamicDayOfWeek day)
|
||||||
|
{
|
||||||
|
return GetDaysOfWeek(new List<DynamicDayOfWeek> { day });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<DayOfWeek> GetDaysOfWeek(List<DynamicDayOfWeek> days)
|
||||||
|
{
|
||||||
|
var list = new List<DayOfWeek>();
|
||||||
|
|
||||||
|
if (days.Contains(DynamicDayOfWeek.Sunday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Weekend) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Everyday))
|
||||||
|
{
|
||||||
|
list.Add(DayOfWeek.Sunday);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (days.Contains(DynamicDayOfWeek.Saturday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Weekend) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Everyday))
|
||||||
|
{
|
||||||
|
list.Add(DayOfWeek.Saturday);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (days.Contains(DynamicDayOfWeek.Monday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Weekday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Everyday))
|
||||||
|
{
|
||||||
|
list.Add(DayOfWeek.Monday);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (days.Contains(DynamicDayOfWeek.Tuesday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Weekday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Everyday))
|
||||||
|
{
|
||||||
|
list.Add(DayOfWeek.Tuesday
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (days.Contains(DynamicDayOfWeek.Wednesday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Weekday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Everyday))
|
||||||
|
{
|
||||||
|
list.Add(DayOfWeek.Wednesday);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (days.Contains(DynamicDayOfWeek.Thursday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Weekday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Everyday))
|
||||||
|
{
|
||||||
|
list.Add(DayOfWeek.Thursday);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (days.Contains(DynamicDayOfWeek.Friday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Weekday) ||
|
||||||
|
days.Contains(DynamicDayOfWeek.Everyday))
|
||||||
|
{
|
||||||
|
list.Add(DayOfWeek.Friday);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class Extensions
|
||||||
|
/// </summary>
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the trailer URL.
|
||||||
|
/// </summary>
|
||||||
|
public static void AddTrailerUrl(this BaseItem item, string url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("url");
|
||||||
|
}
|
||||||
|
|
||||||
|
var current = item.RemoteTrailers.FirstOrDefault(i => string.Equals(i.Url, url, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (current == null)
|
||||||
|
{
|
||||||
|
var mediaUrl = new MediaUrl
|
||||||
|
{
|
||||||
|
Url = url
|
||||||
|
};
|
||||||
|
|
||||||
|
if (item.RemoteTrailers.Length == 0)
|
||||||
|
{
|
||||||
|
item.RemoteTrailers = new[] { mediaUrl };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var list = item.RemoteTrailers.ToArray(item.RemoteTrailers.Length + 1);
|
||||||
|
list[list.Length - 1] = mediaUrl;
|
||||||
|
|
||||||
|
item.RemoteTrailers = list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,129 @@
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public class Game : BaseItem, IHasTrailers, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
|
||||||
|
{
|
||||||
|
public Game()
|
||||||
|
{
|
||||||
|
MultiPartGameFiles = new string[] {};
|
||||||
|
RemoteTrailers = EmptyMediaUrlArray;
|
||||||
|
LocalTrailerIds = new Guid[] {};
|
||||||
|
RemoteTrailerIds = new Guid[] {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid[] LocalTrailerIds { get; set; }
|
||||||
|
public Guid[] RemoteTrailerIds { get; set; }
|
||||||
|
|
||||||
|
public override bool CanDownload()
|
||||||
|
{
|
||||||
|
return IsFileProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsThemeMedia
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the remote trailers.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The remote trailers.</value>
|
||||||
|
public MediaUrl[] RemoteTrailers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of the media.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type of the media.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string MediaType
|
||||||
|
{
|
||||||
|
get { return Model.Entities.MediaType.Game; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the players supported.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The players supported.</value>
|
||||||
|
public int? PlayersSupported { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance is place holder.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance is place holder; otherwise, <c>false</c>.</value>
|
||||||
|
public bool IsPlaceHolder { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the game system.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The game system.</value>
|
||||||
|
public string GameSystem { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this instance is multi part.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance is multi part; otherwise, <c>false</c>.</value>
|
||||||
|
public bool IsMultiPart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the paths to the game files in the event this is a multipart game
|
||||||
|
/// </summary>
|
||||||
|
public string[] MultiPartGameFiles { get; set; }
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
var list = base.GetUserDataKeys();
|
||||||
|
var id = this.GetProviderId(MetadataProviders.Gamesdb);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
list.Insert(0, "Game-Gamesdb-" + id);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<FileSystemMetadata> GetDeletePaths()
|
||||||
|
{
|
||||||
|
if (!IsInMixedFolder)
|
||||||
|
{
|
||||||
|
return new[] {
|
||||||
|
new FileSystemMetadata
|
||||||
|
{
|
||||||
|
FullName = FileSystem.GetDirectoryName(Path),
|
||||||
|
IsDirectory = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.GetDeletePaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UnratedItem GetBlockUnratedType()
|
||||||
|
{
|
||||||
|
return UnratedItem.Game;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameInfo GetLookupInfo()
|
||||||
|
{
|
||||||
|
var id = GetItemLookupInfo<GameInfo>();
|
||||||
|
|
||||||
|
id.GameSystem = GameSystem;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Extensions;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public class GameGenre : BaseItem, IItemByName
|
||||||
|
{
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
var list = base.GetUserDataKeys();
|
||||||
|
|
||||||
|
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CreatePresentationUniqueKey()
|
||||||
|
{
|
||||||
|
return GetUserDataKeys()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetDefaultPrimaryImageAspectRatio()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the folder containing the item.
|
||||||
|
/// If the item is a folder, it returns the folder itself
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The containing folder path.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string ContainingFolderPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsAncestors
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSaveLocalMetadataEnabled()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
|
||||||
|
{
|
||||||
|
query.GenreIds = new[] { Id };
|
||||||
|
query.IncludeItemTypes = new[] { typeof(Game).Name };
|
||||||
|
|
||||||
|
return LibraryManager.GetItemList(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
|
{
|
||||||
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
|
var validName = normalizeName ?
|
||||||
|
FileSystem.GetValidFilename(name).Trim().TrimEnd('.') :
|
||||||
|
name;
|
||||||
|
|
||||||
|
return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.GameGenrePath, validName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRebasedPath()
|
||||||
|
{
|
||||||
|
return GetPath(System.IO.Path.GetFileName(Path), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool RequiresRefresh()
|
||||||
|
{
|
||||||
|
var newPath = GetRebasedPath();
|
||||||
|
if (!string.Equals(Path, newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return base.RequiresRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is called before any metadata refresh and returns true or false indicating if changes were made
|
||||||
|
/// </summary>
|
||||||
|
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
|
||||||
|
{
|
||||||
|
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
|
||||||
|
|
||||||
|
var newPath = GetRebasedPath();
|
||||||
|
if (!string.Equals(Path, newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Path = newPath;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class GameSystem
|
||||||
|
/// </summary>
|
||||||
|
public class GameSystem : Folder, IHasLookupInfo<GameSystemInfo>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Return the id that should be used to key display prefs for this item.
|
||||||
|
/// Default is based on the type for everything except actual generic folders.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The display prefs id.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override Guid DisplayPreferencesId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsInheritedParentImages
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetDefaultPrimaryImageAspectRatio()
|
||||||
|
{
|
||||||
|
double value = 16;
|
||||||
|
value /= 9;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the game system.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The game system.</value>
|
||||||
|
public string GameSystemName { get; set; }
|
||||||
|
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
var list = base.GetUserDataKeys();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(GameSystemName))
|
||||||
|
{
|
||||||
|
list.Insert(0, "GameSystem-" + GameSystemName);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||||
|
{
|
||||||
|
// Don't block. Determine by game
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UnratedItem GetBlockUnratedType()
|
||||||
|
{
|
||||||
|
return UnratedItem.Game;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameSystemInfo GetLookupInfo()
|
||||||
|
{
|
||||||
|
var id = GetItemLookupInfo<GameSystemInfo>();
|
||||||
|
|
||||||
|
id.Path = Path;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Extensions;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class Genre
|
||||||
|
/// </summary>
|
||||||
|
public class Genre : BaseItem, IItemByName
|
||||||
|
{
|
||||||
|
public override List<string> GetUserDataKeys()
|
||||||
|
{
|
||||||
|
var list = base.GetUserDataKeys();
|
||||||
|
|
||||||
|
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
public override string CreatePresentationUniqueKey()
|
||||||
|
{
|
||||||
|
return GetUserDataKeys()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetDefaultPrimaryImageAspectRatio()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the folder containing the item.
|
||||||
|
/// If the item is a folder, it returns the folder itself
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The containing folder path.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override string ContainingFolderPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool IsDisplayedAsFolder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsAncestors
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSaveLocalMetadataEnabled()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
|
||||||
|
{
|
||||||
|
query.GenreIds = new[] { Id };
|
||||||
|
query.ExcludeItemTypes = new[] { typeof(Game).Name, typeof(MusicVideo).Name, typeof(Audio.Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name };
|
||||||
|
|
||||||
|
return LibraryManager.GetItemList(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPeople
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
|
{
|
||||||
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
|
var validName = normalizeName ?
|
||||||
|
FileSystem.GetValidFilename(name).Trim().TrimEnd('.') :
|
||||||
|
name;
|
||||||
|
|
||||||
|
return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.GenrePath, validName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRebasedPath()
|
||||||
|
{
|
||||||
|
return GetPath(System.IO.Path.GetFileName(Path), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool RequiresRefresh()
|
||||||
|
{
|
||||||
|
var newPath = GetRebasedPath();
|
||||||
|
if (!string.Equals(Path, newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return base.RequiresRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is called before any metadata refresh and returns true or false indicating if changes were made
|
||||||
|
/// </summary>
|
||||||
|
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
|
||||||
|
{
|
||||||
|
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
|
||||||
|
|
||||||
|
var newPath = GetRebasedPath();
|
||||||
|
if (!string.Equals(Path, newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Path = newPath;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is just a marker interface to denote top level folders
|
||||||
|
/// </summary>
|
||||||
|
public interface ICollectionFolder : IHasCollectionType
|
||||||
|
{
|
||||||
|
string Path { get; }
|
||||||
|
string Name { get; }
|
||||||
|
Guid Id { get; }
|
||||||
|
string[] PhysicalLocations { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISupportsUserSpecificView
|
||||||
|
{
|
||||||
|
bool EnableUserSpecificView { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasCollectionType
|
||||||
|
{
|
||||||
|
string CollectionType { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IHasAspectRatio
|
||||||
|
/// </summary>
|
||||||
|
public interface IHasAspectRatio
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the aspect ratio.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The aspect ratio.</value>
|
||||||
|
string AspectRatio { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IHasDisplayOrder
|
||||||
|
/// </summary>
|
||||||
|
public interface IHasDisplayOrder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the display order.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The display order.</value>
|
||||||
|
string DisplayOrder { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public interface IHasMediaSources
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the media sources.
|
||||||
|
/// </summary>
|
||||||
|
List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
|
||||||
|
List<MediaStream> GetMediaStreams();
|
||||||
|
Guid Id { get; set; }
|
||||||
|
long? RunTimeTicks { get; set; }
|
||||||
|
string Path { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using MediaBrowser.Model.LiveTv;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public interface IHasProgramAttributes
|
||||||
|
{
|
||||||
|
bool IsMovie { get; set; }
|
||||||
|
bool IsSports { get; }
|
||||||
|
bool IsNews { get; }
|
||||||
|
bool IsKids { get; }
|
||||||
|
bool IsRepeat { get; set; }
|
||||||
|
bool IsSeries { get; set; }
|
||||||
|
ProgramAudio? Audio { get; set; }
|
||||||
|
string EpisodeTitle { get; set; }
|
||||||
|
string ServiceName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface IHasScreenshots
|
||||||
|
/// </summary>
|
||||||
|
public interface IHasScreenshots
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public interface IHasSeries
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the series.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name of the series.</value>
|
||||||
|
string SeriesName { get; set; }
|
||||||
|
string FindSeriesName();
|
||||||
|
string FindSeriesSortName();
|
||||||
|
Guid SeriesId { get; set; }
|
||||||
|
Guid FindSeriesId();
|
||||||
|
string SeriesPresentationUniqueKey { get; set; }
|
||||||
|
string FindSeriesPresentationUniqueKey();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public interface IHasSpecialFeatures
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the special feature ids.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The special feature ids.</value>
|
||||||
|
Guid[] SpecialFeatureIds { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public interface IHasStartDate
|
||||||
|
{
|
||||||
|
DateTime StartDate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Entities
|
||||||
|
{
|
||||||
|
public interface IHasTrailers : IHasProviderIds
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the remote trailers.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The remote trailers.</value>
|
||||||
|
MediaUrl[] RemoteTrailers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the local trailer ids.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The local trailer ids.</value>
|
||||||
|
Guid[] LocalTrailerIds { get; set; }
|
||||||
|
Guid[] RemoteTrailerIds { get; set; }
|
||||||
|
Guid Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HasTrailerExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the trailer ids.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>List<Guid>.</returns>
|
||||||
|
public static List<Guid> GetTrailerIds(this IHasTrailers item)
|
||||||
|
{
|
||||||
|
var list = item.LocalTrailerIds.ToList();
|
||||||
|
list.AddRange(item.RemoteTrailerIds);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue