Implement automatic removal of downloads on Suwayomi after reading, configurable via extension settings (mihonapp/mihon#2673)

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
(cherry picked from commit 1263df9d4111511e49a43463c9808060433ce76d)
This commit is contained in:
Constantin Piber 2025-12-20 13:54:17 +01:00 committed by Cuong-Tran
parent 130aae8515
commit c525ce49af
3 changed files with 42 additions and 14 deletions

View file

@ -11,6 +11,9 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
- `Other` - for technical stuff.
## [Unreleased]
### Added
- Automatically remove downloads on Suwayomi after reading, configurable via extension settings ([@cpiber](https://github.com/cpiber)) ([#2673](https://github.com/mihonapp/mihon/pull/2673))
### Improved
- Minimize memory usage by reducing in-memory cover cache size ([@Lolle2000la](https://github.com/Lolle2000la)) ([#2266](https://github.com/mihonapp/mihon/pull/2266))

View file

@ -23,6 +23,9 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
const val UNREAD = 1L
const val READING = 2L
const val COMPLETED = 3L
private const val TRACKER_DELETE_KEY = "Tracker Delete"
private const val TRACKER_DELETE_DEFAULT = false
}
override fun getStatusList(): List<Long> = listOf(UNREAD, READING, COMPLETED)
@ -55,7 +58,7 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
}
}
return api.updateProgress(track)
return api.updateProgress(track, getPrefTrackerDelete())
}
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
@ -110,6 +113,11 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
return normalized.substringAfterLast('/').toLong()
}
private fun getPrefTrackerDelete(): Boolean {
val preferences = api.sourcePreferences()
return preferences.getBoolean(TRACKER_DELETE_KEY, TRACKER_DELETE_DEFAULT)
}
// KMK -->
override fun hasNotStartedReading(status: Long): Boolean = status == UNREAD
// KMK <--

View file

@ -1,12 +1,15 @@
package eu.kanade.tachiyomi.data.track.suwayomi
import android.content.SharedPreferences
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.awaitSuccess
import eu.kanade.tachiyomi.network.jsonMime
import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.source.sourcePreferences
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.addAll
import kotlinx.serialization.json.buildJsonObject
@ -26,10 +29,13 @@ class SuwayomiApi(private val trackId: Long) {
private val sourceManager: SourceManager by injectLazy()
private val source: HttpSource by lazy { sourceManager.get(sourceId) as HttpSource }
private val configurableSource: ConfigurableSource by lazy { (sourceManager.get(sourceId) as ConfigurableSource) }
private val client: OkHttpClient by lazy { source.client }
private val baseUrl: String by lazy { source.baseUrl.trimEnd('/') }
private val apiUrl: String by lazy { "$baseUrl/api/graphql" }
public fun sourcePreferences(): SharedPreferences = configurableSource.sourcePreferences()
suspend fun getTrackSearch(mangaId: Long): TrackSearch = withIOContext {
val query = """
|query GetManga(${'$'}mangaId: Int!) {
@ -76,9 +82,11 @@ class SuwayomiApi(private val trackId: Long) {
}
}
suspend fun updateProgress(track: Track): Track {
suspend fun updateProgress(track: Track, deleteDownloadsOnServer: Boolean = false): Track {
val mangaId = track.remote_id
// TODO: Include a filter on the chapter number here
// Below, we only consider older chapters; since v2.1.1985 filtering works properly in the query
val chaptersQuery = """
|query GetMangaUnreadChapters(${'$'}mangaId: Int!) {
| chapters(condition: {mangaId: ${'$'}mangaId, isRead: false}) {
@ -110,15 +118,26 @@ class SuwayomiApi(private val trackId: Long) {
.mapNotNull { n -> n.id.takeIf { n.chapterNumber <= track.last_chapter_read } }
}
val markQuery = """
val markQuery = if (deleteDownloadsOnServer) {
"""
|mutation MarkChaptersRead(${'$'}chapters: [Int!]!) {
| updateChapters(input: {ids: ${'$'}chapters, patch: {isRead: true}}) {
| chapters {
| id
| __typename
| }
| deleteDownloadedChapters(input: {ids: ${'$'}chapters}) {
| __typename
| }
|}
""".trimMargin()
} else {
"""
|mutation MarkChaptersRead(${'$'}chapters: [Int!]!) {
| updateChapters(input: {ids: ${'$'}chapters, patch: {isRead: true}}) {
| __typename
| }
|}
""".trimMargin()
}
val markPayload = buildJsonObject {
put("query", markQuery)
putJsonObject("variables") {
@ -140,9 +159,7 @@ class SuwayomiApi(private val trackId: Long) {
val trackQuery = """
|mutation TrackManga(${'$'}mangaId: Int!) {
| trackProgress(input: {mangaId: ${'$'}mangaId}) {
| trackRecords {
| lastChapterRead
| }
| __typename
| }
|}
""".trimMargin()