mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-02 10:24:35 -05:00
refactor getChapter (#268)
* refactor * better naming * fix copytight notice
This commit is contained in:
@@ -13,6 +13,7 @@ import suwayomi.tachidesk.manga.impl.Chapter
|
|||||||
import suwayomi.tachidesk.manga.impl.Library
|
import suwayomi.tachidesk.manga.impl.Library
|
||||||
import suwayomi.tachidesk.manga.impl.Manga
|
import suwayomi.tachidesk.manga.impl.Manga
|
||||||
import suwayomi.tachidesk.manga.impl.Page
|
import suwayomi.tachidesk.manga.impl.Page
|
||||||
|
import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReady
|
||||||
import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass
|
import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass
|
||||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||||
import suwayomi.tachidesk.server.util.handler
|
import suwayomi.tachidesk.server.util.handler
|
||||||
@@ -124,7 +125,7 @@ object MangaController {
|
|||||||
fun chapterRetrieve(ctx: Context) {
|
fun chapterRetrieve(ctx: Context) {
|
||||||
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
val chapterIndex = ctx.pathParam("chapterIndex").toInt()
|
||||||
val mangaId = ctx.pathParam("mangaId").toInt()
|
val mangaId = ctx.pathParam("mangaId").toInt()
|
||||||
ctx.future(future { Chapter.getChapter(chapterIndex, mangaId) })
|
ctx.future(future { getChapterDownloadReady(chapterIndex, mangaId) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/** used to modify a chapter's parameters */
|
/** used to modify a chapter's parameters */
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ package suwayomi.tachidesk.manga.impl
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.chapter.ChapterRecognition
|
import eu.kanade.tachiyomi.util.chapter.ChapterRecognition
|
||||||
@@ -20,11 +19,9 @@ import org.jetbrains.exposed.sql.select
|
|||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
import suwayomi.tachidesk.manga.impl.Manga.getManga
|
import suwayomi.tachidesk.manga.impl.Manga.getManga
|
||||||
import suwayomi.tachidesk.manga.impl.Page.getPageName
|
|
||||||
import suwayomi.tachidesk.manga.impl.util.getChapterDir
|
import suwayomi.tachidesk.manga.impl.util.getChapterDir
|
||||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse
|
|
||||||
import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass
|
import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass
|
||||||
import suwayomi.tachidesk.manga.model.dataclass.MangaChapterDataClass
|
import suwayomi.tachidesk.manga.model.dataclass.MangaChapterDataClass
|
||||||
import suwayomi.tachidesk.manga.model.dataclass.PaginatedList
|
import suwayomi.tachidesk.manga.model.dataclass.PaginatedList
|
||||||
@@ -154,102 +151,6 @@ object Chapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** used to display a chapter, get a chapter in order to show it's pages */
|
|
||||||
suspend fun getChapter(chapterIndex: Int, mangaId: Int): ChapterDataClass {
|
|
||||||
val chapterEntry = transaction {
|
|
||||||
ChapterTable.select {
|
|
||||||
(ChapterTable.sourceOrder eq chapterIndex) and (ChapterTable.manga eq mangaId)
|
|
||||||
}.first()
|
|
||||||
}
|
|
||||||
|
|
||||||
val isPartiallyDownloaded =
|
|
||||||
!(chapterEntry[ChapterTable.isDownloaded] && firstPageExists(mangaId, chapterEntry[ChapterTable.id].value))
|
|
||||||
|
|
||||||
return if (isPartiallyDownloaded) {
|
|
||||||
|
|
||||||
// chapter files may have been deleted
|
|
||||||
transaction {
|
|
||||||
ChapterTable.update({ (ChapterTable.sourceOrder eq chapterIndex) and (ChapterTable.manga eq mangaId) }) {
|
|
||||||
it[isDownloaded] = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
|
|
||||||
val source = getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
|
||||||
|
|
||||||
val pageList = source.fetchPageList(
|
|
||||||
SChapter.create().apply {
|
|
||||||
url = chapterEntry[ChapterTable.url]
|
|
||||||
name = chapterEntry[ChapterTable.name]
|
|
||||||
}
|
|
||||||
).awaitSingle()
|
|
||||||
|
|
||||||
val chapterId = chapterEntry[ChapterTable.id].value
|
|
||||||
val chapterCount = transaction { ChapterTable.select { ChapterTable.manga eq mangaId }.count() }
|
|
||||||
|
|
||||||
// update page list for this chapter
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val pageCount = pageList.count()
|
|
||||||
|
|
||||||
transaction {
|
|
||||||
ChapterTable.update({ (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder eq chapterIndex) }) {
|
|
||||||
it[ChapterTable.pageCount] = pageCount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ChapterDataClass(
|
|
||||||
chapterEntry[ChapterTable.url],
|
|
||||||
chapterEntry[ChapterTable.name],
|
|
||||||
chapterEntry[ChapterTable.date_upload],
|
|
||||||
chapterEntry[ChapterTable.chapter_number],
|
|
||||||
chapterEntry[ChapterTable.scanlator],
|
|
||||||
mangaId,
|
|
||||||
chapterEntry[ChapterTable.isRead],
|
|
||||||
chapterEntry[ChapterTable.isBookmarked],
|
|
||||||
chapterEntry[ChapterTable.lastPageRead],
|
|
||||||
chapterEntry[ChapterTable.lastReadAt],
|
|
||||||
|
|
||||||
chapterEntry[ChapterTable.sourceOrder],
|
|
||||||
chapterEntry[ChapterTable.fetchedAt],
|
|
||||||
chapterEntry[ChapterTable.isDownloaded],
|
|
||||||
pageCount,
|
|
||||||
chapterCount.toInt(),
|
|
||||||
getChapterMetaMap(chapterEntry[ChapterTable.id])
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
ChapterTable.toDataClass(chapterEntry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun firstPageExists(mangaId: Int, chapterId: Int): Boolean {
|
|
||||||
val chapterDir = getChapterDir(mangaId, chapterId)
|
|
||||||
|
|
||||||
return ImageResponse.findFileNameStartingWith(
|
|
||||||
chapterDir,
|
|
||||||
getPageName(1)
|
|
||||||
) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun modifyChapter(
|
fun modifyChapter(
|
||||||
mangaId: Int,
|
mangaId: Int,
|
||||||
chapterIndex: Int,
|
chapterIndex: Int,
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
package suwayomi.tachidesk.manga.impl.chapter
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
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.and
|
||||||
|
import org.jetbrains.exposed.sql.insert
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
import org.jetbrains.exposed.sql.update
|
||||||
|
import suwayomi.tachidesk.manga.impl.Page.getPageName
|
||||||
|
import suwayomi.tachidesk.manga.impl.util.getChapterDir
|
||||||
|
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||||
|
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||||
|
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse
|
||||||
|
import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass
|
||||||
|
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||||
|
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||||
|
import suwayomi.tachidesk.manga.model.table.PageTable
|
||||||
|
import suwayomi.tachidesk.manga.model.table.toDataClass
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun getChapterDownloadReady(chapterIndex: Int, mangaId: Int): ChapterDataClass {
|
||||||
|
val chapter = ChapterForDownload(chapterIndex, mangaId)
|
||||||
|
|
||||||
|
return chapter.asDownloadReady()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ChapterForDownload(
|
||||||
|
private val chapterIndex: Int,
|
||||||
|
private val mangaId: Int
|
||||||
|
) {
|
||||||
|
suspend fun asDownloadReady(): ChapterDataClass {
|
||||||
|
|
||||||
|
if (isNotCompletelyDownloaded()) {
|
||||||
|
markAsNotDownloaded()
|
||||||
|
|
||||||
|
val pageList = fetchPageList()
|
||||||
|
|
||||||
|
updateDatabasePages(pageList)
|
||||||
|
}
|
||||||
|
|
||||||
|
return asDataClass()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun asDataClass() = ChapterTable.toDataClass(chapterEntry)
|
||||||
|
|
||||||
|
var chapterEntry: ResultRow = freshChapterEntry()
|
||||||
|
|
||||||
|
private fun freshChapterEntry() = transaction {
|
||||||
|
ChapterTable.select {
|
||||||
|
(ChapterTable.sourceOrder eq chapterIndex) and (ChapterTable.manga eq mangaId)
|
||||||
|
}.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchPageList(): List<Page> {
|
||||||
|
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
|
||||||
|
val source = getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||||
|
|
||||||
|
return source.fetchPageList(
|
||||||
|
SChapter.create().apply {
|
||||||
|
url = chapterEntry[ChapterTable.url]
|
||||||
|
name = chapterEntry[ChapterTable.name]
|
||||||
|
}
|
||||||
|
).awaitSingle()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun markAsNotDownloaded() {
|
||||||
|
// chapter may be downloaded but if we are here, then images might be deleted and database data be false
|
||||||
|
transaction {
|
||||||
|
ChapterTable.update({ (ChapterTable.sourceOrder eq chapterIndex) and (ChapterTable.manga eq mangaId) }) {
|
||||||
|
it[isDownloaded] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateDatabasePages(pageList: List<Page>) {
|
||||||
|
val chapterId = chapterEntry[ChapterTable.id].value
|
||||||
|
val chapterIndex = chapterEntry[ChapterTable.sourceOrder]
|
||||||
|
val mangaId = chapterEntry[ChapterTable.manga].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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePageCount(pageList, mangaId, chapterIndex)
|
||||||
|
|
||||||
|
// chapter was updated
|
||||||
|
chapterEntry = freshChapterEntry()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePageCount(
|
||||||
|
pageList: List<Page>,
|
||||||
|
mangaId: Int,
|
||||||
|
chapterIndex: Int
|
||||||
|
) {
|
||||||
|
val pageCount = pageList.count()
|
||||||
|
|
||||||
|
transaction {
|
||||||
|
ChapterTable.update({ (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder eq chapterIndex) }) {
|
||||||
|
it[ChapterTable.pageCount] = pageCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isNotCompletelyDownloaded(): Boolean {
|
||||||
|
return !(chapterEntry[ChapterTable.isDownloaded] && firstPageExists())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun firstPageExists(): Boolean {
|
||||||
|
val chapterId = chapterEntry[ChapterTable.id].value
|
||||||
|
|
||||||
|
val chapterDir = getChapterDir(mangaId, chapterId)
|
||||||
|
|
||||||
|
println(chapterDir)
|
||||||
|
println(getPageName(0))
|
||||||
|
|
||||||
|
return ImageResponse.findFileNameStartingWith(
|
||||||
|
chapterDir,
|
||||||
|
getPageName(0)
|
||||||
|
) != null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,8 +12,8 @@ import mu.KotlinLogging
|
|||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
import suwayomi.tachidesk.manga.impl.Chapter.getChapter
|
|
||||||
import suwayomi.tachidesk.manga.impl.Page.getPageImage
|
import suwayomi.tachidesk.manga.impl.Page.getPageImage
|
||||||
|
import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReady
|
||||||
import suwayomi.tachidesk.manga.impl.download.model.DownloadChapter
|
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.Downloading
|
||||||
import suwayomi.tachidesk.manga.impl.download.model.DownloadState.Error
|
import suwayomi.tachidesk.manga.impl.download.model.DownloadState.Error
|
||||||
@@ -47,7 +47,7 @@ class Downloader(private val downloadQueue: CopyOnWriteArrayList<DownloadChapter
|
|||||||
download.state = Downloading
|
download.state = Downloading
|
||||||
step()
|
step()
|
||||||
|
|
||||||
download.chapter = runBlocking { getChapter(download.chapterIndex, download.mangaId) }
|
download.chapter = runBlocking { getChapterDownloadReady(download.chapterIndex, download.mangaId) }
|
||||||
step()
|
step()
|
||||||
|
|
||||||
val pageCount = download.chapter.pageCount
|
val pageCount = download.chapter.pageCount
|
||||||
|
|||||||
Reference in New Issue
Block a user