Fix remaining compiler warnings
This commit is contained in:
parent
85c9bc1f57
commit
4a218a3efe
@ -384,13 +384,13 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
string endpoint,
|
string endpoint,
|
||||||
string? username,
|
string? username,
|
||||||
string folder,
|
string folder,
|
||||||
List<long> paid_post_ids)
|
List<long> paidPostIds)
|
||||||
{
|
{
|
||||||
Log.Debug($"Calling GetMedia - {username}");
|
Log.Debug($"Calling GetMedia - {username}");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Dictionary<long, string> return_urls = new();
|
Dictionary<long, string> returnUrls = new();
|
||||||
const int postLimit = 50;
|
const int postLimit = 50;
|
||||||
int limit = 5;
|
int limit = 5;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
@ -419,7 +419,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
if (string.IsNullOrWhiteSpace(body))
|
if (string.IsNullOrWhiteSpace(body))
|
||||||
{
|
{
|
||||||
Log.Warning("GetMedia returned empty response for {Endpoint}", endpoint);
|
Log.Warning("GetMedia returned empty response for {Endpoint}", endpoint);
|
||||||
return return_urls;
|
return returnUrls;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mediatype == MediaType.Stories)
|
if (mediatype == MediaType.Stories)
|
||||||
@ -485,9 +485,9 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (medium.CanView && !return_urls.ContainsKey(medium.Id))
|
if (medium.CanView && !returnUrls.ContainsKey(medium.Id))
|
||||||
{
|
{
|
||||||
return_urls.Add(medium.Id, mediaUrl);
|
returnUrls.Add(medium.Id, mediaUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -538,22 +538,22 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string highlight_id in highlightIds)
|
foreach (string highlightId in highlightIds)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> highlight_headers =
|
Dictionary<string, string> highlightHeaders =
|
||||||
GetDynamicHeaders("/api2/v2/stories/highlights/" + highlight_id, "");
|
GetDynamicHeaders("/api2/v2/stories/highlights/" + highlightId, "");
|
||||||
|
|
||||||
HttpClient highlight_client = GetHttpClient();
|
HttpClient highlightClient = GetHttpClient();
|
||||||
|
|
||||||
HttpRequestMessage highlight_request = new(HttpMethod.Get,
|
HttpRequestMessage highlightRequest = new(HttpMethod.Get,
|
||||||
$"https://onlyfans.com/api2/v2/stories/highlights/{highlight_id}");
|
$"https://onlyfans.com/api2/v2/stories/highlights/{highlightId}");
|
||||||
|
|
||||||
foreach (KeyValuePair<string, string> keyValuePair in highlight_headers)
|
foreach (KeyValuePair<string, string> keyValuePair in highlightHeaders)
|
||||||
{
|
{
|
||||||
highlight_request.Headers.Add(keyValuePair.Key, keyValuePair.Value);
|
highlightRequest.Headers.Add(keyValuePair.Key, keyValuePair.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
using HttpResponseMessage highlightResponse = await highlight_client.SendAsync(highlight_request);
|
using HttpResponseMessage highlightResponse = await highlightClient.SendAsync(highlightRequest);
|
||||||
highlightResponse.EnsureSuccessStatusCode();
|
highlightResponse.EnsureSuccessStatusCode();
|
||||||
string highlightBody = await highlightResponse.Content.ReadAsStringAsync();
|
string highlightBody = await highlightResponse.Content.ReadAsStringAsync();
|
||||||
HighlightDtos.HighlightMediaDto? highlightMediaDto =
|
HighlightDtos.HighlightMediaDto? highlightMediaDto =
|
||||||
@ -608,9 +608,9 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!return_urls.ContainsKey(medium.Id) && !string.IsNullOrEmpty(storyUrl))
|
if (!returnUrls.ContainsKey(medium.Id) && !string.IsNullOrEmpty(storyUrl))
|
||||||
{
|
{
|
||||||
return_urls.Add(medium.Id, storyUrl);
|
returnUrls.Add(medium.Id, storyUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,7 +618,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return return_urls;
|
return returnUrls;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -640,7 +640,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
|
|
||||||
public async Task<PurchasedEntities.PaidPostCollection> GetPaidPosts(string endpoint, string folder,
|
public async Task<PurchasedEntities.PaidPostCollection> GetPaidPosts(string endpoint, string folder,
|
||||||
string username,
|
string username,
|
||||||
List<long> paid_post_ids, IStatusReporter statusReporter)
|
List<long> paidPostIds, IStatusReporter statusReporter)
|
||||||
{
|
{
|
||||||
Log.Debug($"Calling GetPaidPosts - {username}");
|
Log.Debug($"Calling GetPaidPosts - {username}");
|
||||||
|
|
||||||
@ -726,7 +726,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
{
|
{
|
||||||
if (!previewids.Contains(medium.Id))
|
if (!previewids.Contains(medium.Id))
|
||||||
{
|
{
|
||||||
paid_post_ids.Add(medium.Id);
|
paidPostIds.Add(medium.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (medium.Type == "photo" && !configService.CurrentConfig.DownloadImages)
|
if (medium.Type == "photo" && !configService.CurrentConfig.DownloadImages)
|
||||||
@ -834,7 +834,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<PostEntities.PostCollection> GetPosts(string endpoint, string folder, List<long> paid_post_ids,
|
public async Task<PostEntities.PostCollection> GetPosts(string endpoint, string folder, List<long> paidPostIds,
|
||||||
IStatusReporter statusReporter)
|
IStatusReporter statusReporter)
|
||||||
{
|
{
|
||||||
Log.Debug($"Calling GetPosts - {endpoint}");
|
Log.Debug($"Calling GetPosts - {endpoint}");
|
||||||
@ -978,7 +978,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
|
|
||||||
if (medium.CanView && medium.Files?.Drm == null)
|
if (medium.CanView && medium.Files?.Drm == null)
|
||||||
{
|
{
|
||||||
bool has = paid_post_ids.Any(cus => cus.Equals(medium.Id));
|
bool has = paidPostIds.Any(cus => cus.Equals(medium.Id));
|
||||||
if (!has && !string.IsNullOrEmpty(fullUrl))
|
if (!has && !string.IsNullOrEmpty(fullUrl))
|
||||||
{
|
{
|
||||||
if (!postCollection.Posts.ContainsKey(medium.Id))
|
if (!postCollection.Posts.ContainsKey(medium.Id))
|
||||||
@ -1004,7 +1004,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
TryGetDrmInfo(medium.Files, out string manifestDash, out string cloudFrontPolicy,
|
TryGetDrmInfo(medium.Files, out string manifestDash, out string cloudFrontPolicy,
|
||||||
out string cloudFrontSignature, out string cloudFrontKeyPairId))
|
out string cloudFrontSignature, out string cloudFrontKeyPairId))
|
||||||
{
|
{
|
||||||
bool has = paid_post_ids.Any(cus => cus.Equals(medium.Id));
|
bool has = paidPostIds.Any(cus => cus.Equals(medium.Id));
|
||||||
if (!has && !postCollection.Posts.ContainsKey(medium.Id))
|
if (!has && !postCollection.Posts.ContainsKey(medium.Id))
|
||||||
{
|
{
|
||||||
await dbService.AddMedia(folder, medium.Id, post.Id, manifestDash, null, null, null,
|
await dbService.AddMedia(folder, medium.Id, post.Id, manifestDash, null, null, null,
|
||||||
@ -1197,7 +1197,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<StreamEntities.StreamsCollection> GetStreams(string endpoint, string folder,
|
public async Task<StreamEntities.StreamsCollection> GetStreams(string endpoint, string folder,
|
||||||
List<long> paid_post_ids,
|
List<long> paidPostIds,
|
||||||
IStatusReporter statusReporter)
|
IStatusReporter statusReporter)
|
||||||
{
|
{
|
||||||
Log.Debug($"Calling GetStreams - {endpoint}");
|
Log.Debug($"Calling GetStreams - {endpoint}");
|
||||||
@ -1311,7 +1311,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
|
|
||||||
if (medium.CanView && medium.Files?.Drm == null)
|
if (medium.CanView && medium.Files?.Drm == null)
|
||||||
{
|
{
|
||||||
bool has = paid_post_ids.Any(cus => cus.Equals(medium.Id));
|
bool has = paidPostIds.Any(cus => cus.Equals(medium.Id));
|
||||||
if (!has && !string.IsNullOrEmpty(fullUrl))
|
if (!has && !string.IsNullOrEmpty(fullUrl))
|
||||||
{
|
{
|
||||||
if (!streamsCollection.Streams.ContainsKey(medium.Id))
|
if (!streamsCollection.Streams.ContainsKey(medium.Id))
|
||||||
@ -1327,7 +1327,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
TryGetDrmInfo(medium.Files, out string manifestDash, out string cloudFrontPolicy,
|
TryGetDrmInfo(medium.Files, out string manifestDash, out string cloudFrontPolicy,
|
||||||
out string cloudFrontSignature, out string cloudFrontKeyPairId))
|
out string cloudFrontSignature, out string cloudFrontKeyPairId))
|
||||||
{
|
{
|
||||||
bool has = paid_post_ids.Any(cus => cus.Equals(medium.Id));
|
bool has = paidPostIds.Any(cus => cus.Equals(medium.Id));
|
||||||
if (!has && !streamsCollection.Streams.ContainsKey(medium.Id))
|
if (!has && !streamsCollection.Streams.ContainsKey(medium.Id))
|
||||||
{
|
{
|
||||||
await dbService.AddMedia(folder, medium.Id, stream.Id, manifestDash, null, null, null,
|
await dbService.AddMedia(folder, medium.Id, stream.Id, manifestDash, null, null, null,
|
||||||
@ -1451,7 +1451,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await dbService.AddPost(folder, archive.Id, archive.Text != null ? archive.Text : "",
|
await dbService.AddPost(folder, archive.Id, archive.Text ?? "",
|
||||||
archive.Price ?? "0",
|
archive.Price ?? "0",
|
||||||
archive.Price != null && archive.IsOpened, archive.IsArchived, archive.PostedAt);
|
archive.Price != null && archive.IsOpened, archive.IsArchived, archive.PostedAt);
|
||||||
archivedCollection.ArchivedPostObjects.Add(archive);
|
archivedCollection.ArchivedPostObjects.Add(archive);
|
||||||
@ -1567,7 +1567,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
getParams["id"] = newMessages.List[newMessages.List.Count - 1].Id.ToString();
|
getParams["id"] = newMessages.List[^1].Id.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1601,8 +1601,8 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
{
|
{
|
||||||
DateTime createdAt = list.CreatedAt ?? DateTime.Now;
|
DateTime createdAt = list.CreatedAt ?? DateTime.Now;
|
||||||
await dbService.AddMessage(folder, list.Id, list.Text ?? "", list.Price ?? "0",
|
await dbService.AddMessage(folder, list.Id, list.Text ?? "", list.Price ?? "0",
|
||||||
list.CanPurchaseReason == "opened" ? true :
|
list.CanPurchaseReason == "opened" ||
|
||||||
list.CanPurchaseReason != "opened" ? false : (bool?)null ?? false, false,
|
(list.CanPurchaseReason == "opened" && ((bool?)null ?? false)), false,
|
||||||
createdAt,
|
createdAt,
|
||||||
list.FromUser?.Id ?? int.MinValue);
|
list.FromUser?.Id ?? int.MinValue);
|
||||||
messageCollection.MessageObjects.Add(list);
|
messageCollection.MessageObjects.Add(list);
|
||||||
@ -2907,24 +2907,19 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
throw new Exception("Auth service is missing required fields");
|
throw new Exception("Auth service is missing required fields");
|
||||||
}
|
}
|
||||||
|
|
||||||
string? pssh;
|
|
||||||
|
|
||||||
HttpClient client = new();
|
HttpClient client = new();
|
||||||
HttpRequestMessage request = new(HttpMethod.Get, mpdUrl);
|
HttpRequestMessage request = new(HttpMethod.Get, mpdUrl);
|
||||||
request.Headers.Add("user-agent", currentAuth.UserAgent);
|
request.Headers.Add("user-agent", currentAuth.UserAgent);
|
||||||
request.Headers.Add("Accept", "*/*");
|
request.Headers.Add("Accept", "*/*");
|
||||||
request.Headers.Add("Cookie",
|
request.Headers.Add("Cookie",
|
||||||
$"CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {currentAuth.Cookie};");
|
$"CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {currentAuth.Cookie};");
|
||||||
using (HttpResponseMessage response = await client.SendAsync(request))
|
using HttpResponseMessage response = await client.SendAsync(request);
|
||||||
{
|
response.EnsureSuccessStatusCode();
|
||||||
response.EnsureSuccessStatusCode();
|
string body = await response.Content.ReadAsStringAsync();
|
||||||
string body = await response.Content.ReadAsStringAsync();
|
XNamespace cenc = "urn:mpeg:cenc:2013";
|
||||||
XNamespace ns = "urn:mpeg:dash:schema:mpd:2011";
|
XDocument xmlDoc = XDocument.Parse(body);
|
||||||
XNamespace cenc = "urn:mpeg:cenc:2013";
|
IEnumerable<XElement> psshElements = xmlDoc.Descendants(cenc + "pssh");
|
||||||
XDocument xmlDoc = XDocument.Parse(body);
|
string pssh = psshElements.ElementAt(1).Value;
|
||||||
IEnumerable<XElement> psshElements = xmlDoc.Descendants(cenc + "pssh");
|
|
||||||
pssh = psshElements.ElementAt(1).Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pssh;
|
return pssh;
|
||||||
}
|
}
|
||||||
@ -2956,8 +2951,6 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DateTime lastmodified;
|
|
||||||
|
|
||||||
Auth? currentAuth = authService.CurrentAuth;
|
Auth? currentAuth = authService.CurrentAuth;
|
||||||
if (currentAuth == null || currentAuth.UserAgent == null || currentAuth.Cookie == null)
|
if (currentAuth == null || currentAuth.UserAgent == null || currentAuth.Cookie == null)
|
||||||
{
|
{
|
||||||
@ -2970,14 +2963,12 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
request.Headers.Add("Accept", "*/*");
|
request.Headers.Add("Accept", "*/*");
|
||||||
request.Headers.Add("Cookie",
|
request.Headers.Add("Cookie",
|
||||||
$"CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {currentAuth.Cookie};");
|
$"CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {currentAuth.Cookie};");
|
||||||
using (HttpResponseMessage response =
|
using HttpResponseMessage response =
|
||||||
await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead))
|
await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||||
{
|
response.EnsureSuccessStatusCode();
|
||||||
response.EnsureSuccessStatusCode();
|
DateTime lastmodified = response.Content.Headers.LastModified?.LocalDateTime ?? DateTime.Now;
|
||||||
lastmodified = response.Content.Headers.LastModified?.LocalDateTime ?? DateTime.Now;
|
|
||||||
|
|
||||||
Log.Debug($"Last modified: {lastmodified}");
|
Log.Debug($"Last modified: {lastmodified}");
|
||||||
}
|
|
||||||
|
|
||||||
return lastmodified;
|
return lastmodified;
|
||||||
}
|
}
|
||||||
@ -3061,14 +3052,14 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetDecryptionKeyCDM(Dictionary<string, string> drmHeaders, string licenceURL,
|
public async Task<string> GetDecryptionKeyCDM(Dictionary<string, string> drmHeaders, string licenceUrl,
|
||||||
string pssh)
|
string pssh)
|
||||||
{
|
{
|
||||||
Log.Debug("Calling GetDecryptionKeyCDM");
|
Log.Debug("Calling GetDecryptionKeyCDM");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] resp1 = await PostData(licenceURL, drmHeaders, [0x08, 0x04]);
|
byte[] resp1 = await PostData(licenceUrl, drmHeaders, [0x08, 0x04]);
|
||||||
string certDataB64 = Convert.ToBase64String(resp1);
|
string certDataB64 = Convert.ToBase64String(resp1);
|
||||||
CDMApi cdm = new();
|
CDMApi cdm = new();
|
||||||
byte[]? challenge = cdm.GetChallenge(pssh, certDataB64);
|
byte[]? challenge = cdm.GetChallenge(pssh, certDataB64);
|
||||||
@ -3077,7 +3068,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
throw new Exception("Failed to get challenge from CDM");
|
throw new Exception("Failed to get challenge from CDM");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] resp2 = await PostData(licenceURL, drmHeaders, challenge);
|
byte[] resp2 = await PostData(licenceUrl, drmHeaders, challenge);
|
||||||
string licenseB64 = Convert.ToBase64String(resp2);
|
string licenseB64 = Convert.ToBase64String(resp2);
|
||||||
Log.Debug("resp1: {Resp1}", resp1);
|
Log.Debug("resp1: {Resp1}", resp1);
|
||||||
Log.Debug("certDataB64: {CertDataB64}", certDataB64);
|
Log.Debug("certDataB64: {CertDataB64}", certDataB64);
|
||||||
@ -3156,7 +3147,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
diff.TotalSeconds; // This gives the number of seconds. If you need milliseconds, use diff.TotalMilliseconds
|
diff.TotalSeconds; // This gives the number of seconds. If you need milliseconds, use diff.TotalMilliseconds
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsStringOnlyDigits(string input) => input.All(char.IsDigit);
|
private static bool IsStringOnlyDigits(string input) => input.All(char.IsDigit);
|
||||||
|
|
||||||
|
|
||||||
private HttpClient GetHttpClient()
|
private HttpClient GetHttpClient()
|
||||||
@ -3277,7 +3268,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<Dictionary<string, long>?> GetAllSubscriptions(Dictionary<string, string> getParams,
|
private async Task<Dictionary<string, long>?> GetAllSubscriptions(Dictionary<string, string> getParams,
|
||||||
string endpoint, bool includeRestricted)
|
string endpoint, bool includeRestricted)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -3350,7 +3341,7 @@ public class ApiService(IAuthService authService, IConfigService configService,
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? GetDynamicRules()
|
private static string? GetDynamicRules()
|
||||||
{
|
{
|
||||||
Log.Debug("Calling GetDynamicRules");
|
Log.Debug("Calling GetDynamicRules");
|
||||||
try
|
try
|
||||||
|
|||||||
@ -94,7 +94,7 @@ public class DownloadOrchestrationService(
|
|||||||
{
|
{
|
||||||
long listId = lists[listName];
|
long listId = lists[listName];
|
||||||
List<string> listUsernames = await apiService.GetListUsers($"/lists/{listId}/users") ?? [];
|
List<string> listUsernames = await apiService.GetListUsers($"/lists/{listId}/users") ?? [];
|
||||||
return allUsers.Where(x => listUsernames.Contains(x.Key)).Distinct()
|
return allUsers.Where(x => listUsernames.Contains(x.Key))
|
||||||
.ToDictionary(x => x.Key, x => x.Value);
|
.ToDictionary(x => x.Key, x => x.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Xml.Linq;
|
|
||||||
using FFmpeg.NET;
|
using FFmpeg.NET;
|
||||||
using FFmpeg.NET.Events;
|
using FFmpeg.NET.Events;
|
||||||
using OF_DL.Models;
|
using OF_DL.Models;
|
||||||
@ -31,7 +30,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string path = "/Profile";
|
const string path = "/Profile";
|
||||||
|
|
||||||
if (!Directory.Exists(folder + path))
|
if (!Directory.Exists(folder + path))
|
||||||
{
|
{
|
||||||
@ -61,7 +60,7 @@ public class DownloadService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadProfileImage(string url, string folder, string subFolder, string username)
|
private static async Task DownloadProfileImage(string url, string folder, string subFolder, string username)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(folder + subFolder))
|
if (!Directory.Exists(folder + subFolder))
|
||||||
{
|
{
|
||||||
@ -85,7 +84,7 @@ public class DownloadService(
|
|||||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
MD5 md5 = MD5.Create();
|
MD5 md5 = MD5.Create();
|
||||||
byte[] hash = md5.ComputeHash(memoryStream);
|
byte[] hash = await md5.ComputeHashAsync(memoryStream);
|
||||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
if (!md5Hashes.Contains(BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant()))
|
if (!md5Hashes.Contains(BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant()))
|
||||||
{
|
{
|
||||||
@ -94,7 +93,7 @@ public class DownloadService(
|
|||||||
? response.Content.Headers.LastModified.Value.LocalDateTime.ToString("dd-MM-yyyy")
|
? response.Content.Headers.LastModified.Value.LocalDateTime.ToString("dd-MM-yyyy")
|
||||||
: DateTime.Now.ToString("dd-MM-yyyy"));
|
: DateTime.Now.ToString("dd-MM-yyyy"));
|
||||||
|
|
||||||
using (FileStream fileStream = File.Create(destinationPath))
|
await using (FileStream fileStream = File.Create(destinationPath))
|
||||||
{
|
{
|
||||||
await memoryStream.CopyToAsync(fileStream);
|
await memoryStream.CopyToAsync(fileStream);
|
||||||
}
|
}
|
||||||
@ -104,9 +103,9 @@ public class DownloadService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> DownloadDrmMedia(string user_agent, string policy, string signature, string kvp,
|
private async Task<bool> DownloadDrmMedia(string userAgent, string policy, string signature, string kvp,
|
||||||
string sess, string url, string decryptionKey, string folder, DateTime lastModified, long media_id,
|
string sess, string url, string decryptionKey, string folder, DateTime lastModified, long mediaId,
|
||||||
string api_type, IProgressReporter progressReporter, string customFileName, string filename, string path)
|
string apiType, IProgressReporter progressReporter, string customFileName, string filename, string path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -116,35 +115,12 @@ public class DownloadService(
|
|||||||
string decKey = "";
|
string decKey = "";
|
||||||
if (pos1 >= 0)
|
if (pos1 >= 0)
|
||||||
{
|
{
|
||||||
decKey = decryptionKey.Substring(pos1 + 1);
|
decKey = decryptionKey[(pos1 + 1)..];
|
||||||
}
|
}
|
||||||
|
|
||||||
int streamIndex = 0;
|
int streamIndex = 0;
|
||||||
string tempFilename = $"{folder}{path}/{filename}_source.mp4";
|
string tempFilename = $"{folder}{path}/{filename}_source.mp4";
|
||||||
|
|
||||||
//int? streamIndex = await GetVideoStreamIndexFromMpd(url, policy, signature, kvp, downloadConfig.DownloadVideoResolution);
|
|
||||||
|
|
||||||
//if (streamIndex == null)
|
|
||||||
// throw new Exception($"Could not find video stream for resolution {downloadConfig.DownloadVideoResolution}");
|
|
||||||
|
|
||||||
//string tempFilename;
|
|
||||||
|
|
||||||
//switch (downloadConfig.DownloadVideoResolution)
|
|
||||||
//{
|
|
||||||
// case VideoResolution.source:
|
|
||||||
// tempFilename = $"{folder}{path}/{filename}_source.mp4";
|
|
||||||
// break;
|
|
||||||
// case VideoResolution._240:
|
|
||||||
// tempFilename = $"{folder}{path}/{filename}_240.mp4";
|
|
||||||
// break;
|
|
||||||
// case VideoResolution._720:
|
|
||||||
// tempFilename = $"{folder}{path}/{filename}_720.mp4";
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// tempFilename = $"{folder}{path}/{filename}_source.mp4";
|
|
||||||
// break;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Configure ffmpeg log level and optional report file location
|
// Configure ffmpeg log level and optional report file location
|
||||||
bool ffmpegDebugLogging = Log.IsEnabled(LogEventLevel.Debug);
|
bool ffmpegDebugLogging = Log.IsEnabled(LogEventLevel.Debug);
|
||||||
|
|
||||||
@ -187,7 +163,7 @@ public class DownloadService(
|
|||||||
$"{logLevelArgs} " +
|
$"{logLevelArgs} " +
|
||||||
$"-cenc_decryption_key {decKey} " +
|
$"-cenc_decryption_key {decKey} " +
|
||||||
$"-headers \"{cookieHeader}\" " +
|
$"-headers \"{cookieHeader}\" " +
|
||||||
$"-user_agent \"{user_agent}\" " +
|
$"-user_agent \"{userAgent}\" " +
|
||||||
"-referer \"https://onlyfans.com\" " +
|
"-referer \"https://onlyfans.com\" " +
|
||||||
"-rw_timeout 20000000 " +
|
"-rw_timeout 20000000 " +
|
||||||
"-reconnect 1 -reconnect_streamed 1 -reconnect_on_network_error 1 -reconnect_delay_max 10 " +
|
"-reconnect 1 -reconnect_streamed 1 -reconnect_on_network_error 1 -reconnect_delay_max 10 " +
|
||||||
@ -205,7 +181,7 @@ public class DownloadService(
|
|||||||
{
|
{
|
||||||
_completionSource.TrySetResult(true);
|
_completionSource.TrySetResult(true);
|
||||||
await OnFFMPEGDownloadComplete(tempFilename, lastModified, folder, path, customFileName, filename,
|
await OnFFMPEGDownloadComplete(tempFilename, lastModified, folder, path, customFileName, filename,
|
||||||
media_id, api_type, progressReporter);
|
mediaId, apiType, progressReporter);
|
||||||
};
|
};
|
||||||
await ffmpeg.ExecuteAsync(parameters, CancellationToken.None);
|
await ffmpeg.ExecuteAsync(parameters, CancellationToken.None);
|
||||||
|
|
||||||
@ -287,59 +263,7 @@ public class DownloadService(
|
|||||||
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);
|
||||||
|
|
||||||
_completionSource?.TrySetResult(false);
|
_completionSource.TrySetResult(false);
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int?> GetVideoStreamIndexFromMpd(string mpdUrl, string policy, string signature, string kvp,
|
|
||||||
VideoResolution resolution)
|
|
||||||
{
|
|
||||||
if (authService.CurrentAuth == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpClient client = new();
|
|
||||||
HttpRequestMessage request = new(HttpMethod.Get, mpdUrl);
|
|
||||||
request.Headers.Add("user-agent", authService.CurrentAuth.UserAgent);
|
|
||||||
request.Headers.Add("Accept", "*/*");
|
|
||||||
request.Headers.Add("Cookie",
|
|
||||||
$"CloudFront-Policy={policy}; CloudFront-Signature={signature}; CloudFront-Key-Pair-Id={kvp}; {authService.CurrentAuth.Cookie};");
|
|
||||||
using (HttpResponseMessage response = await client.SendAsync(request))
|
|
||||||
{
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
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";
|
|
||||||
XElement? videoAdaptationSet = doc
|
|
||||||
.Descendants(ns + "AdaptationSet")
|
|
||||||
.FirstOrDefault(e => (string?)e.Attribute("mimeType") == "video/mp4");
|
|
||||||
|
|
||||||
if (videoAdaptationSet == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string targetHeight = resolution switch
|
|
||||||
{
|
|
||||||
VideoResolution._240 => "240",
|
|
||||||
VideoResolution._720 => "720",
|
|
||||||
VideoResolution.source => "1280",
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(resolution))
|
|
||||||
};
|
|
||||||
|
|
||||||
List<XElement> representations = videoAdaptationSet.Elements(ns + "Representation").ToList();
|
|
||||||
|
|
||||||
for (int i = 0; i < representations.Count; i++)
|
|
||||||
{
|
|
||||||
if ((string?)representations[i].Attribute("height") == targetHeight)
|
|
||||||
{
|
|
||||||
return i; // this is the index FFmpeg will use for `-map 0:v:{i}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<string> CalculateFolderMD5(string folder)
|
private static List<string> CalculateFolderMD5(string folder)
|
||||||
@ -900,42 +824,31 @@ public class DownloadService(
|
|||||||
long totalFileSize = 0;
|
long totalFileSize = 0;
|
||||||
if (urls.Count > 250)
|
if (urls.Count > 250)
|
||||||
{
|
{
|
||||||
int batchSize = 250;
|
const int batchSize = 250;
|
||||||
|
|
||||||
List<Task<long>> tasks = new();
|
List<Task<long>> tasks = [];
|
||||||
|
|
||||||
for (int i = 0; i < urls.Count; i += batchSize)
|
for (int i = 0; i < urls.Count; i += batchSize)
|
||||||
{
|
{
|
||||||
List<string> batchUrls = urls.Skip(i).Take(batchSize).ToList();
|
List<string> batchUrls = urls.Skip(i).Take(batchSize).ToList();
|
||||||
|
|
||||||
IEnumerable<Task<long>> batchTasks = batchUrls.Select(GetFileSizeAsync);
|
Task<long>[] batchTasks = batchUrls.Select(GetFileSizeAsync).ToArray();
|
||||||
tasks.AddRange(batchTasks);
|
tasks.AddRange(batchTasks);
|
||||||
|
|
||||||
await Task.WhenAll(batchTasks);
|
await Task.WhenAll(batchTasks);
|
||||||
|
|
||||||
await Task.Delay(5000);
|
await Task.Delay(5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
long[] fileSizes = await Task.WhenAll(tasks);
|
long[] fileSizes = await Task.WhenAll(tasks);
|
||||||
foreach (long fileSize in fileSizes)
|
totalFileSize += fileSizes.Sum();
|
||||||
{
|
|
||||||
totalFileSize += fileSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<Task<long>> tasks = new();
|
List<Task<long>> tasks = [];
|
||||||
|
tasks.AddRange(urls.Select(GetFileSizeAsync));
|
||||||
foreach (string url in urls)
|
|
||||||
{
|
|
||||||
tasks.Add(GetFileSizeAsync(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
long[] fileSizes = await Task.WhenAll(tasks);
|
long[] fileSizes = await Task.WhenAll(tasks);
|
||||||
foreach (long fileSize in fileSizes)
|
totalFileSize += fileSizes.Sum();
|
||||||
{
|
|
||||||
totalFileSize += fileSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalFileSize;
|
return totalFileSize;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ using OF_DL.Helpers;
|
|||||||
using OF_DL.Models;
|
using OF_DL.Models;
|
||||||
using OF_DL.Models.OfdlApi;
|
using OF_DL.Models.OfdlApi;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using static Newtonsoft.Json.JsonConvert;
|
||||||
using WidevineConstants = OF_DL.Widevine.Constants;
|
using WidevineConstants = OF_DL.Widevine.Constants;
|
||||||
|
|
||||||
namespace OF_DL.Services;
|
namespace OF_DL.Services;
|
||||||
@ -30,11 +31,11 @@ public class StartupService(IConfigService configService, IAuthService authServi
|
|||||||
// FFmpeg detection
|
// FFmpeg detection
|
||||||
DetectFfmpeg(result);
|
DetectFfmpeg(result);
|
||||||
|
|
||||||
if (result.FfmpegFound)
|
if (result.FfmpegFound && result.FfmpegPath != null)
|
||||||
{
|
{
|
||||||
// Escape backslashes for Windows
|
// Escape backslashes for Windows
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
|
||||||
result.FfmpegPath!.Contains(@":\") &&
|
result.FfmpegPath.Contains(@":\") &&
|
||||||
!result.FfmpegPath.Contains(@":\\"))
|
!result.FfmpegPath.Contains(@":\\"))
|
||||||
{
|
{
|
||||||
result.FfmpegPath = result.FfmpegPath.Replace(@"\", @"\\");
|
result.FfmpegPath = result.FfmpegPath.Replace(@"\", @"\\");
|
||||||
@ -42,7 +43,7 @@ public class StartupService(IConfigService configService, IAuthService authServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get FFmpeg version
|
// Get FFmpeg version
|
||||||
result.FfmpegVersion = await GetFfmpegVersionAsync(result.FfmpegPath!);
|
result.FfmpegVersion = await GetFfmpegVersionAsync(result.FfmpegPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Widevine device checks
|
// Widevine device checks
|
||||||
@ -51,40 +52,27 @@ public class StartupService(IConfigService configService, IAuthService authServi
|
|||||||
result.DevicePrivateKeyMissing = !File.Exists(Path.Join(WidevineConstants.DEVICES_FOLDER,
|
result.DevicePrivateKeyMissing = !File.Exists(Path.Join(WidevineConstants.DEVICES_FOLDER,
|
||||||
WidevineConstants.DEVICE_NAME, "device_private_key"));
|
WidevineConstants.DEVICE_NAME, "device_private_key"));
|
||||||
|
|
||||||
if (!result.ClientIdBlobMissing)
|
Log.Debug("device_client_id_blob {Status}", result.ClientIdBlobMissing ? "missing" : "found");
|
||||||
{
|
Log.Debug("device_private_key {Status}", result.DevicePrivateKeyMissing ? " missing" : "found");
|
||||||
Log.Debug("device_client_id_blob found");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.Debug("device_client_id_blob missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.DevicePrivateKeyMissing)
|
|
||||||
{
|
|
||||||
Log.Debug("device_private_key found");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.Debug("device_private_key missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
// rules.json validation
|
// rules.json validation
|
||||||
if (File.Exists("rules.json"))
|
if (!File.Exists("rules.json"))
|
||||||
{
|
{
|
||||||
result.RulesJsonExists = true;
|
return result;
|
||||||
try
|
}
|
||||||
{
|
|
||||||
JsonConvert.DeserializeObject<DynamicRules>(File.ReadAllText("rules.json"));
|
result.RulesJsonExists = true;
|
||||||
Log.Debug("Rules.json: ");
|
try
|
||||||
Log.Debug(JsonConvert.SerializeObject(File.ReadAllText("rules.json"), Formatting.Indented));
|
{
|
||||||
result.RulesJsonValid = true;
|
DeserializeObject<DynamicRules>(await File.ReadAllTextAsync("rules.json"));
|
||||||
}
|
Log.Debug("Rules.json: ");
|
||||||
catch (Exception e)
|
Log.Debug(SerializeObject(await File.ReadAllTextAsync("rules.json"), Formatting.Indented));
|
||||||
{
|
result.RulesJsonValid = true;
|
||||||
result.RulesJsonError = e.Message;
|
}
|
||||||
Log.Error("rules.json processing failed.", e.Message);
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
|
result.RulesJsonError = e.Message;
|
||||||
|
Log.Error("rules.json processing failed. {ErrorMessage}", e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -100,7 +88,7 @@ public class StartupService(IConfigService configService, IAuthService authServi
|
|||||||
result.LocalVersion = Assembly.GetEntryAssembly()?.GetName().Version;
|
result.LocalVersion = Assembly.GetEntryAssembly()?.GetName().Version;
|
||||||
|
|
||||||
using CancellationTokenSource cts = new(TimeSpan.FromSeconds(30));
|
using CancellationTokenSource cts = new(TimeSpan.FromSeconds(30));
|
||||||
string? latestReleaseTag = null;
|
string? latestReleaseTag;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -121,18 +109,18 @@ public class StartupService(IConfigService configService, IAuthService authServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.LatestVersion = new Version(latestReleaseTag.Replace("OFDLV", ""));
|
result.LatestVersion = new Version(latestReleaseTag.Replace("OFDLV", ""));
|
||||||
int versionComparison = result.LocalVersion!.CompareTo(result.LatestVersion);
|
int? versionComparison = result.LocalVersion?.CompareTo(result.LatestVersion);
|
||||||
result.IsUpToDate = versionComparison >= 0;
|
result.IsUpToDate = versionComparison >= 0;
|
||||||
|
|
||||||
Log.Debug("Detected client running version " +
|
Log.Debug("Detected client running version " +
|
||||||
$"{result.LocalVersion.Major}.{result.LocalVersion.Minor}.{result.LocalVersion.Build}");
|
$"{result.LocalVersion?.Major}.{result.LocalVersion?.Minor}.{result.LocalVersion?.Build}");
|
||||||
Log.Debug("Latest release version " +
|
Log.Debug("Latest release version " +
|
||||||
$"{result.LatestVersion.Major}.{result.LatestVersion.Minor}.{result.LatestVersion.Build}");
|
$"{result.LatestVersion.Major}.{result.LatestVersion.Minor}.{result.LatestVersion.Build}");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
result.CheckFailed = true;
|
result.CheckFailed = true;
|
||||||
Log.Error("Error checking latest release on GitHub.", e.Message);
|
Log.Error("Error checking latest release on GitHub. {Message}", e.Message);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
Log.Debug("Running in Debug/Local mode. Version check skipped.");
|
Log.Debug("Running in Debug/Local mode. Version check skipped.");
|
||||||
@ -207,7 +195,7 @@ public class StartupService(IConfigService configService, IAuthService authServi
|
|||||||
if (firstLine.StartsWith("ffmpeg version"))
|
if (firstLine.StartsWith("ffmpeg version"))
|
||||||
{
|
{
|
||||||
int versionStart = "ffmpeg version ".Length;
|
int versionStart = "ffmpeg version ".Length;
|
||||||
int copyrightIndex = firstLine.IndexOf(" Copyright");
|
int copyrightIndex = firstLine.IndexOf(" Copyright", StringComparison.Ordinal);
|
||||||
return copyrightIndex > versionStart
|
return copyrightIndex > versionStart
|
||||||
? firstLine.Substring(versionStart, copyrightIndex - versionStart)
|
? firstLine.Substring(versionStart, copyrightIndex - versionStart)
|
||||||
: firstLine.Substring(versionStart);
|
: firstLine.Substring(versionStart);
|
||||||
|
|||||||
@ -61,9 +61,7 @@ public class ThrottledStream : Stream
|
|||||||
TimeSpan sleep = targetTime - actualTime;
|
TimeSpan sleep = targetTime - actualTime;
|
||||||
if (sleep > TimeSpan.Zero)
|
if (sleep > TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
using AutoResetEvent waitHandle = new(false);
|
scheduler.Sleep(sleep).GetAwaiter().GetResult();
|
||||||
scheduler.Sleep(sleep).GetAwaiter().OnCompleted(() => waitHandle.Set());
|
|
||||||
waitHandle.WaitOne();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -264,23 +264,24 @@ public class CDM
|
|||||||
Serializer.Serialize(memoryStream, session.Device.ClientID);
|
Serializer.Serialize(memoryStream, session.Device.ClientID);
|
||||||
byte[] data = Padding.AddPKCS7Padding(memoryStream.ToArray(), 16);
|
byte[] data = Padding.AddPKCS7Padding(memoryStream.ToArray(), 16);
|
||||||
|
|
||||||
using AesCryptoServiceProvider aesProvider = new()
|
using Aes aes = Aes.Create();
|
||||||
{
|
aes.BlockSize = 128;
|
||||||
BlockSize = 128, Padding = PaddingMode.PKCS7, Mode = CipherMode.CBC
|
aes.Padding = PaddingMode.PKCS7;
|
||||||
};
|
aes.Mode = CipherMode.CBC;
|
||||||
aesProvider.GenerateKey();
|
|
||||||
aesProvider.GenerateIV();
|
aes.GenerateKey();
|
||||||
|
aes.GenerateIV();
|
||||||
|
|
||||||
using MemoryStream mstream = new();
|
using MemoryStream mstream = new();
|
||||||
using CryptoStream cryptoStream = new(mstream, aesProvider.CreateEncryptor(aesProvider.Key, aesProvider.IV),
|
using CryptoStream cryptoStream = new(mstream, aes.CreateEncryptor(aes.Key, aes.IV),
|
||||||
CryptoStreamMode.Write);
|
CryptoStreamMode.Write);
|
||||||
cryptoStream.Write(data, 0, data.Length);
|
cryptoStream.Write(data, 0, data.Length);
|
||||||
encryptedClientIdProto.EncryptedClientId = mstream.ToArray();
|
encryptedClientIdProto.EncryptedClientId = mstream.ToArray();
|
||||||
|
|
||||||
using RSACryptoServiceProvider RSA = new();
|
using RSACryptoServiceProvider RSA = new();
|
||||||
RSA.ImportRSAPublicKey(session.ServiceCertificate.DeviceCertificate.PublicKey, out int _);
|
RSA.ImportRSAPublicKey(session.ServiceCertificate.DeviceCertificate.PublicKey, out int _);
|
||||||
encryptedClientIdProto.EncryptedPrivacyKey = RSA.Encrypt(aesProvider.Key, RSAEncryptionPadding.OaepSHA1);
|
encryptedClientIdProto.EncryptedPrivacyKey = RSA.Encrypt(aes.Key, RSAEncryptionPadding.OaepSHA1);
|
||||||
encryptedClientIdProto.EncryptedClientIdIv = aesProvider.IV;
|
encryptedClientIdProto.EncryptedClientIdIv = aes.IV;
|
||||||
encryptedClientIdProto.ServiceId =
|
encryptedClientIdProto.ServiceId =
|
||||||
Encoding.UTF8.GetString(session.ServiceCertificate.DeviceCertificate.ServiceId);
|
Encoding.UTF8.GetString(session.ServiceCertificate.DeviceCertificate.ServiceId);
|
||||||
encryptedClientIdProto.ServiceCertificateSerialNumber =
|
encryptedClientIdProto.ServiceCertificateSerialNumber =
|
||||||
@ -397,27 +398,24 @@ public class CDM
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] keyId;
|
|
||||||
byte[] encryptedKey = key.Key;
|
byte[] encryptedKey = key.Key;
|
||||||
byte[] iv = key.Iv;
|
byte[] iv = key.Iv;
|
||||||
keyId = key.Id;
|
byte[] keyId = key.Id;
|
||||||
if (keyId == null)
|
if (keyId == null)
|
||||||
{
|
{
|
||||||
keyId = Encoding.ASCII.GetBytes(key.Type.ToString());
|
keyId = Encoding.ASCII.GetBytes(key.Type.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] decryptedKey;
|
|
||||||
|
|
||||||
using MemoryStream mstream = new();
|
using MemoryStream mstream = new();
|
||||||
|
|
||||||
using AesCryptoServiceProvider aesProvider = new();
|
using Aes aes = Aes.Create();
|
||||||
aesProvider.Mode = CipherMode.CBC;
|
aes.Padding = PaddingMode.PKCS7;
|
||||||
aesProvider.Padding = PaddingMode.PKCS7;
|
aes.Mode = CipherMode.CBC;
|
||||||
|
|
||||||
using CryptoStream cryptoStream = new(mstream, aesProvider.CreateDecryptor(session.DerivedKeys.Enc, iv),
|
using CryptoStream cryptoStream = new(mstream, aes.CreateDecryptor(session.DerivedKeys.Enc, iv),
|
||||||
CryptoStreamMode.Write);
|
CryptoStreamMode.Write);
|
||||||
cryptoStream.Write(encryptedKey, 0, encryptedKey.Length);
|
cryptoStream.Write(encryptedKey, 0, encryptedKey.Length);
|
||||||
decryptedKey = mstream.ToArray();
|
byte[] decryptedKey = mstream.ToArray();
|
||||||
|
|
||||||
List<string> permissions = [];
|
List<string> permissions = [];
|
||||||
if (type == "OperatorSession")
|
if (type == "OperatorSession")
|
||||||
|
|||||||
@ -12,35 +12,55 @@ public class SpectreDownloadEventHandler : IDownloadEventHandler
|
|||||||
{
|
{
|
||||||
public async Task<T> WithStatusAsync<T>(string statusMessage, Func<IStatusReporter, Task<T>> work)
|
public async Task<T> WithStatusAsync<T>(string statusMessage, Func<IStatusReporter, Task<T>> work)
|
||||||
{
|
{
|
||||||
T result = default!;
|
TaskCompletionSource<T> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
await AnsiConsole.Status()
|
await AnsiConsole.Status()
|
||||||
.StartAsync($"[red]{Markup.Escape(statusMessage)}[/]",
|
.StartAsync($"[red]{Markup.Escape(statusMessage)}[/]",
|
||||||
async ctx =>
|
async ctx =>
|
||||||
{
|
{
|
||||||
SpectreStatusReporter reporter = new(ctx);
|
try
|
||||||
result = await work(reporter);
|
{
|
||||||
|
SpectreStatusReporter reporter = new(ctx);
|
||||||
|
T result = await work(reporter);
|
||||||
|
tcs.TrySetResult(result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
tcs.TrySetException(ex);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return result;
|
|
||||||
|
return await tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<T> WithProgressAsync<T>(string description, long maxValue, bool showSize,
|
public async Task<T> WithProgressAsync<T>(string description, long maxValue, bool showSize,
|
||||||
Func<IProgressReporter, Task<T>> work)
|
Func<IProgressReporter, Task<T>> work)
|
||||||
{
|
{
|
||||||
T result = default!;
|
TaskCompletionSource<T> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
await AnsiConsole.Progress()
|
await AnsiConsole.Progress()
|
||||||
.Columns(GetProgressColumns(showSize))
|
.Columns(GetProgressColumns(showSize))
|
||||||
.StartAsync(async ctx =>
|
.StartAsync(async ctx =>
|
||||||
{
|
{
|
||||||
ProgressTask task = ctx.AddTask($"[red]{Markup.Escape(description)}[/]", false);
|
try
|
||||||
task.MaxValue = maxValue;
|
{
|
||||||
task.StartTask();
|
ProgressTask task = ctx.AddTask($"[red]{Markup.Escape(description)}[/]", false);
|
||||||
|
task.MaxValue = maxValue;
|
||||||
|
task.StartTask();
|
||||||
|
|
||||||
SpectreProgressReporter progressReporter = new(task);
|
SpectreProgressReporter progressReporter = new(task);
|
||||||
result = await work(progressReporter);
|
T result = await work(progressReporter);
|
||||||
|
tcs.TrySetResult(result);
|
||||||
|
|
||||||
task.StopTask();
|
task.StopTask();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
tcs.TrySetException(ex);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return result;
|
|
||||||
|
return await tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnContentFound(string contentType, int mediaCount, int objectCount) =>
|
public void OnContentFound(string contentType, int mediaCount, int objectCount) =>
|
||||||
|
|||||||
@ -219,6 +219,7 @@ public class Program(IServiceProvider serviceProvider)
|
|||||||
Console.WriteLine("\nPress any key to exit.");
|
Console.WriteLine("\nPress any key to exit.");
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment.Exit(2);
|
Environment.Exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -542,7 +543,7 @@ public class Program(IServiceProvider serviceProvider)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedUsers = users.Where(x => listUsernames.Contains($"{x.Key}")).Distinct()
|
selectedUsers = users.Where(x => listUsernames.Contains($"{x.Key}"))
|
||||||
.ToDictionary(x => x.Key, x => x.Value);
|
.ToDictionary(x => x.Key, x => x.Value);
|
||||||
AnsiConsole.Markup(string.Format("[red]Downloading from List(s): {0}[/]",
|
AnsiConsole.Markup(string.Format("[red]Downloading from List(s): {0}[/]",
|
||||||
string.Join(", ", listSelection)));
|
string.Join(", ", listSelection)));
|
||||||
@ -787,6 +788,7 @@ public class Program(IServiceProvider serviceProvider)
|
|||||||
AnsiConsole.MarkupLine("[red]Press any key to exit.[/]");
|
AnsiConsole.MarkupLine("[red]Press any key to exit.[/]");
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment.Exit(2);
|
Environment.Exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user