From 1c7a37960446608e2a7f2ab7d9ed4bf29005dd78 Mon Sep 17 00:00:00 2001
From: crouvpony47 <33804948+crouvpony47@users.noreply.github.com>
Date: Sun, 12 Jan 2025 00:00:16 +0400
Subject: [PATCH] v.2.0.1.0: fix batch mode and minor issues
---
README.md | 20 +++++++++---------
src/AppCore.cs | 11 +---------
src/Program.cs | 23 ++++++++++++++++----
src/Properties/AssemblyInfo.cs | 4 ++--
src/app.manifest | 2 +-
src/authForm.cs | 38 +++++++++++++++++++++++++++++-----
6 files changed, 66 insertions(+), 32 deletions(-)
diff --git a/README.md b/README.md
index 175b15f..10e3011 100644
--- a/README.md
+++ b/README.md
@@ -5,18 +5,18 @@ Yet another mass downloader for FurAffinity.net.
[Download stable win32 builds.](https://github.com/crouvpony47/furdown/releases)
-### Changelog (v.0.5.5.0)
-- adapt to site changes
+### Changelog (v.2.0.1.0)
+- Switched to Edge-based embedded browser for authentification and human verification.
### A note about CF's "I'm Under Attack" mode
-- If you are already logged in but are shown the login form anyway, simply navigate to the FA main page.
+- If you are already logged in but are shown the login form anyway, simply navigate to the FA front page.
### System requirements
-- Windows 7 or newer, might not work on server editions
-- .NET 4.6.2
-- IE11 (for systems where IE11 is not available, compile Furdown from source after adjusting `src/Program.cs:WebBrowserEmulationSet()` accordingly)
+- Windows 7 SP1, 8.1, or 10+. Windows 10 or 11 recommended.
+- .NET Framework 4.6.2
+- Microsoft Edge WebView2 (usually preinstalled on Windows 10 or newer)
-IE11 requirement can be bypassed if you implement an alternative cookie provider, see "Advanced options" section below.
+Edge WebView2 requirement can be bypassed if you implement an alternative cookie provider, see "Advanced options" section below.
### Portable mode
@@ -66,7 +66,7 @@ Override descriptions naming template with TMPLT. __*__
__*__ As templates use the syntax much like that used for environment variables, you may get unexpected results if, say, %FILEPART% is an existing variable.
**Other notes**:
-- You must login in GUI mode at least once before using batch/CLI mode.
+- You must login in GUI mode at least once before using batch/CLI mode unless the cookies/user-agent are provided using the environment variables.
- For non-overridden parameters the value from a current configuration file (the same file used in GUI mode) is used.
**Examples**:
@@ -78,6 +78,6 @@ Note that `%` might need to be escaped as `%%` in batch scripts.
### Advanced options
-The builtin authentication mechanism based on the embedded Internet Explorer can be bypassed by setting FURDOWN_COOKIES and FURDOWN_USERAGENT environment variables to the appropriate values. If only FURDOWN_USERAGENT is set, furdown and its embedded IE will use the User-Agent value provided, and if only FURDOWN_COOKIES is set, it is your responsibility to match the User-Agent of the cookies source and the one used by furdown.
+The builtin authentication mechanism based on the embedded Edge can be bypassed by setting `FURDOWN_COOKIES` and `FURDOWN_USERAGENT` environment variables to the appropriate values. Setting just the `FURDOWN_USERAGENT` has no effect.
-Note that the FURDOWN_COOKIES is expected to contain the entire cookie header value (something like `b=XXX; __gads=XXX; a=XXX; s=XXX; __qca=XXX; sz=XXX; cc=XXX; __cfduid=XXX` where `XXX`s are some values)
+Note that the `FURDOWN_COOKIES` is expected to contain the entire cookie header value (something like `b=XXX; __gads=XXX; a=XXX; s=XXX; __qca=XXX; sz=XXX; cc=XXX; __cfduid=XXX` where `XXX`s are some values)
diff --git a/src/AppCore.cs b/src/AppCore.cs
index 806da19..b6a22be 100644
--- a/src/AppCore.cs
+++ b/src/AppCore.cs
@@ -44,16 +44,6 @@ public class AppCore
public bool isInitialized = false;
- ///
- /// Gets all, including http-only, cookies from WebBrowser component
- ///
- /// URI which is used to get the cookies for
- ///
- private static string GetGlobalCookies(string uri) //fixme
- {
- return CookiesStorage.GetCookieString();
- }
-
///
/// Reads network stream to another stream, throwing excepton if no data was received in reasonable time
///
@@ -153,6 +143,7 @@ public async Task Init()
{
Console.WriteLine("Warning :: could not determine the username to use for the default target gallery url");
}
+ isInitialized = true;
return true;
}
else
diff --git a/src/Program.cs b/src/Program.cs
index c54da45..3895405 100644
--- a/src/Program.cs
+++ b/src/Program.cs
@@ -21,6 +21,7 @@ static void Main()
var args = Environment.GetCommandLineArgs();
if (args.Count() < 2 || args[1] != "-b")
{
+ // GUI mode
if (args.Count() >= 2)
{
Console.WriteLine("Note: found some invalid command line arguments");
@@ -28,13 +29,27 @@ static void Main()
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
- var af = new authForm();
- Application.Run(af);
+ Application.Run(new authForm());
}
else
{
- bool AuthRes = AppCore.Core.Init().Result;
- if (!AuthRes)
+ // batch mode
+ bool hasEnvCookies = (Environment.GetEnvironmentVariable("FURDOWN_COOKIES") != null);
+ bool authRes = false;
+ if (hasEnvCookies)
+ {
+ authRes = AppCore.Core.Init().Result;
+ }
+ else
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ var aForm = new authForm();
+ aForm.BackgroundMode = true;
+ Application.Run(aForm);
+ authRes = AppCore.Core.isInitialized;
+ }
+ if (!authRes)
{
Console.WriteLine("Not authorized! Log in at least once using GUI first.");
Console.WriteLine("Alternatively, provide the 'cookie' and 'user-agent' header values");
diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs
index fa894f4..6f48836 100644
--- a/src/Properties/AssemblyInfo.cs
+++ b/src/Properties/AssemblyInfo.cs
@@ -16,7 +16,7 @@
[assembly: Guid("8b45577e-b5d1-4056-96e6-b2647e18b867")]
-[assembly: AssemblyVersion("2.0.0.0")]
-[assembly: AssemblyFileVersion("2.0.0.0")]
+[assembly: AssemblyVersion("2.0.1.0")]
+[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: NeutralResourcesLanguage("en")]
diff --git a/src/app.manifest b/src/app.manifest
index 03f9094..4af2df1 100644
--- a/src/app.manifest
+++ b/src/app.manifest
@@ -1,6 +1,6 @@
-
+
diff --git a/src/authForm.cs b/src/authForm.cs
index 9ab888b..c1ed402 100644
--- a/src/authForm.cs
+++ b/src/authForm.cs
@@ -27,15 +27,27 @@ public async Task Start()
// initialize WebView2 fully
await edgeWebView.EnsureCoreWebView2Async(null);
// initialize request interception
- edgeWebView.CoreWebView2.AddWebResourceRequestedFilter(
- "https://www.furaffinity.net/*",
- CoreWebView2WebResourceContext.Document,
- CoreWebView2WebResourceRequestSourceKinds.All);
+ try
+ {
+ edgeWebView.CoreWebView2.AddWebResourceRequestedFilter(
+ "https://www.furaffinity.net/*",
+ CoreWebView2WebResourceContext.Document,
+ CoreWebView2WebResourceRequestSourceKinds.All);
+ }
+ catch (Exception)
+ {
+ // fallback to an older (deprecated) filter interface
+ // for legacy WebView versions (i.e. v.109 on Win 7)
+ edgeWebView.CoreWebView2.AddWebResourceRequestedFilter(
+ "https://www.furaffinity.net/*",
+ CoreWebView2WebResourceContext.Document);
+ }
edgeWebView.CoreWebView2.WebResourceRequested += async delegate (
object _sender, CoreWebView2WebResourceRequestedEventArgs args)
{
var uri = new Uri(args.Request.Uri);
- if (uri.AbsolutePath.ToString() == "/" || uri.AbsolutePath.ToString().StartsWith("/user"))
+ if (uri.AbsolutePath.ToString() == "/" || uri.AbsolutePath.ToString().StartsWith("/user")
+ || (uri.AbsolutePath.ToString().StartsWith("/login") && uri.Query.ToString().Contains("__cf")))
{
CoreWebView2HttpRequestHeaders requestHeaders = args.Request.Headers;
if (requestHeaders.Contains("Cookie"))
@@ -67,6 +79,11 @@ public async Task Start()
private void OnAuthSuccessful()
{
+ if (BackgroundMode)
+ {
+ Close();
+ return;
+ }
Hide();
taskForm tf = new taskForm(this, AppCore.Core.defaultUserId);
tf.Show();
@@ -99,6 +116,11 @@ private async void WebViewLoginFlow()
else
{
Console.WriteLine("Does not seem to be authorized (or need to pass CF validation)...");
+ if (BackgroundMode)
+ {
+ Close();
+ return;
+ }
// set up a new login callback
onShouldValidateCookies = async delegate ()
@@ -160,8 +182,14 @@ private async void authForm_Shown(object sender, EventArgs e)
private void authForm_Load(object sender, EventArgs e)
{
Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);
+ if (BackgroundMode)
+ {
+ WindowState = FormWindowState.Minimized;
+ }
}
+ public bool BackgroundMode = false;
+
delegate Task CookieValidationCallback();
private CookieValidationCallback onShouldValidateCookies = null;
}