OF-DL/Cajetan.OF-DL/Services/CajetanApiService.cs

304 lines
10 KiB
C#

namespace OF_DL.Services;
public class CajetanApiService(IAuthService authService, IConfigService configService, ICajetanDbService dbService, ICajetanDownloadEventHandler eventHandler)
: ApiService(authService, configService, dbService), ICajetanApiService
{
private readonly ICajetanDownloadEventHandler _eventHandler = eventHandler;
public new async Task<UserEntities.User?> GetUserInfo(string endpoint)
{
UserEntities.UserInfo? userInfo = await GetDetailedUserInfoAsync(endpoint);
if (userInfo is not null && !endpoint.EndsWith("/me"))
await dbService.UpdateUserInfoAsync(userInfo);
return userInfo;
}
public async Task<UserEntities.UserInfo?> GetDetailedUserInfoAsync(string endpoint)
{
Log.Debug($"Calling GetDetailedUserInfo: {endpoint}");
if (!HasSignedRequestAuth())
return null;
try
{
UserEntities.UserInfo userInfo = new();
Dictionary<string, string> getParams = new()
{
{ "limit", Constants.ApiPageSize.ToString() }, { "order", "publish_date_asc" }
};
HttpClient client = new();
HttpRequestMessage request = await BuildHttpRequestMessage(getParams, endpoint);
using HttpResponseMessage response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
return userInfo;
response.EnsureSuccessStatusCode();
string body = await response.Content.ReadAsStringAsync();
UserDtos.UserDto? userDto = JsonConvert.DeserializeObject<UserDtos.UserDto>(body, s_mJsonSerializerSettings);
userInfo = FromDto(userDto);
return userInfo;
}
catch (Exception ex)
{
ExceptionLoggerHelper.LogException(ex);
}
return null;
}
public async Task<Dictionary<string, long>> GetUsersWithProgressAsync(string typeDisplay, string endpoint, string? typeParam, bool offsetByCount)
{
Dictionary<string, long> usersOfType = await _eventHandler.WithStatusAsync(
statusMessage: $"Getting {typeDisplay} Users",
work: FetchAsync
);
return usersOfType;
async Task<Dictionary<string, long>> FetchAsync(IStatusReporter statusReporter)
{
Dictionary<string, long> users = [];
int limit = 50;
int offset = 0;
bool includeRestricted = true;
Dictionary<string, string> getParams = new()
{
["format"] = "infinite",
["limit"] = limit.ToString(),
["offset"] = offset.ToString()
};
if (!string.IsNullOrWhiteSpace(typeParam))
getParams["type"] = typeParam;
try
{
Log.Debug("Calling GetUsersWithProgress");
HttpClient client = GetHttpClient();
bool isLastLoop = false;
while (true)
{
string? body = await BuildHeaderAndExecuteRequests(getParams, endpoint, client);
if (string.IsNullOrWhiteSpace(body))
break;
SubscriptionDtos.SubscriptionsDto? subscriptions = DeserializeJson<SubscriptionDtos.SubscriptionsDto>(body, s_mJsonSerializerSettings);
if (subscriptions?.List is null)
break;
foreach (SubscriptionDtos.ListItemDto item in subscriptions.List)
{
if (string.IsNullOrWhiteSpace(item?.Username))
continue;
if (users.ContainsKey(item.Username))
continue;
bool isRestricted = item.IsRestricted ?? false;
bool isRestrictedButAllowed = isRestricted && includeRestricted;
if (!isRestricted || isRestrictedButAllowed)
users.Add(item.Username, item.Id);
}
statusReporter.ReportStatus($"[blue]Getting {typeDisplay} Users\n[/] [blue]Found {users.Count}[/]");
if (isLastLoop)
break;
if (!subscriptions.HasMore || subscriptions.List.Count == 0)
isLastLoop = true;
offset += offsetByCount
? subscriptions.List.Count
: limit;
getParams["offset"] = offset.ToString();
}
}
catch (Exception ex)
{
ExceptionLoggerHelper.LogException(ex);
}
return users;
}
}
public new async Task<MessageEntities.MessageCollection> GetMessages(string endpoint, string folder, IStatusReporter statusReporter)
{
(bool couldExtract, long userId) = ExtractUserId(endpoint);
_eventHandler.OnMessage("Getting Unread Chats", "grey");
HashSet<long> usersWithUnread = couldExtract ? await GetUsersWithUnreadMessagesAsync() : [];
MessageEntities.MessageCollection messages = await base.GetMessages(endpoint, folder, statusReporter);
if (usersWithUnread.Contains(userId))
{
_eventHandler.OnMessage("Restoring unread state", "grey");
await MarkAsUnreadAsync($"/chats/{userId}/mark-as-read");
}
return messages;
static (bool couldExtract, long userId) ExtractUserId(string endpoint)
{
string withoutChatsAndMessages = endpoint
.Replace("chats", "", StringComparison.OrdinalIgnoreCase)
.Replace("messages", "", StringComparison.OrdinalIgnoreCase);
string trimmed = withoutChatsAndMessages.Trim(' ', '/', '\\');
if (long.TryParse(trimmed, out long userId))
return (true, userId);
return (false, default);
}
}
public async Task<HashSet<long>> GetUsersWithUnreadMessagesAsync()
{
MessageDtos.ChatsDto unreadChats = await GetChatsAsync("/chats", onlyUnread: true);
HashSet<long> userWithUnread = [];
foreach (MessageDtos.ChatItemDto chatItem in unreadChats.List)
{
if (chatItem?.WithUser?.Id is null)
continue;
if (chatItem.UnreadMessagesCount <= 0)
continue;
userWithUnread.Add(chatItem.WithUser.Id);
}
return userWithUnread;
}
public async Task MarkAsUnreadAsync(string endpoint)
{
Log.Debug($"Calling MarkAsUnread - {endpoint}");
try
{
var result = new { success = false };
string? body = await BuildHeaderAndExecuteRequests([], endpoint, GetHttpClient(), HttpMethod.Delete);
if (!string.IsNullOrWhiteSpace(body))
result = JsonConvert.DeserializeAnonymousType(body, result);
if (result?.success != true)
_eventHandler.OnMessage($"Failed to mark chat as unread! Endpoint: {endpoint}", "yellow");
}
catch (Exception ex)
{
ExceptionLoggerHelper.LogException(ex);
}
}
private async Task<MessageDtos.ChatsDto> GetChatsAsync(string endpoint, bool onlyUnread)
{
Log.Debug($"Calling GetChats - {endpoint}");
MessageDtos.ChatsDto allChats = new();
try
{
int limit = 60;
Dictionary<string, string> getParams = new()
{
{ "limit", $"{limit}" },
{ "offset", "0" },
{ "skip_users", "all" },
{ "order", "recent" }
};
if (onlyUnread)
getParams["filter"] = "unread";
string? body = await BuildHeaderAndExecuteRequests(getParams, endpoint, GetHttpClient());
MessageDtos.ChatsDto? chats = DeserializeJson<MessageDtos.ChatsDto>(body, s_mJsonSerializerSettings);
if (chats is null)
return allChats;
if (chats.HasMore)
{
getParams["offset"] = $"{chats.NextOffset}";
while (true)
{
string? loopbody = await BuildHeaderAndExecuteRequests(getParams, endpoint, GetHttpClient());
MessageDtos.ChatsDto? newChats = DeserializeJson<MessageDtos.ChatsDto>(loopbody, s_mJsonSerializerSettings);
if (newChats is null)
break;
allChats.List.AddRange(newChats.List);
if (!newChats.HasMore)
break;
getParams["offset"] = $"{newChats.NextOffset}";
}
}
}
catch (Exception ex)
{
ExceptionLoggerHelper.LogException(ex);
}
return allChats;
}
private static UserEntities.UserInfo FromDto(UserDtos.UserDto? userDto)
{
if (userDto is null)
return new();
return new()
{
Id = userDto.Id,
Avatar = userDto.Avatar,
Header = userDto.Header,
Name = userDto.Name,
Username = userDto.Username,
SubscribePrice = userDto.SubscribePrice,
CurrentSubscribePrice = userDto.CurrentSubscribePrice,
IsPaywallRequired = userDto.IsPaywallRequired,
IsRestricted = userDto.IsRestricted,
SubscribedBy = userDto.SubscribedBy,
SubscribedByExpire = userDto.SubscribedByExpire,
SubscribedByExpireDate = userDto.SubscribedByExpireDate,
SubscribedByAutoprolong = userDto.SubscribedByAutoprolong,
SubscribedIsExpiredNow = userDto.SubscribedIsExpiredNow,
SubscribedOn = userDto.SubscribedOn,
SubscribedOnExpiredNow = userDto.SubscribedOnExpiredNow,
SubscribedOnDuration = userDto.SubscribedOnDuration,
About = userDto.About,
PostsCount = userDto.PostsCount,
ArchivedPostsCount = userDto.ArchivedPostsCount,
PrivateArchivedPostsCount = userDto.PrivateArchivedPostsCount,
PhotosCount = userDto.PhotosCount,
VideosCount = userDto.VideosCount,
AudiosCount = userDto.AudiosCount,
MediasCount = userDto.MediasCount,
};
}
}