From 2ea66d3c1e0f8f81df6522b1fb6c5f5e89637981 Mon Sep 17 00:00:00 2001 From: DatLag Date: Thu, 16 May 2024 00:56:02 +0200 Subject: [PATCH] prepare list query --- .../src/commonMain/graphql/ListQuery.graphql | 108 ++++++++++++++++++ .../aniflow/anilist/common/ExtendDateTime.kt | 23 +++- .../datlag/aniflow/anilist/model/Character.kt | 43 +++++++ .../datlag/aniflow/anilist/model/Medium.kt | 73 ++++++++++++ 4 files changed, 242 insertions(+), 5 deletions(-) create mode 100644 anilist/src/commonMain/graphql/ListQuery.graphql diff --git a/anilist/src/commonMain/graphql/ListQuery.graphql b/anilist/src/commonMain/graphql/ListQuery.graphql new file mode 100644 index 0000000..1debb2f --- /dev/null +++ b/anilist/src/commonMain/graphql/ListQuery.graphql @@ -0,0 +1,108 @@ +query ListQuery( + $type: MediaType, + $userId: Int, + $page: Int, + $html: Boolean, + $statusVersion: Int, + $sort: [MediaListSort] +) { + Page(page: $page) { + pageInfo { + hasNextPage + }, + mediaList(type: $type, userId: $userId, sort: $sort) { + status, + score(format: POINT_5), + progress, + progressVolumes, + repeat, + startedAt { + year, + month, + day + }, + media { + id, + idMal, + type, + status(version: $statusVersion), + description(asHtml: $html), + episodes, + duration, + chapters, + countryOfOrigin, + popularity, + isFavourite, + isFavouriteBlocked, + isAdult, + format, + bannerImage, + coverImage { + extraLarge, + large, + medium, + color + }, + averageScore, + title { + english, + native, + romaji, + userPreferred + }, + nextAiringEpisode { + episode, + airingAt + }, + rankings { + rank, + allTime, + year, + season, + type + }, + genres, + characters(sort: [FAVOURITES_DESC,RELEVANCE]) { + nodes { + id, + name { + first + middle + last + full + native + userPreferred + }, + image { + large + medium + }, + description(asHtml:$html) + gender, + dateOfBirth { + year + month + day + }, + bloodType, + isFavourite, + isFavouriteBlocked, + } + }, + trailer { + id, + site, + thumbnail + }, + siteUrl, + chapters, + volumes, + startDate { + year, + month, + day + } + } + } + } +} \ No newline at end of file diff --git a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/common/ExtendDateTime.kt b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/common/ExtendDateTime.kt index 868296f..60df18f 100644 --- a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/common/ExtendDateTime.kt +++ b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/common/ExtendDateTime.kt @@ -1,9 +1,6 @@ package dev.datlag.aniflow.anilist.common -import dev.datlag.aniflow.anilist.AiringQuery -import dev.datlag.aniflow.anilist.MediumQuery -import dev.datlag.aniflow.anilist.SeasonQuery -import dev.datlag.aniflow.anilist.TrendingQuery +import dev.datlag.aniflow.anilist.* import dev.datlag.aniflow.anilist.type.FuzzyDate import dev.datlag.aniflow.anilist.type.MediaSeason import kotlinx.datetime.* @@ -63,6 +60,14 @@ internal fun MediumQuery.StartDate.toLocalDate(): LocalDate? { ) } +internal fun ListQuery.StartDate.toLocalDate(): LocalDate? { + return LocalDate( + year = year ?: return null, + monthNumber = month ?: return null, + dayOfMonth = day ?: 1 + ) +} + internal fun AiringQuery.StartedAt.toLocalDate(): LocalDate? { return LocalDate( year = year ?: return null, @@ -93,4 +98,12 @@ internal fun SeasonQuery.StartedAt.toLocalDate(): LocalDate? { monthNumber = month ?: return null, dayOfMonth = day ?: 1 ) -} \ No newline at end of file +} + +internal fun ListQuery.StartedAt.toLocalDate(): LocalDate? { + return LocalDate( + year = year ?: return null, + monthNumber = month ?: return null, + dayOfMonth = day ?: 1 + ) +} diff --git a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Character.kt b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Character.kt index 401d7e4..061b494 100644 --- a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Character.kt +++ b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Character.kt @@ -129,6 +129,15 @@ data class Character( native = name.native?.ifBlank { null }, userPreferred = name.userPreferred?.ifBlank { null } ) + + constructor(name: ListQuery.Name) : this( + first = name.first?.ifBlank { null }, + middle = name.middle?.ifBlank { null }, + last = name.last?.ifBlank { null }, + full = name.full?.ifBlank { null }, + native = name.native?.ifBlank { null }, + userPreferred = name.userPreferred?.ifBlank { null } + ) } @Serializable @@ -160,6 +169,11 @@ data class Character( large = image.large?.ifBlank { null }, medium = image.medium?.ifBlank { null } ) + + constructor(image: ListQuery.Image) : this( + large = image.large?.ifBlank { null }, + medium = image.medium?.ifBlank { null }, + ) } @Serializable @@ -266,6 +280,18 @@ data class Character( year = birth.year ) } + + operator fun invoke(birth: ListQuery.DateOfBirth): BirthDate? { + if (birth.day == null && birth.month == null && birth.year == null) { + return null + } + + return BirthDate( + day = birth.day, + month = birth.month, + year = birth.year + ) + } } } @@ -354,5 +380,22 @@ data class Character( isFavoriteBlocked = character.isFavouriteBlocked ) } + + operator fun invoke(character: ListQuery.Node) : Character? { + val name = character.name?.let(::Name) ?: return null + val image = character.image?.let(::Image) ?: return null + + return Character( + id = character.id, + name = name, + image = image, + gender = character.gender?.ifBlank { null }, + bloodType = character.bloodType?.ifBlank { null }, + birthDate = character.dateOfBirth?.let { BirthDate(it) }, + description = character.description?.ifBlank { null }, + isFavorite = character.isFavourite, + isFavoriteBlocked = character.isFavouriteBlocked + ) + } } } \ No newline at end of file diff --git a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Medium.kt b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Medium.kt index f04504f..ad176ea 100644 --- a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Medium.kt +++ b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/model/Medium.kt @@ -261,6 +261,58 @@ data class Medium( startDate = query.startDate?.toLocalDate() ) + constructor(media: ListQuery.Media, list: ListQuery.MediaList?) : this( + id = media.id, + idMal = media.idMal, + type = media.type ?: MediaType.UNKNOWN__, + status = media.status ?: MediaStatus.UNKNOWN__, + description = media.description?.ifBlank { null }, + _episodes = media.episodes ?: -1, + avgEpisodeDurationInMin = media.duration ?: -1, + format = media.format ?: MediaFormat.UNKNOWN__, + _isAdult = media.isAdult ?: false, + genres = media.genresFilterNotNull()?.toSet() ?: emptySet(), + countryOfOrigin = media.countryOfOrigin?.toString()?.ifBlank { null }, + averageScore = media.averageScore ?: -1, + title = Title( + english = media.title?.english?.ifBlank { null }, + native = media.title?.native?.ifBlank { null }, + romaji = media.title?.romaji?.ifBlank { null }, + userPreferred = media.title?.userPreferred?.ifBlank { null } + ), + bannerImage = media.bannerImage?.ifBlank { null }, + coverImage = CoverImage( + color = media.coverImage?.color?.ifBlank { null }, + medium = media.coverImage?.medium?.ifBlank { null }, + large = media.coverImage?.large?.ifBlank { null }, + extraLarge = media.coverImage?.extraLarge?.ifBlank { null } + ), + nextAiringEpisode = media.nextAiringEpisode?.let(::NextAiring), + ranking = media.rankingsFilterNotNull()?.map(::Ranking)?.toSet() ?: emptySet(), + _characters = media.characters?.nodesFilterNotNull()?.mapNotNull(Character::invoke)?.toSet() ?: emptySet(), + entry = list?.let(::Entry), + trailer = media.trailer?.let { + val site = it.site?.ifBlank { null } + val thumbnail = it.thumbnail?.ifBlank { null } + + if (site == null || thumbnail == null) { + null + } else { + Trailer( + id = it.id?.ifBlank { null }, + site = site, + thumbnail = thumbnail + ) + } + }, + isFavorite = media.isFavourite, + _isFavoriteBlocked = media.isFavouriteBlocked, + siteUrl = media.siteUrl?.ifBlank { null } ?: "$SITE_URL${media.id}", + chapters = media.chapters ?: -1, + volumes = media.volumes ?: -1, + startDate = media.startDate?.toLocalDate() + ) + @Transient val isAdult: Boolean = _isAdult || genres.any { AdultContent.Genre.exists(it) @@ -389,6 +441,14 @@ data class Medium( season = ranking.season?.lastMonth(), type = ranking.type ) + + constructor(ranking: ListQuery.Ranking) : this( + rank = ranking.rank, + allTime = ranking.allTime ?: (ranking.season?.lastMonth() == null && ranking.year == null), + year = ranking.year ?: -1, + season = ranking.season?.lastMonth(), + type = ranking.type + ) } @Serializable @@ -430,6 +490,14 @@ data class Medium( repeatCount = entry.repeat, startDate = entry.startedAt?.toLocalDate() ) + + constructor(entry: ListQuery.MediaList) : this( + score = entry.score, + status = entry.status ?: MediaListStatus.UNKNOWN__, + progress = entry.progress, + repeatCount = entry.repeat, + startDate = entry.startedAt?.toLocalDate() + ) } @Serializable @@ -515,6 +583,11 @@ data class Medium( episodes = nextAiringEpisode.episode, airingAt = nextAiringEpisode.airingAt ) + + constructor(nextAiringEpisode: ListQuery.NextAiringEpisode) : this( + episodes = nextAiringEpisode.episode, + airingAt = nextAiringEpisode.airingAt + ) } companion object {