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