Display staff information on Anilist tracker search results (mihonapp/mihon#1810)

Co-authored-by: Cuong-Tran <cuongtran.tm@gmail.com>
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit b702603965044cfe3ee852f8d0c970b6eb93b97a)
This commit is contained in:
NarwhalHorns 2025-03-06 08:21:05 +00:00 committed by Cuong-Tran
parent 9183c19cd2
commit 7d1ee6c587
No known key found for this signature in database
GPG key ID: 733AA7624B9315C2
8 changed files with 87 additions and 22 deletions

View file

@ -21,6 +21,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
- Add option to export minimal library information to a CSV file ([@Animeboynz](https://github.com/Animeboynz), [@AntsyLich](https://github.com/AntsyLich)) ([#1161](https://github.com/mihonapp/mihon/pull/1161))
- Add back support for drag-and-drop category reordering ([@cuong-tran](https://github.com/cuong-tran)) ([#1427](https://github.com/mihonapp/mihon/pull/1427))
- Add option to mark new duplicate read chapters as read
- Display staff information on Anilist tracker search results ([@NarwhalHorns](https://github.com/NarwhalHorns)) ([#1810](https://github.com/mihonapp/mihon/pull/1810))
### Changed
- Apply "Downloaded only" filter to all entries regardless of favourite status ([@NGB-Was-Taken](https://github.com/NGB-Was-Taken)) ([#1603](https://github.com/mihonapp/mihon/pull/1603))

View file

@ -304,6 +304,15 @@ private fun SearchResultItem(
}
},
)
if (trackSearch.authors.isNotEmpty() || trackSearch.artists.isNotEmpty()) {
Text(
text = (trackSearch.authors + trackSearch.artists).distinct().joinToString(),
modifier = Modifier.secondaryItemAlpha(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodySmall,
)
}
if (type.isNotBlank()) {
SearchResultItemDetails(
title = stringResource(MR.strings.track_type),

View file

@ -97,9 +97,13 @@ internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composab
it.summary = lorem((0..40).random()).joinToString()
it.publishing_status = if (Random.nextBoolean()) "Finished" else ""
it.publishing_type = if (Random.nextBoolean()) "Oneshot" else ""
it.artists = randomNames()
it.authors = randomNames()
it
}
private fun randomNames(): List<String> = (0..(0..3).random()).map { lorem((3..5).random()).joinToString() }
private fun lorem(words: Int): Sequence<String> =
LoremIpsum(words).values
}

View file

@ -143,6 +143,19 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|Page (perPage: 50) {
|media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) {
|id
|staff {
|edges {
|role
|id
|node {
|name {
|full
|userPreferred
|native
|}
|}
|}
|}
|title {
|userPreferred
|}
@ -223,6 +236,19 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|month
|day
|}
|staff {
|edges {
|role
|id
|node {
|name {
|full
|userPreferred
|native
|}
|}
|}
|}
|}
|}
|}
@ -310,9 +336,12 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|staff {
|edges {
|role
|id
|node {
|name {
|full
|userPreferred
|native
|}
|}
|}
@ -345,15 +374,13 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
description = media.description?.htmlDecode()?.ifEmpty { null },
authors = media.staff.edges
.filter { it.role == "Story" || it.role == "Story & Art" }
// KMK -->
.joinToString(", ") { it.node.name.userPreferred }
// KMK <--
.mapNotNull { it.node.name.userPreferred }
.joinToString(", ")
.ifEmpty { null },
artists = media.staff.edges
.filter { it.role == "Art" || it.role == "Story & Art" }
// KMK -->
.joinToString(", ") { it.node.name.userPreferred }
// KMK <--
.mapNotNull { it.node.name.userPreferred }
.joinToString(", ")
.ifEmpty { null },
)
}

View file

@ -19,6 +19,7 @@ data class ALManga(
val startDateFuzzy: Long,
val totalChapters: Long,
val averageScore: Int,
val staff: ALStaff,
) {
fun toTrack() = TrackSearch.create(TrackerManager.ANILIST).apply {
remote_id = remoteId
@ -38,6 +39,11 @@ data class ALManga(
""
}
}
staff.edges.forEach {
val name = it.node.name() ?: return@forEach
if ("Story" in it.role) authors += name
if ("Art" in it.role) artists += name
}
}
}

View file

@ -22,19 +22,3 @@ data class ALMangaMetadataMedia(
val description: String?,
val staff: ALStaff,
)
@Serializable
data class ALStaff(
val edges: List<ALStaffEdge>,
)
@Serializable
data class ALStaffEdge(
val role: String,
val node: ALStaffNode,
)
@Serializable
data class ALStaffNode(
val name: ALItemTitle,
)

View file

@ -13,6 +13,7 @@ data class ALSearchItem(
val startDate: ALFuzzyDate,
val chapters: Long?,
val averageScore: Int?,
val staff: ALStaff,
) {
fun toALManga(): ALManga = ALManga(
remoteId = id,
@ -24,6 +25,7 @@ data class ALSearchItem(
startDateFuzzy = startDate.toEpochMilli(),
totalChapters = chapters ?: 0,
averageScore = averageScore ?: -1,
staff = staff,
)
}
@ -36,3 +38,31 @@ data class ALItemTitle(
data class ItemCover(
val large: String,
)
@Serializable
data class ALStaff(
val edges: List<ALEdge>,
)
@Serializable
data class ALEdge(
val role: String,
val id: Int,
val node: ALStaffNode,
)
@Serializable
data class ALStaffNode(
val name: ALStaffName,
)
@Serializable
data class ALStaffName(
val userPreferred: String?,
val native: String?,
val full: String?,
) {
operator fun invoke(): String? {
return userPreferred ?: full ?: native
}
}

View file

@ -34,6 +34,10 @@ class TrackSearch : Track {
override lateinit var tracking_url: String
var authors: List<String> = emptyList()
var artists: List<String> = emptyList()
var cover_url: String = ""
var summary: String = ""