mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-04-20 21:15:48 +02:00
275 lines
10 KiB
C#
275 lines
10 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using CefSharp;
|
|
using CefSharp.WinForms;
|
|
using TweetDuck.Configuration;
|
|
using TweetDuck.Core.Bridge;
|
|
using TweetDuck.Core.Controls;
|
|
using TweetDuck.Core.Handling;
|
|
using TweetDuck.Core.Handling.General;
|
|
using TweetDuck.Core.Notification;
|
|
using TweetDuck.Core.Other.Interfaces;
|
|
using TweetDuck.Core.Utils;
|
|
using TweetDuck.Resources;
|
|
|
|
namespace TweetDuck.Core{
|
|
sealed class TweetDeckBrowser : ITweetDeckBrowser, IDisposable{
|
|
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 TwitterUtils.IsTweetDeckWebsite(frame);
|
|
}
|
|
}
|
|
}
|
|
|
|
private readonly ChromiumWebBrowser browser;
|
|
|
|
private string prevSoundNotificationPath = null;
|
|
|
|
public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
|
|
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
|
|
|
|
this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){
|
|
DialogHandler = new FileDialogHandler(),
|
|
DragHandler = new DragHandlerBrowser(requestHandler),
|
|
MenuHandler = new ContextMenuBrowser(owner),
|
|
JsDialogHandler = new JavaScriptDialogHandler(),
|
|
KeyboardHandler = new KeyboardHandlerBrowser(owner),
|
|
LifeSpanHandler = new LifeSpanHandler(),
|
|
RequestHandler = requestHandler
|
|
};
|
|
|
|
this.browser.LoadingStateChanged += browser_LoadingStateChanged;
|
|
this.browser.FrameLoadStart += browser_FrameLoadStart;
|
|
this.browser.FrameLoadEnd += browser_FrameLoadEnd;
|
|
this.browser.LoadError += browser_LoadError;
|
|
|
|
this.browser.RegisterAsyncJsObject("$TD", bridge);
|
|
|
|
this.browser.BrowserSettings.BackgroundColor = (uint)TwitterUtils.BackgroundColor.ToArgb();
|
|
this.browser.Dock = DockStyle.None;
|
|
this.browser.Location = ControlExtensions.InvisibleLocation;
|
|
|
|
this.browser.SetupResourceHandler(TweetNotification.AppLogo);
|
|
this.browser.SetupResourceHandler(TwitterUtils.LoadingSpinner);
|
|
|
|
owner.Controls.Add(browser);
|
|
|
|
Program.UserConfig.MuteToggled += UserConfig_MuteToggled;
|
|
Program.UserConfig.ZoomLevelChanged += UserConfig_ZoomLevelChanged;
|
|
Program.UserConfig.SoundNotificationChanged += UserConfig_SoundNotificationInfoChanged;
|
|
}
|
|
|
|
// setup and management
|
|
|
|
private void OnBrowserReady(){
|
|
if (!Ready){
|
|
browser.Location = Point.Empty;
|
|
browser.Dock = DockStyle.Fill;
|
|
Ready = true;
|
|
}
|
|
}
|
|
|
|
public void Focus(){
|
|
browser.Focus();
|
|
}
|
|
|
|
public void SetThrottle(bool throttle){
|
|
if (throttle && browser.Dock == DockStyle.Fill){
|
|
browser.Dock = DockStyle.None;
|
|
browser.Size = Size.Empty;
|
|
}
|
|
else if (!throttle && browser.Dock == DockStyle.None){
|
|
browser.Dock = DockStyle.Fill;
|
|
}
|
|
}
|
|
|
|
public void Dispose(){
|
|
Program.UserConfig.MuteToggled -= UserConfig_MuteToggled;
|
|
Program.UserConfig.ZoomLevelChanged -= UserConfig_ZoomLevelChanged;
|
|
Program.UserConfig.SoundNotificationChanged -= UserConfig_SoundNotificationInfoChanged;
|
|
|
|
browser.Dispose();
|
|
}
|
|
|
|
void ITweetDeckBrowser.RegisterBridge(string name, object obj){
|
|
browser.RegisterAsyncJsObject(name, obj);
|
|
}
|
|
|
|
void ITweetDeckBrowser.OnFrameLoaded(Action<IFrame> callback){
|
|
browser.FrameLoadEnd += (sender, args) => {
|
|
IFrame frame = args.Frame;
|
|
|
|
if (frame.IsMain && TwitterUtils.IsTweetDeckWebsite(frame)){
|
|
callback(frame);
|
|
}
|
|
};
|
|
}
|
|
|
|
void ITweetDeckBrowser.ExecuteFunction(string name, params object[] args){
|
|
browser.ExecuteScriptAsync(name, args);
|
|
}
|
|
|
|
// 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){
|
|
if (Program.UserConfig.ZoomLevel != 100){
|
|
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Program.UserConfig.ZoomLevel);
|
|
}
|
|
|
|
if (TwitterUtils.IsTwitterWebsite(frame)){
|
|
ScriptLoader.ExecuteFile(frame, "twitter.js", browser);
|
|
}
|
|
|
|
frame.ExecuteJavaScriptAsync(TwitterUtils.BackgroundColorOverride);
|
|
}
|
|
}
|
|
|
|
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
|
IFrame frame = e.Frame;
|
|
|
|
if (frame.IsMain && TwitterUtils.IsTweetDeckWebsite(frame)){
|
|
UpdateProperties();
|
|
TweetDeckBridge.RestoreSessionData(frame);
|
|
ScriptLoader.ExecuteFile(frame, "code.js", browser);
|
|
ScriptLoader.ExecuteFile(frame, "update.js", browser);
|
|
|
|
InjectBrowserCSS();
|
|
ReinjectCustomCSS(Program.UserConfig.CustomBrowserCSS);
|
|
UserConfig_SoundNotificationInfoChanged(null, EventArgs.Empty);
|
|
|
|
TweetDeckBridge.ResetStaticProperties();
|
|
|
|
if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)){
|
|
ScriptLoader.ExecuteScript(frame, @"TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
|
|
}
|
|
|
|
if (Program.UserConfig.FirstRun){
|
|
ScriptLoader.ExecuteFile(frame, "introduction.js", browser);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void browser_LoadError(object sender, LoadErrorEventArgs e){
|
|
if (e.ErrorCode == CefErrorCode.Aborted){
|
|
return;
|
|
}
|
|
|
|
if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){
|
|
string errorPage = ScriptLoader.LoadResource("pages/error.html", true);
|
|
|
|
if (errorPage != null){
|
|
browser.LoadHtml(errorPage.Replace("{err}", BrowserUtils.GetErrorName(e.ErrorCode)), "http://td/error");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UserConfig_MuteToggled(object sender, EventArgs e){
|
|
UpdateProperties();
|
|
}
|
|
|
|
private void UserConfig_ZoomLevelChanged(object sender, EventArgs e){
|
|
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Program.UserConfig.ZoomLevel);
|
|
}
|
|
|
|
private void UserConfig_SoundNotificationInfoChanged(object sender, EventArgs e){
|
|
const string soundUrl = "https://ton.twimg.com/tduck/updatesnd";
|
|
bool hasCustomSound = Program.UserConfig.IsCustomSoundNotificationSet;
|
|
|
|
if (prevSoundNotificationPath != Program.UserConfig.NotificationSoundPath){
|
|
browser.SetupResourceHandler(soundUrl, hasCustomSound ? SoundNotification.CreateFileHandler(Program.UserConfig.NotificationSoundPath) : null);
|
|
prevSoundNotificationPath = Program.UserConfig.NotificationSoundPath;
|
|
}
|
|
|
|
browser.ExecuteScriptAsync("TDGF_setSoundNotificationData", hasCustomSound, Program.UserConfig.NotificationSoundVolume);
|
|
}
|
|
|
|
// external handling
|
|
|
|
public void HideVideoOverlay(bool focus){
|
|
if (focus){
|
|
browser.GetBrowser().GetHost().SendFocusEvent(true);
|
|
}
|
|
|
|
browser.ExecuteScriptAsync("$('#td-video-player-overlay').remove()");
|
|
}
|
|
|
|
// javascript calls
|
|
|
|
public void ReloadToTweetDeck(){
|
|
browser.ExecuteScriptAsync($"if(window.TDGF_reload)window.TDGF_reload();else window.location.href='{TwitterUtils.TweetDeckURL}'");
|
|
}
|
|
|
|
public void UpdateProperties(){
|
|
browser.ExecuteScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Browser));
|
|
}
|
|
|
|
public void InjectBrowserCSS(){
|
|
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css", false, browser)?.TrimEnd() ?? string.Empty);
|
|
}
|
|
|
|
public void ReinjectCustomCSS(string css){
|
|
browser.ExecuteScriptAsync("TDGF_reinjectCustomCSS", css?.Replace(Environment.NewLine, " ") ?? string.Empty);
|
|
}
|
|
|
|
public void OnMouseClickExtra(IntPtr param){
|
|
browser.ExecuteScriptAsync("TDGF_onMouseClickExtra", (param.ToInt32() >> 16) & 0xFFFF);
|
|
}
|
|
|
|
public void ShowTweetDetail(string columnId, string chirpId, string fallbackUrl){
|
|
browser.ExecuteScriptAsync("TDGF_showTweetDetail", columnId, chirpId, fallbackUrl);
|
|
}
|
|
|
|
public void AddSearchColumn(string query){
|
|
browser.ExecuteScriptAsync("TDGF_performSearch", query);
|
|
}
|
|
|
|
public void TriggerTweetScreenshot(){
|
|
browser.ExecuteScriptAsync("TDGF_triggerScreenshot()");
|
|
}
|
|
|
|
public void ReloadColumns(){
|
|
browser.ExecuteScriptAsync("TDGF_reloadColumns()");
|
|
}
|
|
|
|
public void PlaySoundNotification(){
|
|
browser.ExecuteScriptAsync("TDGF_playSoundNotification()");
|
|
}
|
|
|
|
public void ApplyROT13(){
|
|
browser.ExecuteScriptAsync("TDGF_applyROT13()");
|
|
}
|
|
|
|
public void ShowUpdateNotification(string versionTag, string releaseNotes){
|
|
browser.ExecuteScriptAsync("TDUF_displayNotification", versionTag, Convert.ToBase64String(Encoding.GetEncoding("iso-8859-1").GetBytes(releaseNotes)));
|
|
}
|
|
}
|
|
}
|