stupid anilist

This commit is contained in:
John Andrews
2024-10-22 08:40:32 +13:00
parent 670713ac73
commit c6e211755f
3 changed files with 205 additions and 127 deletions

View File

@@ -0,0 +1,63 @@
namespace MetaNodes.AniList;
/// <summary>
/// Represents the airing schedule for a specific anime, containing a list of episodes and their air dates.
/// </summary>
public class AniListAirScheduleResponse
{
/// <summary>
/// Gets or sets the airing schedule for the anime.
/// </summary>
public AniListAiringSchedule AiringSchedule { get; set; }
/// <summary>
/// Gets or sets the ID
/// </summary>
public int Id { get; set; }
}
/// <summary>
/// Represents the airing schedule for a specific anime, containing a list of episodes and their air dates.
/// </summary>
public class AniListAiringSchedule
{
/// <summary>
/// Gets or sets the list of edges, where each edge contains information about an episode's airing schedule.
/// </summary>
public List<AniListAiringScheduleEdge> Edges { get; set; }
}
/// <summary>
/// Represents an edge in the airing schedule, containing a node with the episode information.
/// </summary>
public class AniListAiringScheduleEdge
{
/// <summary>
/// Gets or sets the node that contains information about a specific episode.
/// </summary>
public AniListAiringScheduleNode Node { get; set; }
}
/// <summary>
/// Represents an individual episode's airing information.
/// </summary>
public class AniListAiringScheduleNode
{
/// <summary>
/// Gets or sets the episode number.
/// </summary>
public int Episode { get; set; }
/// <summary>
/// Gets or sets the Unix timestamp representing the airing time of the episode.
/// </summary>
public long AiringAt { get; set; }
/// <summary>
/// Gets the airing date and time of the episode as a <see cref="DateTimeOffset"/> object, based on the Unix timestamp <see cref="AiringAt"/>.
/// </summary>
/// <remarks>
/// Converts the <see cref="AiringAt"/> Unix timestamp to a <see cref="DateTimeOffset"/> in UTC format.
/// </remarks>
public DateTimeOffset AirDate => DateTimeOffset.FromUnixTimeSeconds(AiringAt);
}

View File

@@ -19,7 +19,7 @@ public class AniListInterface(NodeParameters _args)
/// </summary>
/// <param name="showName">The name of the anime show to look up.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="AniListShowInfo"/> object.</returns>
public async Task<AniListShowInfo> FetchShowInfo(string showName)
public async Task<AniListShowInfo?> FetchShowInfo(string showName)
{
var query = @"
query ($search: String) {
@@ -47,34 +47,25 @@ public class AniListInterface(NodeParameters _args)
var response = await _HttpClient.PostAsync(AniListGraphQLUrl, content);
var jsonResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var data = JsonSerializer.Deserialize<AniListShowResponse>(jsonResponse, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
var media = data?.Data?.Media;
if (media != null)
{
return new AniListShowInfo
{
Title = media.Title.English?.EmptyAsNull() ??
media.Title.Native?.EmptyAsNull() ?? media.Title.Romaji,
TitleRomaji = media.Title.Romaji,
TitleEnglish = media.Title.English,
TitleNative = media.Title.Native,
Description = media.Description,
Year = media.StartDate.Year,
Score = media.AverageScore
};
}
}
else
if (response.IsSuccessStatusCode == false)
{
_args.Logger?.ELog($"Error fetching data from AniList: {jsonResponse}");
return null;
}
var media = UnwrapResponse<AniListShowInfoResponse>(jsonResponse);
return new AniListShowInfo
{
Title = media.Title.English?.EmptyAsNull() ??
media.Title.Native?.EmptyAsNull() ?? media.Title.Romaji,
TitleRomaji = media.Title.Romaji,
TitleEnglish = media.Title.English,
TitleNative = media.Title.Native,
Description = media.Description,
Year = media.StartDate.Year,
Score = media.AverageScore
};
}
catch (Exception ex)
{
@@ -83,118 +74,142 @@ public class AniListInterface(NodeParameters _args)
return null;
}
/// <summary>
/// Fetches episode information from AniList based on the provided show name.
/// </summary>
/// <param name="showName">The name of the anime show.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of <see cref="AniListEpisodeInfo"/> objects.</returns>
public async Task<List<AniListEpisodeInfo>> FetchEpisode(string showName)
{
var queryAiringSchedule = @"
query ($search: String) {
Media(search: $search, type: ANIME) {
airingSchedule {
edges {
node {
episode
airingAt
}
}
/// <summary>
/// Fetches episode information from AniList based on the provided show name.
/// </summary>
/// <param name="showName">The name of the anime show.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of <see cref="AniListEpisodeInfo"/> objects.</returns>
public async Task<List<AniListEpisodeInfo>> FetchEpisode(string showName)
{
var queryAiringSchedule = @"
query ($search: String) {
Media(search: $search, type: ANIME) {
airingSchedule {
edges {
node {
episode
airingAt
}
id
}
}";
var variablesAiringSchedule = new { search = showName };
var jsonRequestAiringSchedule = JsonSerializer.Serialize(new { query = queryAiringSchedule, variables = variablesAiringSchedule });
var episodeDetails = new List<AniListEpisodeInfo>();
try
{
var content = new StringContent(jsonRequestAiringSchedule, Encoding.UTF8, "application/json");
var responseAiringSchedule = await _HttpClient.PostAsync(AniListGraphQLUrl, content);
var jsonResponseAiringSchedule = await responseAiringSchedule.Content.ReadAsStringAsync();
if (responseAiringSchedule.IsSuccessStatusCode)
{
// var dataAiringSchedule = JsonSerializer.Deserialize<AniListAiringScheduleResponse>(jsonResponseAiringSchedule, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
//
// var media = dataAiringSchedule?.Data?.Media;
//
// if (media != null)
// {
// int mediaId = media.Id;
//
// var queryEpisodeDetails = @"
// query ($id: Int) {
// Media(id: $id) {
// episodes {
// episode
// title {
// romaji
// english
// native
// }
// description
// }
// }
// }";
//
// var variablesEpisodeDetails = new { id = mediaId };
// var jsonRequestEpisodeDetails = JsonSerializer.Serialize(new { query = queryEpisodeDetails, variables = variablesEpisodeDetails });
//
// var contentEpisodeDetails = new StringContent(jsonRequestEpisodeDetails, Encoding.UTF8, "application/json");
// var responseEpisodeDetails = await _HttpClient.PostAsync(AniListGraphQLUrl, contentEpisodeDetails);
// var jsonResponseEpisodeDetails = await responseEpisodeDetails.Content.ReadAsStringAsync();
//
// if (responseEpisodeDetails.IsSuccessStatusCode)
// {
// var dataEpisodeDetails = JsonSerializer.Deserialize<AniListEpisodeResponse>(jsonResponseEpisodeDetails, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
//
// var episodes = dataEpisodeDetails?.Data?.Media?.Episodes;
// if (episodes != null)
// {
// foreach (var episode in episodes)
// {
// episodeDetails.Add(new AniListEpisodeInfo
// {
// EpisodeNumber = episode.Episode,
// Title = episode.Title?.Romaji ?? episode.Title?.English ?? episode.Title?.Native,
// Description = episode.Description
// });
// }
// }
//}
}
else
{
_args.Logger?.ELog($"Error fetching data from AniList: {jsonResponseAiringSchedule}");
}
}
catch (Exception ex)
id
}
}";
var variablesAiringSchedule = new { search = showName };
var jsonRequestAiringSchedule = JsonSerializer.Serialize(new { query = queryAiringSchedule, variables = variablesAiringSchedule });
var episodeDetails = new List<AniListEpisodeInfo>();
try
{
// Send the request to AniList for the airing schedule
var content = new StringContent(jsonRequestAiringSchedule, Encoding.UTF8, "application/json");
var responseAiringSchedule = await _HttpClient.PostAsync(AniListGraphQLUrl, content);
var jsonResponseAiringSchedule = await responseAiringSchedule.Content.ReadAsStringAsync();
if (responseAiringSchedule.IsSuccessStatusCode == false)
{
_args.Logger?.ELog($"Exception occurred: {ex.Message}");
_args.Logger?.ELog($"Error fetching data from AniList: {jsonResponseAiringSchedule}");
return new List<AniListEpisodeInfo>();
}
return episodeDetails;
// Use UnwrapResponse to directly extract AniListAiringSchedule from the JSON response
var airSchedule = UnwrapResponse<AniListAirScheduleResponse>(jsonResponseAiringSchedule);
// Now we can fetch the Media Id
var mediaId = airSchedule.Id;
if (mediaId == 0)
{
_args.Logger?.ELog("No media ID found for the show.");
return new List<AniListEpisodeInfo>();
}
if (airSchedule?.AiringSchedule?.Edges == null)
{
_args.Logger?.ELog("Failed to deserialize the airing schedule data.");
return new List<AniListEpisodeInfo>();
}
// Query episode details based on the media ID
var queryEpisodeDetails = @"
query ($id: Int) {
Media(id: $id) {
episodes {
episode
title {
romaji
english
native
}
description
}
}
}";
var variablesEpisodeDetails = new { id = mediaId };
var jsonRequestEpisodeDetails = JsonSerializer.Serialize(new { query = queryEpisodeDetails, variables = variablesEpisodeDetails });
var contentEpisodeDetails = new StringContent(jsonRequestEpisodeDetails, Encoding.UTF8, "application/json");
var responseEpisodeDetails = await _HttpClient.PostAsync(AniListGraphQLUrl, contentEpisodeDetails);
var jsonResponseEpisodeDetails = await responseEpisodeDetails.Content.ReadAsStringAsync();
if (responseEpisodeDetails.IsSuccessStatusCode == false)
{
_args.Logger?.ELog($"Error fetching episode details from AniList: {jsonResponseEpisodeDetails}");
return new List<AniListEpisodeInfo>();
}
// Deserialize episode details
// var dataEpisodeDetails = JsonSerializer.Deserialize<AniListEpisodeResponse>(
// jsonResponseEpisodeDetails, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
// var episodes = dataEpisodeDetails?.Data?.Media?.Episodes;
//
// if (episodes != null)
// {
// foreach (var episode in episodes)
// {
// episodeDetails.Add(new AniListEpisodeInfo
// {
// EpisodeNumber = episode.Episode,
// Title = episode.Title?.Romaji ?? episode.Title?.English ?? episode.Title?.Native,
// Description = episode.Description
// });
// }
// }
}
/// <summary>
/// Response class for show information.
/// </summary>
public class AniListShowResponse
catch (Exception ex)
{
public AniListShowData Data { get; set; }
_args.Logger?.ELog($"Exception occurred: {ex.Message}");
}
return episodeDetails;
}
/// <summary>
/// Data class for show information.
/// Unwraps a nested JSON response from AniList API, automatically finding the object under data.Media.
/// </summary>
public class AniListShowData
/// <typeparam name="T">The type to deserialize the unwrapped JSON into.</typeparam>
/// <param name="json">The raw JSON string.</param>
/// <returns>The unwrapped object of type <typeparamref name="T"/>.</returns>
public static T UnwrapResponse<T>(string json)
{
public AniListMediaData Media { get; set; }
using var doc = JsonDocument.Parse(json);
// Navigate to data.Media
if (!doc.RootElement.TryGetProperty("data", out var dataElement) ||
!dataElement.TryGetProperty("Media", out var mediaElement))
{
throw new InvalidOperationException("JSON does not contain 'data.Media' structure.");
}
return mediaElement.Deserialize<T>(new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
}
}

View File

@@ -3,7 +3,7 @@ namespace MetaNodes.AniList;
/// <summary>
/// Represents the media data of an anime show from AniList API.
/// </summary>
public class AniListMediaData
public class AniListShowInfoResponse
{
/// <summary>
/// Gets or sets the title information of the media.