Add authors/artists to MAL search results (mihonapp/mihon#2833)

Co-authored-by: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com>
(cherry picked from commit 51b3ab3fd19bdf6a7c3bd2085104392a9c412622)
This commit is contained in:
MajorTanya 2026-01-07 09:16:56 +01:00 committed by Cuong-Tran
parent 69aba243ed
commit ab9e17c739
2 changed files with 43 additions and 27 deletions

View file

@ -175,6 +175,7 @@ class MyAnimeListApi(
}
}
// SY -->
suspend fun getMangaMetadata(track: DomainTrack): TrackMangaMetadata {
return withIOContext {
val url = "$BASE_API_URL/manga".toUri().buildUpon()
@ -188,25 +189,29 @@ class MyAnimeListApi(
authClient.newCall(GET(url.toString()))
.awaitSuccess()
.parseAs<MALMangaMetadata>()
.let {
.let { metadata ->
TrackMangaMetadata(
remoteId = it.id,
title = it.title,
thumbnailUrl = it.covers.large?.ifEmpty { null } ?: it.covers.medium,
description = it.synopsis,
authors = it.authors
.filter { "Story" in it.role }
.joinToString(separator = ", ") { "${it.node.firstName} ${it.node.lastName}".trim() }
remoteId = metadata.id,
title = metadata.title,
thumbnailUrl = metadata.covers.large?.ifEmpty { null } ?: metadata.covers.medium,
description = metadata.synopsis,
artists = metadata.authors
.filter { authorNode -> authorNode.role == "Art" }
.mapNotNull { authorNode -> authorNode.node.getFullName() }
.joinToString()
.ifEmpty { null },
artists = it.authors
.filter { "Art" in it.role }
.joinToString(separator = ", ") { "${it.node.firstName} ${it.node.lastName}".trim() }
authors = metadata.authors
// count all with "Story" or "Story & Art" as authors, like is done for library entries
.filter { authorNode -> authorNode.role.contains("Story") }
.mapNotNull { authorNode -> authorNode.node.getFullName() }
.joinToString()
.ifEmpty { null },
)
}
}
}
}
// SY <--
private suspend fun getListPage(offset: Int): MALSearchResult {
return withIOContext {
@ -252,6 +257,13 @@ class MyAnimeListApi(
publishing_status = searchItem.status.replace("_", " ")
publishing_type = searchItem.mediaType.replace("_", " ")
start_date = searchItem.startDate ?: ""
artists = searchItem.authors
.filter { authorNode -> authorNode.role == "Art" }
.mapNotNull { authorNode -> authorNode.node.getFullName() }
authors = searchItem.authors
// count all with "Story" or "Story & Art" as authors, like is done for library entries
.filter { authorNode -> authorNode.role.contains("Story") }
.mapNotNull { authorNode -> authorNode.node.getFullName() }
}
}
@ -279,7 +291,7 @@ class MyAnimeListApi(
private const val BASE_API_URL = "https://api.myanimelist.net/v2"
private const val SEARCH_FIELDS =
"id,title,synopsis,num_chapters,mean,main_picture,status,media_type,start_date"
"id,title,synopsis,num_chapters,mean,main_picture,status,media_type,start_date,authors{first_name,last_name}"
private const val LIST_PAGINATION_AMOUNT = 250

View file

@ -18,8 +18,26 @@ data class MALManga(
val mediaType: String,
@SerialName("start_date")
val startDate: String?,
val authors: List<MALAuthorNode> = emptyList(),
)
@Serializable
data class MALAuthorNode(
val node: MALAuthor,
val role: String,
)
@Serializable
data class MALAuthor(
val id: Int,
@SerialName("first_name")
val firstName: String,
@SerialName("last_name")
val lastName: String,
) {
fun getFullName(): String? = "$firstName $lastName".trim().ifBlank { null }
}
@Serializable
data class MALMangaCovers(
val large: String?,
@ -33,19 +51,5 @@ data class MALMangaMetadata(
val synopsis: String?,
@SerialName("main_picture")
val covers: MALMangaCovers,
val authors: List<MALAuthor>,
)
@Serializable
data class MALAuthor(
val node: MALAuthorNode,
val role: String,
)
@Serializable
data class MALAuthorNode(
@SerialName("first_name")
val firstName: String,
@SerialName("last_name")
val lastName: String,
val authors: List<MALAuthorNode>,
)