1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-04-11 12:15:44 +02:00

Refactor ScriptLoader to cache files on its own & change method signatures

This commit is contained in:
chylex 2018-07-09 12:22:29 +02:00
parent 47a3444ace
commit 285d400f69
10 changed files with 61 additions and 82 deletions

View File

@ -78,7 +78,7 @@ public FormBrowser(){
this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification));
this.contextMenu = ContextMenuBrowser.CreateMenu(this);
this.plugins.Register(browser, PluginEnvironment.Browser, true);
this.plugins.Register(browser, PluginEnvironment.Browser, this, true);
Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update

View File

@ -30,7 +30,7 @@ protected override FormBorderStyle NotificationBorderStyle{
public FormNotificationExample(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, false){
browser.LoadingStateChanged += browser_LoadingStateChanged;
string exampleTweetHTML = ScriptLoader.LoadResource("pages/example.html", true)?.Replace("{avatar}", TweetNotification.AppLogo.Url) ?? string.Empty;
string exampleTweetHTML = ScriptLoader.LoadResourceSilent("pages/example.html")?.Replace("{avatar}", TweetNotification.AppLogo.Url) ?? string.Empty;
#if DEBUG
exampleTweetHTML = exampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>");

View File

@ -185,7 +185,7 @@ public virtual void ResumeNotification(){
}
protected virtual string GetTweetHTML(TweetNotification tweet){
return tweet.GenerateHtml(IsCursorOverBrowser ? "td-notification td-hover" : "td-notification");
return tweet.GenerateHtml(IsCursorOverBrowser ? "td-notification td-hover" : "td-notification", this);
}
protected virtual void LoadTweet(TweetNotification tweet){

View File

@ -15,11 +15,6 @@
namespace TweetDuck.Core.Notification{
abstract partial class FormNotificationMain : FormNotificationBase, ITweetDeckBrowser{
private const string NotificationScriptFile = "notification.js";
private static readonly string NotificationScriptIdentifier = ScriptLoader.GetRootIdentifier(NotificationScriptFile);
private static readonly string NotificationJS = ScriptLoader.LoadResource(NotificationScriptFile);
private readonly PluginManager plugins;
private readonly int timerBarHeight;
@ -88,7 +83,7 @@ protected FormNotificationMain(FormBrowser owner, PluginManager pluginManager, b
browser.LoadingStateChanged += Browser_LoadingStateChanged;
browser.FrameLoadEnd += Browser_FrameLoadEnd;
plugins.Register(this, PluginEnvironment.Notification);
plugins.Register(this, PluginEnvironment.Notification, this);
mouseHookDelegate = MouseHookProc;
Disposed += (sender, args) => StopMouseHook(true);
@ -106,7 +101,7 @@ void ITweetDeckBrowser.OnFrameLoaded(Action<IFrame> callback){
browser.FrameLoadEnd += (sender, args) => {
IFrame frame = args.Frame;
if (frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){
if (frame.IsMain && browser.Address != "about:blank"){
callback(frame);
}
};
@ -194,9 +189,9 @@ private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEvent
}
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){
if (e.Frame.IsMain && browser.Address != "about:blank"){
e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
ScriptLoader.ExecuteScript(e.Frame, NotificationJS, NotificationScriptIdentifier);
ScriptLoader.ExecuteScript(e.Frame, ScriptLoader.LoadResource("notification.js", this), "root:notification");
}
}

View File

@ -27,7 +27,7 @@ public FormNotificationScreenshotable(Action callback, FormBrowser owner, Plugin
return;
}
string script = ScriptLoader.LoadResource("screenshot.js", true);
string script = ScriptLoader.LoadResourceSilent("screenshot.js");
if (script == null){
this.InvokeAsyncSafe(callback);
@ -44,7 +44,7 @@ public FormNotificationScreenshotable(Action callback, FormBrowser owner, Plugin
}
protected override string GetTweetHTML(TweetNotification tweet){
string html = tweet.GenerateHtml("td-screenshot");
string html = tweet.GenerateHtml("td-screenshot", this);
foreach(InjectedHTML injection in plugins.NotificationInjections){
html = injection.InjectInto(html);

View File

@ -1,5 +1,6 @@
using System;
using System.Text;
using System.Windows.Forms;
using CefSharp;
using TweetDuck.Core.Bridge;
using TweetDuck.Data;
@ -8,7 +9,6 @@
namespace TweetDuck.Core.Notification{
sealed class TweetNotification{
private const string DefaultHeadLayout = @"<html class=""scroll-v os-windows dark txt-size--14"" lang=""en-US"" id=""tduck"" data-td-font=""medium"" data-td-theme=""dark""><head><meta charset=""utf-8""><link href=""https://ton.twimg.com/tweetdeck-web/web/dist/bundle.4b1f87e09d.css"" rel=""stylesheet""><style type='text/css'>body { background: rgb(34, 36, 38) !important }</style>";
private static readonly string CustomCSS = ScriptLoader.LoadResource("styles/notification.css") ?? string.Empty;
public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandler.FromByteArray(Properties.Resources.avatar, "image/png"));
public static TweetNotification Example(string html, int characters){
@ -53,11 +53,11 @@ public int GetDisplayDuration(int value){
return 2000+Math.Max(1000, value*characters);
}
public string GenerateHtml(string bodyClasses){
public string GenerateHtml(string bodyClasses, Control sync){
StringBuilder build = new StringBuilder();
build.Append("<!DOCTYPE html>");
build.Append(TweetDeckBridge.NotificationHeadLayout ?? DefaultHeadLayout);
build.Append("<style type='text/css'>").Append(CustomCSS).Append("</style>");
build.Append("<style type='text/css'>").Append(ScriptLoader.LoadResource("styles/notification.css", sync) ?? string.Empty).Append("</style>");
if (!string.IsNullOrEmpty(Program.UserConfig.CustomNotificationCSS)){
build.Append("<style type='text/css'>").Append(Program.UserConfig.CustomNotificationCSS).Append("</style>");

View File

@ -9,6 +9,7 @@
using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling;
using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Management;
using TweetDuck.Core.Notification;
using TweetDuck.Core.Other.Interfaces;
using TweetDuck.Core.Utils;
@ -41,7 +42,7 @@ public bool IsTweetDeckWebsite{
public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){
DialogHandler = new FileDialogHandler(),
DragHandler = new DragHandlerBrowser(requestHandler),
@ -168,7 +169,7 @@ private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
TweetDeckBridge.ResetStaticProperties();
if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)){
ScriptLoader.ExecuteScript(frame, @"TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
ScriptLoader.ExecuteScript(frame, "TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
}
if (Program.UserConfig.FirstRun){
@ -183,7 +184,7 @@ private void browser_LoadError(object sender, LoadErrorEventArgs e){
}
if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){
string errorPage = ScriptLoader.LoadResource("pages/error.html", true);
string errorPage = ScriptLoader.LoadResourceSilent("pages/error.html");
if (errorPage != null){
browser.LoadHtml(errorPage.Replace("{err}", BrowserUtils.GetErrorName(e.ErrorCode)), "http://td/error");
@ -232,7 +233,7 @@ public void UpdateProperties(){
}
public void InjectBrowserCSS(){
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css", false, browser)?.TrimEnd() ?? string.Empty);
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css", browser)?.TrimEnd() ?? string.Empty);
}
public void ReinjectCustomCSS(string css){

View File

@ -24,14 +24,6 @@ public static bool IncludesDisabledPlugins(this PluginEnvironment environment){
return environment == PluginEnvironment.Browser;
}
public static string GetScriptIdentifier(this PluginEnvironment environment){
switch(environment){
case PluginEnvironment.Browser: return "root:plugins:browser";
case PluginEnvironment.Notification: return "root:plugins:notification";
default: return null;
}
}
public static string GetPluginScriptFile(this PluginEnvironment environment){
switch(environment){
case PluginEnvironment.Browser: return "browser.js";

View File

@ -4,6 +4,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using TweetDuck.Core.Other.Interfaces;
using TweetDuck.Data;
using TweetDuck.Plugins.Enums;
@ -12,15 +13,7 @@
namespace TweetDuck.Plugins{
sealed class PluginManager{
private static IReadOnlyDictionary<PluginEnvironment, string> LoadSetupScripts(){
return PluginEnvironmentExtensions.Map(
null,
ScriptLoader.LoadResource("plugins.browser.js"),
ScriptLoader.LoadResource("plugins.notification.js")
);
}
private static readonly IReadOnlyDictionary<PluginEnvironment, string> PluginSetupScripts = LoadSetupScripts();
private static readonly IReadOnlyDictionary<PluginEnvironment, string> PluginSetupScriptNames = PluginEnvironmentExtensions.Map(null, "plugins.browser.js", "plugins.notification.js");
public string PathOfficialPlugins => Path.Combine(rootPath, "official");
public string PathCustomPlugins => Path.Combine(rootPath, "user");
@ -54,8 +47,8 @@ public PluginManager(string rootPath, string configPath){
Config.PluginChangedState += Config_PluginChangedState;
}
public void Register(ITweetDeckBrowser browser, PluginEnvironment environment, bool asMainBrowser = false){
browser.OnFrameLoaded(frame => ExecutePlugins(frame, environment));
public void Register(ITweetDeckBrowser browser, PluginEnvironment environment, Control sync, bool asMainBrowser = false){
browser.OnFrameLoaded(frame => ExecutePlugins(frame, environment, sync));
browser.RegisterBridge("$TDP", bridge);
if (asMainBrowser){
@ -152,13 +145,11 @@ IEnumerable<Plugin> LoadPluginsFrom(string path, PluginGroup group){
Reloaded?.Invoke(this, new PluginErrorEventArgs(loadErrors));
}
private void ExecutePlugins(IFrame frame, PluginEnvironment environment){
if (!HasAnyPlugin(environment)){
private void ExecutePlugins(IFrame frame, PluginEnvironment environment, Control sync){
if (!HasAnyPlugin(environment) || !ScriptLoader.ExecuteFile(frame, PluginSetupScriptNames[environment], sync)){
return;
}
ScriptLoader.ExecuteScript(frame, PluginSetupScripts[environment], environment.GetScriptIdentifier());
bool includeDisabled = environment.IncludesDisabledPlugins();
if (includeDisabled){

View File

@ -1,5 +1,6 @@
using CefSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;
@ -15,17 +16,29 @@
namespace TweetDuck.Resources{
static class ScriptLoader{
public static string LoadResource(string name, bool silent = false, Control sync = null){
private static readonly Dictionary<string, string> CachedData = new Dictionary<string, string>(16);
public static string LoadResourceSilent(string name){
return LoadResource(name, null);
}
public static string LoadResource(string name, Control sync){
if (CachedData.TryGetValue(name, out string resourceData)){
return resourceData;
}
string path = Program.ScriptPath;
#if DEBUG
if (Directory.Exists(HotSwapTargetDir)){
path = Path.Combine(HotSwapTargetDir, "scripts");
Debug.WriteLine("Hot swap active, redirecting "+name);
}
#endif
string resource;
try{
string path = Program.ScriptPath;
#if DEBUG
if (Directory.Exists(HotSwapTargetDir)){
path = Path.Combine(HotSwapTargetDir, "scripts");
Debug.WriteLine("Hot swap active, redirecting "+name);
}
#endif
string contents = File.ReadAllText(Path.Combine(path, name), Encoding.UTF8);
int separator;
@ -34,7 +47,7 @@ public static string LoadResource(string name, bool silent = false, Control sync
// #<version>\n
if (contents[0] != '#'){
ShowLoadError(silent, sync, $"File {name} appears to be corrupted, please try reinstalling the app.");
ShowLoadError(sync, $"File {name} appears to be corrupted, please try reinstalling the app.");
separator = 0;
}
else{
@ -42,44 +55,33 @@ public static string LoadResource(string name, bool silent = false, Control sync
string fileVersion = contents.Substring(1, separator-1).TrimEnd();
if (fileVersion != Program.VersionTag){
ShowLoadError(silent, sync, $"File {name} is made for a different version of TweetDuck ({fileVersion}) and may not function correctly in this version, please try reinstalling the app.");
ShowLoadError(sync, $"File {name} is made for a different version of TweetDuck ({fileVersion}) and may not function correctly in this version, please try reinstalling the app.");
}
}
return contents.Substring(separator).TrimStart();
resource = contents.Substring(separator).TrimStart();
}catch(Exception ex){
ShowLoadError(silent, sync, $"Could not load {name}. The program will continue running with limited functionality.\n\n{ex.Message}");
return null;
ShowLoadError(sync, $"Could not load {name}. The program will continue running with limited functionality.\n\n{ex.Message}");
resource = null;
}
return CachedData[name] = resource;
}
public static bool ExecuteFile(IFrame frame, string file, Control sync = null){
string script = LoadResource(file, sync == null, sync);
ExecuteScript(frame, script, GetRootIdentifier(file));
public static bool ExecuteFile(IFrame frame, string file, Control sync){
string script = LoadResource(file, sync);
ExecuteScript(frame, script, "root:"+Path.GetFileNameWithoutExtension(file));
return script != null;
}
public static void ExecuteScript(IFrame frame, string script, string identifier){
if (script != null){
frame.ExecuteJavaScriptAsync(script, "td:"+identifier, 1);
frame.ExecuteJavaScriptAsync(script, identifier, 1);
}
}
public static string GetRootIdentifier(string file){
return "root:"+Path.GetFileNameWithoutExtension(file);
}
private static void ShowLoadError(bool silent, Control sync, string message){
if (silent){
return;
}
if (sync == null){
FormMessage.Error("Resource Error", message, FormMessage.OK);
}
else{
sync.InvokeSafe(() => FormMessage.Error("Resource Error", message, FormMessage.OK));
}
private static void ShowLoadError(Control sync, string message){
sync?.InvokeSafe(() => FormMessage.Error("Resource Error", message, FormMessage.OK));
}
#if DEBUG
@ -126,20 +128,18 @@ public static void HotSwap(){
sw.Stop();
Debug.WriteLine("Finished rebuild script in "+sw.ElapsedMilliseconds+" ms");
CachedData.Clear();
// Force update plugin manager setup scripts
string newPluginRoot = Path.Combine(HotSwapTargetDir, "plugins");
const BindingFlags flagsInstance = BindingFlags.Instance | BindingFlags.NonPublic;
const BindingFlags flagsStatic = BindingFlags.Static | BindingFlags.NonPublic;
Type typePluginManager = typeof(PluginManager);
Type typeFormBrowser = typeof(FormBrowser);
// ReSharper disable PossibleNullReferenceException
object pluginSetupScripts = typePluginManager.GetMethod("LoadSetupScripts", flagsStatic).Invoke(null, new object[0]);
typePluginManager.GetField("PluginSetupScripts", flagsStatic).SetValue(null, pluginSetupScripts);
object instPluginManager = typeFormBrowser.GetField("plugins", flagsInstance).GetValue(FormManager.TryFind<FormBrowser>());
typePluginManager.GetField("rootPath", flagsInstance).SetValue(instPluginManager, newPluginRoot);