aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/AppThemeService.cs102
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj1
-rw-r--r--MediaBrowser.Common.Implementations/Security/MBRegistration.cs22
-rw-r--r--MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs2
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs1
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs1
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs8
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Controller/Providers/ItemLookupInfo.cs4
-rw-r--r--MediaBrowser.Controller/Themes/IAppThemeManager.cs38
-rw-r--r--MediaBrowser.Controller/Themes/InternalThemeImage.cs31
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj6
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj6
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj2
-rw-r--r--MediaBrowser.Model/Themes/AppTheme.cs30
-rw-r--r--MediaBrowser.Model/Themes/ThemeImage.cs18
-rw-r--r--MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs1
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj1
-rw-r--r--MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs163
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs9
20 files changed, 438 insertions, 10 deletions
diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs
new file mode 100644
index 000000000..3115fbb36
--- /dev/null
+++ b/MediaBrowser.Api/AppThemeService.cs
@@ -0,0 +1,102 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Themes;
+using MediaBrowser.Model.Themes;
+using ServiceStack;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Api
+{
+ [Route("/Themes", "GET")]
+ [Api(Description = "Gets a list of available themes for an app")]
+ public class GetAppThemes : IReturn<List<AppThemeInfo>>
+ {
+ [ApiMember(Name = "ApplicationName", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ApplicationName { get; set; }
+ }
+
+ [Route("/Themes/Info", "GET")]
+ [Api(Description = "Gets an app theme")]
+ public class GetAppTheme : IReturn<AppTheme>
+ {
+ [ApiMember(Name = "ApplicationName", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ApplicationName { get; set; }
+
+ [ApiMember(Name = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string Name { get; set; }
+ }
+
+ [Route("/Themes/Images", "GET")]
+ [Api(Description = "Gets an app theme")]
+ public class GetAppThemeImage
+ {
+ [ApiMember(Name = "ApplicationName", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ApplicationName { get; set; }
+
+ [ApiMember(Name = "ThemeName", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ThemeName { get; set; }
+
+ [ApiMember(Name = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string Name { get; set; }
+
+ [ApiMember(Name = "Tag", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string Tag { get; set; }
+ }
+
+ [Route("/Themes", "POST")]
+ [Api(Description = "Saves a theme")]
+ public class SaveTheme : AppTheme, IReturnVoid
+ {
+ }
+
+ public class AppThemeService : BaseApiService
+ {
+ private readonly IAppThemeManager _themeManager;
+ private readonly IFileSystem _fileSystem;
+
+ public AppThemeService(IAppThemeManager themeManager, IFileSystem fileSystem)
+ {
+ _themeManager = themeManager;
+ _fileSystem = fileSystem;
+ }
+
+ public object Get(GetAppThemes request)
+ {
+ var result = _themeManager.GetThemes(request.ApplicationName).ToList();
+
+ return ToOptimizedResult(result);
+ }
+
+ public object Get(GetAppTheme request)
+ {
+ var result = _themeManager.GetTheme(request.ApplicationName, request.Name);
+
+ return ToOptimizedResult(result);
+ }
+
+ public void Post(SaveTheme request)
+ {
+ _themeManager.SaveTheme(request);
+ }
+
+ public object Get(GetAppThemeImage request)
+ {
+ var info = _themeManager.GetImageImageInfo(request.ApplicationName, request.ThemeName, request.Name);
+
+ var cacheGuid = new Guid(info.CacheTag);
+
+ TimeSpan? cacheDuration = null;
+
+ if (!string.IsNullOrEmpty(request.Tag) && cacheGuid == new Guid(request.Tag))
+ {
+ cacheDuration = TimeSpan.FromDays(365);
+ }
+
+ var contentType = MimeTypes.GetMimeType(info.Path);
+
+ return ToCachedResult(cacheGuid, info.DateModified, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType);
+ }
+ }
+}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 6e214f960..ee2a7eafc 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -67,6 +67,7 @@
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="AlbumsService.cs" />
+ <Compile Include="AppThemeService.cs" />
<Compile Include="BaseApiService.cs" />
<Compile Include="ConfigurationService.cs" />
<Compile Include="DefaultTheme\DefaultThemeService.cs" />
diff --git a/MediaBrowser.Common.Implementations/Security/MBRegistration.cs b/MediaBrowser.Common.Implementations/Security/MBRegistration.cs
index cbb6bda94..1d64b5ea1 100644
--- a/MediaBrowser.Common.Implementations/Security/MBRegistration.cs
+++ b/MediaBrowser.Common.Implementations/Security/MBRegistration.cs
@@ -14,11 +14,12 @@ namespace MediaBrowser.Common.Implementations.Security
{
private static MBLicenseFile _licenseFile;
- private const string MBValidateUrl = Constants.Constants.MbAdminUrl+"service/registration/validate";
+ private const string MBValidateUrl = Constants.Constants.MbAdminUrl + "service/registration/validate";
private static IApplicationPaths _appPaths;
private static INetworkManager _networkManager;
private static ILogger _logger;
+ private static IApplicationHost _applicationHost;
private static MBLicenseFile LicenseFile
{
@@ -37,24 +38,35 @@ namespace MediaBrowser.Common.Implementations.Security
set { LicenseFile.LegacyKey = value; LicenseFile.Save(); }
}
- public static void Init(IApplicationPaths appPaths, INetworkManager networkManager, ILogManager logManager)
+ public static void Init(IApplicationPaths appPaths, INetworkManager networkManager, ILogManager logManager, IApplicationHost appHost)
{
// Ugly alert (static init)
_appPaths = appPaths;
_networkManager = networkManager;
_logger = logManager.GetLogger("SecurityManager");
+ _applicationHost = appHost;
}
public static async Task<MBRegistrationRecord> GetRegistrationStatus(IHttpClient httpClient, IJsonSerializer jsonSerializer, string feature, string mb2Equivalent = null, string version = null)
{
//check the reg file first to alleviate strain on the MB admin server - must actually check in every 30 days tho
- var reg = new RegRecord {registered = LicenseFile.LastChecked(feature) > DateTime.UtcNow.AddDays(-30)};
+ var reg = new RegRecord { registered = LicenseFile.LastChecked(feature) > DateTime.UtcNow.AddDays(-30) };
if (!reg.registered)
{
var mac = _networkManager.GetMacAddress();
- var data = new Dictionary<string, string> { { "feature", feature }, { "key", SupporterKey }, { "mac", mac }, { "mb2equiv", mb2Equivalent }, { "legacykey", LegacyKey }, { "ver", version }, { "platform", Environment.OSVersion.VersionString } };
+ var data = new Dictionary<string, string>
+ {
+ { "feature", feature },
+ { "key", SupporterKey },
+ { "mac", mac },
+ { "mb2equiv", mb2Equivalent },
+ { "legacykey", LegacyKey },
+ { "ver", version },
+ { "platform", Environment.OSVersion.VersionString },
+ { "isservice", _applicationHost.IsRunningAsService.ToString().ToLower() }
+ };
try
{
@@ -79,7 +91,7 @@ namespace MediaBrowser.Common.Implementations.Security
}
}
- return new MBRegistrationRecord {IsRegistered = reg.registered, ExpirationDate = reg.expDate, RegChecked = true};
+ return new MBRegistrationRecord { IsRegistered = reg.registered, ExpirationDate = reg.expDate, RegChecked = true };
}
}
diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
index 3cfdc8053..d0b108c7d 100644
--- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
+++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
@@ -74,7 +74,7 @@ namespace MediaBrowser.Common.Implementations.Security
_appHost = appHost;
_httpClient = httpClient;
_jsonSerializer = jsonSerializer;
- MBRegistration.Init(_applciationPaths, _networkManager, logManager);
+ MBRegistration.Init(_applciationPaths, _networkManager, logManager, _appHost);
}
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index 8784a7187..4a3c82b46 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -256,6 +256,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (series != null)
{
id.SeriesProviderIds = series.ProviderIds;
+ id.AnimeSeriesIndex = series.AnimeSeriesIndex;
}
id.IndexNumberEnd = IndexNumberEnd;
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index 4fadd8f6e..d371cbb92 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -257,6 +257,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (series != null)
{
id.SeriesProviderIds = series.ProviderIds;
+ id.AnimeSeriesIndex = series.AnimeSeriesIndex;
}
return id;
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index be6c92864..ce0ea4458 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -20,6 +20,8 @@ namespace MediaBrowser.Controller.Entities.TV
public int SeasonCount { get; set; }
+ public int? AnimeSeriesIndex { get; set; }
+
/// <summary>
/// Gets or sets the preferred metadata country code.
/// </summary>
@@ -224,7 +226,11 @@ namespace MediaBrowser.Controller.Entities.TV
public SeriesInfo GetLookupInfo()
{
- return GetItemLookupInfo<SeriesInfo>();
+ var info = GetItemLookupInfo<SeriesInfo>();
+
+ info.AnimeSeriesIndex = AnimeSeriesIndex;
+
+ return info;
}
public override bool BeforeMetadataRefresh()
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 30174982f..c07693b36 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -239,6 +239,8 @@
<Compile Include="Sorting\IUserBaseItemComparer.cs" />
<Compile Include="Providers\BaseItemXmlParser.cs" />
<Compile Include="Sorting\SortExtensions.cs" />
+ <Compile Include="Themes\IAppThemeManager.cs" />
+ <Compile Include="Themes\InternalThemeImage.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
index c2409715a..65ee94556 100644
--- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
@@ -101,6 +101,7 @@ namespace MediaBrowser.Controller.Providers
public Dictionary<string, string> SeriesProviderIds { get; set; }
public int? IndexNumberEnd { get; set; }
+ public int? AnimeSeriesIndex { get; set; }
public EpisodeInfo()
{
@@ -117,7 +118,7 @@ namespace MediaBrowser.Controller.Providers
public class SeriesInfo : ItemLookupInfo
{
-
+ public int? AnimeSeriesIndex { get; set; }
}
public class PersonLookupInfo : ItemLookupInfo
@@ -153,6 +154,7 @@ namespace MediaBrowser.Controller.Providers
public class SeasonInfo : ItemLookupInfo
{
public Dictionary<string, string> SeriesProviderIds { get; set; }
+ public int? AnimeSeriesIndex { get; set; }
public SeasonInfo()
{
diff --git a/MediaBrowser.Controller/Themes/IAppThemeManager.cs b/MediaBrowser.Controller/Themes/IAppThemeManager.cs
new file mode 100644
index 000000000..1a7c2aaab
--- /dev/null
+++ b/MediaBrowser.Controller/Themes/IAppThemeManager.cs
@@ -0,0 +1,38 @@
+using MediaBrowser.Model.Themes;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Themes
+{
+ public interface IAppThemeManager
+ {
+ /// <summary>
+ /// Gets the themes.
+ /// </summary>
+ /// <param name="applicationName">Name of the application.</param>
+ /// <returns>IEnumerable{AppThemeInfo}.</returns>
+ IEnumerable<AppThemeInfo> GetThemes(string applicationName);
+
+ /// <summary>
+ /// Gets the theme.
+ /// </summary>
+ /// <param name="applicationName">Name of the application.</param>
+ /// <param name="name">The name.</param>
+ /// <returns>AppTheme.</returns>
+ AppTheme GetTheme(string applicationName, string name);
+
+ /// <summary>
+ /// Saves the theme.
+ /// </summary>
+ /// <param name="theme">The theme.</param>
+ void SaveTheme(AppTheme theme);
+
+ /// <summary>
+ /// Gets the image image information.
+ /// </summary>
+ /// <param name="applicationName">Name of the application.</param>
+ /// <param name="themeName">Name of the theme.</param>
+ /// <param name="imageName">Name of the image.</param>
+ /// <returns>InternalThemeImage.</returns>
+ InternalThemeImage GetImageImageInfo(string applicationName, string themeName, string imageName);
+ }
+}
diff --git a/MediaBrowser.Controller/Themes/InternalThemeImage.cs b/MediaBrowser.Controller/Themes/InternalThemeImage.cs
new file mode 100644
index 000000000..2b676c25b
--- /dev/null
+++ b/MediaBrowser.Controller/Themes/InternalThemeImage.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace MediaBrowser.Controller.Themes
+{
+ public class InternalThemeImage
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the cache tag.
+ /// </summary>
+ /// <value>The cache tag.</value>
+ public string CacheTag { get; set; }
+
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ public string Path { get; set; }
+
+ /// <summary>
+ /// Gets or sets the date modified.
+ /// </summary>
+ /// <value>The date modified.</value>
+ public DateTime DateModified { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index e9ac46e50..04296de35 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -452,6 +452,12 @@
<Compile Include="..\MediaBrowser.Model\Tasks\TaskTriggerInfo.cs">
<Link>Tasks\TaskTriggerInfo.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Themes\AppTheme.cs">
+ <Link>Themes\AppTheme.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Themes\ThemeImage.cs">
+ <Link>Themes\ThemeImage.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Updates\CheckForUpdateResult.cs">
<Link>Updates\CheckForUpdateResult.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 16e3f2767..56f7fb99d 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -439,6 +439,12 @@
<Compile Include="..\MediaBrowser.Model\Tasks\TaskTriggerInfo.cs">
<Link>Tasks\TaskTriggerInfo.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\Themes\AppTheme.cs">
+ <Link>Themes\AppTheme.cs</Link>
+ </Compile>
+ <Compile Include="..\MediaBrowser.Model\Themes\ThemeImage.cs">
+ <Link>Themes\ThemeImage.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\Updates\CheckForUpdateResult.cs">
<Link>Updates\CheckForUpdateResult.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index d9c7cbffe..10aedb3ba 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -165,6 +165,8 @@
<Compile Include="Session\SessionInfoDto.cs" />
<Compile Include="Session\SystemCommand.cs" />
<Compile Include="Session\UserDataChangeInfo.cs" />
+ <Compile Include="Themes\AppTheme.cs" />
+ <Compile Include="Themes\ThemeImage.cs" />
<Compile Include="Updates\CheckForUpdateResult.cs" />
<Compile Include="Updates\PackageTargetSystem.cs" />
<Compile Include="Updates\InstallationInfo.cs" />
diff --git a/MediaBrowser.Model/Themes/AppTheme.cs b/MediaBrowser.Model/Themes/AppTheme.cs
new file mode 100644
index 000000000..a0532854d
--- /dev/null
+++ b/MediaBrowser.Model/Themes/AppTheme.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Themes
+{
+ public class AppTheme
+ {
+ public string ApplicationName { get; set; }
+
+ public string Name { get; set; }
+
+ public Dictionary<string, string> Options { get; set; }
+
+ public List<ThemeImage> Images { get; set; }
+
+ public AppTheme()
+ {
+ Options = new Dictionary<string, string>(StringComparer.Ordinal);
+
+ Images = new List<ThemeImage>();
+ }
+ }
+
+ public class AppThemeInfo
+ {
+ public string ApplicationName { get; set; }
+
+ public string Name { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Themes/ThemeImage.cs b/MediaBrowser.Model/Themes/ThemeImage.cs
new file mode 100644
index 000000000..2fe0820ae
--- /dev/null
+++ b/MediaBrowser.Model/Themes/ThemeImage.cs
@@ -0,0 +1,18 @@
+
+namespace MediaBrowser.Model.Themes
+{
+ public class ThemeImage
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the cache tag.
+ /// </summary>
+ /// <value>The cache tag.</value>
+ public string CacheTag { get; set; }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
index db839a66e..415205cb1 100644
--- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -25,6 +25,7 @@ namespace MediaBrowser.Server.Implementations.Configuration
: base(applicationPaths, logManager, xmlSerializer)
{
UpdateItemsByNamePath();
+ UpdateTranscodingTempPath();
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 01fd82b19..f0b08b923 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -248,6 +248,7 @@
<Compile Include="Persistence\SqliteUserRepository.cs" />
<Compile Include="Sorting\TrailerCountComparer.cs" />
<Compile Include="Sorting\VideoBitRateComparer.cs" />
+ <Compile Include="Themes\AppThemeManager.cs" />
<Compile Include="Udp\UdpMessageReceivedEventArgs.cs" />
<Compile Include="Udp\UdpServer.cs" />
<Compile Include="WebSocket\AlchemyServer.cs" />
diff --git a/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs b/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs
new file mode 100644
index 000000000..ca792bcd3
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs
@@ -0,0 +1,163 @@
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Themes;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Themes;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Server.Implementations.Themes
+{
+ public class AppThemeManager : IAppThemeManager
+ {
+ private readonly IServerApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
+ private readonly IJsonSerializer _json;
+ private readonly ILogger _logger;
+
+ private readonly string[] _supportedImageExtensions = { ".png", ".jpg", ".jpeg" };
+
+ public AppThemeManager(IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer json, ILogger logger)
+ {
+ _appPaths = appPaths;
+ _fileSystem = fileSystem;
+ _json = json;
+ _logger = logger;
+ }
+
+ private string ThemePath
+ {
+ get
+ {
+ return Path.Combine(_appPaths.ItemsByNamePath, "appthemes");
+ }
+ }
+
+ private string GetThemesPath(string applicationName)
+ {
+ if (string.IsNullOrWhiteSpace(applicationName))
+ {
+ throw new ArgumentNullException("applicationName");
+ }
+
+ // Force everything lowercase for consistency and maximum compatibility with case-sensitive file systems
+ var name = _fileSystem.GetValidFilename(applicationName.ToLower());
+
+ return Path.Combine(ThemePath, name);
+ }
+
+ private string GetThemePath(string applicationName, string name)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ // Force everything lowercase for consistency and maximum compatibility with case-sensitive file systems
+ name = _fileSystem.GetValidFilename(name.ToLower());
+
+ return Path.Combine(GetThemesPath(applicationName), name);
+ }
+
+ public IEnumerable<AppThemeInfo> GetThemes(string applicationName)
+ {
+ var path = GetThemesPath(applicationName);
+
+ try
+ {
+ return Directory
+ .EnumerateFiles(path, "*", SearchOption.AllDirectories)
+ .Where(i => string.Equals(Path.GetExtension(i), ".json", StringComparison.OrdinalIgnoreCase))
+ .Select(i =>
+ {
+ try
+ {
+ return _json.DeserializeFromFile<AppThemeInfo>(i);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error deserializing {0}", ex, i);
+ return null;
+ }
+
+ }).Where(i => i != null);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return new List<AppThemeInfo>();
+ }
+ }
+
+ public AppTheme GetTheme(string applicationName, string name)
+ {
+ var themePath = GetThemePath(applicationName, name);
+ var file = Path.Combine(themePath, "theme.json");
+
+ var theme = _json.DeserializeFromFile<AppTheme>(file);
+
+ theme.Images = new DirectoryInfo(themePath)
+ .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ .Where(i => _supportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
+ .Select(GetThemeImage)
+ .ToList();
+
+ return theme;
+ }
+
+ private ThemeImage GetThemeImage(FileInfo file)
+ {
+ var dateModified = _fileSystem.GetLastWriteTimeUtc(file);
+
+ var cacheTag = (file.FullName + dateModified.Ticks).GetMD5().ToString("N");
+
+ return new ThemeImage
+ {
+ CacheTag = cacheTag,
+ Name = file.Name
+ };
+ }
+
+ public void SaveTheme(AppTheme theme)
+ {
+ var themePath = GetThemePath(theme.ApplicationName, theme.Name);
+ var file = Path.Combine(themePath, "theme.json");
+
+ Directory.CreateDirectory(themePath);
+
+ // Clone it so that we don't serialize all the images - they're always dynamic
+ var clone = new AppTheme
+ {
+ ApplicationName = theme.ApplicationName,
+ Name = theme.Name,
+ Options = theme.Options,
+ Images = null
+ };
+
+ _json.SerializeToFile(clone, file);
+ }
+
+ public InternalThemeImage GetImageImageInfo(string applicationName, string themeName, string imageName)
+ {
+ var themePath = GetThemePath(applicationName, themeName);
+
+ var fullPath = Path.Combine(themePath, imageName);
+
+ var file = new DirectoryInfo(themePath).EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ .First(i => string.Equals(i.FullName, fullPath, StringComparison.OrdinalIgnoreCase));
+
+ var themeImage = GetThemeImage(file);
+
+ return new InternalThemeImage
+ {
+ CacheTag = themeImage.CacheTag,
+ Name = themeImage.Name,
+ Path = file.FullName,
+ DateModified = _fileSystem.GetLastWriteTimeUtc(file)
+ };
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index f199dc048..73f99cda1 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -27,6 +27,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Controller.Themes;
using MediaBrowser.Dlna.PlayTo;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
@@ -49,6 +50,7 @@ using MediaBrowser.Server.Implementations.MediaEncoder;
using MediaBrowser.Server.Implementations.Persistence;
using MediaBrowser.Server.Implementations.ServerManager;
using MediaBrowser.Server.Implementations.Session;
+using MediaBrowser.Server.Implementations.Themes;
using MediaBrowser.Server.Implementations.WebSocket;
using MediaBrowser.ServerApplication.EntryPoints;
using MediaBrowser.ServerApplication.FFMpeg;
@@ -163,7 +165,7 @@ namespace MediaBrowser.ServerApplication
private ILocalizationManager LocalizationManager { get; set; }
private IEncodingManager EncodingManager { get; set; }
-
+
/// <summary>
/// Gets or sets the user data repository.
/// </summary>
@@ -438,6 +440,9 @@ namespace MediaBrowser.ServerApplication
MediaEncoder);
RegisterSingleInstance(EncodingManager);
+ var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
+ RegisterSingleInstance<IAppThemeManager>(appThemeManager);
+
LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager);
RegisterSingleInstance(LiveTvManager);
@@ -747,7 +752,7 @@ namespace MediaBrowser.ServerApplication
// Dlna implementations
list.Add(typeof(PlayToServerEntryPoint).Assembly);
-
+
list.AddRange(Assemblies.GetAssembliesWithParts());
// Include composable parts in the running assembly