Merge branch 'replace-puppeteer-with-playwright' of https://git.ofdl.tools/whimsical-c4lic0/OF-DL into replace-puppeteer-with-playwright

This commit is contained in:
whimsical-c4lic0 2025-12-13 02:09:33 -06:00
commit 5c57178f5b
5 changed files with 157 additions and 52 deletions

View File

@ -31,6 +31,8 @@ public class APIHelper : IAPIHelper
private readonly Auth auth; private readonly Auth auth;
private static DateTime? cachedDynamicRulesExpiration; private static DateTime? cachedDynamicRulesExpiration;
private static DynamicRules? cachedDynamicRules; private static DynamicRules? cachedDynamicRules;
private const int MaxAttempts = 30;
private const int DelayBetweenAttempts = 3000;
static APIHelper() static APIHelper()
{ {
@ -2674,13 +2676,10 @@ public class APIHelper : IAPIHelper
return DateTime.Now; return DateTime.Now;
} }
public async Task<string> GetDecryptionKeyCDRMProject(Dictionary<string, string> drmHeaders, string licenceURL, string pssh) public async Task<string> GetDecryptionKeyCDRMProject(Dictionary<string, string> drmHeaders, string licenceURL, string pssh)
{ {
Log.Debug("Calling GetDecryptionKey"); Log.Debug("Calling GetDecryptionKey");
const int maxAttempts = 30;
const int delayBetweenAttempts = 3000;
int attempt = 0; int attempt = 0;
try try
@ -2701,7 +2700,7 @@ public class APIHelper : IAPIHelper
Log.Debug($"Posting to CDRM Project: {json}"); Log.Debug($"Posting to CDRM Project: {json}");
while (attempt < maxAttempts) while (attempt < MaxAttempts)
{ {
attempt++; attempt++;
@ -2727,19 +2726,19 @@ public class APIHelper : IAPIHelper
} }
else else
{ {
Log.Debug($"CDRM response status not successful. Retrying... Attempt {attempt} of {maxAttempts}"); Log.Debug($"CDRM response status not successful. Retrying... Attempt {attempt} of {MaxAttempts}");
if (attempt < maxAttempts) if (attempt < MaxAttempts)
{ {
await Task.Delay(delayBetweenAttempts); await Task.Delay(DelayBetweenAttempts);
} }
} }
} }
else else
{ {
Log.Debug($"Status not in CDRM response. Retrying... Attempt {attempt} of {maxAttempts}"); Log.Debug($"Status not in CDRM response. Retrying... Attempt {attempt} of {MaxAttempts}");
if (attempt < maxAttempts) if (attempt < MaxAttempts)
{ {
await Task.Delay(delayBetweenAttempts); await Task.Delay(DelayBetweenAttempts);
} }
} }
} }
@ -2764,11 +2763,10 @@ public class APIHelper : IAPIHelper
{ {
Log.Debug("Calling GetDecryptionOFDL"); Log.Debug("Calling GetDecryptionOFDL");
try try
{ {
string dcValue = string.Empty;
HttpClient client = new(); HttpClient client = new();
int attempt = 0;
OFDLRequest ofdlRequest = new OFDLRequest OFDLRequest ofdlRequest = new OFDLRequest
{ {
@ -2781,6 +2779,10 @@ public class APIHelper : IAPIHelper
Log.Debug($"Posting to ofdl.tools: {json}"); Log.Debug($"Posting to ofdl.tools: {json}");
while (attempt < MaxAttempts)
{
attempt++;
HttpRequestMessage request = new(HttpMethod.Post, "https://ofdl.tools/WV") HttpRequestMessage request = new(HttpMethod.Post, "https://ofdl.tools/WV")
{ {
Content = new StringContent(json, Encoding.UTF8, "application/json") Content = new StringContent(json, Encoding.UTF8, "application/json")
@ -2788,10 +2790,16 @@ public class APIHelper : IAPIHelper
using var response = await client.SendAsync(request); using var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ continue;
string body = await response.Content.ReadAsStringAsync(); string body = await response.Content.ReadAsStringAsync();
if (!body.TrimStart().StartsWith('{'))
return body; return body;
Log.Debug($"Received JSON object instead of string. Retrying... Attempt {attempt} of {MaxAttempts}");
await Task.Delay(DelayBetweenAttempts);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -2805,6 +2813,7 @@ public class APIHelper : IAPIHelper
Log.Error("Inner Exception: {0}\n\nStackTrace: {1}", ex.InnerException.Message, ex.InnerException.StackTrace); Log.Error("Inner Exception: {0}\n\nStackTrace: {1}", ex.InnerException.Message, ex.InnerException.StackTrace);
} }
} }
return null; return null;
} }

View File

@ -6,14 +6,15 @@ namespace OF_DL.Helpers;
public static class VersionHelper public static class VersionHelper
{ {
public static string? GetLatestReleaseTag() private static readonly HttpClient httpClient = new HttpClient();
private const string url = "https://git.ofdl.tools/api/v1/repos/sim0n00ps/OF-DL/releases/latest";
public static async Task<string?> GetLatestReleaseTag(CancellationToken cancellationToken = default)
{ {
Log.Debug("Calling GetLatestReleaseTag"); Log.Debug("Calling GetLatestReleaseTag");
try try
{ {
HttpClient client = new(); var response = await httpClient.GetAsync(url, cancellationToken);
HttpRequestMessage request = new(HttpMethod.Get, "https://git.ofdl.tools/api/v1/repos/sim0n00ps/OF-DL/releases/latest");
using var response = client.Send(request);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
@ -21,7 +22,7 @@ public static class VersionHelper
return null; return null;
} }
var body = response.Content.ReadAsStringAsync().Result; var body = await response.Content.ReadAsStringAsync();
Log.Debug("GetLatestReleaseTag API Response: "); Log.Debug("GetLatestReleaseTag API Response: ");
Log.Debug(body); Log.Debug(body);
@ -36,6 +37,10 @@ public static class VersionHelper
return versionCheckResponse.TagName; return versionCheckResponse.TagName;
} }
catch (OperationCanceledException)
{
throw; // Rethrow timeout exceptions to be handled by the caller
}
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("Exception caught: {0}\n\nStackTrace: {1}", ex.Message, ex.StackTrace); Console.WriteLine("Exception caught: {0}\n\nStackTrace: {1}", ex.Message, ex.StackTrace);

View File

@ -526,7 +526,21 @@ public class Program
// Only run the version check if not in DEBUG mode // Only run the version check if not in DEBUG mode
#if !DEBUG #if !DEBUG
Version localVersion = Assembly.GetEntryAssembly()?.GetName().Version; //Only tested with numeric values. Version localVersion = Assembly.GetEntryAssembly()?.GetName().Version; //Only tested with numeric values.
String? latestReleaseTag = VersionHelper.GetLatestReleaseTag();
// Create a cancellation token with 30 second timeout
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
String? latestReleaseTag = null;
try
{
latestReleaseTag = await VersionHelper.GetLatestReleaseTag(cts.Token);
}
catch (OperationCanceledException)
{
AnsiConsole.Markup("[yellow]Version check timed out after 30 seconds.\n[/]");
Log.Warning("Version check timed out after 30 seconds");
latestReleaseTag = null;
}
if (latestReleaseTag == null) if (latestReleaseTag == null)
{ {
@ -543,7 +557,7 @@ public class Program
{ {
// The version on GitHub is more up to date than this local release. // The version on GitHub is more up to date than this local release.
AnsiConsole.Markup("[red]You are running OF-DL version " + $"{localVersion.Major}.{localVersion.Minor}.{localVersion.Build}\n[/]"); AnsiConsole.Markup("[red]You are running OF-DL version " + $"{localVersion.Major}.{localVersion.Minor}.{localVersion.Build}\n[/]");
AnsiConsole.Markup("[red]Please update to the current release, " + $"{latestGiteaRelease.Major}.{latestGiteaRelease.Minor}.{latestGiteaRelease.Build}: [link]https://git.ofdl.tools/sim0n00ps/OF-DL/releases[/]\n[/]"); AnsiConsole.Markup("[red]Please update to the current release, " + $"{latestGiteaRelease.Major}.{latestGiteaRelease.Minor}.{latestGiteaRelease.Build}: [link=https://git.ofdl.tools/sim0n00ps/OF-DL/releases]https://git.ofdl.tools/sim0n00ps/OF-DL/releases[/]\n[/]");
Log.Debug("Detected outdated client running version " + $"{localVersion.Major}.{localVersion.Minor}.{localVersion.Build}"); Log.Debug("Detected outdated client running version " + $"{localVersion.Major}.{localVersion.Minor}.{localVersion.Build}");
Log.Debug("Latest release version " + $"{latestGiteaRelease.Major}.{latestGiteaRelease.Minor}.{latestGiteaRelease.Build}"); Log.Debug("Latest release version " + $"{latestGiteaRelease.Major}.{latestGiteaRelease.Minor}.{latestGiteaRelease.Build}");
} }
@ -748,6 +762,61 @@ public class Program
{ {
config.FFmpegPath = config.FFmpegPath.Replace(@"\", @"\\"); config.FFmpegPath = config.FFmpegPath.Replace(@"\", @"\\");
} }
// Get FFmpeg version
try
{
var processStartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = config.FFmpegPath,
Arguments = "-version",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (var process = System.Diagnostics.Process.Start(processStartInfo))
{
if (process != null)
{
string output = await process.StandardOutput.ReadToEndAsync();
await process.WaitForExitAsync();
// Log full output
Log.Information("FFmpeg version output:\n{Output}", output);
// Parse first line for console output
string firstLine = output.Split('\n')[0].Trim();
if (firstLine.StartsWith("ffmpeg version"))
{
// Extract version string (text between "ffmpeg version " and " Copyright")
int versionStart = "ffmpeg version ".Length;
int copyrightIndex = firstLine.IndexOf(" Copyright");
if (copyrightIndex > versionStart)
{
string version = firstLine.Substring(versionStart, copyrightIndex - versionStart);
AnsiConsole.Markup($"[green]ffmpeg version detected as {version}[/]\n");
}
else
{
// Fallback if Copyright not found
string version = firstLine.Substring(versionStart);
AnsiConsole.Markup($"[green]ffmpeg version detected as {version}[/]\n");
}
}
else
{
AnsiConsole.Markup($"[yellow]ffmpeg version could not be parsed[/]\n");
}
}
}
}
catch (Exception ex)
{
Log.Warning(ex, "Failed to get FFmpeg version");
AnsiConsole.Markup($"[yellow]Could not retrieve ffmpeg version[/]\n");
}
} }
else else
{ {

View File

@ -516,3 +516,23 @@ Allowed values: Any positive integer or `-1`
Description: You won't need to set this, but if you see errors about the configured timeout of 100 seconds elapsing then Description: You won't need to set this, but if you see errors about the configured timeout of 100 seconds elapsing then
you could set this to be more than 100. It is recommended that you leave this as the default value. you could set this to be more than 100. It is recommended that you leave this as the default value.
## DisableTextSanitization
Type: `boolean`
Default: `false`
Allowed values: `true`, `false`
Description: When enabled, post/message text is stored as-is without XML stripping.
## DownloadVideoResolution
Type: `string`
Default: `"source"`
Allowed values: `"source"`, `"240"`, `"720"`
Description: This allows you to download videos in alternative resolutions, by default videos are downloaded in source resolution but some people prefer smoother videos at a lower resolution.

View File

@ -20,6 +20,8 @@ information about what it does, its default value, and the allowed values.
- [DownloadDateSelection](/config/all-configuration-options#downloaddateselection) - [DownloadDateSelection](/config/all-configuration-options#downloaddateselection)
- [CustomDate](/config/all-configuration-options#customdate) - [CustomDate](/config/all-configuration-options#customdate)
- [ShowScrapeSize](/config/all-configuration-options#showscrapesize) - [ShowScrapeSize](/config/all-configuration-options#showscrapesize)
- [DisableTextSanitization](/config/all-configuration-options#disabletextsanitization)
- [DownloadVideoResolution](/config/all-configuration-options#downloadvideoresolution)
- Media - Media
- [DownloadAvatarHeaderPhoto](/config/all-configuration-options#downloadavatarheaderphoto) - [DownloadAvatarHeaderPhoto](/config/all-configuration-options#downloadavatarheaderphoto)
- [DownloadPaidPosts](/config/all-configuration-options#downloadpaidposts) - [DownloadPaidPosts](/config/all-configuration-options#downloadpaidposts)