forked from sim0n00ps/OF-DL
Compare commits
3 Commits
already_do
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 167d6640e3 | |||
| e9786f2341 | |||
|
|
0eae466368 |
@ -630,7 +630,36 @@ public class DownloadHelper : IDownloadHelper
|
||||
// break;
|
||||
//}
|
||||
|
||||
string parameters = $"-cenc_decryption_key {decKey} -headers \"Cookie:CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {sess} Origin: https://onlyfans.com Referer: https://onlyfans.com User-Agent: {user_agent}\" -y -i \"{url}\" -map 0:v:{streamIndex} -map 0:a? -codec copy \"{tempFilename}\"";
|
||||
// Configure ffmpeg log level and optional report file location
|
||||
bool ffmpegDebugLogging = Log.IsEnabled(Serilog.Events.LogEventLevel.Debug);
|
||||
|
||||
string logLevelArgs = ffmpegDebugLogging || downloadConfig.LoggingLevel is LoggingLevel.Verbose or LoggingLevel.Debug
|
||||
? "-loglevel debug -report"
|
||||
: downloadConfig.LoggingLevel switch
|
||||
{
|
||||
LoggingLevel.Information => "-loglevel info",
|
||||
LoggingLevel.Warning => "-loglevel warning",
|
||||
LoggingLevel.Error => "-loglevel error",
|
||||
LoggingLevel.Fatal => "-loglevel fatal",
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
if (logLevelArgs.Contains("-report", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Direct ffmpeg report files into the same logs directory Serilog uses (relative to current working directory)
|
||||
string logDir = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "logs"));
|
||||
Directory.CreateDirectory(logDir);
|
||||
string ffReportPath = Path.Combine(logDir, "ffmpeg-%p-%t.log"); // ffmpeg will replace %p/%t
|
||||
Environment.SetEnvironmentVariable("FFREPORT", $"file={ffReportPath}:level=32");
|
||||
Log.Debug("FFREPORT enabled at: {FFREPORT} (cwd: {Cwd})", Environment.GetEnvironmentVariable("FFREPORT"), Environment.CurrentDirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
Environment.SetEnvironmentVariable("FFREPORT", null);
|
||||
Log.Debug("FFREPORT disabled (cwd: {Cwd})", Environment.CurrentDirectory);
|
||||
}
|
||||
|
||||
string parameters = $"{logLevelArgs} -cenc_decryption_key {decKey} -headers \"Cookie:CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {sess} Origin: https://onlyfans.com Referer: https://onlyfans.com User-Agent: {user_agent}\" -y -i \"{url}\" -map 0:v:{streamIndex} -map 0:a? -codec copy \"{tempFilename}\"".Trim();
|
||||
|
||||
Log.Debug($"Calling FFMPEG with Parameters: {parameters}");
|
||||
|
||||
@ -965,10 +994,20 @@ public class DownloadHelper : IDownloadHelper
|
||||
|
||||
private void OnError(object sender, ConversionErrorEventArgs e)
|
||||
{
|
||||
Log.Debug("[{0} => {1}]: Error: {2}\n{3}", e.Input.Name, e.Output.Name, e.Exception.ExitCode, e.Exception.InnerException);
|
||||
// Guard all fields to avoid NullReference exceptions from FFmpeg.NET
|
||||
var input = e?.Input?.Name ?? "<none>";
|
||||
var output = e?.Output?.Name ?? "<none>";
|
||||
var exitCode = e?.Exception?.ExitCode.ToString() ?? "<unknown>";
|
||||
var message = e?.Exception?.Message ?? "<no message>";
|
||||
var inner = e?.Exception?.InnerException?.Message ?? "<no inner>";
|
||||
|
||||
Log.Error("FFmpeg failed. Input={Input} Output={Output} ExitCode={ExitCode} Message={Message} Inner={Inner}",
|
||||
input, output, exitCode, message, inner);
|
||||
|
||||
_completionSource?.TrySetResult(false);
|
||||
}
|
||||
|
||||
|
||||
#region drm posts
|
||||
public async Task<bool> DownloadMessageDRMVideo(string policy, string signature, string kvp, string url, string decryptionKey, string folder, DateTime lastModified, long media_id, string api_type, ProgressTask task, string? filenameFormat, Messages.List? messageInfo, Messages.Medium? messageMedia, Messages.FromUser? fromUser, Dictionary<string, long> users)
|
||||
{
|
||||
|
||||
228
OF DL/Program.cs
228
OF DL/Program.cs
@ -131,6 +131,10 @@ public class Program
|
||||
if (jsonConfig != null)
|
||||
{
|
||||
var hoconConfig = new StringBuilder();
|
||||
hoconConfig.AppendLine("# Auth");
|
||||
hoconConfig.AppendLine("Auth {");
|
||||
hoconConfig.AppendLine($" DisableBrowserAuth = \"{jsonConfig.DisableBrowserAuth.ToString().ToLower()}\"");
|
||||
hoconConfig.AppendLine("}");
|
||||
hoconConfig.AppendLine("# External Tools");
|
||||
hoconConfig.AppendLine("External {");
|
||||
hoconConfig.AppendLine($" FFmpegPath = \"{jsonConfig.FFmpegPath}\"");
|
||||
@ -255,7 +259,7 @@ public class Program
|
||||
config = new Entities.Config
|
||||
{
|
||||
//Auth
|
||||
DisableBrowserAuth = hoconConfig.GetBoolean("DisableBrowserAuth"),
|
||||
DisableBrowserAuth = hoconConfig.GetBoolean("Auth.DisableBrowserAuth"),
|
||||
|
||||
// FFmpeg Settings
|
||||
FFmpegPath = hoconConfig.GetString("External.FFmpegPath"),
|
||||
@ -375,7 +379,9 @@ public class Program
|
||||
Entities.Config jsonConfig = new Entities.Config();
|
||||
var hoconConfig = new StringBuilder();
|
||||
hoconConfig.AppendLine("# Auth");
|
||||
hoconConfig.AppendLine($"DisableBrowserAuth = {jsonConfig.DisableBrowserAuth.ToString().ToLower()}");
|
||||
hoconConfig.AppendLine("Auth {");
|
||||
hoconConfig.AppendLine($" DisableBrowserAuth = \"{jsonConfig.DisableBrowserAuth.ToString().ToLower()}\"");
|
||||
hoconConfig.AppendLine("}");
|
||||
hoconConfig.AppendLine("# External Tools");
|
||||
hoconConfig.AppendLine("External {");
|
||||
hoconConfig.AppendLine($" FFmpegPath = \"{jsonConfig.FFmpegPath}\"");
|
||||
@ -2689,66 +2695,82 @@ public class Program
|
||||
return;
|
||||
}
|
||||
|
||||
long totalSize = 0;
|
||||
if (downloadContext.DownloadConfig.ShowScrapeSize)
|
||||
long totalSize = 0;
|
||||
if (downloadContext.DownloadConfig.ShowScrapeSize)
|
||||
{
|
||||
totalSize = await downloadContext.DownloadHelper.CalculateTotalFileSize(post.SinglePosts.Values.ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
totalSize = post.SinglePosts.Count;
|
||||
}
|
||||
bool isNew = false;
|
||||
await AnsiConsole.Progress()
|
||||
.Columns(GetProgressColumns(downloadContext.DownloadConfig.ShowScrapeSize))
|
||||
.StartAsync(async ctx =>
|
||||
{
|
||||
var task = ctx.AddTask($"[red]Downloading Post[/]", autoStart: false);
|
||||
task.MaxValue = totalSize;
|
||||
task.StartTask();
|
||||
foreach (KeyValuePair<long, string> postKVP in post.SinglePosts)
|
||||
{
|
||||
totalSize = await downloadContext.DownloadHelper.CalculateTotalFileSize(post.SinglePosts.Values.ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
totalSize = post.SinglePosts.Count;
|
||||
}
|
||||
|
||||
bool anyNew = false;
|
||||
bool anyExisting = false;
|
||||
bool anyFailed = false;
|
||||
await AnsiConsole.Progress()
|
||||
.Columns(GetProgressColumns(downloadContext.DownloadConfig.ShowScrapeSize))
|
||||
.StartAsync(async ctx =>
|
||||
{
|
||||
var task = ctx.AddTask($"[red]Downloading Post[/]", autoStart: false);
|
||||
task.MaxValue = totalSize;
|
||||
task.StartTask();
|
||||
foreach (KeyValuePair<long, string> postKVP in post.SinglePosts)
|
||||
if (postKVP.Value.Contains("cdn3.onlyfans.com/dash/files"))
|
||||
{
|
||||
if (postKVP.Value.Contains("cdn3.onlyfans.com/dash/files"))
|
||||
string[] messageUrlParsed = postKVP.Value.Split(',');
|
||||
string mpdURL = messageUrlParsed[0];
|
||||
string policy = messageUrlParsed[1];
|
||||
string signature = messageUrlParsed[2];
|
||||
string kvp = messageUrlParsed[3];
|
||||
string mediaId = messageUrlParsed[4];
|
||||
string postId = messageUrlParsed[5];
|
||||
string? licenseURL = null;
|
||||
string? pssh = await downloadContext.ApiHelper.GetDRMMPDPSSH(mpdURL, policy, signature, kvp);
|
||||
if (pssh == null)
|
||||
{
|
||||
string[] messageUrlParsed = postKVP.Value.Split(',');
|
||||
string mpdURL = messageUrlParsed[0];
|
||||
string policy = messageUrlParsed[1];
|
||||
string signature = messageUrlParsed[2];
|
||||
string kvp = messageUrlParsed[3];
|
||||
string mediaId = messageUrlParsed[4];
|
||||
string postId = messageUrlParsed[5];
|
||||
string? licenseURL = null;
|
||||
string? pssh = await downloadContext.ApiHelper.GetDRMMPDPSSH(mpdURL, policy, signature, kvp);
|
||||
if (pssh == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
DateTime lastModified = await downloadContext.ApiHelper.GetDRMMPDLastModified(mpdURL, policy, signature, kvp);
|
||||
Dictionary<string, string> drmHeaders = downloadContext.ApiHelper.GetDynamicHeaders($"/api2/v2/users/media/{mediaId}/drm/post/{postId}", "?type=widevine");
|
||||
string decryptionKey;
|
||||
if (clientIdBlobMissing || devicePrivateKeyMissing)
|
||||
{
|
||||
decryptionKey = await downloadContext.ApiHelper.GetDecryptionKeyOFDL(drmHeaders, $"https://onlyfans.com/api2/v2/users/media/{mediaId}/drm/post/{postId}?type=widevine", pssh);
|
||||
}
|
||||
else
|
||||
{
|
||||
decryptionKey = await downloadContext.ApiHelper.GetDecryptionKeyCDM(drmHeaders, $"https://onlyfans.com/api2/v2/users/media/{mediaId}/drm/post/{postId}?type=widevine", pssh);
|
||||
}
|
||||
SinglePost.Medium mediaInfo = post.SinglePostMedia.FirstOrDefault(m => m.id == postKVP.Key);
|
||||
SinglePost postInfo = post.SinglePostObjects.FirstOrDefault(p => p?.media?.Contains(mediaInfo) == true);
|
||||
DateTime lastModified = await downloadContext.ApiHelper.GetDRMMPDLastModified(mpdURL, policy, signature, kvp);
|
||||
Dictionary<string, string> drmHeaders = downloadContext.ApiHelper.GetDynamicHeaders($"/api2/v2/users/media/{mediaId}/drm/post/{postId}", "?type=widevine");
|
||||
string decryptionKey;
|
||||
if (clientIdBlobMissing || devicePrivateKeyMissing)
|
||||
{
|
||||
decryptionKey = await downloadContext.ApiHelper.GetDecryptionKeyOFDL(drmHeaders, $"https://onlyfans.com/api2/v2/users/media/{mediaId}/drm/post/{postId}?type=widevine", pssh);
|
||||
}
|
||||
else
|
||||
{
|
||||
decryptionKey = await downloadContext.ApiHelper.GetDecryptionKeyCDM(drmHeaders, $"https://onlyfans.com/api2/v2/users/media/{mediaId}/drm/post/{postId}?type=widevine", pssh);
|
||||
}
|
||||
SinglePost.Medium mediaInfo = post.SinglePostMedia.FirstOrDefault(m => m.id == postKVP.Key);
|
||||
SinglePost postInfo = post.SinglePostObjects.FirstOrDefault(p => p?.media?.Contains(mediaInfo) == true);
|
||||
|
||||
bool downloaded = await downloadContext.DownloadHelper.DownloadPostDRMVideo(
|
||||
policy: policy,
|
||||
signature: signature,
|
||||
kvp: kvp,
|
||||
url: mpdURL,
|
||||
decryptionKey: decryptionKey,
|
||||
isNew = await downloadContext.DownloadHelper.DownloadPostDRMVideo(
|
||||
policy: policy,
|
||||
signature: signature,
|
||||
kvp: kvp,
|
||||
url: mpdURL,
|
||||
decryptionKey: decryptionKey,
|
||||
folder: path,
|
||||
lastModified: lastModified,
|
||||
media_id: postKVP.Key,
|
||||
api_type: "Posts",
|
||||
task: task,
|
||||
filenameFormat: downloadContext.FileNameFormatConfig.PostFileNameFormat ?? string.Empty,
|
||||
postInfo: postInfo,
|
||||
postMedia: mediaInfo,
|
||||
author: postInfo?.author,
|
||||
users: users);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
SinglePost.Medium? mediaInfo = post.SinglePostMedia.FirstOrDefault(m => (m?.id == postKVP.Key) == true);
|
||||
SinglePost? postInfo = post.SinglePostObjects.FirstOrDefault(p => p?.media?.Contains(mediaInfo) == true);
|
||||
|
||||
isNew = await downloadContext.DownloadHelper.DownloadPostMedia(
|
||||
url: postKVP.Value,
|
||||
folder: path,
|
||||
lastModified: lastModified,
|
||||
media_id: postKVP.Key,
|
||||
api_type: "Posts",
|
||||
task: task,
|
||||
@ -2757,84 +2779,26 @@ public class Program
|
||||
postMedia: mediaInfo,
|
||||
author: postInfo?.author,
|
||||
users: users);
|
||||
if (downloaded)
|
||||
{
|
||||
anyNew = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool recorded = await downloadContext.DBHelper.CheckDownloaded(path, postKVP.Key, "Posts");
|
||||
if (recorded)
|
||||
{
|
||||
anyExisting = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
anyFailed = true;
|
||||
Log.Error("Failed to download DRM media {MediaId} for post {PostId}; not marked downloaded", postKVP.Key, post_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
SinglePost.Medium? mediaInfo = post.SinglePostMedia.FirstOrDefault(m => (m?.id == postKVP.Key) == true);
|
||||
SinglePost? postInfo = post.SinglePostObjects.FirstOrDefault(p => p?.media?.Contains(mediaInfo) == true);
|
||||
|
||||
bool downloaded = await downloadContext.DownloadHelper.DownloadPostMedia(
|
||||
url: postKVP.Value,
|
||||
folder: path,
|
||||
media_id: postKVP.Key,
|
||||
api_type: "Posts",
|
||||
task: task,
|
||||
filenameFormat: downloadContext.FileNameFormatConfig.PostFileNameFormat ?? string.Empty,
|
||||
postInfo: postInfo,
|
||||
postMedia: mediaInfo,
|
||||
author: postInfo?.author,
|
||||
users: users);
|
||||
if (downloaded)
|
||||
{
|
||||
anyNew = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool recorded = await downloadContext.DBHelper.CheckDownloaded(path, postKVP.Key, "Posts");
|
||||
if (recorded)
|
||||
{
|
||||
anyExisting = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
anyFailed = true;
|
||||
Log.Error("Failed to download media {MediaId} for post {PostId}; not marked downloaded", postKVP.Key, post_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Media was null");
|
||||
}
|
||||
Console.WriteLine("Media was null");
|
||||
}
|
||||
}
|
||||
task.StopTask();
|
||||
});
|
||||
if (anyNew)
|
||||
{
|
||||
AnsiConsole.Markup($"[red]Post {post_id} downloaded\n[/]");
|
||||
Log.Debug($"Post {post_id} downloaded");
|
||||
}
|
||||
else if (anyExisting && !anyFailed)
|
||||
{
|
||||
AnsiConsole.Markup($"[red]Post {post_id} already downloaded\n[/]");
|
||||
Log.Debug($"Post {post_id} already downloaded");
|
||||
}
|
||||
else
|
||||
{
|
||||
AnsiConsole.Markup($"[red]Post {post_id} failed to download; no media marked as downloaded\n[/]");
|
||||
Log.Error("Post {PostId} failed to download; no media marked as downloaded", post_id);
|
||||
}
|
||||
task.StopTask();
|
||||
});
|
||||
if (isNew)
|
||||
{
|
||||
AnsiConsole.Markup($"[red]Post {post_id} downloaded\n[/]");
|
||||
Log.Debug($"Post {post_id} downloaded");
|
||||
}
|
||||
else
|
||||
{
|
||||
AnsiConsole.Markup($"[red]Post {post_id} already downloaded\n[/]");
|
||||
Log.Debug($"Post {post_id} already downloaded");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<(bool IsExit, Dictionary<string, long>? selectedUsers, Entities.Config? updatedConfig)> HandleUserSelection(APIHelper apiHelper, Entities.Config currentConfig, Dictionary<string, long> users, Dictionary<string, long> lists)
|
||||
{
|
||||
@ -2992,7 +2956,9 @@ public class Program
|
||||
|
||||
var hoconConfig = new StringBuilder();
|
||||
hoconConfig.AppendLine("# Auth");
|
||||
hoconConfig.AppendLine($"DisableBrowserAuth = {newConfig.DisableBrowserAuth.ToString().ToLower()}");
|
||||
hoconConfig.AppendLine("Auth {");
|
||||
hoconConfig.AppendLine($" DisableBrowserAuth = \"{newConfig.DisableBrowserAuth.ToString().ToLower()}\"");
|
||||
hoconConfig.AppendLine("}");
|
||||
hoconConfig.AppendLine("# External Tools");
|
||||
hoconConfig.AppendLine("External {");
|
||||
hoconConfig.AppendLine($" FFmpegPath = \"{newConfig.FFmpegPath}\"");
|
||||
@ -3152,7 +3118,9 @@ public class Program
|
||||
|
||||
var hoconConfig = new StringBuilder();
|
||||
hoconConfig.AppendLine("# Auth");
|
||||
hoconConfig.AppendLine($"DisableBrowserAuth = {newConfig.DisableBrowserAuth.ToString().ToLower()}");
|
||||
hoconConfig.AppendLine("Auth {");
|
||||
hoconConfig.AppendLine($" DisableBrowserAuth = \"{newConfig.DisableBrowserAuth.ToString().ToLower()}\"");
|
||||
hoconConfig.AppendLine("}");
|
||||
hoconConfig.AppendLine("# External Tools");
|
||||
hoconConfig.AppendLine("External {");
|
||||
hoconConfig.AppendLine($" FFmpegPath = \"{newConfig.FFmpegPath}\"");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user