mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Support batch chapter update api
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.jui.domain.chapter.interactor
|
||||
|
||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||
import ca.gosyer.jui.domain.chapter.model.ChapterBatchEditInput
|
||||
import ca.gosyer.jui.domain.chapter.model.ChapterChange
|
||||
import ca.gosyer.jui.domain.chapter.model.MangaChapterBatchEditInput
|
||||
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
|
||||
import ca.gosyer.jui.domain.manga.model.Manga
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
import org.lighthousegames.logging.logging
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
class BatchUpdateChapter @Inject constructor(private val chapterRepository: ChapterRepository) {
|
||||
|
||||
@JvmName("awaitChapters")
|
||||
suspend fun await(
|
||||
mangaId: Long,
|
||||
chapters: List<Chapter>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null,
|
||||
onError: suspend (Throwable) -> Unit = {}
|
||||
) = asFlow(mangaId, chapters, isRead, isBookmarked, lastPageRead, delete)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to update multiple chapters of $mangaId" }
|
||||
}
|
||||
.collect()
|
||||
|
||||
suspend fun await(
|
||||
mangaId: Long,
|
||||
chapterIds: List<Long>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null,
|
||||
onError: suspend (Throwable) -> Unit = {}
|
||||
) = asFlow(mangaId, chapterIds, isRead, isBookmarked, lastPageRead, delete)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to update multiple chapters of $mangaId" }
|
||||
}
|
||||
.collect()
|
||||
|
||||
@JvmName("awaitChapters")
|
||||
suspend fun await(
|
||||
manga: Manga,
|
||||
chapters: List<Chapter>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null,
|
||||
onError: suspend (Throwable) -> Unit = {}
|
||||
) = asFlow(manga, chapters, isRead, isBookmarked, lastPageRead, delete)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to update multiple chapters of ${manga.title}(${manga.id})" }
|
||||
}
|
||||
.collect()
|
||||
|
||||
|
||||
suspend fun await(
|
||||
manga: Manga,
|
||||
chapterIds: List<Long>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null,
|
||||
onError: suspend (Throwable) -> Unit = {}
|
||||
) = asFlow(manga, chapterIds, isRead, isBookmarked, lastPageRead, delete)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to update multiple chapters of ${manga.title}(${manga.id})" }
|
||||
}
|
||||
.collect()
|
||||
|
||||
@JvmName("awaitChapters")
|
||||
suspend fun await(
|
||||
chapters: List<Chapter>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null,
|
||||
onError: suspend (Throwable) -> Unit = {}
|
||||
) = asFlow(chapters, isRead, isBookmarked, lastPageRead, delete)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to update multiple chapters" }
|
||||
}
|
||||
.collect()
|
||||
|
||||
suspend fun await(
|
||||
chapterIds: List<Long>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null,
|
||||
onError: suspend (Throwable) -> Unit = {}
|
||||
) = asFlow(chapterIds, isRead, isBookmarked, lastPageRead, delete)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to update update multiple chapters" }
|
||||
}
|
||||
.collect()
|
||||
|
||||
@JvmName("asFlowChapters")
|
||||
fun asFlow(
|
||||
mangaId: Long,
|
||||
chapters: List<Chapter>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null
|
||||
) = getFlow(
|
||||
mangaId = mangaId,
|
||||
chapterIds = chapters.map { it.id },
|
||||
isRead = isRead,
|
||||
isBookmarked = isBookmarked,
|
||||
lastPageRead = lastPageRead,
|
||||
delete = delete
|
||||
)
|
||||
|
||||
fun asFlow(
|
||||
mangaId: Long,
|
||||
chapterIds: List<Long>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null
|
||||
) = getFlow(
|
||||
mangaId = mangaId,
|
||||
chapterIds = chapterIds,
|
||||
isRead = isRead,
|
||||
isBookmarked = isBookmarked,
|
||||
lastPageRead = lastPageRead,
|
||||
delete = delete
|
||||
)
|
||||
|
||||
@JvmName("asFlowChapters")
|
||||
fun asFlow(
|
||||
manga: Manga,
|
||||
chapters: List<Chapter>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null
|
||||
) = getFlow(
|
||||
mangaId = manga.id,
|
||||
chapterIds = chapters.map { it.id },
|
||||
isRead = isRead,
|
||||
isBookmarked = isBookmarked,
|
||||
lastPageRead = lastPageRead,
|
||||
delete = delete
|
||||
)
|
||||
|
||||
fun asFlow(
|
||||
manga: Manga,
|
||||
chapterIds: List<Long>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null
|
||||
) = getFlow(
|
||||
mangaId = manga.id,
|
||||
chapterIds = chapterIds,
|
||||
isRead = isRead,
|
||||
isBookmarked = isBookmarked,
|
||||
lastPageRead = lastPageRead,
|
||||
delete = delete
|
||||
)
|
||||
|
||||
@JvmName("asFlowChapters")
|
||||
fun asFlow(
|
||||
chapters: List<Chapter>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null
|
||||
) = getFlow(
|
||||
mangaId = null,
|
||||
chapterIds = chapters.map { it.id },
|
||||
isRead = isRead,
|
||||
isBookmarked = isBookmarked,
|
||||
lastPageRead = lastPageRead,
|
||||
delete = delete
|
||||
)
|
||||
|
||||
|
||||
fun asFlow(
|
||||
chapterIds: List<Long>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null
|
||||
) = getFlow(
|
||||
mangaId = null,
|
||||
chapterIds = chapterIds,
|
||||
isRead = isRead,
|
||||
isBookmarked = isBookmarked,
|
||||
lastPageRead = lastPageRead,
|
||||
delete = delete
|
||||
)
|
||||
|
||||
private fun getFlow(
|
||||
mangaId: Long?,
|
||||
chapterIds: List<Long>,
|
||||
isRead: Boolean? = null,
|
||||
isBookmarked: Boolean? = null,
|
||||
lastPageRead: Int? = null,
|
||||
delete: Boolean? = null
|
||||
) = if (mangaId != null) {
|
||||
chapterRepository.batchUpdateChapter(
|
||||
mangaId,
|
||||
MangaChapterBatchEditInput(
|
||||
chapterIds = chapterIds,
|
||||
change = ChapterChange(
|
||||
isRead = isRead,
|
||||
isBookmarked = isBookmarked,
|
||||
lastPageRead = lastPageRead,
|
||||
delete = delete
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
chapterRepository.batchUpdateChapter(
|
||||
ChapterBatchEditInput(
|
||||
chapterIds = chapterIds,
|
||||
change = ChapterChange(
|
||||
isRead = isRead,
|
||||
isBookmarked = isBookmarked,
|
||||
lastPageRead = lastPageRead,
|
||||
delete = delete
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val log = logging()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.jui.domain.chapter.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ChapterBatchEditInput(
|
||||
val chapterIds: List<Long>? = null,
|
||||
val change: ChapterChange?
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.jui.domain.chapter.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ChapterChange(
|
||||
val isRead: Boolean? = null,
|
||||
val isBookmarked: Boolean? = null,
|
||||
val lastPageRead: Int? = null,
|
||||
val delete: Boolean? = null
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.jui.domain.chapter.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class MangaChapterBatchEditInput(
|
||||
val chapterIds: List<Long>? = null,
|
||||
val chapterIndexes: List<Int>? = null,
|
||||
val change: ChapterChange?
|
||||
)
|
||||
@@ -7,11 +7,16 @@
|
||||
package ca.gosyer.jui.domain.chapter.service
|
||||
|
||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||
import ca.gosyer.jui.domain.chapter.model.ChapterBatchEditInput
|
||||
import ca.gosyer.jui.domain.chapter.model.MangaChapterBatchEditInput
|
||||
import de.jensklingenberg.ktorfit.http.Body
|
||||
import de.jensklingenberg.ktorfit.http.DELETE
|
||||
import de.jensklingenberg.ktorfit.http.Field
|
||||
import de.jensklingenberg.ktorfit.http.FormUrlEncoded
|
||||
import de.jensklingenberg.ktorfit.http.GET
|
||||
import de.jensklingenberg.ktorfit.http.Headers
|
||||
import de.jensklingenberg.ktorfit.http.PATCH
|
||||
import de.jensklingenberg.ktorfit.http.POST
|
||||
import de.jensklingenberg.ktorfit.http.Path
|
||||
import de.jensklingenberg.ktorfit.http.Query
|
||||
import de.jensklingenberg.ktorfit.http.ReqBuilder
|
||||
@@ -44,6 +49,19 @@ interface ChapterRepository {
|
||||
@Field("markPrevRead") markPreviousRead: Boolean? = null
|
||||
): Flow<HttpResponse>
|
||||
|
||||
@POST("api/v1/manga/{mangaId}/chapter/batch")
|
||||
@Headers("Content-Type: application/json")
|
||||
fun batchUpdateChapter(
|
||||
@Path("mangaId") mangaId: Long,
|
||||
@Body input: MangaChapterBatchEditInput
|
||||
): Flow<HttpResponse>
|
||||
|
||||
@POST("api/v1/chapter/batch")
|
||||
@Headers("Content-Type: application/json")
|
||||
fun batchUpdateChapter(
|
||||
@Body input: ChapterBatchEditInput
|
||||
): Flow<HttpResponse>
|
||||
|
||||
@GET("api/v1/manga/{mangaId}/chapter/{chapterIndex}/page/{pageNum}")
|
||||
fun getPage(
|
||||
@Path("mangaId") mangaId: Long,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.jui.domain.manga.interactor
|
||||
|
||||
import ca.gosyer.jui.domain.manga.model.Manga
|
||||
import ca.gosyer.jui.domain.manga.service.MangaRepository
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.singleOrNull
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
import org.lighthousegames.logging.logging
|
||||
|
||||
class GetMangaFull @Inject constructor(private val mangaRepository: MangaRepository) {
|
||||
|
||||
suspend fun await(mangaId: Long, onError: suspend (Throwable) -> Unit = {}) = asFlow(mangaId)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to get full manga $mangaId" }
|
||||
}
|
||||
.singleOrNull()
|
||||
|
||||
suspend fun await(manga: Manga, onError: suspend (Throwable) -> Unit = {}) = asFlow(manga)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to get full manga ${manga.title}(${manga.id})" }
|
||||
}
|
||||
.singleOrNull()
|
||||
|
||||
fun asFlow(mangaId: Long) = mangaRepository.getMangaFull(mangaId)
|
||||
|
||||
fun asFlow(manga: Manga) = mangaRepository.getMangaFull(manga.id)
|
||||
|
||||
companion object {
|
||||
private val log = logging()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.jui.domain.manga.interactor
|
||||
|
||||
import ca.gosyer.jui.domain.manga.model.Manga
|
||||
import ca.gosyer.jui.domain.manga.service.MangaRepository
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.singleOrNull
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
import org.lighthousegames.logging.logging
|
||||
|
||||
class RefreshMangaFull @Inject constructor(private val mangaRepository: MangaRepository) {
|
||||
|
||||
suspend fun await(mangaId: Long, onError: suspend (Throwable) -> Unit = {}) = asFlow(mangaId)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to refresh full manga $mangaId" }
|
||||
}
|
||||
.singleOrNull()
|
||||
|
||||
suspend fun await(manga: Manga, onError: suspend (Throwable) -> Unit = {}) = asFlow(manga)
|
||||
.catch {
|
||||
onError(it)
|
||||
log.warn(it) { "Failed to refresh full manga ${manga.title}(${manga.id})" }
|
||||
}
|
||||
.singleOrNull()
|
||||
|
||||
fun asFlow(mangaId: Long) = mangaRepository.getMangaFull(mangaId, true)
|
||||
|
||||
fun asFlow(manga: Manga) = mangaRepository.getMangaFull(manga.id, true)
|
||||
|
||||
companion object {
|
||||
private val log = logging()
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ package ca.gosyer.jui.domain.manga.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||
import ca.gosyer.jui.domain.source.model.Source
|
||||
import ca.gosyer.jui.i18n.MR
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
@@ -33,14 +34,15 @@ data class Manga(
|
||||
val freshData: Boolean,
|
||||
val meta: MangaMeta,
|
||||
val realUrl: String?,
|
||||
val lastFetchedAt: Long? = 0, // todo remove default
|
||||
val chaptersLastFetchedAt: Long? = 0, // todo remove default
|
||||
val lastFetchedAt: Long?,
|
||||
val chaptersLastFetchedAt: Long?,
|
||||
val inLibraryAt: Long,
|
||||
val unreadCount: Int?,
|
||||
val downloadCount: Int?,
|
||||
val chapterCount: Int? = null, // todo remove default
|
||||
val age: Long? = null, // todo remove default
|
||||
val chaptersAge: Long? = null // todo remove default
|
||||
val chapterCount: Int?,
|
||||
var lastChapterRead: Chapter?,
|
||||
val age: Long?,
|
||||
val chaptersAge: Long?
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
||||
@@ -26,6 +26,12 @@ interface MangaRepository {
|
||||
@Query("onlineFetch") refresh: Boolean = false
|
||||
): Flow<Manga>
|
||||
|
||||
@GET("api/v1/manga/{mangaId}/full")
|
||||
fun getMangaFull(
|
||||
@Path("mangaId") mangaId: Long,
|
||||
@Query("onlineFetch") refresh: Boolean = false
|
||||
): Flow<Manga>
|
||||
|
||||
@GET("api/v1/manga/{mangaId}/thumbnail")
|
||||
fun getMangaThumbnail(
|
||||
@Path("mangaId") mangaId: Long,
|
||||
|
||||
Reference in New Issue
Block a user