diff --git a/app/src/main/java/soko/ekibun/bangumi/api/trim21/BgmIpViewer.kt b/app/src/main/java/soko/ekibun/bangumi/api/trim21/BgmIpViewer.kt index 8bd33ce..3d4f378 100644 --- a/app/src/main/java/soko/ekibun/bangumi/api/trim21/BgmIpViewer.kt +++ b/app/src/main/java/soko/ekibun/bangumi/api/trim21/BgmIpViewer.kt @@ -1,5 +1,6 @@ package soko.ekibun.bangumi.api.trim21 +import android.util.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import soko.ekibun.bangumi.api.bangumi.bean.Subject @@ -26,7 +27,7 @@ object BgmIpViewer { * @param id [Subject.id] */ suspend fun getSeason(id: Int): SeasonData { - return withContext(Dispatchers.Main) { + return withContext(Dispatchers.Default) { val ipView = JsonUtil.toEntity(withContext(Dispatchers.IO) { HttpUtil.fetch("https://www.trim21.cn/api.v1/view_ip/subject/$id").body?.string() ?: "" })!! @@ -46,34 +47,37 @@ object BgmIpViewer { * @param subjectId [Subject.id] * @return List */ - private fun getSeasonNode(it: IpView, subjectId: Int): List { + private fun getSeasonNode(ipView: IpView, subjectId: Int): List { val ret = ArrayList() - val bgmIp = it.nodes?.firstOrNull { it.subject_id == subjectId } ?: return ret - val id = - it.edges?.firstOrNull { edge -> edge.source == bgmIp.id && edge.relation == "主线故事" }?.target ?: bgmIp.id - - for (edge in it.edges?.filter { edge -> edge.target == id && edge.relation == "主线故事" }?.reversed() - ?: ArrayList()) { - ret.add(0, it.nodes.firstOrNull { it.id == edge.source } ?: continue) + val bgmIp = ipView.nodes?.firstOrNull { it.subject_id == subjectId } ?: return ret + val visitNode = { nodeId: Int -> + ipView.nodes.firstOrNull { it.id == nodeId }?.takeIf { it.visit != true } } - ret.add(0, it.nodes.firstOrNull { it.id == id } ?: return ret) - var prevId = id - while (true) { - prevId = it.edges?.firstOrNull { it.source == prevId && it.relation == "前传" }?.target ?: break - for (edge in it.edges.filter { edge -> edge.target == prevId && edge.relation == "主线故事" }.reversed()) { - ret.add(0, it.nodes.firstOrNull { it.id == edge.source } ?: continue) - } - ret.add(0, it.nodes.firstOrNull { it.id == prevId } ?: break) - } - var nextId = id + val id = ipView.edges?.firstOrNull { edge -> + edge.source == bgmIp.id && edge.relation == "主线故事" + }?.target ?: bgmIp.id + + val queue = LinkedList() + queue.add(id + 1) while (true) { - nextId = it.edges?.firstOrNull { it.source == nextId && it.relation == "续集" }?.target ?: break - ret.add(it.nodes.firstOrNull { it.id == nextId } ?: break) - for (edge in it.edges.filter { edge -> edge.target == nextId && edge.relation == "主线故事" }) { - ret.add(it.nodes.firstOrNull { it.id == edge.source } ?: continue) + val nodeId = queue.poll() ?: break + val node = visitNode(nodeId)?.also { + Log.v("node", it.name_cn ?: it.name) + it.visit = true + } ?: continue + ret.add(node) + for (edge in ipView.edges?.filter { edge -> + edge.target == node.id && edge.relation == "主线故事" + }?.reversed() ?: emptyList()) { + ret.add(visitNode(edge.source) ?: continue) } + if (ipView.edges == null) break + queue.addAll(ipView.edges.filter { it.source == nodeId && it.relation == "续集" }.map { it.target }) + queue.addAll(ipView.edges.filter { it.source == nodeId && it.relation == "前传" }.map { it.target }) + queue.addAll(ipView.edges.filter { it.target == nodeId && it.relation == "续集" }.map { it.source }) + queue.addAll(ipView.edges.filter { it.target == nodeId && it.relation == "前传" }.map { it.source }) } - return ret.distinct() + return ret.distinct().sortedBy { it.subject_id } } } diff --git a/app/src/main/java/soko/ekibun/bangumi/api/trim21/bean/IpView.kt b/app/src/main/java/soko/ekibun/bangumi/api/trim21/bean/IpView.kt index 78fa82d..a3610ae 100644 --- a/app/src/main/java/soko/ekibun/bangumi/api/trim21/bean/IpView.kt +++ b/app/src/main/java/soko/ekibun/bangumi/api/trim21/bean/IpView.kt @@ -36,10 +36,11 @@ data class IpView( * @constructor */ data class Node( - val subject_id: Int = 0, - val id: Int = 0, - val image: String? = null, - val name: String? = null, - val name_cn: String? = null + val subject_id: Int = 0, + val id: Int = 0, + val image: String? = null, + val name: String? = null, + val name_cn: String? = null, + var visit: Boolean? = null ) } \ No newline at end of file