aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.WebDashboard/Api/PackageCreator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.WebDashboard/Api/PackageCreator.cs')
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs266
1 files changed, 184 insertions, 82 deletions
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index 34a7f0eac..f6601ce80 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -38,17 +38,17 @@ namespace MediaBrowser.WebDashboard.Api
string appVersion,
bool enableMinification)
{
- var isHtml = IsHtml(path);
-
Stream resourceStream;
if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
{
resourceStream = await GetAllJavascript(mode, localizationCulture, appVersion, enableMinification).ConfigureAwait(false);
+ enableMinification = false;
}
else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
{
resourceStream = await GetAllCss(enableMinification).ConfigureAwait(false);
+ enableMinification = false;
}
else
{
@@ -59,9 +59,26 @@ namespace MediaBrowser.WebDashboard.Api
{
// Don't apply any caching for html pages
// jQuery ajax doesn't seem to handle if-modified-since correctly
- if (isHtml && path.IndexOf("cordovaindex.html", StringComparison.OrdinalIgnoreCase) == -1)
+ if (IsFormat(path, "html"))
+ {
+ if (path.IndexOf("cordovaindex.html", StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ resourceStream = await ModifyHtml(resourceStream, mode, localizationCulture, enableMinification).ConfigureAwait(false);
+ }
+ }
+ else if (IsFormat(path, "js"))
+ {
+ if (path.IndexOf("thirdparty", StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ resourceStream = await ModifyJs(resourceStream, enableMinification).ConfigureAwait(false);
+ }
+ }
+ else if (IsFormat(path, "css"))
{
- resourceStream = await ModifyHtml(resourceStream, mode, localizationCulture, enableMinification).ConfigureAwait(false);
+ if (path.IndexOf("thirdparty", StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ resourceStream = await ModifyCss(resourceStream, enableMinification).ConfigureAwait(false);
+ }
}
}
@@ -72,10 +89,11 @@ namespace MediaBrowser.WebDashboard.Api
/// Determines whether the specified path is HTML.
/// </summary>
/// <param name="path">The path.</param>
+ /// <param name="format">The format.</param>
/// <returns><c>true</c> if the specified path is HTML; otherwise, <c>false</c>.</returns>
- private bool IsHtml(string path)
+ private bool IsFormat(string path, string format)
{
- return Path.GetExtension(path).EndsWith("html", StringComparison.OrdinalIgnoreCase);
+ return Path.GetExtension(path).EndsWith(format, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
@@ -102,7 +120,97 @@ namespace MediaBrowser.WebDashboard.Api
/// <returns>System.String.</returns>
private string GetDashboardResourcePath(string virtualPath)
{
- return Path.Combine(DashboardUIPath, virtualPath.Replace('/', Path.DirectorySeparatorChar));
+ var rootPath = DashboardUIPath;
+
+ var fullPath = Path.Combine(rootPath, virtualPath.Replace('/', Path.DirectorySeparatorChar));
+
+ // Don't allow file system access outside of the source folder
+ if (!_fileSystem.ContainsSubPath(rootPath, fullPath))
+ {
+ throw new UnauthorizedAccessException();
+ }
+
+ return fullPath;
+ }
+
+ public async Task<Stream> ModifyCss(Stream sourceStream, bool enableMinification)
+ {
+ using (sourceStream)
+ {
+ string content;
+
+ using (var memoryStream = new MemoryStream())
+ {
+ await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false);
+
+ content = Encoding.UTF8.GetString(memoryStream.ToArray());
+
+ if (enableMinification)
+ {
+ try
+ {
+ var result = new KristensenCssMinifier().Minify(content, false, Encoding.UTF8);
+
+ if (result.Errors.Count > 0)
+ {
+ _logger.Error("Error minifying css: " + result.Errors[0].Message);
+ }
+ else
+ {
+ content = result.MinifiedContent;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error minifying css", ex);
+ }
+ }
+ }
+
+ var bytes = Encoding.UTF8.GetBytes(content);
+
+ return new MemoryStream(bytes);
+ }
+ }
+
+ public async Task<Stream> ModifyJs(Stream sourceStream, bool enableMinification)
+ {
+ using (sourceStream)
+ {
+ string content;
+
+ using (var memoryStream = new MemoryStream())
+ {
+ await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false);
+
+ content = Encoding.UTF8.GetString(memoryStream.ToArray());
+
+ if (enableMinification)
+ {
+ try
+ {
+ var result = new CrockfordJsMinifier().Minify(content, false, Encoding.UTF8);
+
+ if (result.Errors.Count > 0)
+ {
+ _logger.Error("Error minifying javascript: " + result.Errors[0].Message);
+ }
+ else
+ {
+ content = result.MinifiedContent;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error minifying javascript", ex);
+ }
+ }
+ }
+
+ var bytes = Encoding.UTF8.GetBytes(content);
+
+ return new MemoryStream(bytes);
+ }
}
/// <summary>
@@ -125,6 +233,11 @@ namespace MediaBrowser.WebDashboard.Api
html = Encoding.UTF8.GetString(memoryStream.ToArray());
+ if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
+ {
+ html = ModifyForCordova(html);
+ }
+
if (!string.IsNullOrWhiteSpace(localizationCulture))
{
var lang = localizationCulture.Split('-').FirstOrDefault();
@@ -172,6 +285,39 @@ namespace MediaBrowser.WebDashboard.Api
}
}
+ private string ModifyForCordova(string html)
+ {
+ // Strip everything between CORDOVA_EXCLUDE_START and CORDOVA_EXCLUDE_END
+ html = ReplaceBetween(html, "<!--CORDOVA_EXCLUDE_START-->", "<!--CORDOVA_EXCLUDE_END-->", string.Empty);
+
+ // Replace CORDOVA_REPLACE_SUPPORTER_SUBMIT_START
+ html = ReplaceBetween(html, "<!--CORDOVA_REPLACE_SUPPORTER_SUBMIT_START-->", "<!--CORDOVA_REPLACE_SUPPORTER_SUBMIT_END-->", "<i class=\"fa fa-check\"></i><span>${ButtonPurchase}</span>");
+
+ return html;
+ }
+
+ private string ReplaceBetween(string html, string startToken, string endToken, string newHtml)
+ {
+ var start = html.IndexOf(startToken, StringComparison.OrdinalIgnoreCase);
+
+ if (start == -1)
+ {
+ return html;
+ }
+
+ var end = html.IndexOf(endToken, start, StringComparison.OrdinalIgnoreCase);
+
+ if (end == -1)
+ {
+ return html;
+ }
+
+ string result = html.Substring(start, end - start);
+ html = html.Replace(result, newHtml);
+
+ return ReplaceBetween(html, startToken, endToken, newHtml);
+ }
+
private string GetLocalizationToken(string phrase)
{
return "${" + phrase + "}";
@@ -283,7 +429,14 @@ namespace MediaBrowser.WebDashboard.Api
await AppendResource(memoryStream, "thirdparty/jquery.unveil-custom.js", newLineBytes).ConfigureAwait(false);
- await AppendLocalization(memoryStream, culture).ConfigureAwait(false);
+ var excludePhrases = new List<string>();
+
+ if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
+ {
+ excludePhrases.Add("paypal");
+ }
+
+ await AppendLocalization(memoryStream, culture, excludePhrases).ConfigureAwait(false);
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
if (!string.IsNullOrWhiteSpace(mode))
@@ -327,11 +480,6 @@ namespace MediaBrowser.WebDashboard.Api
}
apiClientFiles.Add("thirdparty/apiclient/connectionmanager.js");
- if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
- {
- apiClientFiles.Add("thirdparty/cordova/remotecontrols.js");
- }
-
foreach (var file in apiClientFiles)
{
using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
@@ -400,7 +548,6 @@ namespace MediaBrowser.WebDashboard.Api
"editorsidebar.js",
"librarymenu.js",
"mediacontroller.js",
- "chromecast.js",
"backdrops.js",
"sync.js",
"syncjob.js",
@@ -413,24 +560,13 @@ namespace MediaBrowser.WebDashboard.Api
"nowplayingpage.js",
"taskbutton.js",
- "ratingdialog.js",
- "aboutpage.js",
"alphapicker.js",
"addpluginpage.js",
- "advancedconfigurationpage.js",
- "metadataadvanced.js",
"autoorganizetv.js",
"autoorganizelog.js",
- "channels.js",
- "channelslatest.js",
- "channelitems.js",
"channelsettings.js",
- "connectlogin.js",
"dashboardgeneral.js",
- "dashboardhosting.js",
"dashboardpage.js",
- "device.js",
- "devices.js",
"devicesupload.js",
"directorybrowser.js",
"dlnaprofile.js",
@@ -439,68 +575,32 @@ namespace MediaBrowser.WebDashboard.Api
"dlnaserversettings.js",
"editcollectionitems.js",
"edititemmetadata.js",
- "edititemimages.js",
"edititemsubtitles.js",
"playbackconfiguration.js",
"cinemamodeconfiguration.js",
"encodingsettings.js",
- "externalplayer.js",
- "favorites.js",
"forgotpassword.js",
"forgotpasswordpin.js",
- "gamesrecommendedpage.js",
- "gamesystemspage.js",
- "gamespage.js",
- "gamegenrepage.js",
- "gamestudiospage.js",
- "homelatest.js",
"indexpage.js",
"itembynamedetailpage.js",
"itemdetailpage.js",
- "itemlistpage.js",
"kids.js",
"librarypathmapping.js",
- "reports.js",
"librarysettings.js",
- "livetvchannel.js",
- "livetvchannels.js",
- "livetvguide.js",
- "livetvitems.js",
- "livetvnewrecording.js",
- "livetvprogram.js",
"livetvrecording.js",
- "livetvrecordinglist.js",
- "livetvrecordings.js",
"livetvtimer.js",
"livetvseriestimer.js",
- "livetvseriestimers.js",
"livetvsettings.js",
- "livetvsuggested.js",
"livetvstatus.js",
- "livetvtimers.js",
- "loginpage.js",
- "logpage.js",
"medialibrarypage.js",
"metadataconfigurationpage.js",
"metadataimagespage.js",
"metadatasubtitles.js",
"metadatanfo.js",
- "moviegenres.js",
"moviecollections.js",
- "movies.js",
- "moviepeople.js",
- "moviesrecommended.js",
- "moviestudios.js",
- "movietrailers.js",
- "musicalbums.js",
- "musicalbumartists.js",
- "musicartists.js",
- "musicgenres.js",
- "musicrecommended.js",
- "musicvideos.js",
"mypreferencesdisplay.js",
"mypreferenceslanguages.js",
@@ -510,7 +610,6 @@ namespace MediaBrowser.WebDashboard.Api
"notificationlist.js",
"notificationsetting.js",
"notificationsettings.js",
- "photos.js",
"playlists.js",
"playlistedit.js",
@@ -520,25 +619,10 @@ namespace MediaBrowser.WebDashboard.Api
"scheduledtaskpage.js",
"scheduledtaskspage.js",
"search.js",
- "selectserver.js",
- "serversecurity.js",
- "songs.js",
- "streamingsettings.js",
- "supporterkeypage.js",
- "supporterpage.js",
"syncactivity.js",
"syncsettings.js",
- "episodes.js",
"thememediaplayer.js",
- "tvgenres.js",
- "tvlatest.js",
- "tvpeople.js",
- "tvrecommended.js",
- "tvshows.js",
- "tvstudios.js",
- "tvupcoming.js",
"useredit.js",
- "usernew.js",
"myprofile.js",
"userpassword.js",
"userprofilespage.js",
@@ -547,15 +631,33 @@ namespace MediaBrowser.WebDashboard.Api
"wizardagreement.js",
"wizardfinishpage.js",
"wizardservice.js",
- "wizardstartpage.js",
- "wizardsettings.js",
- "wizarduserpage.js"
+ "wizardstartpage.js"
};
}
- private async Task AppendLocalization(Stream stream, string culture)
+ private async Task AppendLocalization(Stream stream, string culture, List<string> excludePhrases)
{
- var js = "window.localizationGlossary=" + _jsonSerializer.SerializeToString(_localization.GetJavaScriptLocalizationDictionary(culture));
+ var dictionary = _localization.GetJavaScriptLocalizationDictionary(culture);
+
+ if (excludePhrases.Count > 0)
+ {
+ var removes = new List<string>();
+
+ foreach (var pair in dictionary)
+ {
+ if (excludePhrases.Any(i => pair.Key.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1 || pair.Value.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1))
+ {
+ removes.Add(pair.Key);
+ }
+ }
+
+ foreach (var remove in removes)
+ {
+ dictionary.Remove(remove);
+ }
+ }
+
+ var js = "window.localizationGlossary=" + _jsonSerializer.SerializeToString(dictionary);
var bytes = Encoding.UTF8.GetBytes(js);
await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);