mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-09-14 19:32:10 +02:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
327ef1cbee | |||
15eb823c7f | |||
54613e5242 | |||
df1352cbe3 | |||
0559afd972 | |||
afffca020e | |||
d663cc3f64 | |||
110d41e393 | |||
1a8823f592 | |||
6374a852b0 | |||
a10c7dd7c3 | |||
547c7ea417 | |||
760607995a | |||
4704197c09 | |||
093ac1ac40 | |||
9ed8b0d904 | |||
7346ce370d | |||
adefdadc19 | |||
703bce2d00 | |||
97928ecd84 | |||
be9ea7f64a | |||
ec2aaa8789 | |||
ab14b72526 | |||
d8e304f3c1 |
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
*.txt text eof=lf
|
||||||
|
*.cs diff=csharp
|
@@ -117,8 +117,8 @@ namespace TweetDuck.Core.Bridge{
|
|||||||
form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width, height));
|
form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PlayVideo(string url){
|
public void PlayVideo(string url, string username){
|
||||||
form.InvokeAsyncSafe(() => form.PlayVideo(url));
|
form.InvokeAsyncSafe(() => form.PlayVideo(url, username));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FixClipboard(){
|
public void FixClipboard(){
|
||||||
|
@@ -541,7 +541,7 @@ namespace TweetDuck.Core{
|
|||||||
soundNotification.Play(Config.NotificationSoundPath);
|
soundNotification.Play(Config.NotificationSoundPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PlayVideo(string url){
|
public void PlayVideo(string url, string username){
|
||||||
if (string.IsNullOrEmpty(url)){
|
if (string.IsNullOrEmpty(url)){
|
||||||
videoPlayer?.Close();
|
videoPlayer?.Close();
|
||||||
return;
|
return;
|
||||||
@@ -556,7 +556,7 @@ namespace TweetDuck.Core{
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
videoPlayer.Launch(url);
|
videoPlayer.Launch(url, username);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HideVideoOverlay(){
|
public void HideVideoOverlay(){
|
||||||
|
@@ -7,7 +7,9 @@ using TweetDuck.Core.Bridge;
|
|||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using TweetDuck.Core.Other;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Handling{
|
namespace TweetDuck.Core.Handling{
|
||||||
abstract class ContextMenuBase : IContextMenuHandler{
|
abstract class ContextMenuBase : IContextMenuHandler{
|
||||||
@@ -31,10 +33,11 @@ namespace TweetDuck.Core.Handling{
|
|||||||
private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
|
private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
|
||||||
private const CefMenuCommand MenuCopyLinkUrl = (CefMenuCommand)26501;
|
private const CefMenuCommand MenuCopyLinkUrl = (CefMenuCommand)26501;
|
||||||
private const CefMenuCommand MenuCopyUsername = (CefMenuCommand)26502;
|
private const CefMenuCommand MenuCopyUsername = (CefMenuCommand)26502;
|
||||||
private const CefMenuCommand MenuOpenMediaUrl = (CefMenuCommand)26503;
|
private const CefMenuCommand MenuViewImage = (CefMenuCommand)26503;
|
||||||
private const CefMenuCommand MenuCopyMediaUrl = (CefMenuCommand)26504;
|
private const CefMenuCommand MenuOpenMediaUrl = (CefMenuCommand)26504;
|
||||||
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26505;
|
private const CefMenuCommand MenuCopyMediaUrl = (CefMenuCommand)26505;
|
||||||
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26506;
|
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26506;
|
||||||
|
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26507;
|
||||||
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
|
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
|
||||||
|
|
||||||
private string[] lastHighlightedTweetAuthors;
|
private string[] lastHighlightedTweetAuthors;
|
||||||
@@ -79,6 +82,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
model.AddSeparator();
|
model.AddSeparator();
|
||||||
}
|
}
|
||||||
else if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){
|
else if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){
|
||||||
|
model.AddItem(MenuViewImage, "View image in photo viewer");
|
||||||
model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
|
model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
|
||||||
model.AddItem(MenuCopyMediaUrl, TextCopy("image"));
|
model.AddItem(MenuCopyMediaUrl, TextCopy("image"));
|
||||||
model.AddItem(MenuSaveMedia, TextSave("image"));
|
model.AddItem(MenuSaveMedia, TextSave("image"));
|
||||||
@@ -114,9 +118,35 @@ namespace TweetDuck.Core.Handling{
|
|||||||
SetClipboardText(browserControl.AsControl(), TwitterUtils.GetMediaLink(GetMediaLink(parameters), ImageQuality));
|
SetClipboardText(browserControl.AsControl(), TwitterUtils.GetMediaLink(GetMediaLink(parameters), ImageQuality));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MenuViewImage:
|
||||||
|
string url = GetMediaLink(parameters);
|
||||||
|
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url));
|
||||||
|
|
||||||
|
void ViewFile(){
|
||||||
|
string ext = Path.GetExtension(file);
|
||||||
|
|
||||||
|
if (TwitterUtils.ValidImageExtensions.Contains(ext)){
|
||||||
|
WindowsUtils.OpenAssociatedProgram(file);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
FormMessage.Error("Image Download", "Invalid file extension "+ext, FormMessage.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(file)){
|
||||||
|
ViewFile();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
BrowserUtils.DownloadFileAsync(TwitterUtils.GetMediaLink(url, ImageQuality), file, ViewFile, ex => {
|
||||||
|
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case MenuSaveMedia:
|
case MenuSaveMedia:
|
||||||
if (IsVideo){
|
if (IsVideo){
|
||||||
TwitterUtils.DownloadVideo(GetMediaLink(parameters));
|
TwitterUtils.DownloadVideo(GetMediaLink(parameters), lastHighlightedTweetAuthors.LastOrDefault());
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
TwitterUtils.DownloadImage(GetMediaLink(parameters), lastHighlightedTweetAuthors.LastOrDefault(), ImageQuality);
|
TwitterUtils.DownloadImage(GetMediaLink(parameters), lastHighlightedTweetAuthors.LastOrDefault(), ImageQuality);
|
||||||
|
@@ -21,7 +21,7 @@ namespace TweetDuck.Core.Other{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe(e.Link.LinkData as string);
|
BrowserUtils.OpenExternalBrowser(e.Link.LinkData as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormAbout_HelpRequested(object sender, HelpEventArgs hlpevent){
|
private void FormAbout_HelpRequested(object sender, HelpEventArgs hlpevent){
|
||||||
|
@@ -25,6 +25,7 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
|
|
||||||
private readonly Form owner;
|
private readonly Form owner;
|
||||||
private string lastUrl;
|
private string lastUrl;
|
||||||
|
private string lastUsername;
|
||||||
|
|
||||||
private Process currentProcess;
|
private Process currentProcess;
|
||||||
private DuplexPipe.Server currentPipe;
|
private DuplexPipe.Server currentPipe;
|
||||||
@@ -35,13 +36,14 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
this.owner.FormClosing += owner_FormClosing;
|
this.owner.FormClosing += owner_FormClosing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Launch(string url){
|
public void Launch(string url, string username){
|
||||||
if (Running){
|
if (Running){
|
||||||
Destroy();
|
Destroy();
|
||||||
isClosing = false;
|
isClosing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastUrl = url;
|
lastUrl = url;
|
||||||
|
lastUsername = username;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
currentPipe = DuplexPipe.CreateServer();
|
currentPipe = DuplexPipe.CreateServer();
|
||||||
@@ -84,7 +86,7 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "download":
|
case "download":
|
||||||
TwitterUtils.DownloadVideo(lastUrl);
|
TwitterUtils.DownloadVideo(lastUrl, lastUsername);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "rip":
|
case "rip":
|
||||||
@@ -157,14 +159,14 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
|
|
||||||
switch(exitCode){
|
switch(exitCode){
|
||||||
case 3: // CODE_LAUNCH_FAIL
|
case 3: // CODE_LAUNCH_FAIL
|
||||||
if (FormMessage.Error("Video Playback Error", "Error launching video player, this may be caused by missing Windows Media Player. Do you want to open the video in a browser?", FormMessage.Yes, FormMessage.No)){
|
if (FormMessage.Error("Video Playback Error", "Error launching video player, this may be caused by missing Windows Media Player. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
|
||||||
BrowserUtils.OpenExternalBrowser(lastUrl);
|
BrowserUtils.OpenExternalBrowser(lastUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // CODE_MEDIA_ERROR
|
case 4: // CODE_MEDIA_ERROR
|
||||||
if (FormMessage.Error("Video Playback Error", "The video could not be loaded, most likely due to unknown format. Do you want to open the video in a browser?", FormMessage.Yes, FormMessage.No)){
|
if (FormMessage.Error("Video Playback Error", "The video could not be loaded, most likely due to unknown format. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
|
||||||
BrowserUtils.OpenExternalBrowser(lastUrl);
|
BrowserUtils.OpenExternalBrowser(lastUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,7 +35,7 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void btnOpenWiki_Click(object sender, EventArgs e){
|
private void btnOpenWiki_Click(object sender, EventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe("https://github.com/chylex/TweetDuck/wiki");
|
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnApply_Click(object sender, EventArgs e){
|
private void btnApply_Click(object sender, EventArgs e){
|
||||||
|
@@ -19,7 +19,7 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void btnHelp_Click(object sender, EventArgs e){
|
private void btnHelp_Click(object sender, EventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe("http://peter.sh/experiments/chromium-command-line-switches/");
|
BrowserUtils.OpenExternalBrowser("http://peter.sh/experiments/chromium-command-line-switches/");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnApply_Click(object sender, EventArgs e){
|
private void btnApply_Click(object sender, EventArgs e){
|
||||||
|
@@ -16,7 +16,7 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void btnSendFeedback_Click(object sender, EventArgs e){
|
private void btnSendFeedback_Click(object sender, EventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe("https://github.com/chylex/TweetDuck/issues/new");
|
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/issues/new");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDataCollection_CheckedChanged(object sender, EventArgs e){
|
private void checkDataCollection_CheckedChanged(object sender, EventArgs e){
|
||||||
@@ -24,7 +24,7 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void labelDataCollectionLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
private void labelDataCollectionLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe("https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data");
|
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
static class BrowserCache{
|
static class BrowserCache{
|
||||||
private static bool ClearOnExit { get; set; }
|
private static bool ClearOnExit { get; set; }
|
||||||
|
|
||||||
private static readonly string CacheFolder = Path.Combine(Program.StoragePath, "Cache");
|
public static readonly string CacheFolder = Path.Combine(Program.StoragePath, "Cache");
|
||||||
|
|
||||||
private static IEnumerable<string> CacheFiles{
|
private static IEnumerable<string> CacheFiles{
|
||||||
get{
|
get{
|
||||||
|
@@ -70,12 +70,12 @@ namespace TweetDuck.Core.Utils{
|
|||||||
|
|
||||||
switch(CheckUrl(url)){
|
switch(CheckUrl(url)){
|
||||||
case UrlCheckResult.Fine:
|
case UrlCheckResult.Fine:
|
||||||
OpenExternalBrowserUnsafe(url);
|
WindowsUtils.OpenAssociatedProgram(url);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UrlCheckResult.Tracking:
|
case UrlCheckResult.Tracking:
|
||||||
if (FormMessage.Warning("Blocked URL", "TweetDuck has blocked a tracking url due to privacy concerns. Do you want to visit it anyway?\n"+url, FormMessage.Yes, FormMessage.No)){
|
if (FormMessage.Warning("Blocked URL", "TweetDuck has blocked a tracking url due to privacy concerns. Do you want to visit it anyway?\n"+url, FormMessage.Yes, FormMessage.No)){
|
||||||
OpenExternalBrowserUnsafe(url);
|
WindowsUtils.OpenAssociatedProgram(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -86,10 +86,6 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OpenExternalBrowserUnsafe(string url){
|
|
||||||
using(Process.Start(url)){}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetFileNameFromUrl(string url){
|
public static string GetFileNameFromUrl(string url){
|
||||||
string file = Path.GetFileName(new Uri(url).AbsolutePath);
|
string file = Path.GetFileName(new Uri(url).AbsolutePath);
|
||||||
return string.IsNullOrEmpty(file) ? null : file;
|
return string.IsNullOrEmpty(file) ? null : file;
|
||||||
|
@@ -21,6 +21,10 @@ namespace TweetDuck.Core.Utils{
|
|||||||
"tweetdeck", "TweetDeck", "tweetduck", "TweetDuck", "TD"
|
"tweetdeck", "TweetDeck", "tweetduck", "TweetDuck", "TD"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static readonly string[] ValidImageExtensions = {
|
||||||
|
".jpg", ".jpeg", ".png", ".gif"
|
||||||
|
};
|
||||||
|
|
||||||
public enum ImageQuality{
|
public enum ImageQuality{
|
||||||
Default, Orig
|
Default, Orig
|
||||||
}
|
}
|
||||||
@@ -53,6 +57,10 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetImageFileName(string url){
|
||||||
|
return BrowserUtils.GetFileNameFromUrl(ExtractMediaBaseLink(url));
|
||||||
|
}
|
||||||
|
|
||||||
public static void DownloadImage(string url, string username, ImageQuality quality){
|
public static void DownloadImage(string url, string username, ImageQuality quality){
|
||||||
DownloadImages(new string[]{ url }, username, quality);
|
DownloadImages(new string[]{ url }, username, quality);
|
||||||
}
|
}
|
||||||
@@ -65,7 +73,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
string firstImageLink = GetMediaLink(urls[0], quality);
|
string firstImageLink = GetMediaLink(urls[0], quality);
|
||||||
int qualityIndex = firstImageLink.IndexOf(':', firstImageLink.LastIndexOf('/'));
|
int qualityIndex = firstImageLink.IndexOf(':', firstImageLink.LastIndexOf('/'));
|
||||||
|
|
||||||
string file = BrowserUtils.GetFileNameFromUrl(ExtractMediaBaseLink(firstImageLink));
|
string file = GetImageFileName(firstImageLink);
|
||||||
string ext = Path.GetExtension(file); // includes dot
|
string ext = Path.GetExtension(file); // includes dot
|
||||||
|
|
||||||
string[] fileNameParts = qualityIndex == -1 ? new string[]{
|
string[] fileNameParts = qualityIndex == -1 ? new string[]{
|
||||||
@@ -103,7 +111,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DownloadVideo(string url){
|
public static void DownloadVideo(string url, string username){
|
||||||
string filename = BrowserUtils.GetFileNameFromUrl(url);
|
string filename = BrowserUtils.GetFileNameFromUrl(url);
|
||||||
string ext = Path.GetExtension(filename);
|
string ext = Path.GetExtension(filename);
|
||||||
|
|
||||||
@@ -111,7 +119,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
AutoUpgradeEnabled = true,
|
AutoUpgradeEnabled = true,
|
||||||
OverwritePrompt = true,
|
OverwritePrompt = true,
|
||||||
Title = "Save video",
|
Title = "Save video",
|
||||||
FileName = filename,
|
FileName = string.IsNullOrEmpty(username) ? filename : $"{username} {filename}",
|
||||||
Filter = "Video"+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}")
|
Filter = "Video"+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}")
|
||||||
}){
|
}){
|
||||||
if (dialog.ShowDialog() == DialogResult.OK){
|
if (dialog.ShowDialog() == DialogResult.OK){
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Management;
|
using System.Management;
|
||||||
@@ -49,17 +50,22 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Process StartProcess(string file, string arguments, bool runElevated){
|
public static bool OpenAssociatedProgram(string file, string arguments = "", bool runElevated = false){
|
||||||
ProcessStartInfo processInfo = new ProcessStartInfo{
|
try{
|
||||||
|
using(Process.Start(new ProcessStartInfo{
|
||||||
FileName = file,
|
FileName = file,
|
||||||
Arguments = arguments
|
Arguments = arguments,
|
||||||
};
|
Verb = runElevated ? "runas" : string.Empty,
|
||||||
|
ErrorDialog = true
|
||||||
if (runElevated){
|
})){
|
||||||
processInfo.Verb = "runas";
|
return true;
|
||||||
|
}
|
||||||
|
}catch(Win32Exception e) when (e.NativeErrorCode == 0x000004C7){ // operation canceled by the user
|
||||||
|
return false;
|
||||||
|
}catch(Exception e){
|
||||||
|
Program.Reporter.HandleException("Error opening file", e.Message, true, e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Process.Start(processInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TrySleepUntil(Func<bool> test, int timeoutMillis, int timeStepMillis){
|
public static bool TrySleepUntil(Func<bool> test, int timeoutMillis, int timeStepMillis){
|
||||||
@@ -104,7 +110,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void ClipboardStripHtmlStyles(){
|
public static void ClipboardStripHtmlStyles(){
|
||||||
if (!Clipboard.ContainsText(TextDataFormat.Html)){
|
if (!Clipboard.ContainsText(TextDataFormat.Html) || !Clipboard.ContainsText(TextDataFormat.UnicodeText)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
Program.cs
17
Program.cs
@@ -21,7 +21,7 @@ namespace TweetDuck{
|
|||||||
public const string BrandName = "TweetDuck";
|
public const string BrandName = "TweetDuck";
|
||||||
public const string Website = "https://tweetduck.chylex.com";
|
public const string Website = "https://tweetduck.chylex.com";
|
||||||
|
|
||||||
public const string VersionTag = "1.10.1";
|
public const string VersionTag = "1.10.2";
|
||||||
|
|
||||||
public static readonly bool IsPortable = File.Exists("makeportable");
|
public static readonly bool IsPortable = File.Exists("makeportable");
|
||||||
|
|
||||||
@@ -166,9 +166,13 @@ namespace TweetDuck{
|
|||||||
string updaterArgs = "/SP- /SILENT /CLOSEAPPLICATIONS /UPDATEPATH=\""+ProgramPath+"\" /RUNARGS=\""+Arguments.GetCurrentForInstallerCmd()+"\""+(IsPortable ? " /PORTABLE=1" : "");
|
string updaterArgs = "/SP- /SILENT /CLOSEAPPLICATIONS /UPDATEPATH=\""+ProgramPath+"\" /RUNARGS=\""+Arguments.GetCurrentForInstallerCmd()+"\""+(IsPortable ? " /PORTABLE=1" : "");
|
||||||
bool runElevated = !IsPortable || !WindowsUtils.CheckFolderWritePermission(ProgramPath);
|
bool runElevated = !IsPortable || !WindowsUtils.CheckFolderWritePermission(ProgramPath);
|
||||||
|
|
||||||
WindowsUtils.StartProcess(mainForm.UpdateInstallerPath, updaterArgs, runElevated);
|
if (WindowsUtils.OpenAssociatedProgram(mainForm.UpdateInstallerPath, updaterArgs, runElevated)){
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
RestartWithArgsInternal(Arguments.GetCurrentClean());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetDataStoragePath(){
|
private static string GetDataStoragePath(){
|
||||||
@@ -211,11 +215,14 @@ namespace TweetDuck{
|
|||||||
FormBrowser browserForm = Application.OpenForms.OfType<FormBrowser>().FirstOrDefault();
|
FormBrowser browserForm = Application.OpenForms.OfType<FormBrowser>().FirstOrDefault();
|
||||||
if (browserForm == null)return;
|
if (browserForm == null)return;
|
||||||
|
|
||||||
args.AddFlag(Arguments.ArgRestart);
|
|
||||||
|
|
||||||
browserForm.ForceClose();
|
browserForm.ForceClose();
|
||||||
ExitCleanup();
|
|
||||||
|
|
||||||
|
ExitCleanup();
|
||||||
|
RestartWithArgsInternal(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RestartWithArgsInternal(CommandLineArgs args){
|
||||||
|
args.AddFlag(Arguments.ArgRestart);
|
||||||
Process.Start(Application.ExecutablePath, args.ToString());
|
Process.Start(Application.ExecutablePath, args.ToString());
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
|
25
README.md
25
README.md
@@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
[Follow TweetDuck on Twitter](https://twitter.com/TryTweetDuck) | [Support via PayPal](https://paypal.me/chylex) | [Support via Patreon](https://www.patreon.com/chylex)
|
[Follow TweetDuck on Twitter](https://twitter.com/TryTweetDuck) | [Support via PayPal](https://paypal.me/chylex) | [Support via Patreon](https://www.patreon.com/chylex)
|
||||||
|
|
||||||
<a target='_blank' rel='nofollow' href='https://app.codesponsor.io/link/2W76v7hRmUe7NfaeUKq9K8Wq/chylex/TweetDuck'>
|
|
||||||
<img alt='Sponsor' width='888' height='68' src='https://app.codesponsor.io/embed/2W76v7hRmUe7NfaeUKq9K8Wq/chylex/TweetDuck.svg' />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
# Build Instructions
|
# Build Instructions
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
@@ -33,21 +29,34 @@ To do that, open **TweetDuck Properties**, click the **Debug** tab, make sure yo
|
|||||||
|
|
||||||
### Build
|
### Build
|
||||||
|
|
||||||
To make a release build of TweetDuck, open **Batch Build**, tick all `Release` configurations except for the `UnitTest` project (otherwise the build will fail), and click **Rebuild**. Check the status bar to make sure it says **Rebuild All succeeded**; if not, open the **Output** view and see which part of the build failed.
|
To make a release build of TweetDuck, open **Batch Build**, tick all `Release` configurations except for the `UnitTest` project (otherwise the build will fail), and click **Rebuild**. Check the status bar to make sure it says **Rebuild All succeeded**; if not, see the [Troubleshooting](#troubleshooting) section.
|
||||||
|
|
||||||
After the build succeeds, the **bin/x86/Release** folder will contain files intended for distribution (no debug symbols or other unnecessary files). You may package these files yourself, or see the [Installers](#Installers) section for automated installer generation.
|
After the build succeeds, the `bin/x86/Release` folder will contain files intended for distribution (no debug symbols or other unnecessary files). You may package these files yourself, or see the [Installers](#installers) section for automated installer generation.
|
||||||
|
|
||||||
If you decide to release a custom version publicly, please make it clear that it is not an official release of TweetDuck.
|
If you decide to release a custom version publicly, please make it clear that it is not an official release of TweetDuck.
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
There are a few quirks in the build process that may catch you off guard:
|
||||||
|
|
||||||
|
- **Plugin files are not updated automatically**
|
||||||
|
- Since official plugins (`Resources/Plugins`) are not included in the project, Visual Studio will not automatically detect changes in the files
|
||||||
|
- To ensure plugins are updated when testing the app, click **Rebuild Solution** before clicking **Start**
|
||||||
|
- **Error: The command (...) exited with code 1**
|
||||||
|
- If the post-build event fails, open the **Output** tab and look for the cause
|
||||||
|
- Determine if there was an IO error while copying files or modifying folders, or whether the final .ps1 script failed (`Encountered an error while running PostBuild.ps1 on line xyz`)
|
||||||
|
- Some files are checked for invalid characters:
|
||||||
|
- `Resources/Plugins/emoji-keyboard/emoji-ordering.txt` line endings must be LF (line feed); any CR (carriage return) in the file will cause a failed build, and you will need to ensure correct line endings in your text editor
|
||||||
|
|
||||||
### Installers
|
### Installers
|
||||||
|
|
||||||
TweetDuck uses **Inno Setup** to automate the creation of installers. First, download and install [InnoSetup QuickStart Pack](http://www.jrsoftware.org/isdl.php) (non-unicode; editor and encryption support not required) and the [Inno Download Plugin](https://code.google.com/archive/p/inno-download-plugin).
|
TweetDuck uses **Inno Setup** to automate the creation of installers. First, download and install [InnoSetup QuickStart Pack](http://www.jrsoftware.org/isdl.php) (non-unicode; editor and encryption support not required) and the [Inno Download Plugin](https://code.google.com/archive/p/inno-download-plugin).
|
||||||
|
|
||||||
Next, add the Inno Setup installation folder (usually `C:\Program Files (x86)\Inno Setup 5`) into your **PATH** environment variable. You may need to restart File Explorer for the change to take place.
|
Next, add the Inno Setup installation folder (usually `C:\Program Files (x86)\Inno Setup 5`) into your **PATH** environment variable. You may need to restart File Explorer for the change to take place.
|
||||||
|
|
||||||
Now you can generate installers after a build by running **bld/RUN BUILD.bat**. Note that despite the name, this will only package the files, you still need to run the [build](#Build) in Visual Studio!
|
Now you can generate installers after a build by running `bld/RUN BUILD.bat`. Note that despite the name, this will only package the files, you still need to run the [build](#build) in Visual Studio!
|
||||||
|
|
||||||
After the window closes, three installers will be generated inside the **bld/Output** folder:
|
After the window closes, three installers will be generated inside the `bld/Output` folder:
|
||||||
* **TweetDuck.exe**
|
* **TweetDuck.exe**
|
||||||
* This is the main installer that creates entries in the Start Menu & Programs and Features, and an optional desktop icon
|
* This is the main installer that creates entries in the Start Menu & Programs and Features, and an optional desktop icon
|
||||||
* **TweetDuck.Update.exe**
|
* **TweetDuck.Update.exe**
|
||||||
|
@@ -8,7 +8,7 @@ Edit layout & design
|
|||||||
chylex
|
chylex
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
1.1.4
|
1.1.5
|
||||||
|
|
||||||
[website]
|
[website]
|
||||||
https://tweetduck.chylex.com
|
https://tweetduck.chylex.com
|
||||||
|
@@ -12,6 +12,7 @@ enabled(){
|
|||||||
moveTweetActionsToRight: true,
|
moveTweetActionsToRight: true,
|
||||||
themeColorTweaks: true,
|
themeColorTweaks: true,
|
||||||
revertIcons: true,
|
revertIcons: true,
|
||||||
|
increaseQuoteTextSize: false,
|
||||||
smallComposeTextSize: false,
|
smallComposeTextSize: false,
|
||||||
optimizeAnimations: true,
|
optimizeAnimations: true,
|
||||||
avatarRadius: 2
|
avatarRadius: 2
|
||||||
@@ -366,6 +367,10 @@ enabled(){
|
|||||||
this.css.insert(".tweet-actions > li:nth-child(4) { margin-right: 2px !important }");
|
this.css.insert(".tweet-actions > li:nth-child(4) { margin-right: 2px !important }");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.config.increaseQuoteTextSize){
|
||||||
|
this.css.insert(".quoted-tweet { font-size: 1em !important }");
|
||||||
|
}
|
||||||
|
|
||||||
if (this.config.smallComposeTextSize){
|
if (this.config.smallComposeTextSize){
|
||||||
this.css.insert(".compose-text { font-size: 12px !important; height: 120px !important }");
|
this.css.insert(".compose-text { font-size: 12px !important; height: 120px !important }");
|
||||||
}
|
}
|
||||||
@@ -510,6 +515,10 @@ enabled(){
|
|||||||
html[data-td-font] { font-size: ${this.config.fontSize} !important }
|
html[data-td-font] { font-size: ${this.config.fontSize} !important }
|
||||||
.avatar { border-radius: ${this.config.avatarRadius}% !important }
|
.avatar { border-radius: ${this.config.avatarRadius}% !important }
|
||||||
|
|
||||||
|
${this.config.increaseQuoteTextSize ? `
|
||||||
|
.quoted-tweet { font-size: 1em !important }
|
||||||
|
` : ``}
|
||||||
|
|
||||||
${this.config.revertIcons ? `
|
${this.config.revertIcons ? `
|
||||||
@font-face { font-family: 'tweetdeckold'; src: url(\"https://ton.twimg.com/tweetdeck-web/web/assets/fonts/tweetdeck-regular-webfont.5f4ea87976.woff\") format(\"woff\"); font-weight: normal; font-style: normal }
|
@font-face { font-family: 'tweetdeckold'; src: url(\"https://ton.twimg.com/tweetdeck-web/web/assets/fonts/tweetdeck-regular-webfont.5f4ea87976.woff\") format(\"woff\"); font-weight: normal; font-style: normal }
|
||||||
.icon-reply:before{content:"\\f006";font-family:tweetdeckold}
|
.icon-reply:before{content:"\\f006";font-family:tweetdeckold}
|
||||||
|
@@ -61,15 +61,13 @@
|
|||||||
<option value="16px">Largest (16px)</option>
|
<option value="16px">Largest (16px)</option>
|
||||||
<option value="custom">Custom</option>
|
<option value="custom">Custom</option>
|
||||||
</select>
|
</select>
|
||||||
|
<label class="checkbox">
|
||||||
<!-- ADVANCED -->
|
<input data-td-key="increaseQuoteTextSize" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
||||||
|
Increase quoted tweet font size
|
||||||
<label class="txt-uppercase touch-larger-label">
|
|
||||||
<b>Advanced</b>
|
|
||||||
</label>
|
</label>
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input data-td-key="optimizeAnimations" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
<input data-td-key="smallComposeTextSize" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
||||||
Use more memory for smoother animations
|
Small tweet input font size
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -102,9 +100,15 @@
|
|||||||
<input data-td-key="revertIcons" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
<input data-td-key="revertIcons" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
||||||
Revert icon design
|
Revert icon design
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<!-- ADVANCED -->
|
||||||
|
|
||||||
|
<label class="txt-uppercase touch-larger-label">
|
||||||
|
<b>Advanced</b>
|
||||||
|
</label>
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input data-td-key="smallComposeTextSize" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
<input data-td-key="optimizeAnimations" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
||||||
Small compose tweet font size
|
Use more memory for smoother animations
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -163,11 +167,12 @@
|
|||||||
.td-modal-inner-cols .l-column {
|
.td-modal-inner-cols .l-column {
|
||||||
padding: 15px 9px;
|
padding: 15px 9px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
width: 225px;
|
||||||
font-size: 0; /* fix custom font size breaking the modal layout */
|
font-size: 0; /* fix custom font size breaking the modal layout */
|
||||||
}
|
}
|
||||||
|
|
||||||
.td-modal-inner-cols .l-column:nth-child(2) {
|
.td-modal-inner-cols .l-column:nth-child(3) {
|
||||||
width: 250px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.td-modal-inner-full {
|
.td-modal-inner-full {
|
||||||
@@ -199,6 +204,14 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.td-modal-content select + label.checkbox {
|
||||||
|
margin-top: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td-modal-content input.js-theme-checkbox, .td-modal-content input.js-theme-radio {
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Avatar shape */
|
/* Avatar shape */
|
||||||
|
|
||||||
.td-avatar-shape-container {
|
.td-avatar-shape-container {
|
||||||
|
@@ -9,7 +9,7 @@ Emoji keyboard
|
|||||||
chylex
|
chylex
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
1.4
|
1.4.1
|
||||||
|
|
||||||
[website]
|
[website]
|
||||||
https://tweetduck.chylex.com
|
https://tweetduck.chylex.com
|
||||||
|
@@ -303,23 +303,26 @@ enabled(){
|
|||||||
let firstColon = val.lastIndexOf(':', ele[0].selectionStart);
|
let firstColon = val.lastIndexOf(':', ele[0].selectionStart);
|
||||||
return if firstColon === -1;
|
return if firstColon === -1;
|
||||||
|
|
||||||
let search = val.substring(firstColon+1, ele[0].selectionStart);
|
let search = val.substring(firstColon+1, ele[0].selectionStart).toLowerCase();
|
||||||
return if !/^[a-z_]+$/i.test(search);
|
return if !/^[a-z_]+$/.test(search);
|
||||||
|
|
||||||
let keywords = search.split("_").filter(kw => kw.length > 0).map(kw => kw.toLowerCase());
|
let keywords = search.split("_").filter(kw => kw.length > 0).map(kw => kw.toLowerCase());
|
||||||
return if keywords.length === 0;
|
return if keywords.length === 0;
|
||||||
|
|
||||||
let foundName = me.emojiNames.filter(name => keywords.every(kw => name.includes(kw)));
|
let foundNames = me.emojiNames.filter(name => keywords.every(kw => name.includes(kw)));
|
||||||
|
|
||||||
if (foundName.length === 0){
|
if (foundNames.length === 0){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (foundNames.length > 1 && foundNames.includes(search)){
|
||||||
|
foundNames = [ search ];
|
||||||
|
}
|
||||||
|
|
||||||
lastEmojiKeyword = `:${search}:`;
|
lastEmojiKeyword = `:${search}:`;
|
||||||
lastEmojiPosition = lastEmojiLength = 0;
|
lastEmojiPosition = lastEmojiLength = 0;
|
||||||
|
|
||||||
if (foundName.length === 1){
|
if (foundNames.length === 1){
|
||||||
let foundIndex = me.emojiNames.indexOf(foundName[0]);
|
let foundIndex = me.emojiNames.indexOf(foundNames[0]);
|
||||||
let foundEmoji;
|
let foundEmoji;
|
||||||
|
|
||||||
for(let array of [ me.emojiData1, me.emojiData2[me.selectedSkinTone], me.emojiData3 ]){
|
for(let array of [ me.emojiData1, me.emojiData2[me.selectedSkinTone], me.emojiData3 ]){
|
||||||
@@ -346,7 +349,7 @@ enabled(){
|
|||||||
lastEmojiLength = foundEmoji.length;
|
lastEmojiLength = foundEmoji.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (foundName.length > 1){
|
else if (foundNames.length > 1){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
ele.val(val.substring(0, firstColon)+val.substring(ele[0].selectionStart));
|
ele.val(val.substring(0, firstColon)+val.substring(ele[0].selectionStart));
|
||||||
ele[0].selectionEnd = ele[0].selectionStart = firstColon;
|
ele[0].selectionEnd = ele[0].selectionStart = firstColon;
|
||||||
|
@@ -8,7 +8,7 @@ Custom reply account
|
|||||||
chylex
|
chylex
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
1.2.3
|
1.2.4
|
||||||
|
|
||||||
[website]
|
[website]
|
||||||
https://tweetduck.chylex.com
|
https://tweetduck.chylex.com
|
||||||
@@ -20,4 +20,4 @@ configuration.js
|
|||||||
configuration.default.js
|
configuration.default.js
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
1.8
|
1.10.3
|
@@ -6,7 +6,7 @@ enabled(){
|
|||||||
this.lastSelectedAccount = null;
|
this.lastSelectedAccount = null;
|
||||||
|
|
||||||
this.uiComposeTweetEvent = (e, data) => {
|
this.uiComposeTweetEvent = (e, data) => {
|
||||||
return if data.type !== "reply" || data.popFromInline || !("element" in data);
|
return if !(data.type === "reply" || (data.type === "tweet" && "quotedTweet" in data)) || data.popFromInline || !("element" in data);
|
||||||
|
|
||||||
var query;
|
var query;
|
||||||
|
|
||||||
|
@@ -3,6 +3,18 @@ $ErrorActionPreference = "Stop"
|
|||||||
|
|
||||||
Set-Location $dir
|
Set-Location $dir
|
||||||
|
|
||||||
|
function Check-Carriage-Return{
|
||||||
|
Param([Parameter(Mandatory = $True, Position = 1)] $fname)
|
||||||
|
|
||||||
|
$file = @(Get-ChildItem -Include $fname -Recurse)[0]
|
||||||
|
|
||||||
|
if ((Get-Content -Path $file.FullName -Raw).Contains("`r")){
|
||||||
|
Throw "$fname cannot contain carriage return"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Verified" $file.FullName.Substring($dir.Length)
|
||||||
|
}
|
||||||
|
|
||||||
function Rewrite-File{
|
function Rewrite-File{
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
Param([Parameter(Mandatory = $True, ValueFromPipeline = $True)][array] $lines, [Parameter(Mandatory = $True, Position = 1)] $file)
|
Param([Parameter(Mandatory = $True, ValueFromPipeline = $True)][array] $lines, [Parameter(Mandatory = $True, Position = 1)] $file)
|
||||||
@@ -11,7 +23,10 @@ function Rewrite-File{
|
|||||||
Write-Host "Processed" $file.FullName.Substring($dir.Length)
|
Write-Host "Processed" $file.FullName.Substring($dir.Length)
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Include *.js -Exclude configuration.default.js -Recurse){
|
try{
|
||||||
|
Check-Carriage-Return("emoji-ordering.txt")
|
||||||
|
|
||||||
|
ForEach($file in Get-ChildItem -Filter *.js -Exclude configuration.default.js -Recurse){
|
||||||
$lines = Get-Content -Path $file.FullName
|
$lines = Get-Content -Path $file.FullName
|
||||||
$lines = $lines | % { $_.TrimStart() }
|
$lines = $lines | % { $_.TrimStart() }
|
||||||
$lines = $lines -Replace '^(.*?)((?<=^|[;{}()])\s?//(?:\s.*|$))?$', '$1'
|
$lines = $lines -Replace '^(.*?)((?<=^|[;{}()])\s?//(?:\s.*|$))?$', '$1'
|
||||||
@@ -19,7 +34,7 @@ ForEach($file in Get-ChildItem -Include *.js -Exclude configuration.default.js -
|
|||||||
,$lines | Rewrite-File $file
|
,$lines | Rewrite-File $file
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Include *.css -Recurse){
|
ForEach($file in Get-ChildItem -Filter *.css -Recurse){
|
||||||
$lines = Get-Content -Path $file.FullName
|
$lines = Get-Content -Path $file.FullName
|
||||||
$lines = $lines -Replace '\s*/\*.*?\*/', ''
|
$lines = $lines -Replace '\s*/\*.*?\*/', ''
|
||||||
$lines = $lines -Replace '^\s+(.+):\s?(.+?)(?:\s?(!important))?;$', '$1:$2$3;'
|
$lines = $lines -Replace '^\s+(.+):\s?(.+?)(?:\s?(!important))?;$', '$1:$2$3;'
|
||||||
@@ -27,7 +42,12 @@ ForEach($file in Get-ChildItem -Include *.css -Recurse){
|
|||||||
@(($lines | Where { $_ -ne '' }) -Join ' ') | Rewrite-File $file
|
@(($lines | Where { $_ -ne '' }) -Join ' ') | Rewrite-File $file
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Include *.html -Recurse){
|
ForEach($file in Get-ChildItem -Filter *.html -Recurse){
|
||||||
$lines = Get-Content -Path $file.FullName
|
$lines = Get-Content -Path $file.FullName
|
||||||
,($lines | % { $_.TrimStart() }) | Rewrite-File $file
|
,($lines | % { $_.TrimStart() }) | Rewrite-File $file
|
||||||
}
|
}
|
||||||
|
}catch{
|
||||||
|
Write-Host "Encountered an error while running PostBuild.ps1 on line" $_.InvocationInfo.ScriptLineNumber
|
||||||
|
Write-Host $_
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
@@ -814,25 +814,63 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Make middle click on tweet reply icon open the compose drawer. Only works for non-temporary columns.
|
// Block: Make middle click on tweet reply icon open the compose drawer, retweet icon trigger a quote, and favorite icon open a 'Like from accounts...' modal.
|
||||||
//
|
//
|
||||||
app.delegate(".js-reply-action", "auxclick", function(e){
|
app.delegate(".tweet-action,.tweet-detail-action", "auxclick", function(e){
|
||||||
if (e.which === 2){
|
return if e.which !== 2;
|
||||||
let column = $(this).closest(".js-column");
|
|
||||||
|
|
||||||
if (column && column.hasClass("column") && $("[data-drawer='compose']").hasClass("is-hidden")){
|
let column = TD.controller.columnManager.get($(this).closest("section.js-column").attr("data-column"));
|
||||||
$(document).trigger("uiDrawerShowDrawer", {
|
return if !column;
|
||||||
drawer: "compose",
|
|
||||||
withAnimation: true
|
let ele = $(this).closest("article");
|
||||||
|
let tweet = column.findChirp(ele.attr("data-tweet-id")) || column.findChirp(ele.attr("data-key"));
|
||||||
|
return if !tweet;
|
||||||
|
|
||||||
|
switch($(this).attr("rel")){
|
||||||
|
case "reply":
|
||||||
|
let main = tweet.getMainTweet();
|
||||||
|
|
||||||
|
$(document).trigger("uiDockedComposeTweet", {
|
||||||
|
type: "reply",
|
||||||
|
from: [ tweet.account.getKey() ],
|
||||||
|
inReplyTo: {
|
||||||
|
id: tweet.id,
|
||||||
|
htmlText: main.htmlText,
|
||||||
|
user: {
|
||||||
|
screenName: main.user.screenName,
|
||||||
|
name: main.user.name,
|
||||||
|
profileImageURL: main.user.profileImageURL
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mentions: tweet.getReplyUsers(),
|
||||||
|
element: ele
|
||||||
});
|
});
|
||||||
|
|
||||||
window.setTimeout(() => $(this).trigger("click"), 1);
|
break;
|
||||||
|
|
||||||
|
case "favorite":
|
||||||
|
$(document).trigger("uiShowFavoriteFromOptions", { tweet });
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "retweet":
|
||||||
|
TD.controller.stats.quoteTweet();
|
||||||
|
|
||||||
|
$(document).trigger("uiComposeTweet", {
|
||||||
|
type: "tweet",
|
||||||
|
from: [ tweet.account.getKey() ],
|
||||||
|
quotedTweet: tweet.getMainTweet(),
|
||||||
|
element: ele // triggers reply-account plugin
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -890,12 +928,12 @@
|
|||||||
// Block: Setup video player hooks.
|
// Block: Setup video player hooks.
|
||||||
//
|
//
|
||||||
(function(){
|
(function(){
|
||||||
var playVideo = function(url){
|
window.TDGF_playVideo = function(url, username){
|
||||||
$('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
|
$('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
|
||||||
$TD.playVideo(null);
|
$TD.playVideo(null, null);
|
||||||
}).appendTo(app);
|
}).appendTo(app);
|
||||||
|
|
||||||
$TD.playVideo(url);
|
$TD.playVideo(url, username || null);
|
||||||
};
|
};
|
||||||
|
|
||||||
var getVideoTweetLink = function(obj){
|
var getVideoTweetLink = function(obj){
|
||||||
@@ -904,12 +942,16 @@
|
|||||||
return link.attr("href");
|
return link.attr("href");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var getUsername = function(tweet){
|
||||||
|
return tweet && (tweet.quotedTweet || tweet).getMainUser().screenName;
|
||||||
|
}
|
||||||
|
|
||||||
app.delegate(".js-gif-play", {
|
app.delegate(".js-gif-play", {
|
||||||
click: function(e){
|
click: function(e){
|
||||||
let src = !e.ctrlKey && $(this).closest(".js-media-gif-container").find("video").attr("src");
|
let src = !e.ctrlKey && $(this).closest(".js-media-gif-container").find("video").attr("src");
|
||||||
|
|
||||||
if (src){
|
if (src){
|
||||||
playVideo(src);
|
window.TDGF_playVideo(src, getUsername(highlightedTweetObj));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$TD.openBrowser(getVideoTweetLink($(this)));
|
$TD.openBrowser(getVideoTweetLink($(this)));
|
||||||
@@ -945,7 +987,7 @@
|
|||||||
let media = this.chirp.getMedia().find(media => media.mediaId === this.clickedMediaEntityId);
|
let media = this.chirp.getMedia().find(media => media.mediaId === this.clickedMediaEntityId);
|
||||||
|
|
||||||
if (media && media.isVideo && media.service === "twitter"){
|
if (media && media.isVideo && media.service === "twitter"){
|
||||||
playVideo(media.chooseVideoVariant().url);
|
window.TDGF_playVideo(media.chooseVideoVariant().url, getUsername(this.chirp));
|
||||||
cancelModal = true;
|
cancelModal = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -87,14 +87,14 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Setup global function to change plugin state.
|
// Block: Setup a function to change plugin state.
|
||||||
//
|
//
|
||||||
window.TDPF_setPluginState = function(identifier, enable){
|
window.TDPF_setPluginState = function(identifier, enable){
|
||||||
window.TD_PLUGINS.setState(window.TD_PLUGINS.findObject(identifier), enable);
|
window.TD_PLUGINS.setState(window.TD_PLUGINS.findObject(identifier), enable);
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Setup global function to reload the page.
|
// Block: Setup a function to reload the page.
|
||||||
//
|
//
|
||||||
window.TDPF_requestReload = function(){
|
window.TDPF_requestReload = function(){
|
||||||
if (!isReloading){
|
if (!isReloading){
|
||||||
@@ -102,4 +102,9 @@
|
|||||||
isReloading = true;
|
isReloading = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Block: Setup a function to allow plugins to play video.
|
||||||
|
//
|
||||||
|
window.TDPF_playVideo = window.TDGF_playVideo;
|
||||||
})();
|
})();
|
||||||
|
@@ -46,7 +46,7 @@
|
|||||||
border-radius: 1px !important;
|
border-radius: 1px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-text-container, .compose-reply-tweet, .compose-message-recipient-input-container, .compose-message-recipient, .compose-media-bar-holder, .media-grid-container {
|
.compose-text-container, .compose-reply-tweet, .compose-message-recipient-input-container, .compose-message-recipient, .compose-media-bar-holder, .media-grid-container, .js-quote-tweet-holder {
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ namespace TweetDuck.Updates{
|
|||||||
timerDownloadCheck.Stop();
|
timerDownloadCheck.Stop();
|
||||||
|
|
||||||
if (FormMessage.Error("Update Has Failed", "Could not download the update: "+(updateInfo.DownloadError?.Message ?? "unknown error")+"\n\nDo you want to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
|
if (FormMessage.Error("Update Has Failed", "Could not download the update: "+(updateInfo.DownloadError?.Message ?? "unknown error")+"\n\nDo you want to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe(Program.Website);
|
BrowserUtils.OpenExternalBrowser(Program.Website);
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user