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:
parent
47a3444ace
commit
285d400f69
Core
FormBrowser.cs
Notification
TweetDeckBrowser.csPlugins
Resources
@ -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
|
||||
|
||||
|
@ -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>");
|
||||
|
@ -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){
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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>");
|
||||
|
@ -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){
|
||||
|
@ -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";
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user