mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-06 05:34:05 +02:00
Fix downloading images from DMs
This commit is contained in:
parent
af5d785ff2
commit
38b1057a4c
@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using TweetDuck.Browser.Handling;
|
||||
using TweetDuck.Management;
|
||||
using TweetDuck.Utils;
|
||||
using TweetLib.Browser.Base;
|
||||
using TweetLib.Browser.Events;
|
||||
@ -15,8 +17,7 @@ internal abstract class CefBrowserComponent : IBrowserComponent {
|
||||
public bool Ready { get; private set; }
|
||||
|
||||
public string Url => browser.Address;
|
||||
|
||||
public IFileDownloader FileDownloader => TwitterFileDownloader.Instance;
|
||||
public string CacheFolder => BrowserCache.CacheFolder;
|
||||
|
||||
public event EventHandler<BrowserLoadedEventArgs> BrowserLoaded;
|
||||
public event EventHandler<PageLoadEventArgs> PageLoadStart;
|
||||
@ -100,5 +101,25 @@ public void RunScript(string identifier, string script) {
|
||||
using IFrame frame = browser.GetMainFrame();
|
||||
frame.ExecuteJavaScriptAsync(script, identifier, 1);
|
||||
}
|
||||
|
||||
public void DownloadFile(string url, string path, Action onSuccess, Action<Exception> onError) {
|
||||
Cef.UIThreadTaskFactory.StartNew(() => {
|
||||
try {
|
||||
using IFrame frame = browser.GetMainFrame();
|
||||
var request = frame.CreateRequest(false);
|
||||
|
||||
request.Method = "GET";
|
||||
request.Url = url;
|
||||
request.Flags = UrlRequestFlags.AllowStoredCredentials;
|
||||
request.SetReferrer(Url, ReferrerPolicy.Default);
|
||||
|
||||
var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
var client = new DownloadRequestClient(fileStream, onSuccess, onError);
|
||||
frame.CreateUrlRequest(request, client);
|
||||
} catch (Exception e) {
|
||||
onError?.Invoke(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
62
Browser/Handling/DownloadRequestClient.cs
Normal file
62
Browser/Handling/DownloadRequestClient.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using CefSharp;
|
||||
|
||||
namespace TweetDuck.Browser.Handling {
|
||||
sealed class DownloadRequestClient : UrlRequestClient {
|
||||
private readonly FileStream fileStream;
|
||||
private readonly Action onSuccess;
|
||||
private readonly Action<Exception> onError;
|
||||
|
||||
private bool hasFailed;
|
||||
|
||||
public DownloadRequestClient(FileStream fileStream, Action onSuccess, Action<Exception> onError) {
|
||||
this.fileStream = fileStream;
|
||||
this.onSuccess = onSuccess;
|
||||
this.onError = onError;
|
||||
}
|
||||
|
||||
protected override bool GetAuthCredentials(bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback) {
|
||||
onError?.Invoke(new Exception("This URL requires authentication."));
|
||||
fileStream.Dispose();
|
||||
hasFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void OnDownloadData(IUrlRequest request, Stream data) {
|
||||
if (hasFailed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
data.CopyTo(fileStream);
|
||||
} catch (Exception e) {
|
||||
fileStream.Dispose();
|
||||
onError?.Invoke(e);
|
||||
hasFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRequestComplete(IUrlRequest request) {
|
||||
if (hasFailed) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isEmpty = fileStream.Position == 0;
|
||||
fileStream.Dispose();
|
||||
|
||||
var status = request.RequestStatus;
|
||||
if (status == UrlRequestStatus.Failed) {
|
||||
onError?.Invoke(new Exception("Unknown error."));
|
||||
}
|
||||
else if (status == UrlRequestStatus.Success) {
|
||||
if (isEmpty) {
|
||||
onError?.Invoke(new Exception("File is empty."));
|
||||
return;
|
||||
}
|
||||
|
||||
onSuccess?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -106,6 +106,7 @@
|
||||
<Compile Include="Browser\Handling\ContextMenuNotification.cs" />
|
||||
<Compile Include="Browser\Handling\CustomKeyboardHandler.cs" />
|
||||
<Compile Include="Browser\Handling\CustomLifeSpanHandler.cs" />
|
||||
<Compile Include="Browser\Handling\DownloadRequestClient.cs" />
|
||||
<Compile Include="Browser\Handling\DragHandlerBrowser.cs" />
|
||||
<Compile Include="Browser\Handling\FileDialogHandler.cs" />
|
||||
<Compile Include="Browser\Handling\JavaScriptDialogHandler.cs" />
|
||||
@ -138,7 +139,6 @@
|
||||
<Compile Include="Updates\UpdateInstaller.cs" />
|
||||
<Compile Include="Utils\BrowserUtils.cs" />
|
||||
<Compile Include="Utils\NativeMethods.cs" />
|
||||
<Compile Include="Utils\TwitterFileDownloader.cs" />
|
||||
<Compile Include="Utils\WindowsUtils.cs" />
|
||||
<Compile Include="Version.cs" />
|
||||
</ItemGroup>
|
||||
|
@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using CefSharp;
|
||||
using TweetDuck.Management;
|
||||
using TweetLib.Browser.Interfaces;
|
||||
using TweetLib.Utils.Static;
|
||||
using Cookie = CefSharp.Cookie;
|
||||
|
||||
namespace TweetDuck.Utils {
|
||||
sealed class TwitterFileDownloader : IFileDownloader {
|
||||
public static TwitterFileDownloader Instance { get; } = new TwitterFileDownloader();
|
||||
|
||||
private TwitterFileDownloader() {}
|
||||
|
||||
public string CacheFolder => BrowserCache.CacheFolder;
|
||||
|
||||
public void DownloadFile(string url, string path, Action onSuccess, Action<Exception> onFailure) {
|
||||
const string authCookieName = "auth_token";
|
||||
|
||||
using ICookieManager cookies = Cef.GetGlobalCookieManager();
|
||||
|
||||
cookies.VisitUrlCookiesAsync(url, true).ContinueWith(task => {
|
||||
string cookieStr = null;
|
||||
|
||||
if (task.Status == TaskStatus.RanToCompletion) {
|
||||
Cookie found = task.Result?.Find(cookie => cookie.Name == authCookieName); // the list may be null
|
||||
|
||||
if (found != null) {
|
||||
cookieStr = $"{found.Name}={found.Value}";
|
||||
}
|
||||
}
|
||||
|
||||
WebClient client = WebUtils.NewClient(BrowserUtils.UserAgentChrome);
|
||||
client.Headers[HttpRequestHeader.Cookie] = cookieStr;
|
||||
client.DownloadFileCompleted += WebUtils.FileDownloadCallback(path, onSuccess, onFailure);
|
||||
client.DownloadFileAsync(new Uri(url), path);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -5,8 +5,7 @@
|
||||
namespace TweetLib.Browser.Interfaces {
|
||||
public interface IBrowserComponent : IScriptExecutor {
|
||||
string Url { get; }
|
||||
|
||||
IFileDownloader FileDownloader { get; }
|
||||
string CacheFolder { get; }
|
||||
|
||||
event EventHandler<BrowserLoadedEventArgs> BrowserLoaded;
|
||||
event EventHandler<PageLoadEventArgs> PageLoadStart;
|
||||
@ -14,5 +13,6 @@ public interface IBrowserComponent : IScriptExecutor {
|
||||
|
||||
void Setup(BrowserSetup setup);
|
||||
void AttachBridgeObject(string name, object bridge);
|
||||
void DownloadFile(string url, string path, Action? onSuccess, Action<Exception>? onError);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace TweetLib.Browser.Interfaces {
|
||||
public interface IFileDownloader {
|
||||
string CacheFolder { get; }
|
||||
void DownloadFile(string url, string path, Action? onSuccess, Action<Exception>? onError);
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ internal class BaseContextMenu : IContextMenuHandler {
|
||||
|
||||
public BaseContextMenu(IBrowserComponent browser) {
|
||||
this.browser = browser;
|
||||
this.fileDownloadManager = new FileDownloadManager(browser.FileDownloader);
|
||||
this.fileDownloadManager = new FileDownloadManager(browser);
|
||||
}
|
||||
|
||||
public virtual void Show(IContextMenuBuilder menu, Context context) {
|
||||
|
@ -14,15 +14,15 @@ public sealed class FileDownloadManager {
|
||||
public bool SupportsCopyingImage => App.SystemHandler.CopyImageFromFile != null;
|
||||
public bool SupportsFileSaving => App.FileDialogs != null;
|
||||
|
||||
private readonly IFileDownloader fileDownloader;
|
||||
private readonly IBrowserComponent browserComponent;
|
||||
|
||||
internal FileDownloadManager(IFileDownloader fileDownloader) {
|
||||
this.fileDownloader = fileDownloader;
|
||||
internal FileDownloadManager(IBrowserComponent browserComponent) {
|
||||
this.browserComponent = browserComponent;
|
||||
}
|
||||
|
||||
private void DownloadTempImage(string url, Action<string> process) {
|
||||
string? staticFileName = TwitterUrls.GetImageFileName(url);
|
||||
string file = Path.Combine(fileDownloader.CacheFolder, staticFileName ?? Path.GetRandomFileName());
|
||||
string file = Path.Combine(browserComponent.CacheFolder, staticFileName ?? Path.GetRandomFileName());
|
||||
|
||||
if (staticFileName != null && FileUtils.FileExistsAndNotEmpty(file)) {
|
||||
process(file);
|
||||
@ -36,7 +36,7 @@ static void OnFailure(Exception ex) {
|
||||
App.MessageDialogs.Error("Image Download", "An error occurred while downloading the image: " + ex.Message);
|
||||
}
|
||||
|
||||
fileDownloader.DownloadFile(url, file, OnSuccess, OnFailure);
|
||||
browserComponent.DownloadFile(url, file, OnSuccess, OnFailure);
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,14 +94,14 @@ static void OnFailure(Exception ex) {
|
||||
}
|
||||
|
||||
if (oneImage) {
|
||||
fileDownloader.DownloadFile(firstImageLink, path, null, OnFailure);
|
||||
browserComponent.DownloadFile(firstImageLink, path, null, OnFailure);
|
||||
}
|
||||
else {
|
||||
string pathBase = Path.ChangeExtension(path, null);
|
||||
string pathExt = Path.GetExtension(path);
|
||||
|
||||
for (int index = 0; index < urls.Length; index++) {
|
||||
fileDownloader.DownloadFile(urls[index], $"{pathBase} {index + 1}{pathExt}", null, OnFailure);
|
||||
browserComponent.DownloadFile(urls[index], $"{pathBase} {index + 1}{pathExt}", null, OnFailure);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -129,7 +129,7 @@ static void OnError(Exception ex) {
|
||||
App.MessageDialogs.Error("Video Download", "An error occurred while downloading the video: " + ex.Message);
|
||||
}
|
||||
|
||||
fileDownloader.DownloadFile(url, path, null, OnError);
|
||||
browserComponent.DownloadFile(url, path, null, OnError);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public sealed class TweetDeckBrowser : BaseBrowser<TweetDeckBrowser> {
|
||||
private const string BackgroundColorOverride = "setTimeout(function f(){let h=document.head;if(!h){setTimeout(f,5);return;}let e=document.createElement('style');e.innerHTML='body,body::before{background:#1c6399!important;margin:0}';h.appendChild(e);},1)";
|
||||
|
||||
public TweetDeckFunctions Functions { get; }
|
||||
public FileDownloadManager FileDownloadManager => new (browserComponent.FileDownloader);
|
||||
public FileDownloadManager FileDownloadManager => new (browserComponent);
|
||||
|
||||
private readonly ISoundNotificationHandler soundNotificationHandler;
|
||||
private readonly PluginManager pluginManager;
|
||||
|
Loading…
Reference in New Issue
Block a user