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); } private string GetImagesPath(string applicationName, string themeName) { return Path.Combine(GetThemePath(applicationName, themeName), "images"); } public IEnumerable 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(i); } catch (Exception ex) { _logger.ErrorException("Error deserializing {0}", ex, i); return null; } }).Where(i => i != null); } catch (DirectoryNotFoundException) { return new List(); } } public AppTheme GetTheme(string applicationName, string name) { var themePath = GetThemePath(applicationName, name); var file = Path.Combine(themePath, "theme.json"); var imagesPath = GetImagesPath(applicationName, name); var theme = _json.DeserializeFromFile(file); theme.Images = new DirectoryInfo(imagesPath) .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.AppName, 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 { AppName = theme.AppName, Name = theme.Name, Options = theme.Options, Images = null }; _json.SerializeToFile(clone, file); } public InternalThemeImage GetImageImageInfo(string applicationName, string themeName, string imageName) { var imagesPath = GetImagesPath(applicationName, themeName); var file = new DirectoryInfo(imagesPath).EnumerateFiles("*", SearchOption.TopDirectoryOnly) .First(i => string.Equals(i.Name, imageName, StringComparison.OrdinalIgnoreCase)); var themeImage = GetThemeImage(file); return new InternalThemeImage { CacheTag = themeImage.CacheTag, Name = themeImage.Name, Path = file.FullName, DateModified = _fileSystem.GetLastWriteTimeUtc(file) }; } } }