From 02cec0653591ad24da16ad8ad5547ce6cbfec8b5 Mon Sep 17 00:00:00 2001 From: Constantin Piber <59023762+cpiber@users.noreply.github.com> Date: Sat, 20 Dec 2025 13:54:17 +0100 Subject: [PATCH] Implement automatic removal of downloads on Suwayomi after reading, configurable via extension settings (#2673) Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> (cherry picked from commit 1263df9d4111511e49a43463c9808060433ce76d) # Conflicts: # CHANGELOG.md --- .../tachiyomi/data/track/suwayomi/Suwayomi.kt | 10 ++++- .../data/track/suwayomi/SuwayomiApi.kt | 43 +++++++++++++------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt index 01cb78c28..904fb0292 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt @@ -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 = 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 { @@ -102,4 +105,9 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker { private fun String.getMangaId(): Long = this.substringAfterLast('/').toLong() + + private fun getPrefTrackerDelete(): Boolean { + val preferences = api.sourcePreferences() + return preferences.getBoolean(TRACKER_DELETE_KEY, TRACKER_DELETE_DEFAULT) + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt index 9825b46af..a7e7eda7f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt @@ -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 = """ - |mutation MarkChaptersRead(${'$'}chapters: [Int!]!) { - | updateChapters(input: {ids: ${'$'}chapters, patch: {isRead: true}}) { - | chapters { - | id - | } - | } - |} - """.trimMargin() + val markQuery = if (deleteDownloadsOnServer) { + """ + |mutation MarkChaptersRead(${'$'}chapters: [Int!]!) { + | updateChapters(input: {ids: ${'$'}chapters, patch: {isRead: true}}) { + | __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()