using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; namespace MediaBrowser.WebDashboard.Api { public class PackageCreator { private readonly IFileSystem _fileSystem; private readonly ILogger _logger; private readonly IServerConfigurationManager _config; private readonly string _basePath; private IResourceFileManager _resourceFileManager; public PackageCreator(string basePath, IFileSystem fileSystem, ILogger logger, IServerConfigurationManager config, IResourceFileManager resourceFileManager) { _fileSystem = fileSystem; _logger = logger; _config = config; _basePath = basePath; _resourceFileManager = resourceFileManager; } public async Task GetResource(string virtualPath, string mode, string localizationCulture, string appVersion) { var resourceStream = GetRawResourceStream(virtualPath); if (resourceStream != null) { if (IsFormat(virtualPath, "html")) { if (IsCoreHtml(virtualPath)) { resourceStream = await ModifyHtml(virtualPath, resourceStream, mode, appVersion, localizationCulture).ConfigureAwait(false); } } } return resourceStream; } /// /// Determines whether the specified path is HTML. /// /// The path. /// The format. /// true if the specified path is HTML; otherwise, false. private static bool IsFormat(string path, string format) { return Path.GetExtension(path).EndsWith(format, StringComparison.OrdinalIgnoreCase); } public bool IsCoreHtml(string path) { if (path.IndexOf(".template.html", StringComparison.OrdinalIgnoreCase) != -1) { return false; } return IsFormat(path, "html"); } /// /// Modifies the HTML by adding common meta tags, css and js. /// /// Task{Stream}. public async Task ModifyHtml(string path, Stream sourceStream, string mode, string appVersion, string localizationCulture) { var isMainIndexPage = string.Equals(path, "index.html", StringComparison.OrdinalIgnoreCase); using (sourceStream) { string html; using (var memoryStream = new MemoryStream()) { await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false); var originalBytes = memoryStream.ToArray(); html = Encoding.UTF8.GetString(originalBytes, 0, originalBytes.Length); if (isMainIndexPage) { if (!string.IsNullOrWhiteSpace(localizationCulture)) { var lang = localizationCulture.Split('-').FirstOrDefault(); html = html.Replace("", "" + GetMetaTags(mode)); } // Disable embedded scripts from plugins. We'll run them later once resources have loaded if (html.IndexOf("", "-->"); } if (isMainIndexPage) { html = html.Replace("", GetCommonJavascript(mode, appVersion) + ""); } var bytes = Encoding.UTF8.GetBytes(html); return new MemoryStream(bytes); } } /// /// Gets the meta tags. /// /// System.String. private string GetMetaTags(string mode) { var sb = new StringBuilder(); if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) || string.Equals(mode, "android", StringComparison.OrdinalIgnoreCase)) { sb.Append(""); } return sb.ToString(); } /// /// Gets the common javascript. /// /// The mode. /// The version. /// System.String. private string GetCommonJavascript(string mode, string version) { var builder = new StringBuilder(); builder.Append(""); var versionString = string.IsNullOrWhiteSpace(mode) ? "?v=" + version : string.Empty; var files = new List(); files.Add("scripts/apploader.js" + versionString); if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase)) { files.Insert(0, "cordova.js"); } var tags = files.Select(s => string.Format("", s)).ToArray(); builder.Append(string.Join(string.Empty, tags)); return builder.ToString(); } /// /// Gets the raw resource stream. /// private Stream GetRawResourceStream(string virtualPath) { return _resourceFileManager.GetResourceFileStream(_basePath, virtualPath); } } }