mirror of
https://github.com/chylex/TweetDuck.git
synced 2024-10-17 09:42:45 +02:00
273 lines
8.1 KiB
C#
273 lines
8.1 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using CefSharp;
|
|
using CefSharp.WinForms;
|
|
using TweetDuck.Browser.Adapters;
|
|
using TweetDuck.Browser.Bridge;
|
|
using TweetDuck.Browser.Data;
|
|
using TweetDuck.Browser.Handling;
|
|
using TweetDuck.Browser.Handling.General;
|
|
using TweetDuck.Browser.Notification;
|
|
using TweetDuck.Configuration;
|
|
using TweetDuck.Controls;
|
|
using TweetDuck.Plugins;
|
|
using TweetDuck.Utils;
|
|
using TweetLib.Core.Features.Plugins;
|
|
using TweetLib.Core.Features.Plugins.Enums;
|
|
using TweetLib.Core.Features.Twitter;
|
|
using TweetLib.Core.Utils;
|
|
|
|
namespace TweetDuck.Browser {
|
|
sealed class TweetDeckBrowser : IDisposable {
|
|
private static UserConfig Config => Program.Config.User;
|
|
|
|
private const string NamespaceTweetDeck = "tweetdeck";
|
|
|
|
public bool Ready { get; private set; }
|
|
|
|
public bool Enabled {
|
|
get => browser.Enabled;
|
|
set => browser.Enabled = value;
|
|
}
|
|
|
|
public bool IsTweetDeckWebsite {
|
|
get {
|
|
if (!Ready) {
|
|
return false;
|
|
}
|
|
|
|
using IFrame frame = browser.GetBrowser().MainFrame;
|
|
return TwitterUrls.IsTweetDeck(frame.Url);
|
|
}
|
|
}
|
|
|
|
private readonly ChromiumWebBrowser browser;
|
|
private readonly ResourceHandlers resourceHandlers;
|
|
|
|
private string prevSoundNotificationPath = null;
|
|
|
|
public TweetDeckBrowser(FormBrowser owner, PluginManager plugins, TweetDeckBridge tdBridge, UpdateBridge updateBridge) {
|
|
var resourceRequestHandler = new ResourceRequestHandlerBrowser();
|
|
resourceHandlers = resourceRequestHandler.ResourceHandlers;
|
|
|
|
resourceHandlers.Register(FormNotificationBase.AppLogo);
|
|
resourceHandlers.Register(TwitterUtils.LoadingSpinner);
|
|
|
|
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
|
|
|
|
this.browser = new ChromiumWebBrowser(TwitterUrls.TweetDeck) {
|
|
DialogHandler = new FileDialogHandler(),
|
|
DragHandler = new DragHandlerBrowser(requestHandler),
|
|
MenuHandler = new ContextMenuBrowser(owner),
|
|
JsDialogHandler = new JavaScriptDialogHandler(),
|
|
KeyboardHandler = new KeyboardHandlerBrowser(owner),
|
|
LifeSpanHandler = new CustomLifeSpanHandler(),
|
|
RequestHandler = requestHandler,
|
|
ResourceRequestHandlerFactory = resourceRequestHandler.SelfFactory
|
|
};
|
|
|
|
this.browser.LoadingStateChanged += browser_LoadingStateChanged;
|
|
this.browser.FrameLoadStart += browser_FrameLoadStart;
|
|
this.browser.FrameLoadEnd += browser_FrameLoadEnd;
|
|
this.browser.LoadError += browser_LoadError;
|
|
|
|
this.browser.RegisterJsBridge("$TD", tdBridge);
|
|
this.browser.RegisterJsBridge("$TDU", updateBridge);
|
|
|
|
this.browser.Dock = DockStyle.None;
|
|
this.browser.Location = ControlExtensions.InvisibleLocation;
|
|
this.browser.SetupZoomEvents();
|
|
|
|
owner.Controls.Add(browser);
|
|
plugins.Register(PluginEnvironment.Browser, new PluginDispatcher(browser, TwitterUrls.IsTweetDeck));
|
|
|
|
Config.MuteToggled += Config_MuteToggled;
|
|
Config.SoundNotificationChanged += Config_SoundNotificationInfoChanged;
|
|
}
|
|
|
|
// setup and management
|
|
|
|
public void PrepareSize(Size size) {
|
|
if (!Ready) {
|
|
browser.Size = size;
|
|
}
|
|
}
|
|
|
|
private void OnBrowserReady() {
|
|
if (!Ready) {
|
|
browser.Location = Point.Empty;
|
|
browser.Dock = DockStyle.Fill;
|
|
Ready = true;
|
|
}
|
|
}
|
|
|
|
public void Focus() {
|
|
browser.Focus();
|
|
}
|
|
|
|
public void Dispose() {
|
|
Config.MuteToggled -= Config_MuteToggled;
|
|
Config.SoundNotificationChanged -= Config_SoundNotificationInfoChanged;
|
|
|
|
browser.Dispose();
|
|
}
|
|
|
|
// event handlers
|
|
|
|
private void browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e) {
|
|
if (!e.IsLoading) {
|
|
foreach (string word in TwitterUtils.DictionaryWords) {
|
|
browser.AddWordToDictionary(word);
|
|
}
|
|
|
|
browser.BeginInvoke(new Action(OnBrowserReady));
|
|
browser.LoadingStateChanged -= browser_LoadingStateChanged;
|
|
}
|
|
}
|
|
|
|
private void browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e) {
|
|
IFrame frame = e.Frame;
|
|
|
|
if (frame.IsMain) {
|
|
string url = frame.Url;
|
|
|
|
if (TwitterUrls.IsTweetDeck(url) || (TwitterUrls.IsTwitter(url) && !TwitterUrls.IsTwitterLogin2Factor(url))) {
|
|
frame.ExecuteJavaScriptAsync(TwitterUtils.BackgroundColorOverride);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e) {
|
|
IFrame frame = e.Frame;
|
|
string url = frame.Url;
|
|
|
|
if (frame.IsMain) {
|
|
if (TwitterUrls.IsTweetDeck(url)) {
|
|
UpdateProperties();
|
|
CefScriptExecutor.RunBootstrap(frame, NamespaceTweetDeck);
|
|
|
|
TweetDeckBridge.ResetStaticProperties();
|
|
|
|
if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)) {
|
|
CefScriptExecutor.RunScript(frame, "TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
|
|
}
|
|
|
|
if (Config.FirstRun) {
|
|
CefScriptExecutor.RunBootstrap(frame, "introduction");
|
|
}
|
|
}
|
|
else if (TwitterUrls.IsTwitter(url)) {
|
|
CefScriptExecutor.RunBootstrap(frame, "login");
|
|
}
|
|
|
|
CefScriptExecutor.RunBootstrap(frame, "update");
|
|
}
|
|
}
|
|
|
|
private void browser_LoadError(object sender, LoadErrorEventArgs e) {
|
|
if (e.ErrorCode == CefErrorCode.Aborted) {
|
|
return;
|
|
}
|
|
|
|
if (!e.FailedUrl.StartsWith("td://", StringComparison.Ordinal)) {
|
|
string errorName = Enum.GetName(typeof(CefErrorCode), e.ErrorCode);
|
|
string errorTitle = StringUtils.ConvertPascalCaseToScreamingSnakeCase(errorName ?? string.Empty);
|
|
browser.Load("td://resources/error/error.html#" + Uri.EscapeDataString(errorTitle));
|
|
}
|
|
}
|
|
|
|
private void Config_MuteToggled(object sender, EventArgs e) {
|
|
UpdateProperties();
|
|
}
|
|
|
|
private void Config_SoundNotificationInfoChanged(object sender, EventArgs e) {
|
|
const string soundUrl = "https://ton.twimg.com/tduck/updatesnd";
|
|
|
|
bool hasCustomSound = Config.IsCustomSoundNotificationSet;
|
|
string newNotificationPath = Config.NotificationSoundPath;
|
|
|
|
if (prevSoundNotificationPath != newNotificationPath) {
|
|
prevSoundNotificationPath = newNotificationPath;
|
|
|
|
if (hasCustomSound) {
|
|
resourceHandlers.Register(soundUrl, SoundNotification.CreateFileHandler(newNotificationPath));
|
|
}
|
|
else {
|
|
resourceHandlers.Unregister(soundUrl);
|
|
}
|
|
}
|
|
|
|
browser.ExecuteJsAsync("TDGF_setSoundNotificationData", hasCustomSound, Config.NotificationSoundVolume);
|
|
}
|
|
|
|
// external handling
|
|
|
|
public void HideVideoOverlay(bool focus) {
|
|
if (focus) {
|
|
browser.GetBrowser().GetHost().SendFocusEvent(true);
|
|
}
|
|
|
|
browser.ExecuteJsAsync("$('#td-video-player-overlay').remove()");
|
|
}
|
|
|
|
// javascript calls
|
|
|
|
public void ReloadToTweetDeck() {
|
|
browser.ExecuteJsAsync($"if(window.TDGF_reload)window.TDGF_reload();else window.location.href='{TwitterUrls.TweetDeck}'");
|
|
}
|
|
|
|
public void OnModulesLoaded(string moduleNamespace) {
|
|
if (moduleNamespace == NamespaceTweetDeck) {
|
|
ReinjectCustomCSS(Config.CustomBrowserCSS);
|
|
Config_SoundNotificationInfoChanged(null, EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
public void UpdateProperties() {
|
|
browser.ExecuteJsAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Browser));
|
|
}
|
|
|
|
public void ReinjectCustomCSS(string css) {
|
|
browser.ExecuteJsAsync("TDGF_reinjectCustomCSS", css?.Replace(Environment.NewLine, " ") ?? string.Empty);
|
|
}
|
|
|
|
public void OnMouseClickExtra(IntPtr param) {
|
|
browser.ExecuteJsAsync("TDGF_onMouseClickExtra", (param.ToInt32() >> 16) & 0xFFFF);
|
|
}
|
|
|
|
public void ShowTweetDetail(string columnId, string chirpId, string fallbackUrl) {
|
|
browser.ExecuteJsAsync("TDGF_showTweetDetail", columnId, chirpId, fallbackUrl);
|
|
}
|
|
|
|
public void AddSearchColumn(string query) {
|
|
browser.ExecuteJsAsync("TDGF_performSearch", query);
|
|
}
|
|
|
|
public void TriggerTweetScreenshot(string columnId, string chirpId) {
|
|
browser.ExecuteJsAsync("TDGF_triggerScreenshot", columnId, chirpId);
|
|
}
|
|
|
|
public void ReloadColumns() {
|
|
browser.ExecuteJsAsync("TDGF_reloadColumns()");
|
|
}
|
|
|
|
public void PlaySoundNotification() {
|
|
browser.ExecuteJsAsync("TDGF_playSoundNotification()");
|
|
}
|
|
|
|
public void ApplyROT13() {
|
|
browser.ExecuteJsAsync("TDGF_applyROT13()");
|
|
}
|
|
|
|
public void ShowUpdateNotification(string versionTag, string releaseNotes) {
|
|
browser.ExecuteJsAsync("TDUF_displayNotification", versionTag, Convert.ToBase64String(Encoding.GetEncoding("iso-8859-1").GetBytes(releaseNotes)));
|
|
}
|
|
|
|
public void OpenDevTools() {
|
|
browser.OpenDevToolsCustom();
|
|
}
|
|
}
|
|
}
|