forked from sim0n00ps/OF-DL
Address compiler warning
This commit is contained in:
parent
f7f1fad92d
commit
487de58274
@ -37,7 +37,7 @@ public class Padding
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[]? AddPSSPadding(byte[] hash)
|
public static byte[] AddPssPadding(byte[] hash)
|
||||||
{
|
{
|
||||||
int modBits = 2048;
|
int modBits = 2048;
|
||||||
int hLen = 20;
|
int hLen = 20;
|
||||||
@ -49,10 +49,11 @@ public class Padding
|
|||||||
lmask = (lmask >> 1) | 0x80;
|
lmask = (lmask >> 1) | 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emLen < hLen + hLen + 2)
|
// Commented out since the condition will always be false while emLen = 256 and hLen = 20
|
||||||
{
|
// if (emLen < hLen + hLen + 2)
|
||||||
return null;
|
// {
|
||||||
}
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
byte[] salt = new byte[hLen];
|
byte[] salt = new byte[hLen];
|
||||||
new Random().NextBytes(salt);
|
new Random().NextBytes(salt);
|
||||||
@ -102,7 +103,7 @@ public class Padding
|
|||||||
db[i] = (byte)(maskedDB[i] ^ dbMask[i]);
|
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)..];
|
byte[] unpadded = db[(hLen + onePos + 1)..];
|
||||||
|
|
||||||
return unpadded;
|
return unpadded;
|
||||||
|
|||||||
@ -115,22 +115,22 @@ public class Config : IFileNameFormatConfig
|
|||||||
|
|
||||||
if (CreatorConfigs.TryGetValue(username, out CreatorConfig? creatorConfig))
|
if (CreatorConfigs.TryGetValue(username, out CreatorConfig? creatorConfig))
|
||||||
{
|
{
|
||||||
if (creatorConfig?.PaidPostFileNameFormat != null)
|
if (creatorConfig.PaidPostFileNameFormat != null)
|
||||||
{
|
{
|
||||||
combinedFilenameFormatConfig.PaidPostFileNameFormat = creatorConfig.PaidPostFileNameFormat;
|
combinedFilenameFormatConfig.PaidPostFileNameFormat = creatorConfig.PaidPostFileNameFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creatorConfig?.PostFileNameFormat != null)
|
if (creatorConfig.PostFileNameFormat != null)
|
||||||
{
|
{
|
||||||
combinedFilenameFormatConfig.PostFileNameFormat = creatorConfig.PostFileNameFormat;
|
combinedFilenameFormatConfig.PostFileNameFormat = creatorConfig.PostFileNameFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creatorConfig?.PaidMessageFileNameFormat != null)
|
if (creatorConfig.PaidMessageFileNameFormat != null)
|
||||||
{
|
{
|
||||||
combinedFilenameFormatConfig.PaidMessageFileNameFormat = creatorConfig.PaidMessageFileNameFormat;
|
combinedFilenameFormatConfig.PaidMessageFileNameFormat = creatorConfig.PaidMessageFileNameFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creatorConfig?.MessageFileNameFormat != null)
|
if (creatorConfig.MessageFileNameFormat != null)
|
||||||
{
|
{
|
||||||
combinedFilenameFormatConfig.MessageFileNameFormat = creatorConfig.MessageFileNameFormat;
|
combinedFilenameFormatConfig.MessageFileNameFormat = creatorConfig.MessageFileNameFormat;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using OF_DL.Models.Dtos.Archived;
|
|
||||||
|
|
||||||
namespace OF_DL.Models.Dtos.Common;
|
namespace OF_DL.Models.Dtos.Common;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -136,6 +136,11 @@ public class AuthService(IServiceProvider serviceProvider) : IAuthService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(CurrentAuth.Cookie))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string pattern = @"(auth_id=\d+)|(sess=[^;]+)";
|
string pattern = @"(auth_id=\d+)|(sess=[^;]+)";
|
||||||
MatchCollection matches = Regex.Matches(CurrentAuth.Cookie, pattern);
|
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
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@ -44,7 +44,7 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for command-line arguments
|
// Check for command-line arguments
|
||||||
if (args != null && args.Length > 0)
|
if (args.Length > 0)
|
||||||
{
|
{
|
||||||
const string NON_INTERACTIVE_ARG = "--non-interactive";
|
const string NON_INTERACTIVE_ARG = "--non-interactive";
|
||||||
if (args.Any(a => a.Equals(NON_INTERACTIVE_ARG, StringComparison.OrdinalIgnoreCase)))
|
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")
|
public async Task SaveConfigurationAsync(string filePath = "config.conf")
|
||||||
{
|
{
|
||||||
if (CurrentConfig == null)
|
|
||||||
{
|
|
||||||
Log.Warning("Attempted to save null config to file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string hoconConfig = BuildHoconFromConfig(CurrentConfig);
|
string hoconConfig = BuildHoconFromConfig(CurrentConfig);
|
||||||
@ -409,7 +403,13 @@ public class ConfigService(ILoggingService loggingService) : IConfigService
|
|||||||
ToggleableConfigAttribute? attr = propInfo.GetCustomAttribute<ToggleableConfigAttribute>();
|
ToggleableConfigAttribute? attr = propInfo.GetCustomAttribute<ToggleableConfigAttribute>();
|
||||||
if (attr != null)
|
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)
|
if (attr != null)
|
||||||
{
|
{
|
||||||
bool newValue = selectedNames.Contains(propInfo.Name);
|
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);
|
propInfo.SetValue(newConfig, newValue);
|
||||||
|
|
||||||
if (newValue != oldValue)
|
if (newValue != oldValue.Value)
|
||||||
{
|
{
|
||||||
configChanged = true;
|
configChanged = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -219,17 +219,17 @@ public class DBService(IConfigService configService) : IDBService
|
|||||||
connection))
|
connection))
|
||||||
{
|
{
|
||||||
checkCmd.Parameters.AddWithValue("@userId", user.Value);
|
checkCmd.Parameters.AddWithValue("@userId", user.Value);
|
||||||
using (SqliteDataReader reader = await checkCmd.ExecuteReaderAsync())
|
await using (SqliteDataReader reader = await checkCmd.ExecuteReaderAsync())
|
||||||
{
|
{
|
||||||
if (reader.Read())
|
if (reader.Read())
|
||||||
{
|
{
|
||||||
long storedUserId = reader.GetInt64(0);
|
|
||||||
string storedUsername = reader.GetString(1);
|
string storedUsername = reader.GetString(1);
|
||||||
|
|
||||||
if (storedUsername != user.Key)
|
if (storedUsername != user.Key)
|
||||||
{
|
{
|
||||||
using (SqliteCommand updateCmd =
|
await using (SqliteCommand updateCmd =
|
||||||
new("UPDATE users SET username = @newUsername WHERE user_id = @userId;", connection))
|
new("UPDATE users SET username = @newUsername WHERE user_id = @userId;",
|
||||||
|
connection))
|
||||||
{
|
{
|
||||||
updateCmd.Parameters.AddWithValue("@newUsername", user.Key);
|
updateCmd.Parameters.AddWithValue("@newUsername", user.Key);
|
||||||
updateCmd.Parameters.AddWithValue("@userId", user.Value);
|
updateCmd.Parameters.AddWithValue("@userId", user.Value);
|
||||||
@ -278,13 +278,13 @@ public class DBService(IConfigService configService) : IDBService
|
|||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
// If the record doesn't exist, insert a new one
|
// If the record doesn't exist, insert a new one
|
||||||
using SqliteCommand insertCmd =
|
await using SqliteCommand insertCmd =
|
||||||
new(
|
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)",
|
"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);
|
connection);
|
||||||
insertCmd.Parameters.AddWithValue("@post_id", post_id);
|
insertCmd.Parameters.AddWithValue("@post_id", post_id);
|
||||||
insertCmd.Parameters.AddWithValue("@message_text", message_text ?? (object)DBNull.Value);
|
insertCmd.Parameters.AddWithValue("@message_text", message_text);
|
||||||
insertCmd.Parameters.AddWithValue("@price", price ?? (object)DBNull.Value);
|
insertCmd.Parameters.AddWithValue("@price", price);
|
||||||
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
|
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
|
||||||
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
|
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
|
||||||
insertCmd.Parameters.AddWithValue("@created_at", created_at);
|
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)",
|
"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);
|
connection);
|
||||||
insertCmd.Parameters.AddWithValue("@post_id", post_id);
|
insertCmd.Parameters.AddWithValue("@post_id", post_id);
|
||||||
insertCmd.Parameters.AddWithValue("@message_text", message_text ?? (object)DBNull.Value);
|
insertCmd.Parameters.AddWithValue("@message_text", message_text);
|
||||||
insertCmd.Parameters.AddWithValue("@price", price ?? (object)DBNull.Value);
|
insertCmd.Parameters.AddWithValue("@price", price);
|
||||||
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
|
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
|
||||||
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
|
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
|
||||||
insertCmd.Parameters.AddWithValue("@created_at", created_at);
|
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)",
|
"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);
|
connection);
|
||||||
insertCmd.Parameters.AddWithValue("@post_id", post_id);
|
insertCmd.Parameters.AddWithValue("@post_id", post_id);
|
||||||
insertCmd.Parameters.AddWithValue("@message_text", message_text ?? (object)DBNull.Value);
|
insertCmd.Parameters.AddWithValue("@message_text", message_text);
|
||||||
insertCmd.Parameters.AddWithValue("@price", price ?? (object)DBNull.Value);
|
insertCmd.Parameters.AddWithValue("@price", price);
|
||||||
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
|
insertCmd.Parameters.AddWithValue("@is_paid", is_paid);
|
||||||
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
|
insertCmd.Parameters.AddWithValue("@is_archived", is_archived);
|
||||||
insertCmd.Parameters.AddWithValue("@created_at", created_at);
|
insertCmd.Parameters.AddWithValue("@created_at", created_at);
|
||||||
@ -445,23 +445,21 @@ public class DBService(IConfigService configService) : IDBService
|
|||||||
{
|
{
|
||||||
try
|
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");
|
sql.Append(" and api_type=@api_type");
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return downloaded;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@ -144,9 +144,9 @@ public class DownloadOrchestrationService(
|
|||||||
counts.PaidPostCount = await DownloadContentTypeAsync("Paid Posts",
|
counts.PaidPostCount = await DownloadContentTypeAsync("Paid Posts",
|
||||||
async statusReporter =>
|
async statusReporter =>
|
||||||
await apiService.GetPaidPosts("/posts/paid/post", path, username, PaidPostIds, statusReporter),
|
await apiService.GetPaidPosts("/posts/paid/post", path, username, PaidPostIds, statusReporter),
|
||||||
posts => posts?.PaidPosts?.Count ?? 0,
|
posts => posts.PaidPosts.Count,
|
||||||
posts => posts?.PaidPostObjects?.Count ?? 0,
|
posts => posts.PaidPostObjects.Count,
|
||||||
posts => posts?.PaidPosts?.Values?.ToList(),
|
posts => posts.PaidPosts.Values.ToList(),
|
||||||
async (posts, reporter) => await downloadService.DownloadPaidPosts(username, userId, path, users,
|
async (posts, reporter) => await downloadService.DownloadPaidPosts(username, userId, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, posts, reporter),
|
clientIdBlobMissing, devicePrivateKeyMissing, posts, reporter),
|
||||||
eventHandler);
|
eventHandler);
|
||||||
@ -161,9 +161,9 @@ public class DownloadOrchestrationService(
|
|||||||
counts.PostCount = await DownloadContentTypeAsync("Posts",
|
counts.PostCount = await DownloadContentTypeAsync("Posts",
|
||||||
async statusReporter =>
|
async statusReporter =>
|
||||||
await apiService.GetPosts($"/users/{userId}/posts", path, PaidPostIds, statusReporter),
|
await apiService.GetPosts($"/users/{userId}/posts", path, PaidPostIds, statusReporter),
|
||||||
posts => posts?.Posts?.Count ?? 0,
|
posts => posts.Posts.Count,
|
||||||
posts => posts?.PostObjects?.Count ?? 0,
|
posts => posts.PostObjects.Count,
|
||||||
posts => posts?.Posts?.Values?.ToList(),
|
posts => posts.Posts.Values.ToList(),
|
||||||
async (posts, reporter) => await downloadService.DownloadFreePosts(username, userId, path, users,
|
async (posts, reporter) => await downloadService.DownloadFreePosts(username, userId, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, posts, reporter),
|
clientIdBlobMissing, devicePrivateKeyMissing, posts, reporter),
|
||||||
eventHandler);
|
eventHandler);
|
||||||
@ -174,9 +174,9 @@ public class DownloadOrchestrationService(
|
|||||||
counts.ArchivedCount = await DownloadContentTypeAsync("Archived Posts",
|
counts.ArchivedCount = await DownloadContentTypeAsync("Archived Posts",
|
||||||
async statusReporter =>
|
async statusReporter =>
|
||||||
await apiService.GetArchived($"/users/{userId}/posts", path, statusReporter),
|
await apiService.GetArchived($"/users/{userId}/posts", path, statusReporter),
|
||||||
archived => archived?.ArchivedPosts?.Count ?? 0,
|
archived => archived.ArchivedPosts.Count,
|
||||||
archived => archived?.ArchivedPostObjects?.Count ?? 0,
|
archived => archived.ArchivedPostObjects.Count,
|
||||||
archived => archived?.ArchivedPosts?.Values?.ToList(),
|
archived => archived.ArchivedPosts.Values.ToList(),
|
||||||
async (archived, reporter) => await downloadService.DownloadArchived(username, userId, path, users,
|
async (archived, reporter) => await downloadService.DownloadArchived(username, userId, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, archived, reporter),
|
clientIdBlobMissing, devicePrivateKeyMissing, archived, reporter),
|
||||||
eventHandler);
|
eventHandler);
|
||||||
@ -187,9 +187,9 @@ public class DownloadOrchestrationService(
|
|||||||
counts.StreamsCount = await DownloadContentTypeAsync("Streams",
|
counts.StreamsCount = await DownloadContentTypeAsync("Streams",
|
||||||
async statusReporter =>
|
async statusReporter =>
|
||||||
await apiService.GetStreams($"/users/{userId}/posts/streams", path, PaidPostIds, statusReporter),
|
await apiService.GetStreams($"/users/{userId}/posts/streams", path, PaidPostIds, statusReporter),
|
||||||
streams => streams?.Streams?.Count ?? 0,
|
streams => streams.Streams.Count,
|
||||||
streams => streams?.StreamObjects?.Count ?? 0,
|
streams => streams.StreamObjects.Count,
|
||||||
streams => streams?.Streams?.Values?.ToList(),
|
streams => streams.Streams.Values.ToList(),
|
||||||
async (streams, reporter) => await downloadService.DownloadStreams(username, userId, path, users,
|
async (streams, reporter) => await downloadService.DownloadStreams(username, userId, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, streams, reporter),
|
clientIdBlobMissing, devicePrivateKeyMissing, streams, reporter),
|
||||||
eventHandler);
|
eventHandler);
|
||||||
@ -256,9 +256,9 @@ public class DownloadOrchestrationService(
|
|||||||
counts.MessagesCount = await DownloadContentTypeAsync("Messages",
|
counts.MessagesCount = await DownloadContentTypeAsync("Messages",
|
||||||
async statusReporter =>
|
async statusReporter =>
|
||||||
await apiService.GetMessages($"/chats/{userId}/messages", path, statusReporter),
|
await apiService.GetMessages($"/chats/{userId}/messages", path, statusReporter),
|
||||||
messages => messages.Messages?.Count ?? 0,
|
messages => messages.Messages.Count,
|
||||||
messages => messages.MessageObjects?.Count ?? 0,
|
messages => messages.MessageObjects.Count,
|
||||||
messages => messages?.Messages.Values.ToList(),
|
messages => messages.Messages.Values.ToList(),
|
||||||
async (messages, reporter) => await downloadService.DownloadMessages(username, userId, path, users,
|
async (messages, reporter) => await downloadService.DownloadMessages(username, userId, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, messages, reporter),
|
clientIdBlobMissing, devicePrivateKeyMissing, messages, reporter),
|
||||||
eventHandler);
|
eventHandler);
|
||||||
@ -269,9 +269,9 @@ public class DownloadOrchestrationService(
|
|||||||
counts.PaidMessagesCount = await DownloadContentTypeAsync("Paid Messages",
|
counts.PaidMessagesCount = await DownloadContentTypeAsync("Paid Messages",
|
||||||
async statusReporter =>
|
async statusReporter =>
|
||||||
await apiService.GetPaidMessages("/posts/paid/chat", path, username, statusReporter),
|
await apiService.GetPaidMessages("/posts/paid/chat", path, username, statusReporter),
|
||||||
paidMessages => paidMessages?.PaidMessages?.Count ?? 0,
|
paidMessages => paidMessages.PaidMessages.Count,
|
||||||
paidMessages => paidMessages?.PaidMessageObjects?.Count ?? 0,
|
paidMessages => paidMessages.PaidMessageObjects.Count,
|
||||||
paidMessages => paidMessages?.PaidMessages?.Values?.ToList(),
|
paidMessages => paidMessages.PaidMessages.Values.ToList(),
|
||||||
async (paidMessages, reporter) => await downloadService.DownloadPaidMessages(username, path, users,
|
async (paidMessages, reporter) => await downloadService.DownloadPaidMessages(username, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, paidMessages, reporter),
|
clientIdBlobMissing, devicePrivateKeyMissing, paidMessages, reporter),
|
||||||
eventHandler);
|
eventHandler);
|
||||||
@ -368,7 +368,7 @@ public class DownloadOrchestrationService(
|
|||||||
int paidMessagesCount = 0;
|
int paidMessagesCount = 0;
|
||||||
|
|
||||||
// Download paid posts
|
// Download paid posts
|
||||||
if (purchasedTabCollection.PaidPosts?.PaidPosts?.Count > 0)
|
if (purchasedTabCollection.PaidPosts.PaidPosts.Count > 0)
|
||||||
{
|
{
|
||||||
eventHandler.OnContentFound("Paid Posts",
|
eventHandler.OnContentFound("Paid Posts",
|
||||||
purchasedTabCollection.PaidPosts.PaidPosts.Count,
|
purchasedTabCollection.PaidPosts.PaidPosts.Count,
|
||||||
@ -396,7 +396,7 @@ public class DownloadOrchestrationService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Download paid messages
|
// Download paid messages
|
||||||
if (purchasedTabCollection.PaidMessages?.PaidMessages?.Count > 0)
|
if (purchasedTabCollection.PaidMessages.PaidMessages.Count > 0)
|
||||||
{
|
{
|
||||||
eventHandler.OnContentFound("Paid Messages",
|
eventHandler.OnContentFound("Paid Messages",
|
||||||
purchasedTabCollection.PaidMessages.PaidMessages.Count,
|
purchasedTabCollection.PaidMessages.PaidMessages.Count,
|
||||||
|
|||||||
@ -25,7 +25,7 @@ public class DownloadService(
|
|||||||
IAPIService apiService)
|
IAPIService apiService)
|
||||||
: IDownloadService
|
: IDownloadService
|
||||||
{
|
{
|
||||||
private TaskCompletionSource<bool> _completionSource;
|
private TaskCompletionSource<bool> _completionSource = new();
|
||||||
|
|
||||||
public async Task DownloadAvatarHeader(string? avatarUrl, string? headerUrl, string folder, string username)
|
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);
|
Engine ffmpeg = new(configService.CurrentConfig.FFmpegPath);
|
||||||
ffmpeg.Error += OnError;
|
ffmpeg.Error += OnError;
|
||||||
ffmpeg.Complete += async (sender, args) =>
|
ffmpeg.Complete += async (_, _) =>
|
||||||
{
|
{
|
||||||
_completionSource.TrySetResult(true);
|
_completionSource.TrySetResult(true);
|
||||||
await OnFFMPEGDownloadComplete(tempFilename, lastModified, folder, path, customFileName, filename,
|
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
|
// Guard all fields to avoid NullReference exceptions from FFmpeg.NET
|
||||||
string input = e?.Input?.Name ?? "<none>";
|
string input = e.Input?.Name ?? "<none>";
|
||||||
string output = e?.Output?.Name ?? "<none>";
|
string output = e.Output?.Name ?? "<none>";
|
||||||
string exitCode = e?.Exception?.ExitCode.ToString() ?? "<unknown>";
|
string exitCode = e.Exception?.ExitCode.ToString() ?? "<unknown>";
|
||||||
string message = e?.Exception?.Message ?? "<no message>";
|
string message = e.Exception?.Message ?? "<no message>";
|
||||||
string inner = e?.Exception?.InnerException?.Message ?? "<no inner>";
|
string inner = e.Exception?.InnerException?.Message ?? "<no inner>";
|
||||||
|
|
||||||
Log.Error("FFmpeg failed. Input={Input} Output={Output} ExitCode={ExitCode} Message={Message} Inner={Inner}",
|
Log.Error("FFmpeg failed. Input={Input} Output={Output} ExitCode={ExitCode} Message={Message} Inner={Inner}",
|
||||||
input, output, exitCode, message, inner);
|
input, output, exitCode, message, inner);
|
||||||
@ -310,7 +310,7 @@ public class DownloadService(
|
|||||||
string body = await response.Content.ReadAsStringAsync();
|
string body = await response.Content.ReadAsStringAsync();
|
||||||
XDocument doc = XDocument.Parse(body);
|
XDocument doc = XDocument.Parse(body);
|
||||||
XNamespace ns = "urn:mpeg:dash:schema:mpd:2011";
|
XNamespace ns = "urn:mpeg:dash:schema:mpd:2011";
|
||||||
XNamespace cenc = "urn:mpeg:cenc:2013";
|
// XNamespace cenc = "urn:mpeg:cenc:2013";
|
||||||
XElement? videoAdaptationSet = doc
|
XElement? videoAdaptationSet = doc
|
||||||
.Descendants(ns + "AdaptationSet")
|
.Descendants(ns + "AdaptationSet")
|
||||||
.FirstOrDefault(e => (string?)e.Attribute("mimeType") == "video/mp4");
|
.FirstOrDefault(e => (string?)e.Attribute("mimeType") == "video/mp4");
|
||||||
@ -392,7 +392,6 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string customFileName = "";
|
|
||||||
if (!Directory.Exists(folder + path))
|
if (!Directory.Exists(folder + path))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(folder + path);
|
Directory.CreateDirectory(folder + path);
|
||||||
@ -580,19 +579,19 @@ public class DownloadService(
|
|||||||
public static async Task<DateTime> GetDRMVideoLastModified(string url, Auth auth)
|
public static async Task<DateTime> GetDRMVideoLastModified(string url, Auth auth)
|
||||||
{
|
{
|
||||||
string[] messageUrlParsed = url.Split(',');
|
string[] messageUrlParsed = url.Split(',');
|
||||||
string mpdURL = messageUrlParsed[0];
|
string mpdUrl = messageUrlParsed[0];
|
||||||
string policy = messageUrlParsed[1];
|
string policy = messageUrlParsed[1];
|
||||||
string signature = messageUrlParsed[2];
|
string signature = messageUrlParsed[2];
|
||||||
string kvp = messageUrlParsed[3];
|
string kvp = messageUrlParsed[3];
|
||||||
|
|
||||||
mpdURL = mpdURL.Replace(".mpd", "_source.mp4");
|
mpdUrl = mpdUrl.Replace(".mpd", "_source.mp4");
|
||||||
|
|
||||||
using HttpClient client = new();
|
using HttpClient client = new();
|
||||||
client.DefaultRequestHeaders.Add("Cookie",
|
client.DefaultRequestHeaders.Add("Cookie",
|
||||||
$"CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {auth.Cookie}");
|
$"CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {auth.Cookie}");
|
||||||
client.DefaultRequestHeaders.Add("User-Agent", auth.UserAgent);
|
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.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
if (response.Content.Headers.LastModified != null)
|
if (response.Content.Headers.LastModified != null)
|
||||||
@ -624,8 +623,8 @@ public class DownloadService(
|
|||||||
/// Processes the download and database update of media.
|
/// Processes the download and database update of media.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="folder">The folder where the media is stored.</param>
|
/// <param name="folder">The folder where the media is stored.</param>
|
||||||
/// <param name="media_id">The ID of the media.</param>
|
/// <param name="mediaId">The ID of the media.</param>
|
||||||
/// <param name="api_type"></param>
|
/// <param name="apiType"></param>
|
||||||
/// <param name="url">The URL from where to download the media.</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="path">The relative path to the media.</param>
|
||||||
/// <param name="serverFilename"></param>
|
/// <param name="serverFilename"></param>
|
||||||
@ -634,8 +633,8 @@ public class DownloadService(
|
|||||||
/// <param name="progressReporter"></param>
|
/// <param name="progressReporter"></param>
|
||||||
/// <returns>A Task resulting in a boolean indicating whether the media is newly downloaded or not.</returns>
|
/// <returns>A Task resulting in a boolean indicating whether the media is newly downloaded or not.</returns>
|
||||||
public async Task<bool> ProcessMediaDownload(string folder,
|
public async Task<bool> ProcessMediaDownload(string folder,
|
||||||
long media_id,
|
long mediaId,
|
||||||
string api_type,
|
string apiType,
|
||||||
string url,
|
string url,
|
||||||
string path,
|
string path,
|
||||||
string serverFilename,
|
string serverFilename,
|
||||||
@ -645,11 +644,11 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!await dbService.CheckDownloaded(folder, media_id, api_type))
|
if (!await dbService.CheckDownloaded(folder, mediaId, apiType))
|
||||||
{
|
{
|
||||||
return await HandleNewMedia(folder,
|
return await HandleNewMedia(folder,
|
||||||
media_id,
|
mediaId,
|
||||||
api_type,
|
apiType,
|
||||||
url,
|
url,
|
||||||
path,
|
path,
|
||||||
serverFilename,
|
serverFilename,
|
||||||
@ -658,11 +657,11 @@ public class DownloadService(
|
|||||||
progressReporter);
|
progressReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool status = await HandlePreviouslyDownloadedMediaAsync(folder, media_id, api_type, progressReporter);
|
bool status = await HandlePreviouslyDownloadedMediaAsync(folder, mediaId, apiType, progressReporter);
|
||||||
if (configService.CurrentConfig.RenameExistingFilesWhenCustomFormatIsSelected &&
|
if (configService.CurrentConfig.RenameExistingFilesWhenCustomFormatIsSelected &&
|
||||||
serverFilename != resolvedFilename)
|
serverFilename != resolvedFilename)
|
||||||
{
|
{
|
||||||
await HandleRenamingOfExistingFilesAsync(folder, media_id, api_type, path, serverFilename,
|
await HandleRenamingOfExistingFilesAsync(folder, mediaId, apiType, path, serverFilename,
|
||||||
resolvedFilename, extension);
|
resolvedFilename, extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,9 +676,9 @@ public class DownloadService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<bool> HandleRenamingOfExistingFilesAsync(string folder,
|
private async Task HandleRenamingOfExistingFilesAsync(string folder,
|
||||||
long media_id,
|
long mediaId,
|
||||||
string api_type,
|
string apiType,
|
||||||
string path,
|
string path,
|
||||||
string serverFilename,
|
string serverFilename,
|
||||||
string resolvedFilename,
|
string resolvedFilename,
|
||||||
@ -689,7 +688,7 @@ public class DownloadService(
|
|||||||
string fullPathWithTheNewFileName = $"{folder}{path}/{resolvedFilename}{extension}";
|
string fullPathWithTheNewFileName = $"{folder}{path}/{resolvedFilename}{extension}";
|
||||||
if (!File.Exists(fullPathWithTheServerFileName))
|
if (!File.Exists(fullPathWithTheServerFileName))
|
||||||
{
|
{
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -699,14 +698,13 @@ public class DownloadService(
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"An error occurred: {ex.Message}");
|
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);
|
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);
|
lastModified);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1084,17 +1082,13 @@ public class DownloadService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(string decryptionKey, DateTime lastModified)?> GetDecryptionInfo(
|
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,
|
string mediaId, string contentId, string drmType,
|
||||||
bool clientIdBlobMissing, bool devicePrivateKeyMissing)
|
bool clientIdBlobMissing, bool devicePrivateKeyMissing)
|
||||||
{
|
{
|
||||||
string? pssh = await apiService.GetDRMMPDPSSH(mpdURL, policy, signature, kvp);
|
string pssh = await apiService.GetDRMMPDPSSH(mpdUrl, policy, signature, kvp);
|
||||||
if (pssh == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime lastModified = await apiService.GetDRMMPDLastModified(mpdURL, policy, signature, kvp);
|
DateTime lastModified = await apiService.GetDRMMPDLastModified(mpdUrl, policy, signature, kvp);
|
||||||
Dictionary<string, string> drmHeaders =
|
Dictionary<string, string> drmHeaders =
|
||||||
apiService.GetDynamicHeaders($"/api2/v2/users/media/{mediaId}/drm/{drmType}/{contentId}",
|
apiService.GetDynamicHeaders($"/api2/v2/users/media/{mediaId}/drm/{drmType}/{contentId}",
|
||||||
"?type=widevine");
|
"?type=widevine");
|
||||||
@ -1220,7 +1214,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadArchived - {username}");
|
Log.Debug($"Calling DownloadArchived - {username}");
|
||||||
|
|
||||||
if (archived == null || archived.ArchivedPosts.Count == 0)
|
if (archived.ArchivedPosts.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Found 0 Archived Posts");
|
Log.Debug("Found 0 Archived Posts");
|
||||||
return new DownloadResult
|
return new DownloadResult
|
||||||
@ -1244,8 +1238,9 @@ public class DownloadService(
|
|||||||
bool isNew;
|
bool isNew;
|
||||||
ArchivedEntities.Medium? mediaInfo =
|
ArchivedEntities.Medium? mediaInfo =
|
||||||
archived.ArchivedPostMedia.FirstOrDefault(m => m.Id == archivedKVP.Key);
|
archived.ArchivedPostMedia.FirstOrDefault(m => m.Id == archivedKVP.Key);
|
||||||
ArchivedEntities.ListItem? postInfo =
|
ArchivedEntities.ListItem? postInfo = mediaInfo == null
|
||||||
archived.ArchivedPostObjects.FirstOrDefault(p => p?.Media?.Contains(mediaInfo) == true);
|
? null
|
||||||
|
: archived.ArchivedPostObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
|
||||||
string filenameFormat =
|
string filenameFormat =
|
||||||
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
|
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
|
||||||
|
|
||||||
@ -1300,7 +1295,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadMessages - {username}");
|
Log.Debug($"Calling DownloadMessages - {username}");
|
||||||
|
|
||||||
if (messages == null || messages.Messages.Count == 0)
|
if (messages.Messages.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Found 0 Messages");
|
Log.Debug("Found 0 Messages");
|
||||||
return new DownloadResult
|
return new DownloadResult
|
||||||
@ -1323,11 +1318,11 @@ public class DownloadService(
|
|||||||
bool isNew;
|
bool isNew;
|
||||||
MessageEntities.Medium? mediaInfo = messages.MessageMedia.FirstOrDefault(m => m.Id == messageKVP.Key);
|
MessageEntities.Medium? mediaInfo = messages.MessageMedia.FirstOrDefault(m => m.Id == messageKVP.Key);
|
||||||
MessageEntities.ListItem? messageInfo = messages.MessageObjects.FirstOrDefault(p =>
|
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 =
|
string filenameFormat =
|
||||||
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).MessageFileNameFormat ?? "";
|
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).MessageFileNameFormat ?? "";
|
||||||
string messagePath = configService.CurrentConfig.FolderPerMessage && messageInfo != null &&
|
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/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Messages/Free";
|
: "/Messages/Free";
|
||||||
|
|
||||||
@ -1383,7 +1378,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadPaidMessages - {username}");
|
Log.Debug($"Calling DownloadPaidMessages - {username}");
|
||||||
|
|
||||||
if (paidMessageCollection == null || paidMessageCollection.PaidMessages.Count == 0)
|
if (paidMessageCollection.PaidMessages.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Found 0 Paid Messages");
|
Log.Debug("Found 0 Paid Messages");
|
||||||
return new DownloadResult
|
return new DownloadResult
|
||||||
@ -1408,11 +1403,11 @@ public class DownloadService(
|
|||||||
MessageEntities.Medium? mediaInfo =
|
MessageEntities.Medium? mediaInfo =
|
||||||
paidMessageCollection.PaidMessageMedia.FirstOrDefault(m => m.Id == kvpEntry.Key);
|
paidMessageCollection.PaidMessageMedia.FirstOrDefault(m => m.Id == kvpEntry.Key);
|
||||||
PurchasedEntities.ListItem? messageInfo = paidMessageCollection.PaidMessageObjects.FirstOrDefault(p =>
|
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 =
|
string filenameFormat =
|
||||||
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).MessageFileNameFormat ?? "";
|
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).MessageFileNameFormat ?? "";
|
||||||
string paidMsgPath = configService.CurrentConfig.FolderPerPaidMessage && messageInfo != null &&
|
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/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Messages/Paid";
|
: "/Messages/Paid";
|
||||||
|
|
||||||
@ -1465,7 +1460,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadStreams - {username}");
|
Log.Debug($"Calling DownloadStreams - {username}");
|
||||||
|
|
||||||
if (streams == null || streams.Streams.Count == 0)
|
if (streams.Streams.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Found 0 Streams");
|
Log.Debug("Found 0 Streams");
|
||||||
return new DownloadResult
|
return new DownloadResult
|
||||||
@ -1487,12 +1482,12 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
bool isNew;
|
bool isNew;
|
||||||
StreamEntities.Medium? mediaInfo = streams.StreamMedia.FirstOrDefault(m => m.Id == kvpEntry.Key);
|
StreamEntities.Medium? mediaInfo = streams.StreamMedia.FirstOrDefault(m => m.Id == kvpEntry.Key);
|
||||||
StreamEntities.ListItem? streamInfo =
|
StreamEntities.ListItem? streamInfo = mediaInfo == null
|
||||||
streams.StreamObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
|
? null
|
||||||
|
: streams.StreamObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
|
||||||
string filenameFormat =
|
string filenameFormat =
|
||||||
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
|
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
|
||||||
string streamPath = configService.CurrentConfig.FolderPerPost && streamInfo != null &&
|
string streamPath = configService.CurrentConfig.FolderPerPost && streamInfo != null && streamInfo.Id != 0
|
||||||
streamInfo?.Id is not null && streamInfo?.PostedAt is not null
|
|
||||||
? $"/Posts/Free/{streamInfo.Id} {streamInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
|
? $"/Posts/Free/{streamInfo.Id} {streamInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Posts/Free";
|
: "/Posts/Free";
|
||||||
|
|
||||||
@ -1546,7 +1541,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadFreePosts - {username}");
|
Log.Debug($"Calling DownloadFreePosts - {username}");
|
||||||
|
|
||||||
if (posts == null || posts.Posts.Count == 0)
|
if (posts.Posts.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Found 0 Posts");
|
Log.Debug("Found 0 Posts");
|
||||||
return new DownloadResult
|
return new DownloadResult
|
||||||
@ -1566,13 +1561,13 @@ public class DownloadService(
|
|||||||
foreach (KeyValuePair<long, string> postKVP in posts.Posts)
|
foreach (KeyValuePair<long, string> postKVP in posts.Posts)
|
||||||
{
|
{
|
||||||
bool isNew;
|
bool isNew;
|
||||||
PostEntities.Medium? mediaInfo = posts.PostMedia.FirstOrDefault(m => m?.Id == postKVP.Key);
|
PostEntities.Medium? mediaInfo = posts.PostMedia.FirstOrDefault(m => m.Id == postKVP.Key);
|
||||||
PostEntities.ListItem? postInfo =
|
PostEntities.ListItem? postInfo = mediaInfo == null
|
||||||
posts.PostObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
|
? null
|
||||||
|
: posts.PostObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
|
||||||
string filenameFormat =
|
string filenameFormat =
|
||||||
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
|
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
|
||||||
string postPath = configService.CurrentConfig.FolderPerPost && postInfo != null &&
|
string postPath = configService.CurrentConfig.FolderPerPost && postInfo != null && postInfo.Id != 0
|
||||||
postInfo?.Id is not null && postInfo?.PostedAt is not null
|
|
||||||
? $"/Posts/Free/{postInfo.Id} {postInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
|
? $"/Posts/Free/{postInfo.Id} {postInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Posts/Free";
|
: "/Posts/Free";
|
||||||
|
|
||||||
@ -1625,7 +1620,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadPaidPosts - {username}");
|
Log.Debug($"Calling DownloadPaidPosts - {username}");
|
||||||
|
|
||||||
if (purchasedPosts == null || purchasedPosts.PaidPosts.Count == 0)
|
if (purchasedPosts.PaidPosts.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Found 0 Paid Posts");
|
Log.Debug("Found 0 Paid Posts");
|
||||||
return new DownloadResult
|
return new DownloadResult
|
||||||
@ -1649,11 +1644,11 @@ public class DownloadService(
|
|||||||
MessageEntities.Medium? mediaInfo =
|
MessageEntities.Medium? mediaInfo =
|
||||||
purchasedPosts.PaidPostMedia.FirstOrDefault(m => m.Id == postKVP.Key);
|
purchasedPosts.PaidPostMedia.FirstOrDefault(m => m.Id == postKVP.Key);
|
||||||
PurchasedEntities.ListItem? postInfo =
|
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 =
|
string filenameFormat =
|
||||||
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
|
configService.CurrentConfig.GetCreatorFileNameFormatConfig(username).PostFileNameFormat ?? "";
|
||||||
string paidPostPath = configService.CurrentConfig.FolderPerPaidPost && postInfo != null &&
|
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/{postInfo.Id} {postInfo.PostedAt.Value:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Posts/Paid";
|
: "/Posts/Paid";
|
||||||
|
|
||||||
@ -1706,7 +1701,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadPaidPostsPurchasedTab - {username}");
|
Log.Debug($"Calling DownloadPaidPostsPurchasedTab - {username}");
|
||||||
|
|
||||||
if (purchasedPosts == null || purchasedPosts.PaidPosts.Count == 0)
|
if (purchasedPosts.PaidPosts.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Found 0 Paid Posts");
|
Log.Debug("Found 0 Paid Posts");
|
||||||
return new DownloadResult { TotalCount = 0, MediaType = "Paid Posts", Success = true };
|
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);
|
purchasedPosts?.PaidPostMedia?.FirstOrDefault(m => m.Id == purchasedPostKVP.Key);
|
||||||
PurchasedEntities.ListItem? postInfo = mediaInfo != null
|
PurchasedEntities.ListItem? postInfo = mediaInfo != null
|
||||||
? purchasedPosts?.PaidPostObjects?.FirstOrDefault(p =>
|
? purchasedPosts?.PaidPostObjects?.FirstOrDefault(p =>
|
||||||
p?.Media?.Any(m => m.Id == purchasedPostKVP.Key) == true)
|
p.Media?.Any(m => m.Id == purchasedPostKVP.Key) == true)
|
||||||
: null;
|
: null;
|
||||||
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
|
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
|
||||||
.PaidPostFileNameFormat ?? "";
|
.PaidPostFileNameFormat ?? "";
|
||||||
string paidPostPath = configService.CurrentConfig.FolderPerPaidPost && postInfo != null &&
|
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/{postInfo.Id} {postInfo.PostedAt.Value:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Posts/Paid";
|
: "/Posts/Paid";
|
||||||
|
|
||||||
@ -1766,7 +1761,7 @@ public class DownloadService(
|
|||||||
Log.Debug($"Paid Posts Already Downloaded: {oldCount} New Paid Posts Downloaded: {newCount}");
|
Log.Debug($"Paid Posts Already Downloaded: {oldCount} New Paid Posts Downloaded: {newCount}");
|
||||||
return new DownloadResult
|
return new DownloadResult
|
||||||
{
|
{
|
||||||
TotalCount = purchasedPosts.PaidPosts.Count,
|
TotalCount = purchasedPosts?.PaidPosts.Count ?? 0,
|
||||||
NewDownloads = newCount,
|
NewDownloads = newCount,
|
||||||
ExistingDownloads = oldCount,
|
ExistingDownloads = oldCount,
|
||||||
MediaType = "Paid Posts",
|
MediaType = "Paid Posts",
|
||||||
@ -1780,7 +1775,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadPaidMessagesPurchasedTab - {username}");
|
Log.Debug($"Calling DownloadPaidMessagesPurchasedTab - {username}");
|
||||||
|
|
||||||
if (paidMessageCollection == null || paidMessageCollection.PaidMessages.Count == 0)
|
if (paidMessageCollection.PaidMessages.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Found 0 Paid Messages");
|
Log.Debug("Found 0 Paid Messages");
|
||||||
return new DownloadResult { TotalCount = 0, MediaType = "Paid Messages", Success = true };
|
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);
|
paidMessageCollection.PaidMessageMedia.FirstOrDefault(m => m.Id == paidMessageKVP.Key);
|
||||||
PurchasedEntities.ListItem? messageInfo =
|
PurchasedEntities.ListItem? messageInfo =
|
||||||
paidMessageCollection.PaidMessageObjects.FirstOrDefault(p =>
|
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)
|
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
|
||||||
.PaidMessageFileNameFormat ?? "";
|
.PaidMessageFileNameFormat ?? "";
|
||||||
string paidMsgPath = configService.CurrentConfig.FolderPerPaidMessage && messageInfo != null &&
|
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/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Messages/Paid";
|
: "/Messages/Paid";
|
||||||
|
|
||||||
@ -1853,7 +1848,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadSinglePost - {username}");
|
Log.Debug($"Calling DownloadSinglePost - {username}");
|
||||||
|
|
||||||
if (post == null || post.SinglePosts.Count == 0)
|
if (post.SinglePosts.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Debug("Couldn't find post");
|
Log.Debug("Couldn't find post");
|
||||||
return new DownloadResult { TotalCount = 0, MediaType = "Posts", Success = true };
|
return new DownloadResult { TotalCount = 0, MediaType = "Posts", Success = true };
|
||||||
@ -1864,12 +1859,12 @@ public class DownloadService(
|
|||||||
foreach (KeyValuePair<long, string> postKVP in post.SinglePosts)
|
foreach (KeyValuePair<long, string> postKVP in post.SinglePosts)
|
||||||
{
|
{
|
||||||
PostEntities.Medium? mediaInfo = post.SinglePostMedia.FirstOrDefault(m => m.Id == postKVP.Key);
|
PostEntities.Medium? mediaInfo = post.SinglePostMedia.FirstOrDefault(m => m.Id == postKVP.Key);
|
||||||
PostEntities.SinglePost? postInfo =
|
PostEntities.SinglePost? postInfo = mediaInfo == null
|
||||||
post.SinglePostObjects.FirstOrDefault(p => p?.Media?.Contains(mediaInfo) == true);
|
? null
|
||||||
|
: post.SinglePostObjects.FirstOrDefault(p => p.Media?.Contains(mediaInfo) == true);
|
||||||
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
|
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
|
||||||
.PostFileNameFormat ?? "";
|
.PostFileNameFormat ?? "";
|
||||||
string postPath = configService.CurrentConfig.FolderPerPost && postInfo != null &&
|
string postPath = configService.CurrentConfig.FolderPerPost && postInfo != null && postInfo.Id != 0
|
||||||
postInfo?.Id is not null && postInfo?.PostedAt is not null
|
|
||||||
? $"/Posts/Free/{postInfo.Id} {postInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
|
? $"/Posts/Free/{postInfo.Id} {postInfo.PostedAt:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Posts/Free";
|
: "/Posts/Free";
|
||||||
|
|
||||||
@ -1930,12 +1925,7 @@ public class DownloadService(
|
|||||||
PurchasedEntities.SinglePaidMessageCollection singlePaidMessageCollection,
|
PurchasedEntities.SinglePaidMessageCollection singlePaidMessageCollection,
|
||||||
IProgressReporter progressReporter)
|
IProgressReporter progressReporter)
|
||||||
{
|
{
|
||||||
Log.Debug($"Calling DownloadSinglePaidMessage - {username}");
|
Log.Debug("Calling DownloadSinglePaidMessage - {Username}", username);
|
||||||
|
|
||||||
if (singlePaidMessageCollection == null)
|
|
||||||
{
|
|
||||||
return new DownloadResult { TotalCount = 0, MediaType = "Paid Messages", Success = true };
|
|
||||||
}
|
|
||||||
|
|
||||||
int totalNew = 0, totalOld = 0;
|
int totalNew = 0, totalOld = 0;
|
||||||
|
|
||||||
@ -1949,11 +1939,11 @@ public class DownloadService(
|
|||||||
m.Id == paidMessageKVP.Key);
|
m.Id == paidMessageKVP.Key);
|
||||||
MessageEntities.SingleMessage? messageInfo =
|
MessageEntities.SingleMessage? messageInfo =
|
||||||
singlePaidMessageCollection.SingleMessageObjects.FirstOrDefault(p =>
|
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)
|
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
|
||||||
.PaidMessageFileNameFormat ?? "";
|
.PaidMessageFileNameFormat ?? "";
|
||||||
string previewMsgPath = configService.CurrentConfig.FolderPerMessage && messageInfo != null &&
|
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/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Messages/Free";
|
: "/Messages/Free";
|
||||||
|
|
||||||
@ -2002,12 +1992,12 @@ public class DownloadService(
|
|||||||
m.Id == paidMessageKVP.Key);
|
m.Id == paidMessageKVP.Key);
|
||||||
MessageEntities.SingleMessage? messageInfo =
|
MessageEntities.SingleMessage? messageInfo =
|
||||||
singlePaidMessageCollection.SingleMessageObjects.FirstOrDefault(p =>
|
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)
|
string filenameFormat = configService.CurrentConfig.GetCreatorFileNameFormatConfig(username)
|
||||||
.PaidMessageFileNameFormat ?? "";
|
.PaidMessageFileNameFormat ?? "";
|
||||||
string singlePaidMsgPath = configService.CurrentConfig.FolderPerPaidMessage &&
|
string singlePaidMsgPath = configService.CurrentConfig.FolderPerPaidMessage &&
|
||||||
messageInfo != null && messageInfo?.Id is not null &&
|
messageInfo != null && messageInfo.Id != 0 &&
|
||||||
messageInfo?.CreatedAt is not null
|
messageInfo.CreatedAt is not null
|
||||||
? $"/Messages/Paid/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
|
? $"/Messages/Paid/{messageInfo.Id} {messageInfo.CreatedAt.Value:yyyy-MM-dd HH-mm-ss}"
|
||||||
: "/Messages/Paid";
|
: "/Messages/Paid";
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ public class StartupService(IConfigService configService, IAuthService authServi
|
|||||||
!result.FfmpegPath.Contains(@":\\"))
|
!result.FfmpegPath.Contains(@":\\"))
|
||||||
{
|
{
|
||||||
result.FfmpegPath = result.FfmpegPath.Replace(@"\", @"\\");
|
result.FfmpegPath = result.FfmpegPath.Replace(@"\", @"\\");
|
||||||
configService.CurrentConfig!.FFmpegPath = result.FfmpegPath;
|
configService.CurrentConfig.FFmpegPath = result.FfmpegPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get FFmpeg version
|
// Get FFmpeg version
|
||||||
@ -144,7 +144,7 @@ public class StartupService(IConfigService configService, IAuthService authServi
|
|||||||
|
|
||||||
private void DetectFfmpeg(StartupResult result)
|
private void DetectFfmpeg(StartupResult result)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(configService.CurrentConfig!.FFmpegPath) &&
|
if (!string.IsNullOrEmpty(configService.CurrentConfig.FFmpegPath) &&
|
||||||
ValidateFilePath(configService.CurrentConfig.FFmpegPath))
|
ValidateFilePath(configService.CurrentConfig.FFmpegPath))
|
||||||
{
|
{
|
||||||
result.FfmpegFound = true;
|
result.FfmpegFound = true;
|
||||||
|
|||||||
@ -67,7 +67,7 @@ public class ThrottledStream : Stream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task ThrottleAsync(int bytes)
|
private async Task ThrottleAsync(int bytes)
|
||||||
{
|
{
|
||||||
if (!shouldThrottle)
|
if (!shouldThrottle)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -21,6 +21,7 @@ internal static class XmlUtils
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@ -112,7 +112,7 @@ public class CDM
|
|||||||
{
|
{
|
||||||
//needed for HBO Max
|
//needed for HBO Max
|
||||||
|
|
||||||
PSSHBox psshBox = PSSHBox.FromByteArray(initData);
|
PsshBox psshBox = PsshBox.FromByteArray(initData);
|
||||||
cencHeader = Serializer.Deserialize<WidevineCencHeader>(new MemoryStream(psshBox.Data));
|
cencHeader = Serializer.Deserialize<WidevineCencHeader>(new MemoryStream(psshBox.Data));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -278,7 +278,7 @@ public class CDM
|
|||||||
encryptedClientIdProto.EncryptedClientId = mstream.ToArray();
|
encryptedClientIdProto.EncryptedClientId = mstream.ToArray();
|
||||||
|
|
||||||
using RSACryptoServiceProvider RSA = new();
|
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.EncryptedPrivacyKey = RSA.Encrypt(aesProvider.Key, RSAEncryptionPadding.OaepSHA1);
|
||||||
encryptedClientIdProto.EncryptedClientIdIv = aesProvider.IV;
|
encryptedClientIdProto.EncryptedClientIdIv = aesProvider.IV;
|
||||||
encryptedClientIdProto.ServiceId =
|
encryptedClientIdProto.ServiceId =
|
||||||
|
|||||||
@ -29,5 +29,13 @@ public class CDMApi
|
|||||||
CDM.ProvideLicense(SessionId, Convert.FromBase64String(licenseB64));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,10 @@ public class CDMDevice
|
|||||||
using StreamReader reader = File.OpenText(privateKeyPath);
|
using StreamReader reader = File.OpenText(privateKeyPath);
|
||||||
DeviceKeys = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
|
DeviceKeys = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("No device private key found");
|
||||||
|
}
|
||||||
|
|
||||||
if (vmpBytes != null)
|
if (vmpBytes != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,34 +1,34 @@
|
|||||||
namespace OF_DL.Widevine;
|
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;
|
KIDs = kids;
|
||||||
Data = data;
|
Data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<byte[]> KIDs { get; set; } = new();
|
public List<byte[]> KIDs { get; set; }
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
|
|
||||||
public static PSSHBox FromByteArray(byte[] psshbox)
|
public static PsshBox FromByteArray(byte[] psshbox)
|
||||||
{
|
{
|
||||||
using MemoryStream stream = new(psshbox);
|
using MemoryStream stream = new(psshbox);
|
||||||
|
|
||||||
stream.Seek(4, SeekOrigin.Current);
|
stream.Seek(4, SeekOrigin.Current);
|
||||||
byte[] header = new byte[4];
|
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");
|
throw new Exception("Not a pssh box");
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.Seek(20, SeekOrigin.Current);
|
stream.Seek(20, SeekOrigin.Current);
|
||||||
byte[] kidCountBytes = new byte[4];
|
byte[] kidCountBytes = new byte[4];
|
||||||
stream.Read(kidCountBytes, 0, 4);
|
stream.ReadExactly(kidCountBytes, 0, 4);
|
||||||
|
|
||||||
if (BitConverter.IsLittleEndian)
|
if (BitConverter.IsLittleEndian)
|
||||||
{
|
{
|
||||||
@ -41,12 +41,12 @@ internal class PSSHBox
|
|||||||
for (int i = 0; i < kidCount; i++)
|
for (int i = 0; i < kidCount; i++)
|
||||||
{
|
{
|
||||||
byte[] kid = new byte[16];
|
byte[] kid = new byte[16];
|
||||||
stream.Read(kid);
|
stream.ReadExactly(kid);
|
||||||
kids.Add(kid);
|
kids.Add(kid);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] dataLengthBytes = new byte[4];
|
byte[] dataLengthBytes = new byte[4];
|
||||||
stream.Read(dataLengthBytes);
|
stream.ReadExactly(dataLengthBytes);
|
||||||
|
|
||||||
if (BitConverter.IsLittleEndian)
|
if (BitConverter.IsLittleEndian)
|
||||||
{
|
{
|
||||||
@ -57,12 +57,12 @@ internal class PSSHBox
|
|||||||
|
|
||||||
if (dataLength == 0)
|
if (dataLength == 0)
|
||||||
{
|
{
|
||||||
return new PSSHBox(kids, []);
|
return new PsshBox(kids, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] data = new byte[dataLength];
|
byte[] data = new byte[dataLength];
|
||||||
stream.Read(data);
|
stream.ReadExactly(data);
|
||||||
|
|
||||||
return new PSSHBox(kids, data);
|
return new PsshBox(kids, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user