Feature/graphql chapter pages mutation handle downloaded chapters (#665)
* Update chapter page refresh logic with logic from "ChapterMutation" * Rename function to "getChapterDownloadReadyByIndex" * Update "ChapterForDownload" to work with only "chapterId" being passed * Return database chapter page list in case chapter is downloaded In case the chapter is downloaded, fetching the chapter pages info should not be needed. It should also currently break reading downloaded chapters while being offline, since the page request will always fail, since there is no internet connection
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
package suwayomi.tachidesk.graphql.mutations
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.batchInsert
|
||||
import org.jetbrains.exposed.sql.deleteWhere
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
@@ -11,11 +9,9 @@ import org.jetbrains.exposed.sql.update
|
||||
import suwayomi.tachidesk.graphql.types.ChapterMetaType
|
||||
import suwayomi.tachidesk.graphql.types.ChapterType
|
||||
import suwayomi.tachidesk.manga.impl.Chapter
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrNull
|
||||
import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReadyById
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.PageTable
|
||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.CompletableFuture
|
||||
@@ -203,43 +199,15 @@ class ChapterMutation {
|
||||
): CompletableFuture<FetchChapterPagesPayload> {
|
||||
val (clientMutationId, chapterId) = input
|
||||
|
||||
val chapter = transaction { ChapterTable.select { ChapterTable.id eq chapterId }.first() }
|
||||
val manga = transaction { MangaTable.select { MangaTable.id eq chapter[ChapterTable.manga] }.first() }
|
||||
val source = getCatalogueSourceOrNull(manga[MangaTable.sourceReference])!!
|
||||
|
||||
return future {
|
||||
source.getPageList(
|
||||
SChapter.create().apply {
|
||||
url = chapter[ChapterTable.url]
|
||||
name = chapter[ChapterTable.name]
|
||||
}
|
||||
)
|
||||
}.thenApply { pageList ->
|
||||
transaction {
|
||||
PageTable.deleteWhere { PageTable.chapter eq chapterId }
|
||||
PageTable.batchInsert(pageList) { page ->
|
||||
this[PageTable.index] = page.index
|
||||
this[PageTable.url] = page.url
|
||||
this[PageTable.imageUrl] = page.imageUrl
|
||||
this[PageTable.chapter] = chapterId
|
||||
}
|
||||
ChapterTable.update({ ChapterTable.id eq chapterId }) {
|
||||
val pageCount = pageList.size
|
||||
it[ChapterTable.pageCount] = pageCount
|
||||
it[ChapterTable.lastPageRead] = chapter[ChapterTable.lastPageRead].coerceAtMost(pageCount - 1)
|
||||
}
|
||||
}
|
||||
|
||||
val mangaId = manga[MangaTable.id].value
|
||||
val chapterIndex = chapter[ChapterTable.sourceOrder]
|
||||
getChapterDownloadReadyById(chapterId)
|
||||
}.thenApply { chapter ->
|
||||
FetchChapterPagesPayload(
|
||||
clientMutationId = clientMutationId,
|
||||
pages = List(pageList.size) { index ->
|
||||
"/api/v1/manga/$mangaId/chapter/$chapterIndex/page/$index"
|
||||
pages = List(chapter.pageCount) { index ->
|
||||
"/api/v1/manga/${chapter.mangaId}/chapter/${chapter.index}/page/$index"
|
||||
},
|
||||
chapter = ChapterType(
|
||||
transaction { ChapterTable.select { ChapterTable.id eq chapterId }.first() }
|
||||
)
|
||||
chapter = ChapterType(chapter)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ package suwayomi.tachidesk.manga.controller
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import io.javalin.http.HttpCode
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
@@ -18,7 +17,7 @@ import suwayomi.tachidesk.manga.impl.Chapter
|
||||
import suwayomi.tachidesk.manga.impl.Library
|
||||
import suwayomi.tachidesk.manga.impl.Manga
|
||||
import suwayomi.tachidesk.manga.impl.Page
|
||||
import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReady
|
||||
import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReadyByIndex
|
||||
import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass
|
||||
import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass
|
||||
import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass
|
||||
@@ -293,7 +292,7 @@ object MangaController {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, mangaId, chapterIndex ->
|
||||
ctx.future(future { getChapterDownloadReady(chapterIndex, mangaId) })
|
||||
ctx.future(future { getChapterDownloadReadyByIndex(chapterIndex, mangaId) })
|
||||
},
|
||||
withResults = {
|
||||
json<ChapterDataClass>(HttpCode.OK)
|
||||
|
||||
+44
-34
@@ -10,8 +10,10 @@ package suwayomi.tachidesk.manga.impl.chapter
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.batchInsert
|
||||
import org.jetbrains.exposed.sql.deleteWhere
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.jetbrains.exposed.sql.update
|
||||
@@ -27,15 +29,24 @@ import suwayomi.tachidesk.manga.model.table.PageTable
|
||||
import suwayomi.tachidesk.manga.model.table.toDataClass
|
||||
import java.io.File
|
||||
|
||||
suspend fun getChapterDownloadReady(chapterIndex: Int, mangaId: Int): ChapterDataClass {
|
||||
val chapter = ChapterForDownload(chapterIndex, mangaId)
|
||||
suspend fun getChapterDownloadReady(chapterId: Int? = null, chapterIndex: Int? = null, mangaId: Int? = null): ChapterDataClass {
|
||||
val chapter = ChapterForDownload(chapterId, chapterIndex, mangaId)
|
||||
|
||||
return chapter.asDownloadReady()
|
||||
}
|
||||
|
||||
suspend fun getChapterDownloadReadyById(chapterId: Int): ChapterDataClass {
|
||||
return getChapterDownloadReady(chapterId = chapterId)
|
||||
}
|
||||
|
||||
suspend fun getChapterDownloadReadyByIndex(chapterIndex: Int, mangaId: Int): ChapterDataClass {
|
||||
return getChapterDownloadReady(chapterIndex = chapterIndex, mangaId = mangaId)
|
||||
}
|
||||
|
||||
private class ChapterForDownload(
|
||||
private val chapterIndex: Int,
|
||||
private val mangaId: Int
|
||||
optChapterId: Int? = null,
|
||||
optChapterIndex: Int? = null,
|
||||
optMangaId: Int? = null
|
||||
) {
|
||||
suspend fun asDownloadReady(): ChapterDataClass {
|
||||
if (isNotCompletelyDownloaded()) {
|
||||
@@ -51,11 +62,27 @@ private class ChapterForDownload(
|
||||
|
||||
private fun asDataClass() = ChapterTable.toDataClass(chapterEntry)
|
||||
|
||||
var chapterEntry: ResultRow = freshChapterEntry()
|
||||
var chapterEntry: ResultRow
|
||||
val chapterId: Int
|
||||
val chapterIndex: Int
|
||||
val mangaId: Int
|
||||
|
||||
private fun freshChapterEntry() = transaction {
|
||||
init {
|
||||
chapterEntry = freshChapterEntry(optChapterId, optChapterIndex, optMangaId)
|
||||
chapterId = chapterEntry[ChapterTable.id].value
|
||||
chapterIndex = chapterEntry[ChapterTable.sourceOrder]
|
||||
mangaId = chapterEntry[ChapterTable.manga].value
|
||||
}
|
||||
|
||||
private fun freshChapterEntry(optChapterId: Int? = null, optChapterIndex: Int? = null, optMangaId: Int? = null) = transaction {
|
||||
ChapterTable.select {
|
||||
(ChapterTable.sourceOrder eq chapterIndex) and (ChapterTable.manga eq mangaId)
|
||||
if (optChapterId != null) {
|
||||
ChapterTable.id eq optChapterId
|
||||
} else if (optChapterIndex != null && optMangaId != null) {
|
||||
(ChapterTable.sourceOrder eq optChapterIndex) and (ChapterTable.manga eq optMangaId)
|
||||
} else {
|
||||
throw Exception("'optChapterId' or 'optChapterIndex' and 'optMangaId' have to be passed")
|
||||
}
|
||||
}.first()
|
||||
}
|
||||
|
||||
@@ -81,48 +108,31 @@ private class ChapterForDownload(
|
||||
}
|
||||
|
||||
private fun updateDatabasePages(pageList: List<Page>) {
|
||||
val chapterId = chapterEntry[ChapterTable.id].value
|
||||
|
||||
transaction {
|
||||
pageList.forEach { page ->
|
||||
val pageEntry = transaction {
|
||||
PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }
|
||||
.firstOrNull()
|
||||
}
|
||||
if (pageEntry == null) {
|
||||
PageTable.insert {
|
||||
it[index] = page.index
|
||||
it[url] = page.url
|
||||
it[imageUrl] = page.imageUrl
|
||||
it[chapter] = chapterId
|
||||
}
|
||||
} else {
|
||||
PageTable.update({ (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }) {
|
||||
it[url] = page.url
|
||||
it[imageUrl] = page.imageUrl
|
||||
}
|
||||
}
|
||||
PageTable.deleteWhere { PageTable.chapter eq chapterId }
|
||||
PageTable.batchInsert(pageList) { page ->
|
||||
this[PageTable.index] = page.index
|
||||
this[PageTable.url] = page.url
|
||||
this[PageTable.imageUrl] = page.imageUrl
|
||||
this[PageTable.chapter] = chapterId
|
||||
}
|
||||
}
|
||||
|
||||
updatePageCount(pageList, chapterId)
|
||||
|
||||
// chapter was updated
|
||||
chapterEntry = freshChapterEntry()
|
||||
chapterEntry = freshChapterEntry(chapterId, chapterIndex, mangaId)
|
||||
}
|
||||
|
||||
private fun updatePageCount(
|
||||
pageList: List<Page>,
|
||||
chapterId: Int
|
||||
) {
|
||||
val pageCount = pageList.count()
|
||||
|
||||
transaction {
|
||||
val lastPageRead = ChapterTable.select { ChapterTable.id eq chapterId }.firstOrNull()?.get(ChapterTable.lastPageRead) ?: 0
|
||||
|
||||
ChapterTable.update({ ChapterTable.id eq chapterId }) {
|
||||
val pageCount = pageList.size
|
||||
it[ChapterTable.pageCount] = pageCount
|
||||
it[ChapterTable.lastPageRead] = lastPageRead.coerceAtMost(pageCount - 1)
|
||||
it[ChapterTable.lastPageRead] = chapterEntry[ChapterTable.lastPageRead].coerceAtMost(pageCount - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.jetbrains.exposed.sql.update
|
||||
import suwayomi.tachidesk.manga.impl.ChapterDownloadHelper
|
||||
import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReady
|
||||
import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReadyByIndex
|
||||
import suwayomi.tachidesk.manga.impl.download.model.DownloadChapter
|
||||
import suwayomi.tachidesk.manga.impl.download.model.DownloadState.Downloading
|
||||
import suwayomi.tachidesk.manga.impl.download.model.DownloadState.Error
|
||||
@@ -98,7 +98,7 @@ class Downloader(
|
||||
download.state = Downloading
|
||||
step(download, true)
|
||||
|
||||
download.chapter = getChapterDownloadReady(download.chapterIndex, download.mangaId)
|
||||
download.chapter = getChapterDownloadReadyByIndex(download.chapterIndex, download.mangaId)
|
||||
step(download, false)
|
||||
|
||||
ChapterDownloadHelper.download(download.mangaId, download.chapter.id, download, scope, this::step)
|
||||
|
||||
Reference in New Issue
Block a user