Add GPL modules

pull/1154/head
Andrew Rabert 5 years ago
parent 9bac3ac616
commit a86b71899e

@ -231,7 +231,7 @@ namespace Emby.Notifications
}
}
var hasSeries = item as IHasSeriesName;
var hasSeries = item as IHasSeries;
if (hasSeries != null)
{

@ -318,7 +318,6 @@ namespace Emby.Server.Implementations
private IMediaEncoder MediaEncoder { get; set; }
private ISubtitleEncoder SubtitleEncoder { get; set; }
private IConnectManager ConnectManager { get; set; }
private ISessionManager SessionManager { get; set; }
private ILiveTvManager LiveTvManager { get; set; }
@ -839,8 +838,6 @@ namespace Emby.Server.Implementations
}
}
protected abstract IConnectManager CreateConnectManager();
protected virtual IHttpClient CreateHttpClient()
{
return new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, GetDefaultUserAgent);
@ -947,7 +944,7 @@ namespace Emby.Server.Implementations
AuthenticationRepository = GetAuthenticationRepository();
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);
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();
RegisterSingleInstance<IEncryptionManager>(encryptionManager);
ConnectManager = CreateConnectManager();
RegisterSingleInstance(ConnectManager);
DeviceManager = new DeviceManager(AuthenticationRepository, JsonSerializer, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
RegisterSingleInstance(DeviceManager);
@ -1045,11 +1039,11 @@ namespace Emby.Server.Implementations
RegisterSingleInstance(activityLogRepo);
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<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);
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;
var hasSeries = item as IHasSeriesName;
var hasSeries = item as IHasSeries;
if (hasSeries != null)
{
if (!string.Equals(hasSeries.SeriesName, info.SeriesName, StringComparison.OrdinalIgnoreCase))
@ -1215,4 +1215,4 @@ namespace Emby.Server.Implementations.Channels
return result;
}
}
}
}

@ -942,7 +942,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@Album", item.Album);
saveItemStatement.TryBind("@IsVirtualItem", item.IsVirtualItem);
var hasSeriesName = item as IHasSeriesName;
var hasSeriesName = item as IHasSeries;
if (hasSeriesName != null)
{
saveItemStatement.TryBind("@SeriesName", hasSeriesName.SeriesName);
@ -1757,7 +1757,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
var hasSeriesName = item as IHasSeriesName;
var hasSeriesName = item as IHasSeries;
if (hasSeriesName != null)
{
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;
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;
_config = config;
SessionManager = sessionManager;
ConnectManager = connectManager;
UserManager = userManager;
NetworkManager = networkManager;
}
public IUserManager UserManager { get; private set; }
public IAuthorizationContext AuthorizationContext { get; private set; }
public IConnectManager ConnectManager { get; private set; }
public ISessionManager SessionManager { get; private set; }
public INetworkManager NetworkManager { get; private set; }

@ -13,13 +13,11 @@ namespace Emby.Server.Implementations.HttpServer.Security
public class AuthorizationContext : IAuthorizationContext
{
private readonly IAuthenticationRepository _authRepo;
private readonly IConnectManager _connectManager;
private readonly IUserManager _userManager;
public AuthorizationContext(IAuthenticationRepository authRepo, IConnectManager connectManager, IUserManager userManager)
public AuthorizationContext(IAuthenticationRepository authRepo, IUserManager userManager)
{
_authRepo = authRepo;
_connectManager = connectManager;
_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<IDtoService> _dtoServiceFactory;
private readonly Func<IConnectManager> _connectFactory;
private readonly IServerApplicationHost _appHost;
private readonly IFileSystem _fileSystem;
private readonly ICryptoProvider _cryptographyProvider;
@ -82,7 +81,7 @@ namespace Emby.Server.Implementations.Library
private IAuthenticationProvider[] _authenticationProviders;
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;
UserRepository = userRepository;
@ -90,7 +89,6 @@ namespace Emby.Server.Implementations.Library
_networkManager = networkManager;
_imageProcessorFactory = imageProcessorFactory;
_dtoServiceFactory = dtoServiceFactory;
_connectFactory = connectFactory;
_appHost = appHost;
_jsonSerializer = jsonSerializer;
_fileSystem = fileSystem;

@ -61,21 +61,6 @@ namespace MediaBrowser.Api
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>
/// Class InstallPackage
/// </summary>
@ -146,30 +131,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <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>
/// Gets the specified request.
/// </summary>

@ -148,7 +148,6 @@ namespace MediaBrowser.Api.Playback
DisposeTranscodingThrottler();
DisposeLiveStream();
DisposeLogStream();
DisposeIsoMount();
TranscodingJob = null;
}
@ -251,9 +250,9 @@ namespace MediaBrowser.Api.Playback
public DeviceProfile DeviceProfile { get; set; }
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;
}
var hasSeries = item as IHasSeriesName;
var hasSeries = item as IHasSeries;
if (hasSeries != null)
{
result.Series = hasSeries.SeriesName;

@ -51,16 +51,14 @@ namespace MediaBrowser.Api
private readonly IServerConfigurationManager _config;
private readonly IServerApplicationHost _appHost;
private readonly IUserManager _userManager;
private readonly IConnectManager _connectManager;
private readonly IMediaEncoder _mediaEncoder;
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;
_appHost = appHost;
_userManager = userManager;
_connectManager = connectManager;
_mediaEncoder = mediaEncoder;
_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&lt;DeviceInfo&gt;.</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&lt;System.Double&gt;.</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&lt;Guid&gt;.</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…
Cancel
Save