Fix Hikka search failing due to unclosed response & show toast on remote-removed titles (#3548)

* Fix Hikka search failing due to unclosed response

This closes #3547.

I have also included a precautionary refactor of the `getRead` method
in HikkaApi.kt, which by the looks of it _could_ leak an unclosed
response as well.

The try/catch with awaitSuccess pattern has been used in this same way
in the Bangumi and MangaBaka implementations as well. The benefit here
is that `awaitSuccess()` closes the response on error before throwing
an `HttpException`.

* Show toast on remote-removed list entries
This commit is contained in:
MajorTanya
2026-07-08 19:41:23 +02:00
committed by GitHub
parent 0ff654205f
commit ab58a9952e
4 changed files with 22 additions and 14 deletions
+1
View File
@@ -14,6 +14,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
### Added ### Added
- [Hikka](https://hikka.io/) tracker support ([@Lorg0n](https://github.com/Lorg0n)) ([#1386](https://github.com/mihonapp/mihon/pull/1386)) - [Hikka](https://hikka.io/) tracker support ([@Lorg0n](https://github.com/Lorg0n)) ([#1386](https://github.com/mihonapp/mihon/pull/1386))
- Fix Hikka not defaulting to "Plan to Read" for unread titles ([@MajorTanya](https://github.com/MajorTanya)) ([#3534](https://github.com/mihonapp/mihon/pull/3534)) - Fix Hikka not defaulting to "Plan to Read" for unread titles ([@MajorTanya](https://github.com/MajorTanya)) ([#3534](https://github.com/mihonapp/mihon/pull/3534))
- Fix Hikka search throwing error due to unclosed response ([@MajorTanya](https://github.com/MajorTanya)) ([#3548](https://github.com/mihonapp/mihon/pull/3548))
- Add support for [MangaBaka](https://mangabaka.org) tracker ([@MajorTanya](https://github.com/MajorTanya)) ([#3047](https://github.com/mihonapp/mihon/pull/3047)) - Add support for [MangaBaka](https://mangabaka.org) tracker ([@MajorTanya](https://github.com/MajorTanya)) ([#3047](https://github.com/mihonapp/mihon/pull/3047))
- Support resumable image downloads if supported by source ([@xMohnad](https://github.com/xMohnad)) ([#3167](https://github.com/mihonapp/mihon/pull/3167)) - Support resumable image downloads if supported by source ([@xMohnad](https://github.com/xMohnad)) ([#3167](https://github.com/mihonapp/mihon/pull/3167))
- Display authors and description in Shikimori search results ([@MajorTanya](https://github.com/MajorTanya)) ([#3499](https://github.com/mihonapp/mihon/pull/3499)) - Display authors and description in Shikimori search results ([@MajorTanya](https://github.com/MajorTanya)) ([#3499](https://github.com/mihonapp/mihon/pull/3499))
@@ -125,14 +125,13 @@ class Hikka(id: Long) : BaseTracker(id, "Hikka"), DeletableTracker {
track.copyPersonalFrom(remoteTrack) track.copyPersonalFrom(remoteTrack)
track.total_chapters = remoteTrack.total_chapters track.total_chapters = remoteTrack.total_chapters
val readContent = api.getRead(track) val readContent = api.getRead(track) ?: throw Exception("Could not find manga")
if (readContent != null) {
track.score = readContent.score.toDouble() track.score = readContent.score.toDouble()
track.last_chapter_read = readContent.chapters.toDouble() track.last_chapter_read = readContent.chapters.toDouble()
track.status = toTrackStatus(readContent.status) track.status = toTrackStatus(readContent.status)
track.started_reading_date = (readContent.startDate ?: 0L) * 1000 track.started_reading_date = (readContent.startDate ?: 0L) * 1000
track.finished_reading_date = (readContent.endDate ?: 0L) * 1000 track.finished_reading_date = (readContent.endDate ?: 0L) * 1000
}
return track return track
} }
@@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.track.hikka.dto.HKUser
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.DELETE import eu.kanade.tachiyomi.network.DELETE
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.HttpException
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.PUT import eu.kanade.tachiyomi.network.PUT
import eu.kanade.tachiyomi.network.awaitSuccess import eu.kanade.tachiyomi.network.awaitSuccess
@@ -103,12 +104,16 @@ class HikkaApi(
val slug = track.tracking_url.split("/")[4] val slug = track.tracking_url.split("/")[4]
val url = "$BASE_API_URL/read/manga/$slug".toUri().buildUpon().build() val url = "$BASE_API_URL/read/manga/$slug".toUri().buildUpon().build()
with(json) { with(json) {
val response = authClient.newCall(GET(url.toString())).execute() try {
if (response.code == 404) { authClient.newCall(GET(url.toString()))
return@withIOContext null .awaitSuccess()
.parseAs<HKRead>()
} catch (e: HttpException) {
if (e.code == 404) {
null
} else {
throw e
} }
response.use {
it.parseAs<HKRead>()
} }
} }
} }
@@ -22,11 +22,14 @@ class HikkaInterceptor(private val hikka: Hikka) : Interceptor {
refreshTokenResponse.close() refreshTokenResponse.close()
hikka.logout() hikka.logout()
throw Exception("Hikka: The token is expired") throw Exception("Hikka: The token is expired")
} else {
refreshTokenResponse.close()
} }
val authTokenInfoResponse = chain.proceed(HikkaApi.authTokenInfo(currAuth.accessToken)) val authTokenInfoResponse = chain.proceed(HikkaApi.authTokenInfo(currAuth.accessToken))
if (!authTokenInfoResponse.isSuccessful) { if (!authTokenInfoResponse.isSuccessful) {
authTokenInfoResponse.close() authTokenInfoResponse.close()
throw Exception("Hikka: Auth token info failed")
} }
val authTokenInfo = json.decodeFromString<HKAuthTokenInfo>(authTokenInfoResponse.body.string()) val authTokenInfo = json.decodeFromString<HKAuthTokenInfo>(authTokenInfoResponse.body.string())