Address compiler warning

This commit is contained in:
whimsical-c4lic0 2026-02-10 02:08:51 -06:00
parent f7f1fad92d
commit 487de58274
16 changed files with 720 additions and 784 deletions

View File

@ -37,7 +37,7 @@ public class Padding
return result;
}
public static byte[]? AddPSSPadding(byte[] hash)
public static byte[] AddPssPadding(byte[] hash)
{
int modBits = 2048;
int hLen = 20;
@ -49,10 +49,11 @@ public class Padding
lmask = (lmask >> 1) | 0x80;
}
if (emLen < hLen + hLen + 2)
{
return null;
}
// Commented out since the condition will always be false while emLen = 256 and hLen = 20
// if (emLen < hLen + hLen + 2)
// {
// return null;
// }
byte[] salt = new byte[hLen];
new Random().NextBytes(salt);
@ -102,7 +103,7 @@ public class Padding
db[i] = (byte)(maskedDB[i] ^ dbMask[i]);
}
int onePos = BitConverter.ToString(db[hLen..]).Replace("-", "").IndexOf("01") / 2;
int onePos = BitConverter.ToString(db[hLen..]).Replace("-", "").IndexOf("01", StringComparison.Ordinal) / 2;
byte[] unpadded = db[(hLen + onePos + 1)..];
return unpadded;

View File

@ -115,22 +115,22 @@ public class Config : IFileNameFormatConfig
if (CreatorConfigs.TryGetValue(username, out CreatorConfig? creatorConfig))
{
if (creatorConfig?.PaidPostFileNameFormat != null)
if (creatorConfig.PaidPostFileNameFormat != null)
{
combinedFilenameFormatConfig.PaidPostFileNameFormat = creatorConfig.PaidPostFileNameFormat;
}
if (creatorConfig?.PostFileNameFormat != null)
if (creatorConfig.PostFileNameFormat != null)
{
combinedFilenameFormatConfig.PostFileNameFormat = creatorConfig.PostFileNameFormat;
}
if (creatorConfig?.PaidMessageFileNameFormat != null)
if (creatorConfig.PaidMessageFileNameFormat != null)
{
combinedFilenameFormatConfig.PaidMessageFileNameFormat = creatorConfig.PaidMessageFileNameFormat;
}
if (creatorConfig?.MessageFileNameFormat != null)
if (creatorConfig.MessageFileNameFormat != null)
{
combinedFilenameFormatConfig.MessageFileNameFormat = creatorConfig.MessageFileNameFormat;
}

View File

@ -1,5 +1,4 @@
using Newtonsoft.Json;
using OF_DL.Models.Dtos.Archived;
namespace OF_DL.Models.Dtos.Common;

File diff suppressed because it is too large Load Diff

View File

@ -136,6 +136,11 @@ public class AuthService(IServiceProvider serviceProvider) : IAuthService
return;
}
if (string.IsNullOrWhiteSpace(CurrentAuth.Cookie))
{
return;
}
string pattern = @"(auth_id=\d+)|(sess=[^;]+)";
MatchCollection matches = Regex.Matches(CurrentAuth.Cookie, pattern);
@ -176,7 +181,7 @@ public class AuthService(IServiceProvider serviceProvider) : IAuthService
}
}
private async Task<Auth?> GetAuthFromBrowser(bool isDocker = false)
private async Task<Auth?> GetAuthFromBrowser()
{
try
{

View File

@ -44,7 +44,7 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
}
// Check for command-line arguments
if (args != null && args.Length > 0)
if (args.Length > 0)
{
const string NON_INTERACTIVE_ARG = "--non-interactive";
if (args.Any(a => a.Equals(NON_INTERACTIVE_ARG, StringComparison.OrdinalIgnoreCase)))
@ -71,12 +71,6 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
public async Task SaveConfigurationAsync(string filePath = "config.conf")
{
if (CurrentConfig == null)
{
Log.Warning("Attempted to save null config to file");
return;
}
try
{
string hoconConfig = BuildHoconFromConfig(CurrentConfig);
@ -409,7 +403,13 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
ToggleableConfigAttribute? attr = propInfo.GetCustomAttribute<ToggleableConfigAttribute>();
if (attr != null)
{
result.Add((propInfo.Name, (bool)propInfo.GetValue(CurrentConfig)!));
bool? value = (bool?)propInfo.GetValue(CurrentConfig);
if (value == null)
{
continue;
}
result.Add((propInfo.Name, value.Value));
}
}
@ -427,10 +427,16 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
if (attr != null)
{
bool newValue = selectedNames.Contains(propInfo.Name);
bool oldValue = (bool)propInfo.GetValue(CurrentConfig)!;
bool? oldValue = (bool?)propInfo.GetValue(CurrentConfig);
if (oldValue == null)
{
continue;
}
propInfo.SetValue(newConfig, newValue);
if (newValue != oldValue)
if (newValue != oldValue.Value)
{
configChanged = true;
}

View File

@ -219,17 +219,17 @@ public class DBService(IConfigService configService) : IDBService
connection))
{
checkCmd.Parameters.AddWithValue("@userId", user.Value);
using (SqliteDataReader reader = await checkCmd.ExecuteReaderAsync())
await using (SqliteDataReader reader = await checkCmd.ExecuteReaderAsync())
{
if (reader.Read())
{
long storedUserId = reader.GetInt64(0);
string storedUsername = reader.GetString(1);
if (storedUsername != user.Key)
{
using (SqliteCommand updateCmd =
new("UPDATE users SET username = @newUsername WHERE user_id = @userId;", connection))
await using (SqliteCommand updateCmd =
new("UPDATE users SET username = @newUsername WHERE user_id = @userId;",
connection))
{
updateCmd.Parameters.AddWithValue("@newUsername", user.Key);
updateCmd.Parameters.AddWithValue("@userId", user.Value);
@ -278,13 +278,13 @@ public class DBService(IConfigService configService) : IDBService
if (count == 0)
{
// If the record doesn't exist, insert a new one
using SqliteCommand insertCmd =
await using SqliteCommand insertCmd =
new(
"INSERT INTO messages(post_id, text, price, paid, archived, created_at, user_id, record_created_at) VALUES(@post_id, @message_text, @price, @is_paid, @is_archived, @created_at, @user_id, @record_created_at)",
connection);
insertCmd.Parameters.AddWithValue("@post_id", post_id);
insertCmd.Parameters.AddWithValue("@message_text", message_text ?? (object)DBNull.Value);
insertCmd.Parameters.AddWithValue("@price", price ?? (object)DBNull.Value);
insertCmd.Parameters.AddWithValue("@message_text", message_text);
insertCmd.Parameters.AddWithValue("@price", price);
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
insertCmd.Parameters.AddWithValue("@created_at", created_at);
@ -328,8 +328,8 @@ public class DBService(IConfigService configService) : IDBService
"INSERT INTO posts(post_id, text, price, paid, archived, created_at, record_created_at) VALUES(@post_id, @message_text, @price, @is_paid, @is_archived, @created_at, @record_created_at)",
connection);
insertCmd.Parameters.AddWithValue("@post_id", post_id);
insertCmd.Parameters.AddWithValue("@message_text", message_text ?? (object)DBNull.Value);
insertCmd.Parameters.AddWithValue("@price", price ?? (object)DBNull.Value);
insertCmd.Parameters.AddWithValue("@message_text", message_text);
insertCmd.Parameters.AddWithValue("@price", price);
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
insertCmd.Parameters.AddWithValue("@created_at", created_at);
@ -372,8 +372,8 @@ public class DBService(IConfigService configService) : IDBService
"INSERT INTO stories(post_id, text, price, paid, archived, created_at, record_created_at) VALUES(@post_id, @message_text, @price, @is_paid, @is_archived, @created_at, @record_created_at)",
connection);
insertCmd.Parameters.AddWithValue("@post_id", post_id);
insertCmd.Parameters.AddWithValue("@message_text", message_text ?? (object)DBNull.Value);
insertCmd.Parameters.AddWithValue("@price", price ?? (object)DBNull.Value);
insertCmd.Parameters.AddWithValue("@message_text", message_text);
insertCmd.Parameters.AddWithValue("@price", price);
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
insertCmd.Parameters.AddWithValue("@created_at", created_at);
@ -445,23 +445,21 @@ public class DBService(IConfigService configService) : IDBService
{
try
{
bool downloaded = false;
bool downloaded;
using (SqliteConnection connection = new($"Data Source={folder}/Metadata/user_data.db"))
await using SqliteConnection connection = new($"Data Source={folder}/Metadata/user_data.db");
StringBuilder sql = new("SELECT downloaded FROM medias WHERE media_id=@media_id");
if (configService.CurrentConfig.DownloadDuplicatedMedia)
{
StringBuilder sql = new("SELECT downloaded FROM medias WHERE media_id=@media_id");
if (configService.CurrentConfig.DownloadDuplicatedMedia)
{
sql.Append(" and api_type=@api_type");
}
connection.Open();
using SqliteCommand cmd = new(sql.ToString(), connection);
cmd.Parameters.AddWithValue("@media_id", media_id);
cmd.Parameters.AddWithValue("@api_type", api_type);
downloaded = Convert.ToBoolean(await cmd.ExecuteScalarAsync());
sql.Append(" and api_type=@api_type");
}
connection.Open();
await using SqliteCommand cmd = new(sql.ToString(), connection);
cmd.Parameters.AddWithValue("@media_id", media_id);
cmd.Parameters.AddWithValue("@api_type", api_type);
downloaded = Convert.ToBoolean(await cmd.ExecuteScalarAsync());
return downloaded;
}
catch (Exception ex)

View File

@ -144,9 +144,9 @@ public class DownloadOrchestrationService(
counts.PaidPostCount = await DownloadContentTypeAsync("Paid Posts",
async statusReporter =>
await apiService.GetPaidPosts("/posts/paid/post", path, username, PaidPostIds, statusReporter),
posts => posts?.PaidPosts?.Count ?? 0,
posts => posts?.PaidPostObjects?.Count ?? 0,
posts => posts?.PaidPosts?.Values?.ToList(),
posts => posts.PaidPosts.Count,
posts => posts.PaidPostObjects.Count,
posts => posts.PaidPosts.Values.ToList(),
async (posts, reporter) => await downloadService.DownloadPaidPosts(username, userId, path, users,
clientIdBlobMissing, devicePrivateKeyMissing, posts, reporter),
eventHandler);
@ -161,9 +161,9 @@ public class DownloadOrchestrationService(
counts.PostCount = await DownloadContentTypeAsync("Posts",
async statusReporter =>
await apiService.GetPosts($"/users/{userId}/posts", path, PaidPostIds, statusReporter),
posts => posts?.Posts?.Count ?? 0,
posts => posts?.PostObjects?.Count ?? 0,
posts => posts?.Posts?.Values?.ToList(),
posts => posts.Posts.Count,
posts => posts.PostObjects.Count,
posts => posts.Posts.Values.ToList(),
async (posts, reporter) => await downloadService.DownloadFreePosts(username, userId, path, users,
clientIdBlobMissing, devicePrivateKeyMissing, posts, reporter),
eventHandler);
@ -174,9 +174,9 @@ public class DownloadOrchestrationService(
counts.ArchivedCount = await DownloadContentTypeAsync("Archived Posts",
async statusReporter =>
await apiService.GetArchived($"/users/{userId}/posts", path, statusReporter),
archived => archived?.ArchivedPosts?.Count ?? 0,
archived => archived?.ArchivedPostObjects?.Count ?? 0,
archived => archived?.ArchivedPosts?.Values?.ToList(),
archived => archived.ArchivedPosts.Count,
archived => archived.ArchivedPostObjects.Count,
archived => archived.ArchivedPosts.Values.ToList(),
async (archived, reporter) => await downloadService.DownloadArchived(username, userId, path, users,
clientIdBlobMissing, devicePrivateKeyMissing, archived, reporter),
eventHandler);
@ -187,9 +187,9 @@ public class DownloadOrchestrationService(
counts.StreamsCount = await DownloadContentTypeAsync("Streams",
async statusReporter =>
await apiService.GetStreams($"/users/{userId}/posts/streams", path, PaidPostIds, statusReporter),
streams => streams?.Streams?.Count ?? 0,
streams => streams?.StreamObjects?.Count ?? 0,
streams => streams?.Streams?.Values?.ToList(),
streams => streams.Streams.Count,
streams => streams.StreamObjects.Count,
streams => streams.Streams.Values.ToList(),
async (streams, reporter) => await downloadService.DownloadStreams(username, userId, path, users,
clientIdBlobMissing, devicePrivateKeyMissing, streams, reporter),
eventHandler);
@ -256,9 +256,9 @@ public class DownloadOrchestrationService(
counts.MessagesCount = await DownloadContentTypeAsync("Messages",
async statusReporter =>
await apiService.GetMessages($"/chats/{userId}/messages", path, statusReporter),
messages => messages.Messages?.Count ?? 0,
messages => messages.MessageObjects?.Count ?? 0,
messages => messages?.Messages.Values.ToList(),
messages => messages.Messages.Count,
messages => messages.MessageObjects.Count,
messages => messages.Messages.Values.ToList(),
async (messages, reporter) => await downloadService.DownloadMessages(username, userId, path, users,
clientIdBlobMissing, devicePrivateKeyMissing, messages, reporter),
eventHandler);
@ -269,9 +269,9 @@ public class DownloadOrchestrationService(
counts.PaidMessagesCount = await DownloadContentTypeAsync("Paid Messages",
async statusReporter =>
await apiService.GetPaidMessages("/posts/paid/chat", path, username, statusReporter),
paidMessages => paidMessages?.PaidMessages?.Count ?? 0,
paidMessages => paidMessages?.PaidMessageObjects?.Count ?? 0,
paidMessages => paidMessages?.PaidMessages?.Values?.ToList(),
paidMessages => paidMessages.PaidMessages.Count,
paidMessages => paidMessages.PaidMessageObjects.Count,
paidMessages => paidMessages.PaidMessages.Values.ToList(),
async (paidMessages, reporter) => await downloadService.DownloadPaidMessages(username, path, users,
clientIdBlobMissing, devicePrivateKeyMissing, paidMessages, reporter),
eventHandler);
@ -368,7 +368,7 @@ public class DownloadOrchestrationService(
int paidMessagesCount = 0;
// Download paid posts
if (purchasedTabCollection.PaidPosts?.PaidPosts?.Count > 0)
if (purchasedTabCollection.PaidPosts.PaidPosts.Count > 0)
{
eventHandler.OnContentFound("Paid Posts",
purchasedTabCollection.PaidPosts.PaidPosts.Count,
@ -396,7 +396,7 @@ public class DownloadOrchestrationService(
}
// Download paid messages
if (purchasedTabCollection.PaidMessages?.PaidMessages?.Count > 0)
if (purchasedTabCollection.PaidMessages.PaidMessages.Count > 0)
{
eventHandler.OnContentFound("Paid Messages",
purchasedTabCollection.PaidMessages.PaidMessages.Count,

View File

@ -25,7 +25,7 @@ public class DownloadService(
IAPIService apiService)
: IDownloadService
{
private TaskCompletionSource<bool> _completionSource;
private TaskCompletionSource<bool> _completionSource = new();
public async Task DownloadAvatarHeader(string? avatarUrl, string? headerUrl, string folder, string username)
{
@ -201,7 +201,7 @@ public class DownloadService(
Engine ffmpeg = new(configService.CurrentConfig.FFmpegPath);
ffmpeg.Error += OnError;
ffmpeg.Complete += async (sender, args) =>
ffmpeg.Complete += async (_, _) =>
{
_completionSource.TrySetResult(true);
await OnFFMPEGDownloadComplete(tempFilename, lastModified, folder, path, customFileName, filename,
@ -275,14 +275,14 @@ public class DownloadService(
}
}
private void OnError(object sender, ConversionErrorEventArgs e)
private void OnError(object? sender, ConversionErrorEventArgs e)
{
// Guard all fields to avoid NullReference exceptions from FFmpeg.NET
string input = e?.Input?.Name ?? "<none>";
string output = e?.Output?.Name ?? "<none>";
string exitCode = e?.Exception?.ExitCode.ToString() ?? "<unknown>";
string message = e?.Exception?.Message ?? "<no message>";
string inner = e?.Exception?.InnerException?.Message ?? "<no inner>";
string input = e.Input?.Name ?? "<none>";
string output = e.Output?.Name ?? "<none>";
string exitCode = e.Exception?.ExitCode.ToString() ?? "<unknown>";
string message = e.Exception?.Message ?? "<no message>";
string 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);
@ -310,7 +310,7 @@ public class DownloadService(
string body = await response.Content.ReadAsStringAsync();
XDocument doc = XDocument.Parse(body);
XNamespace ns = "urn:mpeg:dash:schema:mpd:2011";
XNamespace cenc = "urn:mpeg:cenc:2013";
// XNamespace cenc = "urn:mpeg:cenc:2013";
XElement? videoAdaptationSet = doc
.Descendants(ns + "AdaptationSet")
.FirstOrDefault(e => (string?)e.Attribute("mimeType") == "video/mp4");
@ -392,7 +392,6 @@ public class DownloadService(
{
try
{
string customFileName = "";
if (!Directory.Exists(folder + path))
{
Directory.CreateDirectory(folder + path);
@ -580,19 +579,19 @@ public class DownloadService(
public static async Task<DateTime> GetDRMVideoLastModified(string url, Auth auth)
{
string[] messageUrlParsed = url.Split(',');
string mpdURL = messageUrlParsed[0];
string mpdUrl = messageUrlParsed[0];
string policy = messageUrlParsed[1];
string signature = messageUrlParsed[2];
string kvp = messageUrlParsed[3];
mpdURL = mpdURL.Replace(".mpd", "_source.mp4");
mpdUrl = mpdUrl.Replace(".mpd", "_source.mp4");
using HttpClient client = new();
client.DefaultRequestHeaders.Add("Cookie",
$"CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {auth.Cookie}");
client.DefaultRequestHeaders.Add("User-Agent", auth.UserAgent);
using HttpResponseMessage response = await client.GetAsync(mpdURL, HttpCompletionOption.ResponseHeadersRead);
using HttpResponseMessage response = await client.GetAsync(mpdUrl, HttpCompletionOption.ResponseHeadersRead);
if (response.IsSuccessStatusCode)
{
if (response.Content.Headers.LastModified != null)
@ -624,8 +623,8 @@ public class DownloadService(
/// Processes the download and database update of media.
/// </summary>
/// <param name="folder">The folder where the media is stored.</param>
/// <param name="media_id">The ID of the media.</param>
/// <param name="api_type"></param>
/// <param name="mediaId">The ID of the media.</param>
/// <param name="apiType"></param>
/// <param name="url">The URL from where to download the media.</param>
/// <param name="path">The relative path to the media.</param>
/// <param name="serverFilename"></param>
@ -634,8 +633,8 @@ public class DownloadService(
/// <param name="progressReporter"></param>
/// <returns>A Task resulting in a boolean indicating whether the media is newly downloaded or not.</returns>
public async Task<bool> ProcessMediaDownload(string folder,
long media_id,
string api_type,
long mediaId,
string apiType,
string url,
string path,
string serverFilename,
@ -645,11 +644,11 @@ public class DownloadService(
{
try
{
if (!await dbService.CheckDownloaded(folder, media_id, api_type))
if (!await dbService.CheckDownloaded(folder, mediaId, apiType))
{
return await HandleNewMedia(folder,
media_id,
api_type,
mediaId,
apiType,
url,
path,
serverFilename,
@ -658,11 +657,11 @@ public class DownloadService(
progressReporter);
}
bool status = await HandlePreviouslyDownloadedMediaAsync(folder, media_id, api_type, progressReporter);
bool status = await HandlePreviouslyDownloadedMediaAsync(folder, mediaId, apiType, progressReporter);
if (configService.CurrentConfig.RenameExistingFilesWhenCustomFormatIsSelected &&
serverFilename != resolvedFilename)
{
await HandleRenamingOfExistingFilesAsync(folder, media_id, api_type, path, serverFilename,
await HandleRenamingOfExistingFilesAsync(folder, mediaId, apiType, path, serverFilename,
resolvedFilename, extension);
}
@ -677,9 +676,9 @@ public class DownloadService(
}
private async Task<bool> HandleRenamingOfExistingFilesAsync(string folder,
long media_id,
string api_type,
private async Task HandleRenamingOfExistingFilesAsync(string folder,
long mediaId,
string apiType,
string path,
string serverFilename,
string resolvedFilename,
@ -689,7 +688,7 @@ public class DownloadService(
string fullPathWithTheNewFileName = $"{folder}{path}/{resolvedFilename}{extension}";
if (!File.Exists(fullPathWithTheServerFileName))
{
return false;
return;
}
try
@ -699,14 +698,13 @@ public class DownloadService(
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
return false;
return;
}
long size = await dbService.GetStoredFileSize(folder, media_id, api_type);
long size = await dbService.GetStoredFileSize(folder, mediaId, apiType);
DateTime lastModified = File.GetLastWriteTime(fullPathWithTheNewFileName);
await dbService.UpdateMedia(folder, media_id, api_type, folder + path, resolvedFilename + extension, size, true,
await dbService.UpdateMedia(folder, mediaId, apiType, folder + path, resolvedFilename + extension, size, true,
lastModified);
return true;
}
@ -1084,17 +1082,13 @@ public class DownloadService(
}
public async Task<(string decryptionKey, DateTime lastModified)?> GetDecryptionInfo(
string mpdURL, string policy, string signature, string kvp,
string mpdUrl, string policy, string signature, string kvp,
string mediaId, string contentId, string drmType,
bool clientIdBlobMissing, bool devicePrivateKeyMissing)
{
string? pssh = await apiService.GetDRMMPDPSSH(mpdURL, policy, signature, kvp);
if (pssh == null)
{
return null;
}
string pssh = await apiService.GetDRMMPDPSSH(mpdUrl, policy, signature, kvp);
DateTime lastModified = await apiService.GetDRMMPDLastModified(mpdURL, policy, signature, kvp);
DateTime lastModified = await apiService.GetDRMMPDLastModified(mpdUrl, policy, signature, kvp);
Dictionary<string, string> drmHeaders =
apiService.GetDynamicHeaders($"/api2/v2/users/media/{mediaId}/drm/{drmType}/{contentId}",
"?type=widevine");
@ -1220,7 +1214,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadArchived - {username}");
if (archived == null || archived.ArchivedPosts.Count == 0)
if (archived.ArchivedPosts.Count == 0)
{
Log.Debug("Found 0 Archived Posts");
return new DownloadResult
@ -1244,8 +1238,9 @@ public class DownloadService(
bool isNew;
ArchivedEntities.Medium? mediaInfo =
archived.ArchivedPostMedia.FirstOrDefault(m => m.Id == archivedKVP.Key);
ArchivedEntities.ListItem? postInfo =
archived.ArchivedPostObjects.FirstOrDefault(p => p?.Media?.Contains(mediaInfo) == true);
ArchivedEntities.ListItem? postInfo = mediaInfo == null
? null
: archived.ArchivedPostObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
string filenameFormat =
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
@ -1300,7 +1295,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadMessages - {username}");
if (messages == null || messages.Messages.Count == 0)
if (messages.Messages.Count == 0)
{
Log.Debug("Found 0 Messages");
return new DownloadResult
@ -1323,11 +1318,11 @@ public class DownloadService(
bool isNew;
MessageEntities.Medium? mediaInfo = messages.MessageMedia.FirstOrDefault(m => m.Id == messageKVP.Key);
MessageEntities.ListItem? messageInfo = messages.MessageObjects.FirstOrDefault(p =>
p?.Media?.Any(m => m.Id == messageKVP.Key) == true);
p.Media?.Any(m => m.Id == messageKVP.Key) == true);
string filenameFormat =
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).MessageFileNameFormat ?? "";
string messagePath = configService.CurrentConfig.FolderPerMessage && messageInfo != null &&
messageInfo?.Id is not null && messageInfo?.CreatedAt is not null
messageInfo.Id != 0 && messageInfo.CreatedAt is not null
? $"/Messages/Free/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
: "/Messages/Free";
@ -1383,7 +1378,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadPaidMessages - {username}");
if (paidMessageCollection == null || paidMessageCollection.PaidMessages.Count == 0)
if (paidMessageCollection.PaidMessages.Count == 0)
{
Log.Debug("Found 0 Paid Messages");
return new DownloadResult
@ -1408,11 +1403,11 @@ public class DownloadService(
MessageEntities.Medium? mediaInfo =
paidMessageCollection.PaidMessageMedia.FirstOrDefault(m => m.Id == kvpEntry.Key);
PurchasedEntities.ListItem? messageInfo = paidMessageCollection.PaidMessageObjects.FirstOrDefault(p =>
p?.Media?.Any(m => m.Id == kvpEntry.Key) == true);
p.Media?.Any(m => m.Id == kvpEntry.Key) == true);
string filenameFormat =
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).MessageFileNameFormat ?? "";
string paidMsgPath = configService.CurrentConfig.FolderPerPaidMessage && messageInfo != null &&
messageInfo?.Id is not null && messageInfo?.CreatedAt is not null
messageInfo.Id != 0 && messageInfo.CreatedAt is not null
? $"/Messages/Paid/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
: "/Messages/Paid";
@ -1465,7 +1460,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadStreams - {username}");
if (streams == null || streams.Streams.Count == 0)
if (streams.Streams.Count == 0)
{
Log.Debug("Found 0 Streams");
return new DownloadResult
@ -1487,12 +1482,12 @@ public class DownloadService(
{
bool isNew;
StreamEntities.Medium? mediaInfo = streams.StreamMedia.FirstOrDefault(m => m.Id == kvpEntry.Key);
StreamEntities.ListItem? streamInfo =
streams.StreamObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
StreamEntities.ListItem? streamInfo = mediaInfo == null
? null
: streams.StreamObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
string filenameFormat =
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
string streamPath = configService.CurrentConfig.FolderPerPost && streamInfo != null &&
streamInfo?.Id is not null && streamInfo?.PostedAt is not null
string streamPath = configService.CurrentConfig.FolderPerPost && streamInfo != null && streamInfo.Id != 0
? $"/Posts/Free/{streamInfo.Id} {streamInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
: "/Posts/Free";
@ -1546,7 +1541,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadFreePosts - {username}");
if (posts == null || posts.Posts.Count == 0)
if (posts.Posts.Count == 0)
{
Log.Debug("Found 0 Posts");
return new DownloadResult
@ -1566,13 +1561,13 @@ public class DownloadService(
foreach (KeyValuePair<long, string> postKVP in posts.Posts)
{
bool isNew;
PostEntities.Medium? mediaInfo = posts.PostMedia.FirstOrDefault(m => m?.Id == postKVP.Key);
PostEntities.ListItem? postInfo =
posts.PostObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
PostEntities.Medium? mediaInfo = posts.PostMedia.FirstOrDefault(m => m.Id == postKVP.Key);
PostEntities.ListItem? postInfo = mediaInfo == null
? null
: posts.PostObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
string filenameFormat =
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
string postPath = configService.CurrentConfig.FolderPerPost && postInfo != null &&
postInfo?.Id is not null && postInfo?.PostedAt is not null
string postPath = configService.CurrentConfig.FolderPerPost && postInfo != null && postInfo.Id != 0
? $"/Posts/Free/{postInfo.Id} {postInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
: "/Posts/Free";
@ -1625,7 +1620,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadPaidPosts - {username}");
if (purchasedPosts == null || purchasedPosts.PaidPosts.Count == 0)
if (purchasedPosts.PaidPosts.Count == 0)
{
Log.Debug("Found 0 Paid Posts");
return new DownloadResult
@ -1649,11 +1644,11 @@ public class DownloadService(
MessageEntities.Medium? mediaInfo =
purchasedPosts.PaidPostMedia.FirstOrDefault(m => m.Id == postKVP.Key);
PurchasedEntities.ListItem? postInfo =
purchasedPosts.PaidPostObjects.FirstOrDefault(p => p?.Media?.Any(m => m.Id == postKVP.Key) == true);
purchasedPosts.PaidPostObjects.FirstOrDefault(p => p.Media?.Any(m => m.Id == postKVP.Key) == true);
string filenameFormat =
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
string paidPostPath = configService.CurrentConfig.FolderPerPaidPost && postInfo != null &&
postInfo?.Id is not null && postInfo?.PostedAt is not null
postInfo.Id != 0 && postInfo.PostedAt is not null
? $"/Posts/Paid/{postInfo.Id} {postInfo.PostedAt.Value:yyyy-MM-dd HH-mm-ss}"
: "/Posts/Paid";
@ -1706,7 +1701,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadPaidPostsPurchasedTab - {username}");
if (purchasedPosts == null || purchasedPosts.PaidPosts.Count == 0)
if (purchasedPosts.PaidPosts.Count == 0)
{
Log.Debug("Found 0 Paid Posts");
return new DownloadResult { TotalCount = 0, MediaType = "Paid Posts", Success = true };
@ -1721,12 +1716,12 @@ public class DownloadService(
purchasedPosts?.PaidPostMedia?.FirstOrDefault(m => m.Id == purchasedPostKVP.Key);
PurchasedEntities.ListItem? postInfo = mediaInfo != null
? purchasedPosts?.PaidPostObjects?.FirstOrDefault(p =>
p?.Media?.Any(m => m.Id == purchasedPostKVP.Key) == true)
p.Media?.Any(m => m.Id == purchasedPostKVP.Key) == true)
: null;
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
.PaidPostFileNameFormat ?? "";
string paidPostPath = configService.CurrentConfig.FolderPerPaidPost && postInfo != null &&
postInfo?.Id is not null && postInfo?.PostedAt is not null
postInfo.Id != 0 && postInfo.PostedAt is not null
? $"/Posts/Paid/{postInfo.Id} {postInfo.PostedAt.Value:yyyy-MM-dd HH-mm-ss}"
: "/Posts/Paid";
@ -1766,7 +1761,7 @@ public class DownloadService(
Log.Debug($"Paid Posts Already Downloaded: {oldCount} New Paid Posts Downloaded: {newCount}");
return new DownloadResult
{
TotalCount = purchasedPosts.PaidPosts.Count,
TotalCount = purchasedPosts?.PaidPosts.Count ?? 0,
NewDownloads = newCount,
ExistingDownloads = oldCount,
MediaType = "Paid Posts",
@ -1780,7 +1775,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadPaidMessagesPurchasedTab - {username}");
if (paidMessageCollection == null || paidMessageCollection.PaidMessages.Count == 0)
if (paidMessageCollection.PaidMessages.Count == 0)
{
Log.Debug("Found 0 Paid Messages");
return new DownloadResult { TotalCount = 0, MediaType = "Paid Messages", Success = true };
@ -1795,11 +1790,11 @@ public class DownloadService(
paidMessageCollection.PaidMessageMedia.FirstOrDefault(m => m.Id == paidMessageKVP.Key);
PurchasedEntities.ListItem? messageInfo =
paidMessageCollection.PaidMessageObjects.FirstOrDefault(p =>
p?.Media?.Any(m => m.Id == paidMessageKVP.Key) == true);
p.Media?.Any(m => m.Id == paidMessageKVP.Key) == true);
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
.PaidMessageFileNameFormat ?? "";
string paidMsgPath = configService.CurrentConfig.FolderPerPaidMessage && messageInfo != null &&
messageInfo?.Id is not null && messageInfo?.CreatedAt is not null
messageInfo.Id != 0 && messageInfo.CreatedAt is not null
? $"/Messages/Paid/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
: "/Messages/Paid";
@ -1853,7 +1848,7 @@ public class DownloadService(
{
Log.Debug($"Calling DownloadSinglePost - {username}");
if (post == null || post.SinglePosts.Count == 0)
if (post.SinglePosts.Count == 0)
{
Log.Debug("Couldn't find post");
return new DownloadResult { TotalCount = 0, MediaType = "Posts", Success = true };
@ -1864,12 +1859,12 @@ public class DownloadService(
foreach (KeyValuePair<long, string> postKVP in post.SinglePosts)
{
PostEntities.Medium? mediaInfo = post.SinglePostMedia.FirstOrDefault(m => m.Id == postKVP.Key);
PostEntities.SinglePost? postInfo =
post.SinglePostObjects.FirstOrDefault(p => p?.Media?.Contains(mediaInfo) == true);
PostEntities.SinglePost? postInfo = mediaInfo == null
? null
: post.SinglePostObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
.PostFileNameFormat ?? "";
string postPath = configService.CurrentConfig.FolderPerPost && postInfo != null &&
postInfo?.Id is not null && postInfo?.PostedAt is not null
string postPath = configService.CurrentConfig.FolderPerPost && postInfo != null && postInfo.Id != 0
? $"/Posts/Free/{postInfo.Id} {postInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
: "/Posts/Free";
@ -1930,12 +1925,7 @@ public class DownloadService(
PurchasedEntities.SinglePaidMessageCollection singlePaidMessageCollection,
IProgressReporter progressReporter)
{
Log.Debug($"Calling DownloadSinglePaidMessage - {username}");
if (singlePaidMessageCollection == null)
{
return new DownloadResult { TotalCount = 0, MediaType = "Paid Messages", Success = true };
}
Log.Debug("Calling DownloadSinglePaidMessage - {Username}", username);
int totalNew = 0, totalOld = 0;
@ -1949,11 +1939,11 @@ public class DownloadService(
m.Id == paidMessageKVP.Key);
MessageEntities.SingleMessage? messageInfo =
singlePaidMessageCollection.SingleMessageObjects.FirstOrDefault(p =>
p?.Media?.Any(m => m.Id == paidMessageKVP.Key) == true);
p.Media?.Any(m => m.Id == paidMessageKVP.Key) == true);
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
.PaidMessageFileNameFormat ?? "";
string previewMsgPath = configService.CurrentConfig.FolderPerMessage && messageInfo != null &&
messageInfo?.Id is not null && messageInfo?.CreatedAt is not null
messageInfo.Id != 0 && messageInfo.CreatedAt is not null
? $"/Messages/Free/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
: "/Messages/Free";
@ -2002,12 +1992,12 @@ public class DownloadService(
m.Id == paidMessageKVP.Key);
MessageEntities.SingleMessage? messageInfo =
singlePaidMessageCollection.SingleMessageObjects.FirstOrDefault(p =>
p?.Media?.Any(m => m.Id == paidMessageKVP.Key) == true);
p.Media?.Any(m => m.Id == paidMessageKVP.Key) == true);
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
.PaidMessageFileNameFormat ?? "";
string singlePaidMsgPath = configService.CurrentConfig.FolderPerPaidMessage &&
messageInfo != null && messageInfo?.Id is not null &&
messageInfo?.CreatedAt is not null
messageInfo != null && messageInfo.Id != 0 &&
messageInfo.CreatedAt is not null
? $"/Messages/Paid/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
: "/Messages/Paid";

View File

@ -38,7 +38,7 @@ public class StartupService(IConfigService configService, IAuthService authServi
!result.FfmpegPath.Contains(@":\\"))
{
result.FfmpegPath = result.FfmpegPath.Replace(@"\", @"\\");
configService.CurrentConfig!.FFmpegPath = result.FfmpegPath;
configService.CurrentConfig.FFmpegPath = result.FfmpegPath;
}
// Get FFmpeg version
@ -144,7 +144,7 @@ public class StartupService(IConfigService configService, IAuthService authServi
private void DetectFfmpeg(StartupResult result)
{
if (!string.IsNullOrEmpty(configService.CurrentConfig!.FFmpegPath) &&
if (!string.IsNullOrEmpty(configService.CurrentConfig.FFmpegPath) &&
ValidateFilePath(configService.CurrentConfig.FFmpegPath))
{
result.FfmpegFound = true;

View File

@ -67,7 +67,7 @@ public class ThrottledStream : Stream
}
}
protected async Task ThrottleAsync(int bytes)
private async Task ThrottleAsync(int bytes)
{
if (!shouldThrottle)
{

View File

@ -21,6 +21,7 @@ internal static class XmlUtils
}
catch
{
// ignored
}
return "";

View File

@ -112,7 +112,7 @@ public class CDM
{
//needed for HBO Max
PSSHBox psshBox = PSSHBox.FromByteArray(initData);
PsshBox psshBox = PsshBox.FromByteArray(initData);
cencHeader = Serializer.Deserialize<WidevineCencHeader>(new MemoryStream(psshBox.Data));
}
catch
@ -278,7 +278,7 @@ public class CDM
encryptedClientIdProto.EncryptedClientId = mstream.ToArray();
using RSACryptoServiceProvider RSA = new();
RSA.ImportRSAPublicKey(session.ServiceCertificate.DeviceCertificate.PublicKey, out int bytesRead);
RSA.ImportRSAPublicKey(session.ServiceCertificate.DeviceCertificate.PublicKey, out int _);
encryptedClientIdProto.EncryptedPrivacyKey = RSA.Encrypt(aesProvider.Key, RSAEncryptionPadding.OaepSHA1);
encryptedClientIdProto.EncryptedClientIdIv = aesProvider.IV;
encryptedClientIdProto.ServiceId =

View File

@ -29,5 +29,13 @@ public class CDMApi
CDM.ProvideLicense(SessionId, Convert.FromBase64String(licenseB64));
}
public List<ContentKey> GetKeys() => CDM.GetKeys(SessionId);
public List<ContentKey> GetKeys()
{
if (SessionId == null)
{
throw new Exception("No session ID set. Could not get keys");
}
return CDM.GetKeys(SessionId);
}
}

View File

@ -43,6 +43,10 @@ public class CDMDevice
using StreamReader reader = File.OpenText(privateKeyPath);
DeviceKeys = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
}
else
{
throw new Exception("No device private key found");
}
if (vmpBytes != null)
{

View File

@ -1,34 +1,34 @@
namespace OF_DL.Widevine;
internal class PSSHBox
internal class PsshBox
{
private static readonly byte[] PSSH_HEADER = new byte[] { 0x70, 0x73, 0x73, 0x68 };
private static readonly byte[] s_psshHeader = [0x70, 0x73, 0x73, 0x68];
private PSSHBox(List<byte[]> kids, byte[] data)
private PsshBox(List<byte[]> kids, byte[] data)
{
KIDs = kids;
Data = data;
}
public List<byte[]> KIDs { get; set; } = new();
public List<byte[]> KIDs { get; set; }
public byte[] Data { get; set; }
public static PSSHBox FromByteArray(byte[] psshbox)
public static PsshBox FromByteArray(byte[] psshbox)
{
using MemoryStream stream = new(psshbox);
stream.Seek(4, SeekOrigin.Current);
byte[] header = new byte[4];
stream.Read(header, 0, 4);
stream.ReadExactly(header, 0, 4);
if (!header.SequenceEqual(PSSH_HEADER))
if (!header.SequenceEqual(s_psshHeader))
{
throw new Exception("Not a pssh box");
}
stream.Seek(20, SeekOrigin.Current);
byte[] kidCountBytes = new byte[4];
stream.Read(kidCountBytes, 0, 4);
stream.ReadExactly(kidCountBytes, 0, 4);
if (BitConverter.IsLittleEndian)
{
@ -41,12 +41,12 @@ internal class PSSHBox
for (int i = 0; i < kidCount; i++)
{
byte[] kid = new byte[16];
stream.Read(kid);
stream.ReadExactly(kid);
kids.Add(kid);
}
byte[] dataLengthBytes = new byte[4];
stream.Read(dataLengthBytes);
stream.ReadExactly(dataLengthBytes);
if (BitConverter.IsLittleEndian)
{
@ -57,12 +57,12 @@ internal class PSSHBox
if (dataLength == 0)
{
return new PSSHBox(kids, []);
return new PsshBox(kids, []);
}
byte[] data = new byte[dataLength];
stream.Read(data);
stream.ReadExactly(data);
return new PSSHBox(kids, data);
return new PsshBox(kids, data);
}
}