add recentChapters endpoint
This commit is contained in:
@@ -69,6 +69,7 @@ dependencies {
|
||||
|
||||
// uncomment to test extensions directly
|
||||
// implementation(fileTree("lib/"))
|
||||
implementation(kotlin("script-runtime"))
|
||||
}
|
||||
|
||||
application {
|
||||
|
||||
@@ -19,6 +19,7 @@ import suwayomi.tachidesk.manga.controller.DownloadController
|
||||
import suwayomi.tachidesk.manga.controller.ExtensionController
|
||||
import suwayomi.tachidesk.manga.controller.MangaController
|
||||
import suwayomi.tachidesk.manga.controller.SourceController
|
||||
import suwayomi.tachidesk.manga.controller.UpdateController
|
||||
|
||||
object MangaAPI {
|
||||
fun defineEndpoints() {
|
||||
@@ -106,5 +107,9 @@ object MangaAPI {
|
||||
get("{mangaId}/chapter/{chapterIndex}", DownloadController::queueChapter)
|
||||
delete("{mangaId}/chapter/{chapterIndex}", DownloadController::unqueueChapter)
|
||||
}
|
||||
|
||||
path("update") {
|
||||
get("recentChapters", UpdateController::recentChapters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package suwayomi.tachidesk.manga.controller
|
||||
|
||||
import io.javalin.http.Context
|
||||
import suwayomi.tachidesk.manga.impl.Chapter
|
||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||
|
||||
/*
|
||||
* 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/. */
|
||||
|
||||
object UpdateController {
|
||||
/** get recently updated manga chapters */
|
||||
fun recentChapters(ctx: Context) {
|
||||
ctx.future(
|
||||
future {
|
||||
Chapter.getRecentChapters()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import suwayomi.tachidesk.manga.impl.util.getChapterDir
|
||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse
|
||||
import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass
|
||||
import suwayomi.tachidesk.manga.model.dataclass.MangaChapterDataClass
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
@@ -68,6 +69,7 @@ object Chapter {
|
||||
}
|
||||
|
||||
val chapterCount = chapterList.count()
|
||||
var now = Instant.now().epochSecond
|
||||
|
||||
transaction {
|
||||
chapterList.reversed().forEachIndexed { index, fetchedChapter ->
|
||||
@@ -81,6 +83,7 @@ object Chapter {
|
||||
it[scanlator] = fetchedChapter.scanlator
|
||||
|
||||
it[sourceOrder] = index + 1
|
||||
it[fetchedAt] = now++
|
||||
it[ChapterTable.manga] = mangaId
|
||||
}
|
||||
} else {
|
||||
@@ -137,6 +140,7 @@ object Chapter {
|
||||
dbChapter[ChapterTable.lastReadAt],
|
||||
|
||||
chapterCount - index,
|
||||
dbChapter[ChapterTable.fetchedAt],
|
||||
dbChapter[ChapterTable.isDownloaded],
|
||||
|
||||
dbChapter[ChapterTable.pageCount],
|
||||
@@ -220,6 +224,7 @@ object Chapter {
|
||||
chapterEntry[ChapterTable.lastReadAt],
|
||||
|
||||
chapterEntry[ChapterTable.sourceOrder],
|
||||
chapterEntry[ChapterTable.fetchedAt],
|
||||
chapterEntry[ChapterTable.isDownloaded],
|
||||
pageCount,
|
||||
chapterCount.toInt(),
|
||||
@@ -314,4 +319,21 @@ object Chapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getRecentChapters(): List<MangaChapterDataClass> {
|
||||
return transaction {
|
||||
val x = (ChapterTable innerJoin MangaTable)
|
||||
// .selectAll()
|
||||
.select { (MangaTable.inLibrary eq true) and (ChapterTable.fetchedAt greater MangaTable.inLibraryAt) }
|
||||
|
||||
println(x.count())
|
||||
|
||||
x.map {
|
||||
MangaChapterDataClass(
|
||||
MangaTable.toDataClass(it),
|
||||
ChapterTable.toDataClass(it)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import suwayomi.tachidesk.manga.impl.Manga.getManga
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import java.time.Instant
|
||||
|
||||
object Library {
|
||||
suspend fun addMangaToLibrary(mangaId: Int) {
|
||||
@@ -25,8 +26,9 @@ object Library {
|
||||
val defaultCategories = CategoryTable.select { CategoryTable.isDefault eq true }.toList()
|
||||
|
||||
MangaTable.update({ MangaTable.id eq manga.id }) {
|
||||
it[MangaTable.inLibrary] = true
|
||||
it[MangaTable.defaultCategory] = defaultCategories.isEmpty()
|
||||
it[inLibrary] = true
|
||||
it[inLibraryAt] = Instant.now().epochSecond
|
||||
it[defaultCategory] = defaultCategories.isEmpty()
|
||||
}
|
||||
|
||||
defaultCategories.forEach { category ->
|
||||
|
||||
@@ -61,6 +61,7 @@ object Manga {
|
||||
mangaEntry[MangaTable.genre].toGenreList(),
|
||||
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
|
||||
mangaEntry[MangaTable.inLibrary],
|
||||
mangaEntry[MangaTable.inLibraryAt],
|
||||
getSource(mangaEntry[MangaTable.sourceReference]),
|
||||
getMangaMetaMap(mangaId),
|
||||
mangaEntry[MangaTable.realUrl],
|
||||
@@ -121,6 +122,7 @@ object Manga {
|
||||
fetchedManga.genre.toGenreList(),
|
||||
MangaStatus.valueOf(fetchedManga.status).name,
|
||||
mangaEntry[MangaTable.inLibrary],
|
||||
mangaEntry[MangaTable.inLibraryAt],
|
||||
getSource(mangaEntry[MangaTable.sourceReference]),
|
||||
getMangaMetaMap(mangaId),
|
||||
mangaEntry[MangaTable.realUrl],
|
||||
|
||||
@@ -81,6 +81,7 @@ object MangaList {
|
||||
manga.genre.toGenreList(),
|
||||
MangaStatus.valueOf(manga.status).name,
|
||||
false, // It's a new manga entry
|
||||
0,
|
||||
meta = getMangaMetaMap(mangaId),
|
||||
realUrl = mangaEntry[MangaTable.realUrl],
|
||||
freshData = true
|
||||
@@ -103,6 +104,7 @@ object MangaList {
|
||||
mangaEntry[MangaTable.genre].toGenreList(),
|
||||
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
|
||||
mangaEntry[MangaTable.inLibrary],
|
||||
mangaEntry[MangaTable.inLibraryAt],
|
||||
meta = getMangaMetaMap(mangaId),
|
||||
realUrl = mangaEntry[MangaTable.realUrl],
|
||||
freshData = false
|
||||
|
||||
@@ -31,6 +31,9 @@ data class ChapterDataClass(
|
||||
/** this chapter's index, starts with 1 */
|
||||
val index: Int,
|
||||
|
||||
/** the date we fist saw this chapter*/
|
||||
val fetchedAt: Long,
|
||||
|
||||
/** is chapter downloaded */
|
||||
val downloaded: Boolean,
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package suwayomi.tachidesk.manga.model.dataclass
|
||||
|
||||
/*
|
||||
* 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/. */
|
||||
|
||||
data class MangaChapterDataClass(
|
||||
val manga: MangaDataClass,
|
||||
val chapter: ChapterDataClass,
|
||||
)
|
||||
@@ -26,6 +26,7 @@ data class MangaDataClass(
|
||||
val genre: List<String> = emptyList(),
|
||||
val status: String = MangaStatus.UNKNOWN.name,
|
||||
val inLibrary: Boolean = false,
|
||||
val inLibraryAt: Long = 0,
|
||||
val source: SourceDataClass? = null,
|
||||
|
||||
/** meta data for clients */
|
||||
|
||||
@@ -25,6 +25,7 @@ object ChapterTable : IntIdTable() {
|
||||
val isBookmarked = bool("bookmark").default(false)
|
||||
val lastPageRead = integer("last_page_read").default(0)
|
||||
val lastReadAt = long("last_read_at").default(0)
|
||||
val fetchedAt = long("fetched_at").default(0)
|
||||
|
||||
val sourceOrder = integer("source_order")
|
||||
|
||||
@@ -48,6 +49,7 @@ fun ChapterTable.toDataClass(chapterEntry: ResultRow) =
|
||||
chapterEntry[lastPageRead],
|
||||
chapterEntry[lastReadAt],
|
||||
chapterEntry[sourceOrder],
|
||||
chapterEntry[fetchedAt],
|
||||
chapterEntry[isDownloaded],
|
||||
chapterEntry[pageCount],
|
||||
transaction { ChapterTable.select { manga eq chapterEntry[manga].value }.count().toInt() },
|
||||
|
||||
@@ -31,6 +31,7 @@ object MangaTable : IntIdTable() {
|
||||
|
||||
val inLibrary = bool("in_library").default(false)
|
||||
val defaultCategory = bool("default_category").default(true)
|
||||
val inLibraryAt = long("in_library_at").default(0)
|
||||
|
||||
// the [source] field name is used by some ancestor of IntIdTable
|
||||
val sourceReference = long("source")
|
||||
@@ -56,6 +57,7 @@ fun MangaTable.toDataClass(mangaEntry: ResultRow) =
|
||||
mangaEntry[genre].toGenreList(),
|
||||
Companion.valueOf(mangaEntry[status]).name,
|
||||
mangaEntry[inLibrary],
|
||||
mangaEntry[inLibraryAt],
|
||||
meta = getMangaMetaMap(mangaEntry[id].value),
|
||||
realUrl = mangaEntry[realUrl],
|
||||
)
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package suwayomi.tachidesk.server.database.migration
|
||||
|
||||
/*
|
||||
* 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 de.neonew.exposed.migrations.helpers.AddColumnMigration
|
||||
|
||||
@Suppress("ClassName", "unused")
|
||||
class M0017_ChapterFetchedAt : AddColumnMigration(
|
||||
"Chapter",
|
||||
"fetched_at",
|
||||
"BIGINT",
|
||||
"0"
|
||||
)
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package suwayomi.tachidesk.server.database.migration
|
||||
|
||||
/*
|
||||
* 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 de.neonew.exposed.migrations.helpers.AddColumnMigration
|
||||
|
||||
@Suppress("ClassName", "unused")
|
||||
class M0018_MangaInLibraryAt : AddColumnMigration(
|
||||
"Manga",
|
||||
"in_library_at",
|
||||
"BIGINT",
|
||||
"0"
|
||||
)
|
||||
Reference in New Issue
Block a user