[skip ci] Formatting

This commit is contained in:
Syer10
2024-09-03 21:37:18 -04:00
parent e968a2195a
commit 6c1fbfa63b
220 changed files with 2493 additions and 2519 deletions

View File

@@ -20,8 +20,8 @@ data class AboutDataClass(
)
object About {
fun getAbout(): AboutDataClass {
return AboutDataClass(
fun getAbout(): AboutDataClass =
AboutDataClass(
BuildConfig.NAME,
BuildConfig.VERSION,
BuildConfig.REVISION,
@@ -30,5 +30,4 @@ object About {
BuildConfig.GITHUB,
BuildConfig.DISCORD,
)
}
}

View File

@@ -31,18 +31,26 @@ object AppUpdate {
suspend fun checkUpdate(): List<UpdateDataClass> {
val stableJson =
json.parseToJsonElement(
network.client.newCall(
GET(LATEST_STABLE_CHANNEL_URL),
).await().body.string(),
).jsonObject
json
.parseToJsonElement(
network.client
.newCall(
GET(LATEST_STABLE_CHANNEL_URL),
).await()
.body
.string(),
).jsonObject
val previewJson =
json.parseToJsonElement(
network.client.newCall(
GET(LATEST_PREVIEW_CHANNEL_URL),
).await().body.string(),
).jsonObject
json
.parseToJsonElement(
network.client
.newCall(
GET(LATEST_PREVIEW_CHANNEL_URL),
).await()
.body
.string(),
).jsonObject
return listOf(
UpdateDataClass(

View File

@@ -38,10 +38,10 @@ object GlobalMeta {
}
}
fun getMetaMap(): Map<String, String> {
return transaction {
GlobalMetaTable.selectAll()
fun getMetaMap(): Map<String, String> =
transaction {
GlobalMetaTable
.selectAll()
.associate { it[GlobalMetaTable.key] to it[GlobalMetaTable.value] }
}
}
}

View File

@@ -14,12 +14,14 @@ inline fun <T> asDataFetcherResult(block: () -> T): DataFetcherResult<T?> {
if (result.isFailure) {
logger.error(result.exceptionOrNull()) { "asDataFetcherResult: failed due to" }
return DataFetcherResult.newResult<T?>()
return DataFetcherResult
.newResult<T?>()
.error(result.exceptionOrNull()?.toGraphQLError())
.build()
}
return DataFetcherResult.newResult<T?>()
return DataFetcherResult
.newResult<T?>()
.data(result.getOrNull())
.build()
}

View File

@@ -10,21 +10,13 @@ class CustomCacheMap<K, V> : CacheMap<K, V> {
cache = HashMap()
}
override fun containsKey(key: K): Boolean {
return cache.containsKey(key)
}
override fun containsKey(key: K): Boolean = cache.containsKey(key)
override fun get(key: K): CompletableFuture<V> {
return cache[key]!!
}
override fun get(key: K): CompletableFuture<V> = cache[key]!!
fun getKeys(): Collection<K> {
return cache.keys.toSet()
}
fun getKeys(): Collection<K> = cache.keys.toSet()
override fun getAll(): Collection<CompletableFuture<V>> {
return cache.values
}
override fun getAll(): Collection<CompletableFuture<V>> = cache.values
override fun set(
key: K,

View File

@@ -30,7 +30,8 @@ class CategoryDataLoader : KotlinDataLoader<Int, CategoryType> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val categories =
CategoryTable.select { CategoryTable.id inList ids }
CategoryTable
.select { CategoryTable.id inList ids }
.map { CategoryType(it) }
.associateBy { it.id }
ids.map { categories[it] }
@@ -66,7 +67,8 @@ class CategoriesForMangaDataLoader : KotlinDataLoader<Int, CategoryNodeList> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val itemsByRef =
CategoryMangaTable.innerJoin(CategoryTable)
CategoryMangaTable
.innerJoin(CategoryTable)
.select { CategoryMangaTable.manga inList ids }
.map { Pair(it[CategoryMangaTable.manga].value, CategoryType(it)) }
.groupBy { it.first }

View File

@@ -32,7 +32,8 @@ class ChapterDataLoader : KotlinDataLoader<Int, ChapterType?> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val chapters =
ChapterTable.select { ChapterTable.id inList ids }
ChapterTable
.select { ChapterTable.id inList ids }
.map { ChapterType(it) }
.associateBy { it.id }
ids.map { chapters[it] }
@@ -50,7 +51,8 @@ class ChaptersForMangaDataLoader : KotlinDataLoader<Int, ChapterNodeList> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val chaptersByMangaId =
ChapterTable.select { ChapterTable.manga inList ids }
ChapterTable
.select { ChapterTable.manga inList ids }
.map { ChapterType(it) }
.groupBy { it.mangaId }
ids.map { (chaptersByMangaId[it] ?: emptyList()).toNodeList() }
@@ -128,7 +130,8 @@ class HasDuplicateChaptersForMangaDataLoader : KotlinDataLoader<Int, Boolean> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val duplicatedChapterCountByMangaId =
ChapterTable.slice(ChapterTable.manga, ChapterTable.chapter_number, ChapterTable.chapter_number.count())
ChapterTable
.slice(ChapterTable.manga, ChapterTable.chapter_number, ChapterTable.chapter_number.count())
.select { (ChapterTable.manga inList ids) and (ChapterTable.chapter_number greaterEq 0f) }
.groupBy(ChapterTable.manga, ChapterTable.chapter_number)
.having { ChapterTable.chapter_number.count() greater 1 }

View File

@@ -28,7 +28,8 @@ class ExtensionDataLoader : KotlinDataLoader<String, ExtensionType?> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val extensions =
ExtensionTable.select { ExtensionTable.pkgName inList ids }
ExtensionTable
.select { ExtensionTable.pkgName inList ids }
.map { ExtensionType(it) }
.associateBy { it.pkgName }
ids.map { extensions[it] }
@@ -46,7 +47,8 @@ class ExtensionForSourceDataLoader : KotlinDataLoader<Long, ExtensionType?> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val extensions =
ExtensionTable.innerJoin(SourceTable)
ExtensionTable
.innerJoin(SourceTable)
.select { SourceTable.id inList ids }
.toList()
.map { Triple(it[SourceTable.id].value, it[ExtensionTable.pkgName], it) }

View File

@@ -33,7 +33,8 @@ class MangaDataLoader : KotlinDataLoader<Int, MangaType?> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val manga =
MangaTable.select { MangaTable.id inList ids }
MangaTable
.select { MangaTable.id inList ids }
.map { MangaType(it) }
.associateBy { it.id }
ids.map { manga[it] }
@@ -63,7 +64,8 @@ class MangaForCategoryDataLoader : KotlinDataLoader<Int, MangaNodeList> {
} else {
emptyMap()
} +
CategoryMangaTable.innerJoin(MangaTable)
CategoryMangaTable
.innerJoin(MangaTable)
.select { CategoryMangaTable.category inList ids }
.map { Pair(it[CategoryMangaTable.category].value, MangaType(it)) }
.groupBy { it.first }
@@ -84,7 +86,8 @@ class MangaForSourceDataLoader : KotlinDataLoader<Long, MangaNodeList> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val mangaBySourceId =
MangaTable.select { MangaTable.sourceReference inList ids }
MangaTable
.select { MangaTable.sourceReference inList ids }
.map { MangaType(it) }
.groupBy { it.sourceId }
ids.map { (mangaBySourceId[it] ?: emptyList()).toNodeList() }
@@ -104,7 +107,8 @@ class MangaForIdsDataLoader : KotlinDataLoader<List<Int>, MangaNodeList> {
addLogger(Slf4jSqlDebugLogger)
val ids = mangaIds.flatten().distinct()
val manga =
MangaTable.select { MangaTable.id inList ids }
MangaTable
.select { MangaTable.id inList ids }
.map { MangaType(it) }
mangaIds.map { mangaIds ->
manga.filter { it.id in mangaIds }.toNodeList()

View File

@@ -28,7 +28,8 @@ class GlobalMetaDataLoader : KotlinDataLoader<String, GlobalMetaType?> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId =
GlobalMetaTable.select { GlobalMetaTable.key inList ids }
GlobalMetaTable
.select { GlobalMetaTable.key inList ids }
.map { GlobalMetaType(it) }
.associateBy { it.key }
ids.map { metasByRefId[it] }
@@ -46,7 +47,8 @@ class ChapterMetaDataLoader : KotlinDataLoader<Int, List<ChapterMetaType>> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId =
ChapterMetaTable.select { ChapterMetaTable.ref inList ids }
ChapterMetaTable
.select { ChapterMetaTable.ref inList ids }
.map { ChapterMetaType(it) }
.groupBy { it.chapterId }
ids.map { metasByRefId[it].orEmpty() }
@@ -64,7 +66,8 @@ class MangaMetaDataLoader : KotlinDataLoader<Int, List<MangaMetaType>> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId =
MangaMetaTable.select { MangaMetaTable.ref inList ids }
MangaMetaTable
.select { MangaMetaTable.ref inList ids }
.map { MangaMetaType(it) }
.groupBy { it.mangaId }
ids.map { metasByRefId[it].orEmpty() }
@@ -82,7 +85,8 @@ class CategoryMetaDataLoader : KotlinDataLoader<Int, List<CategoryMetaType>> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId =
CategoryMetaTable.select { CategoryMetaTable.ref inList ids }
CategoryMetaTable
.select { CategoryMetaTable.ref inList ids }
.map { CategoryMetaType(it) }
.groupBy { it.categoryId }
ids.map { metasByRefId[it].orEmpty() }
@@ -100,7 +104,8 @@ class SourceMetaDataLoader : KotlinDataLoader<Long, List<SourceMetaType>> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val metasByRefId =
SourceMetaTable.select { SourceMetaTable.ref inList ids }
SourceMetaTable
.select { SourceMetaTable.ref inList ids }
.map { SourceMetaType(it) }
.groupBy { it.sourceId }
ids.map { metasByRefId[it].orEmpty() }

View File

@@ -30,7 +30,8 @@ class SourceDataLoader : KotlinDataLoader<Long, SourceType?> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val source =
SourceTable.select { SourceTable.id inList ids }
SourceTable
.select { SourceTable.id inList ids }
.mapNotNull { SourceType(it) }
.associateBy { it.id }
ids.map { source[it] }
@@ -49,7 +50,8 @@ class SourcesForExtensionDataLoader : KotlinDataLoader<String, SourceNodeList> {
addLogger(Slf4jSqlDebugLogger)
val sourcesByExtensionPkg =
SourceTable.innerJoin(ExtensionTable)
SourceTable
.innerJoin(ExtensionTable)
.select { ExtensionTable.pkgName inList ids }
.map { Pair(it[ExtensionTable.pkgName], SourceType(it)) }
.groupBy { it.first }

View File

@@ -89,7 +89,8 @@ class TrackRecordsForMangaIdDataLoader : KotlinDataLoader<Int, TrackRecordNodeLi
transaction {
addLogger(Slf4jSqlDebugLogger)
val trackRecordsByMangaId =
TrackRecordTable.select { TrackRecordTable.mangaId inList ids }
TrackRecordTable
.select { TrackRecordTable.mangaId inList ids }
.map { TrackRecordType(it) }
.groupBy { it.mangaId }
ids.map { (trackRecordsByMangaId[it] ?: emptyList()).toNodeList() }
@@ -107,7 +108,8 @@ class DisplayScoreForTrackRecordDataLoader : KotlinDataLoader<Int, String> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val trackRecords =
TrackRecordTable.select { TrackRecordTable.id inList ids }
TrackRecordTable
.select { TrackRecordTable.id inList ids }
.toList()
.map { it.toTrack() }
.associateBy { it.id!! }
@@ -128,7 +130,8 @@ class TrackRecordsForTrackerIdDataLoader : KotlinDataLoader<Int, TrackRecordNode
transaction {
addLogger(Slf4jSqlDebugLogger)
val trackRecordsBySyncId =
TrackRecordTable.select { TrackRecordTable.trackerId inList ids }
TrackRecordTable
.select { TrackRecordTable.trackerId inList ids }
.map { TrackRecordType(it) }
.groupBy { it.mangaId }
ids.map { (trackRecordsBySyncId[it] ?: emptyList()).toNodeList() }
@@ -146,7 +149,8 @@ class TrackRecordDataLoader : KotlinDataLoader<Int, TrackRecordType> {
transaction {
addLogger(Slf4jSqlDebugLogger)
val trackRecordsId =
TrackRecordTable.select { TrackRecordTable.id inList ids }
TrackRecordTable
.select { TrackRecordTable.id inList ids }
.map { TrackRecordType(it) }
.associateBy { it.id }
ids.map { trackRecordsId[it] }

View File

@@ -38,15 +38,14 @@ class CategoryMutation {
val meta: CategoryMetaType,
)
fun setCategoryMeta(input: SetCategoryMetaInput): DataFetcherResult<SetCategoryMetaPayload?> {
return asDataFetcherResult {
fun setCategoryMeta(input: SetCategoryMetaInput): DataFetcherResult<SetCategoryMetaPayload?> =
asDataFetcherResult {
val (clientMutationId, meta) = input
Category.modifyMeta(meta.categoryId, meta.key, meta.value)
SetCategoryMetaPayload(clientMutationId, meta)
}
}
data class DeleteCategoryMetaInput(
val clientMutationId: String? = null,
@@ -60,14 +59,15 @@ class CategoryMutation {
val category: CategoryType,
)
fun deleteCategoryMeta(input: DeleteCategoryMetaInput): DataFetcherResult<DeleteCategoryMetaPayload?> {
return asDataFetcherResult {
fun deleteCategoryMeta(input: DeleteCategoryMetaInput): DataFetcherResult<DeleteCategoryMetaPayload?> =
asDataFetcherResult {
val (clientMutationId, categoryId, key) = input
val (meta, category) =
transaction {
val meta =
CategoryMetaTable.select { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) }
CategoryMetaTable
.select { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) }
.firstOrNull()
CategoryMetaTable.deleteWhere { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) }
@@ -86,7 +86,6 @@ class CategoryMutation {
DeleteCategoryMetaPayload(clientMutationId, meta, category)
}
}
data class UpdateCategoryPatch(
val name: String? = null,
@@ -153,8 +152,8 @@ class CategoryMutation {
}
}
fun updateCategory(input: UpdateCategoryInput): DataFetcherResult<UpdateCategoryPayload?> {
return asDataFetcherResult {
fun updateCategory(input: UpdateCategoryInput): DataFetcherResult<UpdateCategoryPayload?> =
asDataFetcherResult {
val (clientMutationId, id, patch) = input
updateCategories(listOf(id), patch)
@@ -169,10 +168,9 @@ class CategoryMutation {
category = category,
)
}
}
fun updateCategories(input: UpdateCategoriesInput): DataFetcherResult<UpdateCategoriesPayload?> {
return asDataFetcherResult {
fun updateCategories(input: UpdateCategoriesInput): DataFetcherResult<UpdateCategoriesPayload?> =
asDataFetcherResult {
val (clientMutationId, ids, patch) = input
updateCategories(ids, patch)
@@ -187,7 +185,6 @@ class CategoryMutation {
categories = categories,
)
}
}
data class UpdateCategoryOrderPayload(
val clientMutationId: String?,
@@ -200,8 +197,8 @@ class CategoryMutation {
val position: Int,
)
fun updateCategoryOrder(input: UpdateCategoryOrderInput): DataFetcherResult<UpdateCategoryOrderPayload?> {
return asDataFetcherResult {
fun updateCategoryOrder(input: UpdateCategoryOrderInput): DataFetcherResult<UpdateCategoryOrderPayload?> =
asDataFetcherResult {
val (clientMutationId, categoryId, position) = input
require(position > 0) {
"'order' must not be <= 0"
@@ -242,7 +239,6 @@ class CategoryMutation {
categories = categories,
)
}
}
data class CreateCategoryInput(
val clientMutationId: String? = null,
@@ -258,8 +254,8 @@ class CategoryMutation {
val category: CategoryType,
)
fun createCategory(input: CreateCategoryInput): DataFetcherResult<CreateCategoryPayload?> {
return asDataFetcherResult {
fun createCategory(input: CreateCategoryInput): DataFetcherResult<CreateCategoryPayload?> =
asDataFetcherResult {
val (clientMutationId, name, order, default, includeInUpdate, includeInDownload) = input
transaction {
require(CategoryTable.select { CategoryTable.name eq input.name }.isEmpty()) {
@@ -305,7 +301,6 @@ class CategoryMutation {
CreateCategoryPayload(clientMutationId, category)
}
}
data class DeleteCategoryInput(
val clientMutationId: String? = null,
@@ -332,12 +327,14 @@ class CategoryMutation {
val (category, mangas) =
transaction {
val category =
CategoryTable.select { CategoryTable.id eq categoryId }
CategoryTable
.select { CategoryTable.id eq categoryId }
.firstOrNull()
val mangas =
transaction {
MangaTable.innerJoin(CategoryMangaTable)
MangaTable
.innerJoin(CategoryMangaTable)
.select { CategoryMangaTable.category eq categoryId }
.map { MangaType(it) }
}
@@ -403,9 +400,10 @@ class CategoryMutation {
ids.filter { it != DEFAULT_CATEGORY_ID }.forEach { mangaId ->
patch.addToCategories.forEach { categoryId ->
val existingMapping =
CategoryMangaTable.select {
(CategoryMangaTable.manga eq mangaId) and (CategoryMangaTable.category eq categoryId)
}.isNotEmpty()
CategoryMangaTable
.select {
(CategoryMangaTable.manga eq mangaId) and (CategoryMangaTable.category eq categoryId)
}.isNotEmpty()
if (!existingMapping) {
add(mangaId to categoryId)
@@ -422,8 +420,8 @@ class CategoryMutation {
}
}
fun updateMangaCategories(input: UpdateMangaCategoriesInput): DataFetcherResult<UpdateMangaCategoriesPayload?> {
return asDataFetcherResult {
fun updateMangaCategories(input: UpdateMangaCategoriesInput): DataFetcherResult<UpdateMangaCategoriesPayload?> =
asDataFetcherResult {
val (clientMutationId, id, patch) = input
updateMangas(listOf(id), patch)
@@ -438,10 +436,9 @@ class CategoryMutation {
manga = manga,
)
}
}
fun updateMangasCategories(input: UpdateMangasCategoriesInput): DataFetcherResult<UpdateMangasCategoriesPayload?> {
return asDataFetcherResult {
fun updateMangasCategories(input: UpdateMangasCategoriesInput): DataFetcherResult<UpdateMangasCategoriesPayload?> =
asDataFetcherResult {
val (clientMutationId, ids, patch) = input
updateMangas(ids, patch)
@@ -456,5 +453,4 @@ class CategoryMutation {
mangas = mangas,
)
}
}
}

View File

@@ -95,8 +95,8 @@ class ChapterMutation {
}
}
fun updateChapter(input: UpdateChapterInput): DataFetcherResult<UpdateChapterPayload?> {
return asDataFetcherResult {
fun updateChapter(input: UpdateChapterInput): DataFetcherResult<UpdateChapterPayload?> =
asDataFetcherResult {
val (clientMutationId, id, patch) = input
updateChapters(listOf(id), patch)
@@ -111,10 +111,9 @@ class ChapterMutation {
chapter = chapter,
)
}
}
fun updateChapters(input: UpdateChaptersInput): DataFetcherResult<UpdateChaptersPayload?> {
return asDataFetcherResult {
fun updateChapters(input: UpdateChaptersInput): DataFetcherResult<UpdateChaptersPayload?> =
asDataFetcherResult {
val (clientMutationId, ids, patch) = input
updateChapters(ids, patch)
@@ -129,7 +128,6 @@ class ChapterMutation {
chapters = chapters,
)
}
}
data class FetchChaptersInput(
val clientMutationId: String? = null,
@@ -150,7 +148,8 @@ class ChapterMutation {
val chapters =
transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }
ChapterTable
.select { ChapterTable.manga eq mangaId }
.orderBy(ChapterTable.sourceOrder)
.map { ChapterType(it) }
}
@@ -173,15 +172,14 @@ class ChapterMutation {
val meta: ChapterMetaType,
)
fun setChapterMeta(input: SetChapterMetaInput): DataFetcherResult<SetChapterMetaPayload?> {
return asDataFetcherResult {
fun setChapterMeta(input: SetChapterMetaInput): DataFetcherResult<SetChapterMetaPayload?> =
asDataFetcherResult {
val (clientMutationId, meta) = input
Chapter.modifyChapterMeta(meta.chapterId, meta.key, meta.value)
SetChapterMetaPayload(clientMutationId, meta)
}
}
data class DeleteChapterMetaInput(
val clientMutationId: String? = null,
@@ -195,14 +193,15 @@ class ChapterMutation {
val chapter: ChapterType,
)
fun deleteChapterMeta(input: DeleteChapterMetaInput): DataFetcherResult<DeleteChapterMetaPayload?> {
return asDataFetcherResult {
fun deleteChapterMeta(input: DeleteChapterMetaInput): DataFetcherResult<DeleteChapterMetaPayload?> =
asDataFetcherResult {
val (clientMutationId, chapterId, key) = input
val (meta, chapter) =
transaction {
val meta =
ChapterMetaTable.select { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
ChapterMetaTable
.select { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
.firstOrNull()
ChapterMetaTable.deleteWhere { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
@@ -221,7 +220,6 @@ class ChapterMutation {
DeleteChapterMetaPayload(clientMutationId, meta, chapter)
}
}
data class FetchChapterPagesInput(
val clientMutationId: String? = null,

View File

@@ -37,7 +37,8 @@ class DownloadMutation {
clientMutationId = clientMutationId,
chapters =
transaction {
ChapterTable.select { ChapterTable.id inList chapters }
ChapterTable
.select { ChapterTable.id inList chapters }
.map { ChapterType(it) }
},
)
@@ -195,8 +196,8 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun startDownloader(input: StartDownloaderInput): CompletableFuture<DataFetcherResult<StartDownloaderPayload?>> {
return future {
fun startDownloader(input: StartDownloaderInput): CompletableFuture<DataFetcherResult<StartDownloaderPayload?>> =
future {
asDataFetcherResult {
DownloadManager.start()
@@ -211,7 +212,6 @@ class DownloadMutation {
)
}
}
}
data class StopDownloaderInput(
val clientMutationId: String? = null,
@@ -222,8 +222,8 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun stopDownloader(input: StopDownloaderInput): CompletableFuture<DataFetcherResult<StopDownloaderPayload?>> {
return future {
fun stopDownloader(input: StopDownloaderInput): CompletableFuture<DataFetcherResult<StopDownloaderPayload?>> =
future {
asDataFetcherResult {
DownloadManager.stop()
@@ -238,7 +238,6 @@ class DownloadMutation {
)
}
}
}
data class ClearDownloaderInput(
val clientMutationId: String? = null,
@@ -249,8 +248,8 @@ class DownloadMutation {
val downloadStatus: DownloadStatus,
)
fun clearDownloader(input: ClearDownloaderInput): CompletableFuture<DataFetcherResult<ClearDownloaderPayload?>> {
return future {
fun clearDownloader(input: ClearDownloaderInput): CompletableFuture<DataFetcherResult<ClearDownloaderPayload?>> =
future {
asDataFetcherResult {
DownloadManager.clear()
@@ -265,7 +264,6 @@ class DownloadMutation {
)
}
}
}
data class ReorderChapterDownloadInput(
val clientMutationId: String? = null,

View File

@@ -48,7 +48,8 @@ class ExtensionMutation {
) {
val extensions =
transaction {
ExtensionTable.select { ExtensionTable.pkgName inList ids }
ExtensionTable
.select { ExtensionTable.pkgName inList ids }
.map { ExtensionType(it) }
}
@@ -80,7 +81,9 @@ class ExtensionMutation {
val extension =
transaction {
ExtensionTable.select { ExtensionTable.pkgName eq id }.firstOrNull()
ExtensionTable
.select { ExtensionTable.pkgName eq id }
.firstOrNull()
?.let { ExtensionType(it) }
}
@@ -101,7 +104,8 @@ class ExtensionMutation {
val extensions =
transaction {
ExtensionTable.select { ExtensionTable.pkgName inList ids }
ExtensionTable
.select { ExtensionTable.pkgName inList ids }
.map { ExtensionType(it) }
}
@@ -131,7 +135,8 @@ class ExtensionMutation {
val extensions =
transaction {
ExtensionTable.select { ExtensionTable.name neq LocalSource.EXTENSION_NAME }
ExtensionTable
.select { ExtensionTable.name neq LocalSource.EXTENSION_NAME }
.map { ExtensionType(it) }
}

View File

@@ -59,8 +59,8 @@ class InfoMutation {
}
}
fun resetWebUIUpdateStatus(): CompletableFuture<DataFetcherResult<WebUIUpdateStatus?>> {
return future {
fun resetWebUIUpdateStatus(): CompletableFuture<DataFetcherResult<WebUIUpdateStatus?>> =
future {
asDataFetcherResult {
withTimeout(30.seconds) {
val isUpdateFinished = WebInterfaceManager.status.value.state != DOWNLOADING
@@ -74,5 +74,4 @@ class InfoMutation {
}
}
}
}
}

View File

@@ -76,7 +76,8 @@ class MangaMutation {
// try to initialize uninitialized in library manga to ensure that the expected data is available (chapter list, metadata, ...)
val mangas =
transaction {
MangaTable.select { (MangaTable.id inList ids) and (MangaTable.initialized eq false) }
MangaTable
.select { (MangaTable.id inList ids) and (MangaTable.initialized eq false) }
.map { MangaTable.toDataClass(it) }
}
@@ -198,7 +199,8 @@ class MangaMutation {
val (meta, manga) =
transaction {
val meta =
MangaMetaTable.select { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) }
MangaMetaTable
.select { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) }
.firstOrNull()
MangaMetaTable.deleteWhere { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) }

View File

@@ -48,7 +48,8 @@ class MetaMutation {
val meta =
transaction {
val meta =
GlobalMetaTable.select { GlobalMetaTable.key eq key }
GlobalMetaTable
.select { GlobalMetaTable.key eq key }
.firstOrNull()
GlobalMetaTable.deleteWhere { GlobalMetaTable.key eq key }

View File

@@ -138,7 +138,9 @@ class SettingsMutation {
return SetSettingsPayload(clientMutationId, SettingsType())
}
data class ResetSettingsInput(val clientMutationId: String? = null)
data class ResetSettingsInput(
val clientMutationId: String? = null,
)
data class ResetSettingsPayload(
val clientMutationId: String?,

View File

@@ -68,14 +68,17 @@ class SourceMutation {
val (meta, source) =
transaction {
val meta =
SourceMetaTable.select { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) }
SourceMetaTable
.select { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) }
.firstOrNull()
SourceMetaTable.deleteWhere { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) }
val source =
transaction {
SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()
SourceTable
.select { SourceTable.id eq sourceId }
.firstOrNull()
?.let { SourceType(it) }
}
@@ -139,7 +142,8 @@ class SourceMutation {
val mangas =
transaction {
MangaTable.select { MangaTable.id inList mangaIds }
MangaTable
.select { MangaTable.id inList mangaIds }
.map { MangaType(it) }
}.sortedBy {
mangaIds.indexOf(it.id)

View File

@@ -126,9 +126,10 @@ class TrackMutation {
)
val trackRecord =
transaction {
TrackRecordTable.select {
TrackRecordTable.mangaId eq mangaId and (TrackRecordTable.trackerId eq trackerId)
}.first()
TrackRecordTable
.select {
TrackRecordTable.mangaId eq mangaId and (TrackRecordTable.trackerId eq trackerId)
}.first()
}
BindTrackPayload(
clientMutationId,
@@ -154,9 +155,10 @@ class TrackMutation {
Track.refresh(recordId)
val trackRecord =
transaction {
TrackRecordTable.select {
TrackRecordTable.id eq recordId
}.first()
TrackRecordTable
.select {
TrackRecordTable.id eq recordId
}.first()
}
FetchTrackPayload(
clientMutationId,
@@ -184,9 +186,10 @@ class TrackMutation {
Track.unbind(recordId, deleteRemoteTrack)
val trackRecord =
transaction {
TrackRecordTable.select {
TrackRecordTable.id eq recordId
}.firstOrNull()
TrackRecordTable
.select {
TrackRecordTable.id eq recordId
}.firstOrNull()
}
UnbindTrackPayload(
clientMutationId,
@@ -213,7 +216,8 @@ class TrackMutation {
Track.trackChapter(mangaId)
val trackRecords =
transaction {
TrackRecordTable.select { TrackRecordTable.mangaId eq mangaId }
TrackRecordTable
.select { TrackRecordTable.mangaId eq mangaId }
.toList()
}
TrackProgressPayload(
@@ -241,8 +245,8 @@ class TrackMutation {
val trackRecord: TrackRecordType?,
)
fun updateTrack(input: UpdateTrackInput): CompletableFuture<UpdateTrackPayload> {
return future {
fun updateTrack(input: UpdateTrackInput): CompletableFuture<UpdateTrackPayload> =
future {
Track.update(
Track.UpdateInput(
input.recordId,
@@ -257,14 +261,14 @@ class TrackMutation {
val trackRecord =
transaction {
TrackRecordTable.select {
TrackRecordTable.id eq input.recordId
}.firstOrNull()
TrackRecordTable
.select {
TrackRecordTable.id eq input.recordId
}.firstOrNull()
}
UpdateTrackPayload(
input.clientMutationId,
trackRecord?.let { TrackRecordType(it) },
)
}
}
}

View File

@@ -33,7 +33,5 @@ class BackupQuery {
)
}
fun restoreStatus(id: String): BackupRestoreStatus? {
return ProtoBackupImport.getRestoreState(id)?.toStatus()
}
fun restoreStatus(id: String): BackupRestoreStatus? = ProtoBackupImport.getRestoreState(id)?.toStatus()
}

View File

@@ -45,31 +45,29 @@ class CategoryQuery {
fun category(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<CategoryType> {
return dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
}
): CompletableFuture<CategoryType> = dataFetchingEnvironment.getValueFromDataLoader("CategoryDataLoader", id)
enum class CategoryOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<CategoryType> {
enum class CategoryOrderBy(
override val column: Column<out Comparable<*>>,
) : OrderBy<CategoryType> {
ID(CategoryTable.id),
NAME(CategoryTable.name),
ORDER(CategoryTable.order),
;
override fun greater(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun greater(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> CategoryTable.id greater cursor.value.toInt()
NAME -> greaterNotUnique(CategoryTable.name, CategoryTable.id, cursor, String::toString)
ORDER -> greaterNotUnique(CategoryTable.order, CategoryTable.id, cursor, String::toInt)
}
}
override fun less(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun less(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> CategoryTable.id less cursor.value.toInt()
NAME -> lessNotUnique(CategoryTable.name, CategoryTable.id, cursor, String::toString)
ORDER -> lessNotUnique(CategoryTable.order, CategoryTable.id, cursor, String::toInt)
}
}
override fun asCursor(type: CategoryType): Cursor {
val value =
@@ -113,14 +111,13 @@ class CategoryQuery {
override val or: List<CategoryFilter>? = null,
override val not: CategoryFilter? = null,
) : Filter<CategoryFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
override fun getOpList(): List<Op<Boolean>> =
listOfNotNull(
andFilterWithCompareEntity(CategoryTable.id, id),
andFilterWithCompare(CategoryTable.order, order),
andFilterWithCompareString(CategoryTable.name, name),
andFilterWithCompare(CategoryTable.isDefault, default),
)
}
}
fun categories(

View File

@@ -54,11 +54,11 @@ class ChapterQuery {
fun chapter(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<ChapterType> {
return dataFetchingEnvironment.getValueFromDataLoader("ChapterDataLoader", id)
}
): CompletableFuture<ChapterType> = dataFetchingEnvironment.getValueFromDataLoader("ChapterDataLoader", id)
enum class ChapterOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<ChapterType> {
enum class ChapterOrderBy(
override val column: Column<out Comparable<*>>,
) : OrderBy<ChapterType> {
ID(ChapterTable.id),
SOURCE_ORDER(ChapterTable.sourceOrder),
NAME(ChapterTable.name),
@@ -68,8 +68,8 @@ class ChapterQuery {
FETCHED_AT(ChapterTable.fetchedAt),
;
override fun greater(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun greater(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> ChapterTable.id greater cursor.value.toInt()
SOURCE_ORDER -> greaterNotUnique(ChapterTable.sourceOrder, ChapterTable.id, cursor, String::toInt)
NAME -> greaterNotUnique(ChapterTable.name, ChapterTable.id, cursor, String::toString)
@@ -78,10 +78,9 @@ class ChapterQuery {
LAST_READ_AT -> greaterNotUnique(ChapterTable.lastReadAt, ChapterTable.id, cursor, String::toLong)
FETCHED_AT -> greaterNotUnique(ChapterTable.fetchedAt, ChapterTable.id, cursor, String::toLong)
}
}
override fun less(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun less(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> ChapterTable.id less cursor.value.toInt()
SOURCE_ORDER -> lessNotUnique(ChapterTable.sourceOrder, ChapterTable.id, cursor, String::toInt)
NAME -> lessNotUnique(ChapterTable.name, ChapterTable.id, cursor, String::toString)
@@ -90,7 +89,6 @@ class ChapterQuery {
LAST_READ_AT -> lessNotUnique(ChapterTable.lastReadAt, ChapterTable.id, cursor, String::toLong)
FETCHED_AT -> lessNotUnique(ChapterTable.fetchedAt, ChapterTable.id, cursor, String::toLong)
}
}
override fun asCursor(type: ChapterType): Cursor {
val value =
@@ -175,8 +173,8 @@ class ChapterQuery {
override val or: List<ChapterFilter>? = null,
override val not: ChapterFilter? = null,
) : Filter<ChapterFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
override fun getOpList(): List<Op<Boolean>> =
listOfNotNull(
andFilterWithCompareEntity(ChapterTable.id, id),
andFilterWithCompareString(ChapterTable.url, url),
andFilterWithCompareString(ChapterTable.name, name),
@@ -194,7 +192,6 @@ class ChapterQuery {
andFilterWithCompare(ChapterTable.isDownloaded, isDownloaded),
andFilterWithCompare(ChapterTable.pageCount, pageCount),
)
}
fun getLibraryOp() = andFilterWithCompare(MangaTable.inLibrary, inLibrary)
}

View File

@@ -7,9 +7,8 @@ import suwayomi.tachidesk.server.JavalinSetup.future
import java.util.concurrent.CompletableFuture
class DownloadQuery {
fun downloadStatus(): CompletableFuture<DownloadStatus> {
return future {
fun downloadStatus(): CompletableFuture<DownloadStatus> =
future {
DownloadStatus(DownloadManager.status.first())
}
}
}

View File

@@ -46,31 +46,29 @@ class ExtensionQuery {
fun extension(
dataFetchingEnvironment: DataFetchingEnvironment,
pkgName: String,
): CompletableFuture<ExtensionType> {
return dataFetchingEnvironment.getValueFromDataLoader("ExtensionDataLoader", pkgName)
}
): CompletableFuture<ExtensionType> = dataFetchingEnvironment.getValueFromDataLoader("ExtensionDataLoader", pkgName)
enum class ExtensionOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<ExtensionType> {
enum class ExtensionOrderBy(
override val column: Column<out Comparable<*>>,
) : OrderBy<ExtensionType> {
PKG_NAME(ExtensionTable.pkgName),
NAME(ExtensionTable.name),
APK_NAME(ExtensionTable.apkName),
;
override fun greater(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun greater(cursor: Cursor): Op<Boolean> =
when (this) {
PKG_NAME -> ExtensionTable.pkgName greater cursor.value
NAME -> greaterNotUnique(ExtensionTable.name, ExtensionTable.pkgName, cursor, String::toString)
APK_NAME -> greaterNotUnique(ExtensionTable.apkName, ExtensionTable.pkgName, cursor, String::toString)
}
}
override fun less(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun less(cursor: Cursor): Op<Boolean> =
when (this) {
PKG_NAME -> ExtensionTable.pkgName less cursor.value
NAME -> lessNotUnique(ExtensionTable.name, ExtensionTable.pkgName, cursor, String::toString)
APK_NAME -> lessNotUnique(ExtensionTable.apkName, ExtensionTable.pkgName, cursor, String::toString)
}
}
override fun asCursor(type: ExtensionType): Cursor {
val value =
@@ -137,8 +135,8 @@ class ExtensionQuery {
override val or: List<ExtensionFilter>? = null,
override val not: ExtensionFilter? = null,
) : Filter<ExtensionFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
override fun getOpList(): List<Op<Boolean>> =
listOfNotNull(
andFilterWithCompareString(ExtensionTable.repo, repo),
andFilterWithCompareString(ExtensionTable.apkName, apkName),
andFilterWithCompareString(ExtensionTable.iconUrl, iconUrl),
@@ -152,7 +150,6 @@ class ExtensionQuery {
andFilterWithCompare(ExtensionTable.hasUpdate, hasUpdate),
andFilterWithCompare(ExtensionTable.isObsolete, isObsolete),
)
}
}
fun extensions(

View File

@@ -22,8 +22,8 @@ class InfoQuery {
val discord: String,
)
fun aboutServer(): AboutServerPayload {
return AboutServerPayload(
fun aboutServer(): AboutServerPayload =
AboutServerPayload(
BuildConfig.NAME,
BuildConfig.VERSION,
BuildConfig.REVISION,
@@ -32,7 +32,6 @@ class InfoQuery {
BuildConfig.GITHUB,
BuildConfig.DISCORD,
)
}
data class CheckForServerUpdatesPayload(
/** [channel] mirrors [suwayomi.tachidesk.server.BuildConfig.BUILD_TYPE] */
@@ -41,8 +40,8 @@ class InfoQuery {
val url: String,
)
fun checkForServerUpdates(): CompletableFuture<List<CheckForServerUpdatesPayload>> {
return future {
fun checkForServerUpdates(): CompletableFuture<List<CheckForServerUpdatesPayload>> =
future {
AppUpdate.checkUpdate().map {
CheckForServerUpdatesPayload(
channel = it.channel,
@@ -51,16 +50,14 @@ class InfoQuery {
)
}
}
}
fun aboutWebUI(): CompletableFuture<AboutWebUI> {
return future {
fun aboutWebUI(): CompletableFuture<AboutWebUI> =
future {
WebInterfaceManager.getAboutInfo()
}
}
fun checkForWebUIUpdate(): CompletableFuture<WebUIUpdateCheck> {
return future {
fun checkForWebUIUpdate(): CompletableFuture<WebUIUpdateCheck> =
future {
val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable(WebUIFlavor.current, raiseError = true)
WebUIUpdateCheck(
channel = serverConfig.webUIChannel.value,
@@ -68,9 +65,6 @@ class InfoQuery {
updateAvailable,
)
}
}
fun getWebUIUpdateStatus(): WebUIUpdateStatus {
return WebInterfaceManager.status.value
}
fun getWebUIUpdateStatus(): WebUIUpdateStatus = WebInterfaceManager.status.value
}

View File

@@ -50,34 +50,32 @@ class MangaQuery {
fun manga(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<MangaType> {
return dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
}
): CompletableFuture<MangaType> = dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
enum class MangaOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<MangaType> {
enum class MangaOrderBy(
override val column: Column<out Comparable<*>>,
) : OrderBy<MangaType> {
ID(MangaTable.id),
TITLE(MangaTable.title),
IN_LIBRARY_AT(MangaTable.inLibraryAt),
LAST_FETCHED_AT(MangaTable.lastFetchedAt),
;
override fun greater(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun greater(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> MangaTable.id greater cursor.value.toInt()
TITLE -> greaterNotUnique(MangaTable.title, MangaTable.id, cursor, String::toString)
IN_LIBRARY_AT -> greaterNotUnique(MangaTable.inLibraryAt, MangaTable.id, cursor, String::toLong)
LAST_FETCHED_AT -> greaterNotUnique(MangaTable.lastFetchedAt, MangaTable.id, cursor, String::toLong)
}
}
override fun less(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun less(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> MangaTable.id less cursor.value.toInt()
TITLE -> lessNotUnique(MangaTable.title, MangaTable.id, cursor, String::toString)
IN_LIBRARY_AT -> lessNotUnique(MangaTable.inLibraryAt, MangaTable.id, cursor, String::toLong)
LAST_FETCHED_AT -> lessNotUnique(MangaTable.lastFetchedAt, MangaTable.id, cursor, String::toLong)
}
}
override fun asCursor(type: MangaType): Cursor {
val value =
@@ -197,8 +195,8 @@ class MangaQuery {
override val or: List<MangaFilter>? = null,
override val not: MangaFilter? = null,
) : Filter<MangaFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
override fun getOpList(): List<Op<Boolean>> =
listOfNotNull(
andFilterWithCompareEntity(MangaTable.id, id),
andFilterWithCompare(MangaTable.sourceReference, sourceId),
andFilterWithCompareString(MangaTable.url, url),
@@ -217,7 +215,6 @@ class MangaQuery {
andFilterWithCompare(MangaTable.chaptersLastFetchedAt, chaptersLastFetchedAt),
andFilterWithCompareEntity(CategoryMangaTable.category, categoryId),
)
}
}
fun mangas(
@@ -243,11 +240,13 @@ class MangaQuery {
val queryResults =
transaction {
val res =
MangaTable.leftJoin(CategoryMangaTable).slice(
distinctOn(MangaTable.id),
*(MangaTable.columns).toTypedArray(),
*(CategoryMangaTable.columns).toTypedArray(),
).selectAll()
MangaTable
.leftJoin(CategoryMangaTable)
.slice(
distinctOn(MangaTable.id),
*(MangaTable.columns).toTypedArray(),
*(CategoryMangaTable.columns).toTypedArray(),
).selectAll()
res.applyOps(condition, filter)

View File

@@ -41,28 +41,26 @@ class MetaQuery {
fun meta(
dataFetchingEnvironment: DataFetchingEnvironment,
key: String,
): CompletableFuture<GlobalMetaType> {
return dataFetchingEnvironment.getValueFromDataLoader("GlobalMetaDataLoader", key)
}
): CompletableFuture<GlobalMetaType> = dataFetchingEnvironment.getValueFromDataLoader("GlobalMetaDataLoader", key)
enum class MetaOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<GlobalMetaType> {
enum class MetaOrderBy(
override val column: Column<out Comparable<*>>,
) : OrderBy<GlobalMetaType> {
KEY(GlobalMetaTable.key),
VALUE(GlobalMetaTable.value),
;
override fun greater(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun greater(cursor: Cursor): Op<Boolean> =
when (this) {
KEY -> GlobalMetaTable.key greater cursor.value
VALUE -> greaterNotUnique(GlobalMetaTable.value, GlobalMetaTable.key, cursor, String::toString)
}
}
override fun less(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun less(cursor: Cursor): Op<Boolean> =
when (this) {
KEY -> GlobalMetaTable.key less cursor.value
VALUE -> lessNotUnique(GlobalMetaTable.value, GlobalMetaTable.key, cursor, String::toString)
}
}
override fun asCursor(type: GlobalMetaType): Cursor {
val value =
@@ -99,12 +97,11 @@ class MetaQuery {
override val or: List<MetaFilter>? = null,
override val not: MetaFilter? = null,
) : Filter<MetaFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
override fun getOpList(): List<Op<Boolean>> =
listOfNotNull(
andFilterWithCompareString(GlobalMetaTable.key, key),
andFilterWithCompareString(GlobalMetaTable.value, value),
)
}
}
fun metas(

View File

@@ -3,7 +3,5 @@ package suwayomi.tachidesk.graphql.queries
import suwayomi.tachidesk.graphql.types.SettingsType
class SettingsQuery {
fun settings(): SettingsType {
return SettingsType()
}
fun settings(): SettingsType = SettingsType()
}

View File

@@ -45,31 +45,29 @@ class SourceQuery {
fun source(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Long,
): CompletableFuture<SourceType> {
return dataFetchingEnvironment.getValueFromDataLoader("SourceDataLoader", id)
}
): CompletableFuture<SourceType> = dataFetchingEnvironment.getValueFromDataLoader("SourceDataLoader", id)
enum class SourceOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<SourceType> {
enum class SourceOrderBy(
override val column: Column<out Comparable<*>>,
) : OrderBy<SourceType> {
ID(SourceTable.id),
NAME(SourceTable.name),
LANG(SourceTable.lang),
;
override fun greater(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun greater(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> SourceTable.id greater cursor.value.toLong()
NAME -> greaterNotUnique(SourceTable.name, SourceTable.id, cursor, String::toString)
LANG -> greaterNotUnique(SourceTable.lang, SourceTable.id, cursor, String::toString)
}
}
override fun less(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun less(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> SourceTable.id less cursor.value.toLong()
NAME -> lessNotUnique(SourceTable.name, SourceTable.id, cursor, String::toString)
LANG -> lessNotUnique(SourceTable.lang, SourceTable.id, cursor, String::toString)
}
}
override fun asCursor(type: SourceType): Cursor {
val value =
@@ -113,14 +111,13 @@ class SourceQuery {
override val or: List<SourceFilter>? = null,
override val not: SourceFilter? = null,
) : Filter<SourceFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
override fun getOpList(): List<Op<Boolean>> =
listOfNotNull(
andFilterWithCompareEntity(SourceTable.id, id),
andFilterWithCompareString(SourceTable.name, name),
andFilterWithCompareString(SourceTable.lang, lang),
andFilterWithCompare(SourceTable.isNsfw, isNsfw),
)
}
}
fun sources(

View File

@@ -46,9 +46,7 @@ class TrackQuery {
fun tracker(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<TrackerType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", id)
}
): CompletableFuture<TrackerType> = dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", id)
enum class TrackerOrderBy {
ID,
@@ -59,8 +57,8 @@ class TrackQuery {
fun greater(
tracker: TrackerType,
cursor: Cursor,
): Boolean {
return when (this) {
): Boolean =
when (this) {
ID -> tracker.id > cursor.value.toInt()
NAME -> tracker.name > cursor.value
IS_LOGGED_IN -> {
@@ -68,13 +66,12 @@ class TrackQuery {
!value || tracker.isLoggedIn
}
}
}
fun less(
tracker: TrackerType,
cursor: Cursor,
): Boolean {
return when (this) {
): Boolean =
when (this) {
ID -> tracker.id < cursor.value.toInt()
NAME -> tracker.name < cursor.value
IS_LOGGED_IN -> {
@@ -82,7 +79,6 @@ class TrackQuery {
value || !tracker.isLoggedIn
}
}
}
fun asCursor(type: TrackerType): Cursor {
val value =
@@ -244,11 +240,12 @@ class TrackQuery {
fun trackRecord(
dataFetchingEnvironment: DataFetchingEnvironment,
id: Int,
): CompletableFuture<TrackRecordType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordType>("TrackRecordDataLoader", id)
}
): CompletableFuture<TrackRecordType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordType>("TrackRecordDataLoader", id)
enum class TrackRecordOrderBy(override val column: Column<out Comparable<*>>) : OrderBy<TrackRecordType> {
enum class TrackRecordOrderBy(
override val column: Column<out Comparable<*>>,
) : OrderBy<TrackRecordType> {
ID(TrackRecordTable.id),
MANGA_ID(TrackRecordTable.mangaId),
TRACKER_ID(TrackRecordTable.trackerId),
@@ -261,8 +258,8 @@ class TrackQuery {
FINISH_DATE(TrackRecordTable.finishDate),
;
override fun greater(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun greater(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> TrackRecordTable.id greater cursor.value.toInt()
MANGA_ID -> greaterNotUnique(TrackRecordTable.mangaId, TrackRecordTable.id, cursor)
TRACKER_ID -> greaterNotUnique(TrackRecordTable.trackerId, TrackRecordTable.id, cursor, String::toInt)
@@ -274,10 +271,9 @@ class TrackQuery {
START_DATE -> greaterNotUnique(TrackRecordTable.startDate, TrackRecordTable.id, cursor, String::toLong)
FINISH_DATE -> greaterNotUnique(TrackRecordTable.finishDate, TrackRecordTable.id, cursor, String::toLong)
}
}
override fun less(cursor: Cursor): Op<Boolean> {
return when (this) {
override fun less(cursor: Cursor): Op<Boolean> =
when (this) {
ID -> TrackRecordTable.id less cursor.value.toInt()
MANGA_ID -> lessNotUnique(TrackRecordTable.mangaId, TrackRecordTable.id, cursor)
TRACKER_ID -> lessNotUnique(TrackRecordTable.trackerId, TrackRecordTable.id, cursor, String::toInt)
@@ -289,7 +285,6 @@ class TrackQuery {
START_DATE -> lessNotUnique(TrackRecordTable.startDate, TrackRecordTable.id, cursor, String::toLong)
FINISH_DATE -> lessNotUnique(TrackRecordTable.finishDate, TrackRecordTable.id, cursor, String::toLong)
}
}
override fun asCursor(type: TrackRecordType): Cursor {
val value =
@@ -367,8 +362,8 @@ class TrackQuery {
override val or: List<TrackRecordFilter>? = null,
override val not: TrackRecordFilter? = null,
) : Filter<TrackRecordFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
override fun getOpList(): List<Op<Boolean>> =
listOfNotNull(
andFilterWithCompareEntity(TrackRecordTable.id, id),
andFilterWithCompareEntity(TrackRecordTable.mangaId, mangaId),
andFilterWithCompare(TrackRecordTable.trackerId, trackerId),
@@ -383,7 +378,6 @@ class TrackQuery {
andFilterWithCompare(TrackRecordTable.startDate, startDate),
andFilterWithCompare(TrackRecordTable.finishDate, finishDate),
)
}
}
fun trackRecords(
@@ -484,10 +478,12 @@ class TrackQuery {
val query: String,
)
data class SearchTrackerPayload(val trackSearches: List<TrackSearchType>)
data class SearchTrackerPayload(
val trackSearches: List<TrackSearchType>,
)
fun searchTracker(input: SearchTrackerInput): CompletableFuture<SearchTrackerPayload> {
return future {
fun searchTracker(input: SearchTrackerInput): CompletableFuture<SearchTrackerPayload> =
future {
val tracker =
requireNotNull(TrackerManager.getTracker(input.trackerId)) {
"Tracker not found"
@@ -501,5 +497,4 @@ class TrackQuery {
},
)
}
}
}

View File

@@ -12,13 +12,11 @@ import java.util.concurrent.CompletableFuture
class UpdateQuery {
private val updater by DI.global.instance<IUpdater>()
fun updateStatus(): CompletableFuture<UpdateStatus> {
return future { UpdateStatus(updater.status.first()) }
}
fun updateStatus(): CompletableFuture<UpdateStatus> = future { UpdateStatus(updater.status.first()) }
data class LastUpdateTimestampPayload(val timestamp: Long)
data class LastUpdateTimestampPayload(
val timestamp: Long,
)
fun lastUpdateTimestamp(): LastUpdateTimestampPayload {
return LastUpdateTimestampPayload(updater.getLastUpdateTimestamp())
}
fun lastUpdateTimestamp(): LastUpdateTimestampPayload = LastUpdateTimestampPayload(updater.getLastUpdateTimestamp())
}

View File

@@ -17,11 +17,16 @@ import org.jetbrains.exposed.sql.or
import org.jetbrains.exposed.sql.stringParam
import org.jetbrains.exposed.sql.upperCase
class ILikeEscapeOp(expr1: Expression<*>, expr2: Expression<*>, like: Boolean, val escapeChar: Char?) : ComparisonOp(
expr1,
expr2,
if (like) "ILIKE" else "NOT ILIKE",
) {
class ILikeEscapeOp(
expr1: Expression<*>,
expr2: Expression<*>,
like: Boolean,
val escapeChar: Char?,
) : ComparisonOp(
expr1,
expr2,
if (like) "ILIKE" else "NOT ILIKE",
) {
override fun toQueryBuilder(queryBuilder: QueryBuilder) {
super.toQueryBuilder(queryBuilder)
if (escapeChar != null) {
@@ -67,11 +72,15 @@ class ILikeEscapeOp(expr1: Expression<*>, expr2: Expression<*>, like: Boolean, v
}
}
class DistinctFromOp(expr1: Expression<*>, expr2: Expression<*>, not: Boolean) : ComparisonOp(
expr1,
expr2,
if (not) "IS NOT DISTINCT FROM" else "IS DISTINCT FROM",
) {
class DistinctFromOp(
expr1: Expression<*>,
expr2: Expression<*>,
not: Boolean,
) : ComparisonOp(
expr1,
expr2,
if (not) "IS NOT DISTINCT FROM" else "IS DISTINCT FROM",
) {
companion object {
fun <T> distinctFrom(
expression: ExpressionWithColumnType<T>,
@@ -472,7 +481,9 @@ fun <T : String, S : T?> andFilterWithCompareString(
return opAnd.op
}
class OpAnd(var op: Op<Boolean>? = null) {
class OpAnd(
var op: Op<Boolean>? = null,
) {
fun <T> andWhere(
value: T?,
andPart: SqlExpressionBuilder.(T & Any) -> Op<Boolean>,

View File

@@ -38,26 +38,29 @@ class JavalinGraphQLRequestParser : GraphQLRequestParser<Context> {
GraphQLServerRequest::class.java,
)
val map =
context.formParam("map")?.let {
context.jsonMapper().fromJsonString(
it,
Map::class.java as Class<Map<String, List<String>>>,
)
}.orEmpty()
context
.formParam("map")
?.let {
context.jsonMapper().fromJsonString(
it,
Map::class.java as Class<Map<String, List<String>>>,
)
}.orEmpty()
val mapItems =
map.flatMap { (key, variables) ->
val file = context.uploadedFile(key)
variables.map { fullVariable ->
val variable = fullVariable.removePrefix("variables.").substringBefore('.')
val listIndex = fullVariable.substringAfterLast('.').toIntOrNull()
MapItem(
variable,
listIndex,
file,
)
}
}.groupBy { it.variable }
map
.flatMap { (key, variables) ->
val file = context.uploadedFile(key)
variables.map { fullVariable ->
val variable = fullVariable.removePrefix("variables.").substringBefore('.')
val listIndex = fullVariable.substringAfterLast('.').toIntOrNull()
MapItem(
variable,
listIndex,
file,
)
}
}.groupBy { it.variable }
when (request) {
is GraphQLRequest -> {
@@ -91,8 +94,8 @@ class JavalinGraphQLRequestParser : GraphQLRequestParser<Context> {
* Example map "{ "0": ["variables.file"] }"
* TODO nested objects
*/
private fun Map<String, Any?>.modifyFiles(map: Map<String, List<MapItem>>): Map<String, Any?> {
return mapValues { (name, value) ->
private fun Map<String, Any?>.modifyFiles(map: Map<String, List<MapItem>>): Map<String, Any?> =
mapValues { (name, value) ->
if (map.containsKey(name)) {
val items = map[name].orEmpty()
if (items.size > 1) {
@@ -110,5 +113,4 @@ class JavalinGraphQLRequestParser : GraphQLRequestParser<Context> {
value
}
}
}
}

View File

@@ -46,8 +46,8 @@ import suwayomi.tachidesk.graphql.dataLoaders.UnreadChapterCountForMangaDataLoad
class TachideskDataLoaderRegistryFactory {
companion object {
fun create(): KotlinDataLoaderRegistryFactory {
return KotlinDataLoaderRegistryFactory(
fun create(): KotlinDataLoaderRegistryFactory =
KotlinDataLoaderRegistryFactory(
MangaDataLoader(),
ChapterDataLoader(),
ChaptersForMangaDataLoader(),
@@ -84,6 +84,5 @@ class TachideskDataLoaderRegistryFactory {
TrackRecordsForTrackerIdDataLoader(),
TrackRecordDataLoader(),
)
}
}
}

View File

@@ -34,7 +34,8 @@ class TachideskGraphQLServer(
@OptIn(DelicateCoroutinesApi::class)
fun handleSubscriptionMessage(context: WsMessageContext) {
subscriptionProtocolHandler.handleMessage(context)
subscriptionProtocolHandler
.handleMessage(context)
.map { objectMapper.writeValueAsString(it) }
.map { context.send(it) }
.launchIn(GlobalScope)
@@ -46,7 +47,8 @@ class TachideskGraphQLServer(
companion object {
private fun getGraphQLObject(): GraphQL =
GraphQL.newGraphQL(schema)
GraphQL
.newGraphQL(schema)
.subscriptionExecutionStrategy(FlowSubscriptionExecutionStrategy())
.mutationExecutionStrategy(AsyncExecutionStrategy())
.build()

View File

@@ -43,7 +43,5 @@ object TemporaryFileStorage {
}
}
fun retrieveFile(name: String): Path {
return folder.resolve(name)
}
fun retrieveFile(name: String): Path = folder.resolve(name)
}

View File

@@ -12,18 +12,21 @@ import graphql.schema.CoercingSerializeException
import graphql.schema.GraphQLScalarType
import java.util.Locale
data class Cursor(val value: String)
data class Cursor(
val value: String,
)
val GraphQLCursor: GraphQLScalarType =
GraphQLScalarType.newScalar()
GraphQLScalarType
.newScalar()
.name(
"Cursor",
).description("A location in a connection that can be used for resuming pagination.").coercing(GraphqlCursorCoercing()).build()
).description("A location in a connection that can be used for resuming pagination.")
.coercing(GraphqlCursorCoercing())
.build()
private class GraphqlCursorCoercing : Coercing<Cursor, String> {
private fun toStringImpl(input: Any): String? {
return (input as? Cursor)?.value
}
private fun toStringImpl(input: Any): String? = (input as? Cursor)?.value
private fun parseValueImpl(
input: Any,
@@ -58,54 +61,44 @@ private class GraphqlCursorCoercing : Coercing<Cursor, String> {
return Cursor(input.value)
}
private fun valueToLiteralImpl(input: Any): StringValue {
return StringValue.newStringValue(input.toString()).build()
}
private fun valueToLiteralImpl(input: Any): StringValue = StringValue.newStringValue(input.toString()).build()
@Deprecated("")
override fun serialize(dataFetcherResult: Any): String {
return toStringImpl(dataFetcherResult) ?: throw CoercingSerializeException(
override fun serialize(dataFetcherResult: Any): String =
toStringImpl(dataFetcherResult) ?: throw CoercingSerializeException(
CoercingUtil.i18nMsg(
Locale.getDefault(),
"String.unexpectedRawValueType",
CoercingUtil.typeName(dataFetcherResult),
),
)
}
@Throws(CoercingSerializeException::class)
override fun serialize(
dataFetcherResult: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): String {
return toStringImpl(dataFetcherResult) ?: throw CoercingSerializeException(
): String =
toStringImpl(dataFetcherResult) ?: throw CoercingSerializeException(
CoercingUtil.i18nMsg(
locale,
"String.unexpectedRawValueType",
CoercingUtil.typeName(dataFetcherResult),
),
)
}
@Deprecated("")
override fun parseValue(input: Any): Cursor {
return parseValueImpl(input, Locale.getDefault())
}
override fun parseValue(input: Any): Cursor = parseValueImpl(input, Locale.getDefault())
@Throws(CoercingParseValueException::class)
override fun parseValue(
input: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): Cursor {
return parseValueImpl(input, locale)
}
): Cursor = parseValueImpl(input, locale)
@Deprecated("")
override fun parseLiteral(input: Any): Cursor {
return parseLiteralImpl(input, Locale.getDefault())
}
override fun parseLiteral(input: Any): Cursor = parseLiteralImpl(input, Locale.getDefault())
@Throws(CoercingParseLiteralException::class)
override fun parseLiteral(
@@ -113,20 +106,14 @@ private class GraphqlCursorCoercing : Coercing<Cursor, String> {
variables: CoercedVariables,
graphQLContext: GraphQLContext,
locale: Locale,
): Cursor {
return parseLiteralImpl(input, locale)
}
): Cursor = parseLiteralImpl(input, locale)
@Deprecated("")
override fun valueToLiteral(input: Any): Value<*> {
return valueToLiteralImpl(input)
}
override fun valueToLiteral(input: Any): Value<*> = valueToLiteralImpl(input)
override fun valueToLiteral(
input: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): Value<*> {
return valueToLiteralImpl(input)
}
): Value<*> = valueToLiteralImpl(input)
}

View File

@@ -13,13 +13,15 @@ import graphql.schema.GraphQLScalarType
import java.util.Locale
val GraphQLLongAsString: GraphQLScalarType =
GraphQLScalarType.newScalar()
.name("LongString").description("A 64-bit signed integer as a String").coercing(GraphqlLongAsStringCoercing()).build()
GraphQLScalarType
.newScalar()
.name("LongString")
.description("A 64-bit signed integer as a String")
.coercing(GraphqlLongAsStringCoercing())
.build()
private class GraphqlLongAsStringCoercing : Coercing<Long, String> {
private fun toStringImpl(input: Any): String {
return input.toString()
}
private fun toStringImpl(input: Any): String = input.toString()
private fun parseValueImpl(
input: Any,
@@ -54,42 +56,30 @@ private class GraphqlLongAsStringCoercing : Coercing<Long, String> {
return input.value.toLong()
}
private fun valueToLiteralImpl(input: Any): StringValue {
return StringValue.newStringValue(input.toString()).build()
}
private fun valueToLiteralImpl(input: Any): StringValue = StringValue.newStringValue(input.toString()).build()
@Deprecated("")
override fun serialize(dataFetcherResult: Any): String {
return toStringImpl(dataFetcherResult)
}
override fun serialize(dataFetcherResult: Any): String = toStringImpl(dataFetcherResult)
@Throws(CoercingSerializeException::class)
override fun serialize(
dataFetcherResult: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): String {
return toStringImpl(dataFetcherResult)
}
): String = toStringImpl(dataFetcherResult)
@Deprecated("")
override fun parseValue(input: Any): Long {
return parseValueImpl(input, Locale.getDefault())
}
override fun parseValue(input: Any): Long = parseValueImpl(input, Locale.getDefault())
@Throws(CoercingParseValueException::class)
override fun parseValue(
input: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): Long {
return parseValueImpl(input, locale)
}
): Long = parseValueImpl(input, locale)
@Deprecated("")
override fun parseLiteral(input: Any): Long {
return parseLiteralImpl(input, Locale.getDefault())
}
override fun parseLiteral(input: Any): Long = parseLiteralImpl(input, Locale.getDefault())
@Throws(CoercingParseLiteralException::class)
override fun parseLiteral(
@@ -97,20 +87,14 @@ private class GraphqlLongAsStringCoercing : Coercing<Long, String> {
variables: CoercedVariables,
graphQLContext: GraphQLContext,
locale: Locale,
): Long {
return parseLiteralImpl(input, locale)
}
): Long = parseLiteralImpl(input, locale)
@Deprecated("")
override fun valueToLiteral(input: Any): Value<*> {
return valueToLiteralImpl(input)
}
override fun valueToLiteral(input: Any): Value<*> = valueToLiteralImpl(input)
override fun valueToLiteral(
input: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): Value<*> {
return valueToLiteralImpl(input)
}
): Value<*> = valueToLiteralImpl(input)
}

View File

@@ -27,8 +27,8 @@ interface Order<By : OrderBy<*>> {
val byType: SortOrder?
}
fun SortOrder?.maybeSwap(value: Any?): SortOrder {
return if (value != null) {
fun SortOrder?.maybeSwap(value: Any?): SortOrder =
if (value != null) {
when (this) {
SortOrder.ASC -> SortOrder.DESC
SortOrder.DESC -> SortOrder.ASC
@@ -41,7 +41,6 @@ fun SortOrder?.maybeSwap(value: Any?): SortOrder {
} else {
this ?: SortOrder.ASC
}
}
fun <T> Query.applyBeforeAfter(
before: Cursor?,
@@ -72,9 +71,7 @@ fun <T : Comparable<T>> greaterNotUnique(
idColumn: Column<EntityID<Int>>,
cursor: Cursor,
toValue: (String) -> T,
): Op<Boolean> {
return greaterNotUniqueImpl(column, idColumn, cursor, String::toInt, toValue)
}
): Op<Boolean> = greaterNotUniqueImpl(column, idColumn, cursor, String::toInt, toValue)
@JvmName("greaterNotUniqueLongKey")
fun <T : Comparable<T>> greaterNotUnique(
@@ -82,18 +79,14 @@ fun <T : Comparable<T>> greaterNotUnique(
idColumn: Column<EntityID<Long>>,
cursor: Cursor,
toValue: (String) -> T,
): Op<Boolean> {
return greaterNotUniqueImpl(column, idColumn, cursor, String::toLong, toValue)
}
): Op<Boolean> = greaterNotUniqueImpl(column, idColumn, cursor, String::toLong, toValue)
@JvmName("greaterNotUniqueIntKeyIntValue")
fun greaterNotUnique(
column: Column<EntityID<Int>>,
idColumn: Column<EntityID<Int>>,
cursor: Cursor,
): Op<Boolean> {
return greaterNotUniqueImpl(column, idColumn, cursor, String::toInt, String::toInt)
}
): Op<Boolean> = greaterNotUniqueImpl(column, idColumn, cursor, String::toInt, String::toInt)
private fun <K : Comparable<K>, V : Comparable<V>> greaterNotUniqueImpl(
column: Column<V>,
@@ -138,9 +131,7 @@ fun <T : Comparable<T>> lessNotUnique(
idColumn: Column<EntityID<Int>>,
cursor: Cursor,
toValue: (String) -> T,
): Op<Boolean> {
return lessNotUniqueImpl(column, idColumn, cursor, String::toInt, toValue)
}
): Op<Boolean> = lessNotUniqueImpl(column, idColumn, cursor, String::toInt, toValue)
@JvmName("lessNotUniqueLongKey")
fun <T : Comparable<T>> lessNotUnique(
@@ -148,18 +139,14 @@ fun <T : Comparable<T>> lessNotUnique(
idColumn: Column<EntityID<Long>>,
cursor: Cursor,
toValue: (String) -> T,
): Op<Boolean> {
return lessNotUniqueImpl(column, idColumn, cursor, String::toLong, toValue)
}
): Op<Boolean> = lessNotUniqueImpl(column, idColumn, cursor, String::toLong, toValue)
@JvmName("lessNotUniqueIntKeyIntValue")
fun lessNotUnique(
column: Column<EntityID<Int>>,
idColumn: Column<EntityID<Int>>,
cursor: Cursor,
): Op<Boolean> {
return lessNotUniqueImpl(column, idColumn, cursor, String::toInt, String::toInt)
}
): Op<Boolean> = lessNotUniqueImpl(column, idColumn, cursor, String::toInt, String::toInt)
private fun <K : Comparable<K>, V : Comparable<V>> lessNotUniqueImpl(
column: Column<V>,

View File

@@ -2,4 +2,9 @@ package suwayomi.tachidesk.graphql.server.primitives
import org.jetbrains.exposed.sql.ResultRow
data class QueryResults<T>(val total: Long, val firstKey: T, val lastKey: T, val results: List<ResultRow>)
data class QueryResults<T>(
val total: Long,
val firstKey: T,
val lastKey: T,
val results: List<ResultRow>,
)

View File

@@ -10,7 +10,8 @@ import io.javalin.http.UploadedFile
import java.util.Locale
val GraphQLUpload =
GraphQLScalarType.newScalar()
GraphQLScalarType
.newScalar()
.name("Upload")
.description("A file part in a multipart request")
.coercing(GraphqlUploadCoercing())
@@ -34,35 +35,25 @@ private class GraphqlUploadCoercing : Coercing<UploadedFile, Void?> {
}
@Deprecated("")
override fun serialize(dataFetcherResult: Any): Void? {
throw CoercingSerializeException("Upload is an input-only type")
}
override fun serialize(dataFetcherResult: Any): Void? = throw CoercingSerializeException("Upload is an input-only type")
@Throws(CoercingSerializeException::class)
override fun serialize(
dataFetcherResult: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): Void? {
throw CoercingSerializeException("Upload is an input-only type")
}
): Void? = throw CoercingSerializeException("Upload is an input-only type")
@Deprecated("")
override fun parseValue(input: Any): UploadedFile {
return parseValueImpl(input, Locale.getDefault())
}
override fun parseValue(input: Any): UploadedFile = parseValueImpl(input, Locale.getDefault())
@Throws(CoercingParseValueException::class)
override fun parseValue(
input: Any,
graphQLContext: GraphQLContext,
locale: Locale,
): UploadedFile {
return parseValueImpl(input, locale)
}
): UploadedFile = parseValueImpl(input, locale)
@Deprecated("")
override fun parseLiteral(input: Any): UploadedFile {
return parseValueImpl(input, Locale.getDefault())
}
override fun parseLiteral(input: Any): UploadedFile = parseValueImpl(input, Locale.getDefault())
}

View File

@@ -99,14 +99,13 @@ class ApolloSubscriptionProtocolHandler(
onDisconnect(context)
}
private fun convertToMessageOrNull(payload: String): SubscriptionOperationMessage? {
return try {
private fun convertToMessageOrNull(payload: String): SubscriptionOperationMessage? =
try {
objectMapper.readValue(payload)
} catch (exception: Exception) {
logger.error("Error parsing the subscription message", exception)
null
}
}
private fun startSubscription(
operationMessage: SubscriptionOperationMessage,
@@ -133,15 +132,15 @@ class ApolloSubscriptionProtocolHandler(
try {
val request = objectMapper.convertValue<GraphQLRequest>(payload)
return subscriptionHandler.executeSubscription(request, graphQLContext)
return subscriptionHandler
.executeSubscription(request, graphQLContext)
.map {
if (it.errors?.isNotEmpty() == true) {
SubscriptionOperationMessage(type = GQL_ERROR.type, id = operationMessage.id, payload = it.errors)
} else {
SubscriptionOperationMessage(type = GQL_NEXT.type, id = operationMessage.id, payload = it)
}
}
.onCompletion { if (it == null) emitAll(onComplete(operationMessage)) }
}.onCompletion { if (it == null) emitAll(onComplete(operationMessage)) }
.onStart { sessionState.saveOperation(context, operationMessage, currentCoroutineContext().job) }
} catch (exception: Exception) {
logger.error("Error running graphql subscription", exception)
@@ -169,13 +168,10 @@ class ApolloSubscriptionProtocolHandler(
/**
* Called with the publisher has completed on its own.
*/
private fun onComplete(operationMessage: SubscriptionOperationMessage): Flow<SubscriptionOperationMessage> {
return sessionState.completeOperation(operationMessage)
}
private fun onComplete(operationMessage: SubscriptionOperationMessage): Flow<SubscriptionOperationMessage> =
sessionState.completeOperation(operationMessage)
private fun onPing(): Flow<SubscriptionOperationMessage> {
return flowOf(pongMessage)
}
private fun onPing(): Flow<SubscriptionOperationMessage> = flowOf(pongMessage)
private fun onDisconnect(context: WsContext): Flow<SubscriptionOperationMessage> {
logger.debug("Session \"${context.sessionId}\" disconnected")

View File

@@ -71,9 +71,7 @@ internal class ApolloSubscriptionSessionState {
.onCompletion { removeActiveOperation(operationMessage.id ?: return@onCompletion) }
}
private fun getCompleteMessage(): Flow<SubscriptionOperationMessage> {
return emptyFlow()
}
private fun getCompleteMessage(): Flow<SubscriptionOperationMessage> = emptyFlow()
/**
* Remove active running subscription from the cache and cancel if needed

View File

@@ -23,18 +23,24 @@ data class SubscriptionOperationMessage(
val id: String? = null,
val payload: Any? = null,
) {
enum class CommonMessages(val type: String) {
enum class CommonMessages(
val type: String,
) {
GQL_PING("ping"),
GQL_PONG("pong"),
GQL_COMPLETE("complete"),
}
enum class ClientMessages(val type: String) {
enum class ClientMessages(
val type: String,
) {
GQL_CONNECTION_INIT("connection_init"),
GQL_SUBSCRIBE("subscribe"),
}
enum class ServerMessages(val type: String) {
enum class ServerMessages(
val type: String,
) {
GQL_CONNECTION_ACK("connection_ack"),
GQL_NEXT("next"),
GQL_ERROR("error"),

View File

@@ -13,9 +13,8 @@ import suwayomi.tachidesk.graphql.types.DownloadStatus
import suwayomi.tachidesk.manga.impl.download.DownloadManager
class DownloadSubscription {
fun downloadChanged(): Flow<DownloadStatus> {
return DownloadManager.status.map { downloadStatus ->
fun downloadChanged(): Flow<DownloadStatus> =
DownloadManager.status.map { downloadStatus ->
DownloadStatus(downloadStatus)
}
}
}

View File

@@ -5,7 +5,5 @@ import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
import suwayomi.tachidesk.server.util.WebInterfaceManager
class InfoSubscription {
fun webUIUpdateStatusChange(): Flow<WebUIUpdateStatus> {
return WebInterfaceManager.status
}
fun webUIUpdateStatusChange(): Flow<WebUIUpdateStatus> = WebInterfaceManager.status
}

View File

@@ -18,9 +18,8 @@ import suwayomi.tachidesk.manga.impl.update.IUpdater
class UpdateSubscription {
private val updater by DI.global.instance<IUpdater>()
fun updateStatusChanged(): Flow<UpdateStatus> {
return updater.status.map { updateStatus ->
fun updateStatusChanged(): Flow<UpdateStatus> =
updater.status.map { updateStatus ->
UpdateStatus(updateStatus)
}
}
}

View File

@@ -16,8 +16,8 @@ data class BackupRestoreStatus(
val mangaProgress: Int,
)
fun ProtoBackupImport.BackupRestoreState.toStatus(): BackupRestoreStatus {
return when (this) {
fun ProtoBackupImport.BackupRestoreState.toStatus(): BackupRestoreStatus =
when (this) {
ProtoBackupImport.BackupRestoreState.Idle ->
BackupRestoreStatus(
state = BackupRestoreState.IDLE,
@@ -49,4 +49,3 @@ fun ProtoBackupImport.BackupRestoreState.toStatus(): BackupRestoreStatus {
mangaProgress = current,
)
}
}

View File

@@ -36,13 +36,11 @@ class CategoryType(
IncludeOrExclude.fromValue(row[CategoryTable.includeInDownload]),
)
fun mangas(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaNodeList>("MangaForCategoryDataLoader", id)
}
fun mangas(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaNodeList> =
dataFetchingEnvironment.getValueFromDataLoader<Int, MangaNodeList>("MangaForCategoryDataLoader", id)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<CategoryMetaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<CategoryMetaType>>("CategoryMetaDataLoader", id)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<CategoryMetaType>> =
dataFetchingEnvironment.getValueFromDataLoader<Int, List<CategoryMetaType>>("CategoryMetaDataLoader", id)
}
data class CategoryNodeList(
@@ -57,8 +55,8 @@ data class CategoryNodeList(
) : Edge()
companion object {
fun List<CategoryType>.toNodeList(): CategoryNodeList {
return CategoryNodeList(
fun List<CategoryType>.toNodeList(): CategoryNodeList =
CategoryNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -70,7 +68,6 @@ data class CategoryNodeList(
),
totalCount = size,
)
}
private fun List<CategoryType>.getEdges(): List<CategoryEdge> {
if (isEmpty()) return emptyList()

View File

@@ -90,13 +90,11 @@ class ChapterType(
dataClass.pageCount,
)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
}
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<ChapterMetaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<ChapterMetaType>>("ChapterMetaDataLoader", id)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<ChapterMetaType>> =
dataFetchingEnvironment.getValueFromDataLoader<Int, List<ChapterMetaType>>("ChapterMetaDataLoader", id)
}
data class ChapterNodeList(
@@ -111,8 +109,8 @@ data class ChapterNodeList(
) : Edge()
companion object {
fun List<ChapterType>.toNodeList(): ChapterNodeList {
return ChapterNodeList(
fun List<ChapterType>.toNodeList(): ChapterNodeList =
ChapterNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -124,7 +122,6 @@ data class ChapterNodeList(
),
totalCount = size,
)
}
private fun List<ChapterType>.getEdges(): List<ChapterEdge> {
if (isEmpty()) return emptyList()

View File

@@ -100,8 +100,8 @@ data class DownloadNodeList(
) : Edge()
companion object {
fun List<DownloadType>.toNodeList(): DownloadNodeList {
return DownloadNodeList(
fun List<DownloadType>.toNodeList(): DownloadNodeList =
DownloadNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -113,7 +113,6 @@ data class DownloadNodeList(
),
totalCount = size,
)
}
private fun List<DownloadType>.getEdges(): List<DownloadEdge> {
if (isEmpty()) return emptyList()

View File

@@ -48,9 +48,8 @@ class ExtensionType(
isObsolete = row[ExtensionTable.isObsolete],
)
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<String, SourceNodeList>("SourcesForExtensionDataLoader", pkgName)
}
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceNodeList> =
dataFetchingEnvironment.getValueFromDataLoader<String, SourceNodeList>("SourcesForExtensionDataLoader", pkgName)
}
data class ExtensionNodeList(
@@ -65,8 +64,8 @@ data class ExtensionNodeList(
) : Edge()
companion object {
fun List<ExtensionType>.toNodeList(): ExtensionNodeList {
return ExtensionNodeList(
fun List<ExtensionType>.toNodeList(): ExtensionNodeList =
ExtensionNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -78,7 +77,6 @@ data class ExtensionNodeList(
),
totalCount = size,
)
}
private fun List<ExtensionType>.getEdges(): List<ExtensionEdge> {
if (isEmpty()) return emptyList()

View File

@@ -62,8 +62,10 @@ class MangaType(
val mangaForIdsDataLoader =
dataFetchingEnvironment.getDataLoader<List<Int>, MangaNodeList>("MangaForIdsDataLoader")
@Suppress("UNCHECKED_CAST")
(mangaForIdsDataLoader.cacheMap as CustomCacheMap<List<Int>, MangaNodeList>).getKeys()
.filter { it.contains(mangaId) }.forEach { mangaForIdsDataLoader.clear(it) }
(mangaForIdsDataLoader.cacheMap as CustomCacheMap<List<Int>, MangaNodeList>)
.getKeys()
.filter { it.contains(mangaId) }
.forEach { mangaForIdsDataLoader.clear(it) }
dataFetchingEnvironment.getDataLoader<Int, Int>("DownloadedChapterCountForMangaDataLoader").clear(mangaId)
dataFetchingEnvironment.getDataLoader<Int, Int>("UnreadChapterCountForMangaDataLoader").clear(mangaId)
@@ -74,9 +76,10 @@ class MangaType(
dataFetchingEnvironment.getDataLoader<Int, ChapterType>("LatestFetchedChapterForMangaDataLoader").clear(mangaId)
dataFetchingEnvironment.getDataLoader<Int, ChapterType>("LatestUploadedChapterForMangaDataLoader").clear(mangaId)
dataFetchingEnvironment.getDataLoader<Int, ChapterType>("FirstUnreadChapterForMangaDataLoader").clear(mangaId)
dataFetchingEnvironment.getDataLoader<Int, ChapterNodeList>(
"ChaptersForMangaDataLoader",
).clear(mangaId)
dataFetchingEnvironment
.getDataLoader<Int, ChapterNodeList>(
"ChaptersForMangaDataLoader",
).clear(mangaId)
dataFetchingEnvironment.getDataLoader<Int, List<MangaMetaType>>("MangaMetaDataLoader").clear(mangaId)
dataFetchingEnvironment.getDataLoader<Int, CategoryNodeList>("CategoriesForMangaDataLoader").clear(mangaId)
}
@@ -124,45 +127,35 @@ class MangaType(
dataClass.chaptersLastFetchedAt,
)
fun downloadCount(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Int> {
return dataFetchingEnvironment.getValueFromDataLoader("DownloadedChapterCountForMangaDataLoader", id)
}
fun downloadCount(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Int> =
dataFetchingEnvironment.getValueFromDataLoader("DownloadedChapterCountForMangaDataLoader", id)
fun unreadCount(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Int> {
return dataFetchingEnvironment.getValueFromDataLoader("UnreadChapterCountForMangaDataLoader", id)
}
fun unreadCount(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Int> =
dataFetchingEnvironment.getValueFromDataLoader("UnreadChapterCountForMangaDataLoader", id)
fun bookmarkCount(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Int> {
return dataFetchingEnvironment.getValueFromDataLoader("BookmarkedChapterCountForMangaDataLoader", id)
}
fun bookmarkCount(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Int> =
dataFetchingEnvironment.getValueFromDataLoader("BookmarkedChapterCountForMangaDataLoader", id)
fun hasDuplicateChapters(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Boolean> {
return dataFetchingEnvironment.getValueFromDataLoader("HasDuplicateChaptersForMangaDataLoader", id)
}
fun hasDuplicateChapters(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Boolean> =
dataFetchingEnvironment.getValueFromDataLoader("HasDuplicateChaptersForMangaDataLoader", id)
fun lastReadChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> {
return dataFetchingEnvironment.getValueFromDataLoader("LastReadChapterForMangaDataLoader", id)
}
fun lastReadChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> =
dataFetchingEnvironment.getValueFromDataLoader("LastReadChapterForMangaDataLoader", id)
fun latestReadChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> {
return dataFetchingEnvironment.getValueFromDataLoader("LatestReadChapterForMangaDataLoader", id)
}
fun latestReadChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> =
dataFetchingEnvironment.getValueFromDataLoader("LatestReadChapterForMangaDataLoader", id)
fun latestFetchedChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> {
return dataFetchingEnvironment.getValueFromDataLoader("LatestFetchedChapterForMangaDataLoader", id)
}
fun latestFetchedChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> =
dataFetchingEnvironment.getValueFromDataLoader("LatestFetchedChapterForMangaDataLoader", id)
fun latestUploadedChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> {
return dataFetchingEnvironment.getValueFromDataLoader("LatestUploadedChapterForMangaDataLoader", id)
}
fun latestUploadedChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> =
dataFetchingEnvironment.getValueFromDataLoader("LatestUploadedChapterForMangaDataLoader", id)
fun firstUnreadChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> {
return dataFetchingEnvironment.getValueFromDataLoader("FirstUnreadChapterForMangaDataLoader", id)
}
fun firstUnreadChapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType?> =
dataFetchingEnvironment.getValueFromDataLoader("FirstUnreadChapterForMangaDataLoader", id)
fun chapters(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, ChapterNodeList>("ChaptersForMangaDataLoader", id)
}
fun chapters(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterNodeList> =
dataFetchingEnvironment.getValueFromDataLoader<Int, ChapterNodeList>("ChaptersForMangaDataLoader", id)
fun age(): Long? {
if (lastFetchedAt == null) return null
@@ -175,21 +168,17 @@ class MangaType(
return Instant.now().epochSecond.minus(chaptersLastFetchedAt!!)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<MangaMetaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<MangaMetaType>>("MangaMetaDataLoader", id)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<MangaMetaType>> =
dataFetchingEnvironment.getValueFromDataLoader<Int, List<MangaMetaType>>("MangaMetaDataLoader", id)
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, CategoryNodeList>("CategoriesForMangaDataLoader", id)
}
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryNodeList> =
dataFetchingEnvironment.getValueFromDataLoader<Int, CategoryNodeList>("CategoriesForMangaDataLoader", id)
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceType?> {
return dataFetchingEnvironment.getValueFromDataLoader<Long, SourceType?>("SourceDataLoader", sourceId)
}
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceType?> =
dataFetchingEnvironment.getValueFromDataLoader<Long, SourceType?>("SourceDataLoader", sourceId)
fun trackRecords(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackRecordNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordNodeList>("TrackRecordsForMangaIdDataLoader", id)
}
fun trackRecords(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackRecordNodeList> =
dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordNodeList>("TrackRecordsForMangaIdDataLoader", id)
}
data class MangaNodeList(
@@ -204,8 +193,8 @@ data class MangaNodeList(
) : Edge()
companion object {
fun List<MangaType>.toNodeList(): MangaNodeList {
return MangaNodeList(
fun List<MangaType>.toNodeList(): MangaNodeList =
MangaNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -217,7 +206,6 @@ data class MangaNodeList(
),
totalCount = size,
)
}
private fun List<MangaType>.getEdges(): List<MangaEdge> {
if (isEmpty()) return emptyList()

View File

@@ -31,9 +31,8 @@ class ChapterMetaType(
chapterId = row[ChapterMetaTable.ref].value,
)
fun chapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, ChapterType>("ChapterDataLoader", chapterId)
}
fun chapter(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ChapterType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, ChapterType>("ChapterDataLoader", chapterId)
}
class MangaMetaType(
@@ -47,9 +46,8 @@ class MangaMetaType(
mangaId = row[MangaMetaTable.ref].value,
)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
}
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
}
class CategoryMetaType(
@@ -63,9 +61,8 @@ class CategoryMetaType(
categoryId = row[CategoryMetaTable.ref].value,
)
fun category(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, CategoryType>("CategoryDataLoader", categoryId)
}
fun category(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, CategoryType>("CategoryDataLoader", categoryId)
}
class SourceMetaType(
@@ -79,9 +76,8 @@ class SourceMetaType(
sourceId = row[SourceMetaTable.ref],
)
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceType> {
return dataFetchingEnvironment.getValueFromDataLoader<Long, SourceType>("SourceDataLoader", sourceId)
}
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceType> =
dataFetchingEnvironment.getValueFromDataLoader<Long, SourceType>("SourceDataLoader", sourceId)
}
class GlobalMetaType(
@@ -106,8 +102,8 @@ data class GlobalMetaNodeList(
) : Edge()
companion object {
fun List<GlobalMetaType>.toNodeList(): GlobalMetaNodeList {
return GlobalMetaNodeList(
fun List<GlobalMetaType>.toNodeList(): GlobalMetaNodeList =
GlobalMetaNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -119,7 +115,6 @@ data class GlobalMetaNodeList(
),
totalCount = size,
)
}
private fun List<GlobalMetaType>.getEdges(): List<MetaEdge> {
if (isEmpty()) return emptyList()

View File

@@ -67,25 +67,18 @@ class SourceType(
displayName = catalogueSource.toString(),
)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Long, MangaNodeList>("MangaForSourceDataLoader", id)
}
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaNodeList> =
dataFetchingEnvironment.getValueFromDataLoader<Long, MangaNodeList>("MangaForSourceDataLoader", id)
fun extension(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ExtensionType> {
return dataFetchingEnvironment.getValueFromDataLoader<Long, ExtensionType>("ExtensionForSourceDataLoader", id)
}
fun extension(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<ExtensionType> =
dataFetchingEnvironment.getValueFromDataLoader<Long, ExtensionType>("ExtensionForSourceDataLoader", id)
fun preferences(): List<Preference> {
return getSourcePreferencesRaw(id).map { preferenceOf(it) }
}
fun preferences(): List<Preference> = getSourcePreferencesRaw(id).map { preferenceOf(it) }
fun filters(): List<Filter> {
return getCatalogueSourceOrStub(id).getFilterList().map { filterOf(it) }
}
fun filters(): List<Filter> = getCatalogueSourceOrStub(id).getFilterList().map { filterOf(it) }
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<SourceMetaType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Long, List<SourceMetaType>>("SourceMetaDataLoader", id)
}
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<SourceMetaType>> =
dataFetchingEnvironment.getValueFromDataLoader<Long, List<SourceMetaType>>("SourceMetaDataLoader", id)
}
@Suppress("ktlint:standard:function-naming")
@@ -118,8 +111,8 @@ data class SourceNodeList(
) : Edge()
companion object {
fun List<SourceType>.toNodeList(): SourceNodeList {
return SourceNodeList(
fun List<SourceType>.toNodeList(): SourceNodeList =
SourceNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -131,7 +124,6 @@ data class SourceNodeList(
),
totalCount = size,
)
}
private fun List<SourceType>.getEdges(): List<SourceEdge> {
if (isEmpty()) return emptyList()
@@ -151,15 +143,29 @@ data class SourceNodeList(
sealed interface Filter
data class HeaderFilter(val name: String) : Filter
data class HeaderFilter(
val name: String,
) : Filter
data class SeparatorFilter(val name: String) : Filter
data class SeparatorFilter(
val name: String,
) : Filter
data class SelectFilter(val name: String, val values: List<String>, val default: Int) : Filter
data class SelectFilter(
val name: String,
val values: List<String>,
val default: Int,
) : Filter
data class TextFilter(val name: String, val default: String) : Filter
data class TextFilter(
val name: String,
val default: String,
) : Filter
data class CheckBoxFilter(val name: String, val default: Boolean) : Filter
data class CheckBoxFilter(
val name: String,
val default: Boolean,
) : Filter
enum class TriState {
IGNORE,
@@ -167,19 +173,32 @@ enum class TriState {
EXCLUDE,
}
data class TriStateFilter(val name: String, val default: TriState) : Filter
data class TriStateFilter(
val name: String,
val default: TriState,
) : Filter
data class SortFilter(val name: String, val values: List<String>, val default: SortSelection?) : Filter {
data class SortSelection(val index: Int, val ascending: Boolean) {
data class SortFilter(
val name: String,
val values: List<String>,
val default: SortSelection?,
) : Filter {
data class SortSelection(
val index: Int,
val ascending: Boolean,
) {
constructor(selection: SourceFilter.Sort.Selection) :
this(selection.index, selection.ascending)
}
}
data class GroupFilter(val name: String, val filters: List<Filter>) : Filter
data class GroupFilter(
val name: String,
val filters: List<Filter>,
) : Filter
fun filterOf(filter: SourceFilter<*>): Filter {
return when (filter) {
fun filterOf(filter: SourceFilter<*>): Filter =
when (filter) {
is SourceFilter.Header -> HeaderFilter(filter.name)
is SourceFilter.Separator -> SeparatorFilter(filter.name)
is SourceFilter.Select<*> -> SelectFilter(filter.name, filter.displayValues, filter.state)
@@ -202,7 +221,6 @@ fun filterOf(filter: SourceFilter<*>): Filter {
is SourceFilter.Sort -> SortFilter(filter.name, filter.values.asList(), filter.state?.let(SortFilter::SortSelection))
else -> throw RuntimeException("sealed class cannot have more subtypes!")
}
}
/*sealed interface FilterChange {
val position: Int
@@ -372,8 +390,8 @@ data class MultiSelectListPreference(
val entryValues: List<String>,
) : Preference
fun preferenceOf(preference: SourcePreference): Preference {
return when (preference) {
fun preferenceOf(preference: SourcePreference): Preference =
when (preference) {
is SourceSwitchPreference ->
SwitchPreference(
preference.key,
@@ -430,4 +448,3 @@ fun preferenceOf(preference: SourcePreference): Preference {
)
else -> throw RuntimeException("sealed class cannot have more subtypes!")
}
}

View File

@@ -40,21 +40,17 @@ class TrackerType(
tracker.supportsTrackDeletion,
)
fun statuses(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<TrackStatusType>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<TrackStatusType>>("TrackerStatusesDataLoader", id)
}
fun statuses(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<TrackStatusType>> =
dataFetchingEnvironment.getValueFromDataLoader<Int, List<TrackStatusType>>("TrackerStatusesDataLoader", id)
fun scores(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<String>> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, List<String>>("TrackerScoresDataLoader", id)
}
fun scores(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<String>> =
dataFetchingEnvironment.getValueFromDataLoader<Int, List<String>>("TrackerScoresDataLoader", id)
fun trackRecords(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackRecordNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordNodeList>("TrackRecordsForTrackerIdDataLoader", id)
}
fun trackRecords(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackRecordNodeList> =
dataFetchingEnvironment.getValueFromDataLoader<Int, TrackRecordNodeList>("TrackRecordsForTrackerIdDataLoader", id)
fun isTokenExpired(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Boolean> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, Boolean>("TrackerTokenExpiredDataLoader", id)
}
fun isTokenExpired(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<Boolean> =
dataFetchingEnvironment.getValueFromDataLoader<Int, Boolean>("TrackerTokenExpiredDataLoader", id)
}
class TrackStatusType(
@@ -93,17 +89,14 @@ class TrackRecordType(
row[TrackRecordTable.finishDate],
)
fun displayScore(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<String> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, String>("DisplayScoreForTrackRecordDataLoader", id)
}
fun displayScore(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<String> =
dataFetchingEnvironment.getValueFromDataLoader<Int, String>("DisplayScoreForTrackRecordDataLoader", id)
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
}
fun manga(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<MangaType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, MangaType>("MangaDataLoader", mangaId)
fun tracker(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackerType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", trackerId)
}
fun tracker(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackerType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", trackerId)
}
class TrackSearchType(
@@ -133,9 +126,8 @@ class TrackSearchType(
row[TrackSearchTable.startDate],
)
fun tracker(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackerType> {
return dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", trackerId)
}
fun tracker(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<TrackerType> =
dataFetchingEnvironment.getValueFromDataLoader<Int, TrackerType>("TrackerDataLoader", trackerId)
}
data class TrackRecordNodeList(
@@ -150,8 +142,8 @@ data class TrackRecordNodeList(
) : Edge()
companion object {
fun List<TrackRecordType>.toNodeList(): TrackRecordNodeList {
return TrackRecordNodeList(
fun List<TrackRecordType>.toNodeList(): TrackRecordNodeList =
TrackRecordNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -163,7 +155,6 @@ data class TrackRecordNodeList(
),
totalCount = size,
)
}
private fun List<TrackRecordType>.getEdges(): List<TrackRecordEdge> {
if (isEmpty()) return emptyList()
@@ -193,8 +184,8 @@ data class TrackerNodeList(
) : Edge()
companion object {
fun List<TrackerType>.toNodeList(): TrackerNodeList {
return TrackerNodeList(
fun List<TrackerType>.toNodeList(): TrackerNodeList =
TrackerNodeList(
nodes = this,
edges = getEdges(),
pageInfo =
@@ -206,7 +197,6 @@ data class TrackerNodeList(
),
totalCount = size,
)
}
private fun List<TrackerType>.getEdges(): List<TrackerEdge> {
if (isEmpty()) return emptyList()

View File

@@ -28,9 +28,10 @@ class UpdateStatus(
runningJobs = UpdateStatusType(status.mangaStatusMap[JobStatus.RUNNING]?.map { it.id }.orEmpty()),
completeJobs =
UpdateStatusType(
status.mangaStatusMap[JobStatus.COMPLETE]?.map {
it.id
}.orEmpty(),
status.mangaStatusMap[JobStatus.COMPLETE]
?.map {
it.id
}.orEmpty(),
JobStatus.COMPLETE,
status.running,
true,
@@ -50,9 +51,8 @@ class UpdateStatusCategoryType(
@get:GraphQLIgnore
val categoryIds: List<Int>,
) {
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryNodeList> {
return dataFetchingEnvironment.getValueFromDataLoader("CategoryForIdsDataLoader", categoryIds)
}
fun categories(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<CategoryNodeList> =
dataFetchingEnvironment.getValueFromDataLoader("CategoryForIdsDataLoader", categoryIds)
}
class UpdateStatusType(

View File

@@ -247,7 +247,8 @@ object SourceController {
description("All source search")
}
},
behaviorOf = { ctx, searchTerm -> // TODO
behaviorOf = { ctx, searchTerm ->
// TODO
ctx.json(Search.sourceGlobalSearch(searchTerm))
},
withResults = {

View File

@@ -36,10 +36,11 @@ object Category {
return transaction {
if (CategoryTable.select { CategoryTable.name eq name }.firstOrNull() == null) {
val newCategoryId =
CategoryTable.insertAndGetId {
it[CategoryTable.name] = name
it[CategoryTable.order] = Int.MAX_VALUE
}.value
CategoryTable
.insertAndGetId {
it[CategoryTable.name] = name
it[CategoryTable.order] = Int.MAX_VALUE
}.value
normalizeCategories()
@@ -60,7 +61,8 @@ object Category {
transaction {
CategoryTable.update({ CategoryTable.id eq categoryId }) {
if (
categoryId != DEFAULT_CATEGORY_ID && name != null &&
categoryId != DEFAULT_CATEGORY_ID &&
name != null &&
!name.equals(DEFAULT_CATEGORY_NAME, ignoreCase = true)
) {
it[CategoryTable.name] = name
@@ -82,9 +84,11 @@ object Category {
if (from == 0 || to == 0) return
transaction {
val categories =
CategoryTable.select {
CategoryTable.id neq DEFAULT_CATEGORY_ID
}.orderBy(CategoryTable.order to SortOrder.ASC).toMutableList()
CategoryTable
.select {
CategoryTable.id neq DEFAULT_CATEGORY_ID
}.orderBy(CategoryTable.order to SortOrder.ASC)
.toMutableList()
categories.add(to - 1, categories.removeAt(from - 1))
categories.forEachIndexed { index, cat ->
CategoryTable.update({ CategoryTable.id eq cat[CategoryTable.id].value }) {
@@ -106,7 +110,8 @@ object Category {
/** make sure category order numbers starts from 1 and is consecutive */
fun normalizeCategories() {
transaction {
CategoryTable.selectAll()
CategoryTable
.selectAll()
.orderBy(CategoryTable.order to SortOrder.ASC)
.sortedWith(compareBy({ it[CategoryTable.id].value != 0 }, { it[CategoryTable.order] }))
.forEachIndexed { index, cat ->
@@ -130,9 +135,10 @@ object Category {
const val DEFAULT_CATEGORY_ID = 0
const val DEFAULT_CATEGORY_NAME = "Default"
fun getCategoryList(): List<CategoryDataClass> {
return transaction {
CategoryTable.selectAll()
fun getCategoryList(): List<CategoryDataClass> =
transaction {
CategoryTable
.selectAll()
.orderBy(CategoryTable.order to SortOrder.ASC)
.let {
if (needsDefaultCategory()) {
@@ -140,41 +146,39 @@ object Category {
} else {
it.andWhere { CategoryTable.id neq DEFAULT_CATEGORY_ID }
}
}
.map {
}.map {
CategoryTable.toDataClass(it)
}
}
}
fun getCategoryById(categoryId: Int): CategoryDataClass? {
return transaction {
fun getCategoryById(categoryId: Int): CategoryDataClass? =
transaction {
CategoryTable.select { CategoryTable.id eq categoryId }.firstOrNull()?.let {
CategoryTable.toDataClass(it)
}
}
}
fun getCategorySize(categoryId: Int): Int {
return transaction {
fun getCategorySize(categoryId: Int): Int =
transaction {
if (categoryId == DEFAULT_CATEGORY_ID) {
MangaTable
.leftJoin(CategoryMangaTable)
.select { MangaTable.inLibrary eq true }
.andWhere { CategoryMangaTable.manga.isNull() }
} else {
CategoryMangaTable.leftJoin(MangaTable).select { CategoryMangaTable.category eq categoryId }
CategoryMangaTable
.leftJoin(MangaTable)
.select { CategoryMangaTable.category eq categoryId }
.andWhere { MangaTable.inLibrary eq true }
}.count().toInt()
}
}
fun getCategoryMetaMap(categoryId: Int): Map<String, String> {
return transaction {
CategoryMetaTable.select { CategoryMetaTable.ref eq categoryId }
fun getCategoryMetaMap(categoryId: Int): Map<String, String> =
transaction {
CategoryMetaTable
.select { CategoryMetaTable.ref eq categoryId }
.associate { it[CategoryMetaTable.key] to it[CategoryMetaTable.value] }
}
}
fun modifyMeta(
categoryId: Int,

View File

@@ -38,9 +38,10 @@ object CategoryManga {
if (categoryId == DEFAULT_CATEGORY_ID) return
fun notAlreadyInCategory() =
CategoryMangaTable.select {
(CategoryMangaTable.category eq categoryId) and (CategoryMangaTable.manga eq mangaId)
}.isEmpty()
CategoryMangaTable
.select {
(CategoryMangaTable.category eq categoryId) and (CategoryMangaTable.manga eq mangaId)
}.isEmpty()
transaction {
if (notAlreadyInCategory()) {
@@ -69,15 +70,17 @@ object CategoryManga {
// Select the required columns from the MangaTable and add the aggregate functions to compute unread, download, and chapter counts
val unreadCount =
wrapAsExpression<Long>(
ChapterTable.slice(
ChapterTable.id.count(),
).select((ChapterTable.isRead eq false) and (ChapterTable.manga eq MangaTable.id)),
ChapterTable
.slice(
ChapterTable.id.count(),
).select((ChapterTable.isRead eq false) and (ChapterTable.manga eq MangaTable.id)),
)
val downloadedCount =
wrapAsExpression<Long>(
ChapterTable.slice(
ChapterTable.id.count(),
).select((ChapterTable.isDownloaded eq true) and (ChapterTable.manga eq MangaTable.id)),
ChapterTable
.slice(
ChapterTable.id.count(),
).select((ChapterTable.isDownloaded eq true) and (ChapterTable.manga eq MangaTable.id)),
)
val chapterCount = ChapterTable.id.count().alias("chapter_count")
@@ -119,20 +122,23 @@ object CategoryManga {
/**
* list of categories that a manga belongs to
*/
fun getMangaCategories(mangaId: Int): List<CategoryDataClass> {
return transaction {
CategoryMangaTable.innerJoin(CategoryTable).select {
CategoryMangaTable.manga eq mangaId
}.orderBy(CategoryTable.order to SortOrder.ASC).map {
CategoryTable.toDataClass(it)
}
fun getMangaCategories(mangaId: Int): List<CategoryDataClass> =
transaction {
CategoryMangaTable
.innerJoin(CategoryTable)
.select {
CategoryMangaTable.manga eq mangaId
}.orderBy(CategoryTable.order to SortOrder.ASC)
.map {
CategoryTable.toDataClass(it)
}
}
}
fun getMangasCategories(mangaIDs: List<Int>): Map<Int, List<CategoryDataClass>> {
return buildMap {
fun getMangasCategories(mangaIDs: List<Int>): Map<Int, List<CategoryDataClass>> =
buildMap {
transaction {
CategoryMangaTable.innerJoin(CategoryTable)
CategoryMangaTable
.innerJoin(CategoryTable)
.select { CategoryMangaTable.manga inList mangaIDs }
.groupBy { it[CategoryMangaTable.manga] }
.forEach {
@@ -143,5 +149,4 @@ object CategoryManga {
}
}
}
}
}

View File

@@ -50,14 +50,13 @@ import java.util.TreeSet
import java.util.concurrent.TimeUnit
import kotlin.math.max
private fun List<ChapterDataClass>.removeDuplicates(currentChapter: ChapterDataClass): List<ChapterDataClass> {
return groupBy { it.chapterNumber }
private fun List<ChapterDataClass>.removeDuplicates(currentChapter: ChapterDataClass): List<ChapterDataClass> =
groupBy { it.chapterNumber }
.map { (_, chapters) ->
chapters.find { it.id == currentChapter.id }
?: chapters.find { it.scanlator == currentChapter.scanlator }
?: chapters.first()
}
}
object Chapter {
private val logger = KotlinLogging.logger { }
@@ -66,12 +65,13 @@ object Chapter {
suspend fun getChapterList(
mangaId: Int,
onlineFetch: Boolean = false,
): List<ChapterDataClass> {
return if (onlineFetch) {
): List<ChapterDataClass> =
if (onlineFetch) {
getSourceChapters(mangaId)
} else {
transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }
ChapterTable
.select { ChapterTable.manga eq mangaId }
.orderBy(ChapterTable.sourceOrder to SortOrder.DESC)
.map {
ChapterTable.toDataClass(it)
@@ -80,18 +80,16 @@ object Chapter {
getSourceChapters(mangaId)
}
}
}
fun getCountOfMangaChapters(mangaId: Int): Int {
return transaction { ChapterTable.select { ChapterTable.manga eq mangaId }.count().toInt() }
}
fun getCountOfMangaChapters(mangaId: Int): Int = transaction { ChapterTable.select { ChapterTable.manga eq mangaId }.count().toInt() }
private suspend fun getSourceChapters(mangaId: Int): List<ChapterDataClass> {
val chapterList = fetchChapterList(mangaId)
val dbChapterMap =
transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }
ChapterTable
.select { ChapterTable.manga eq mangaId }
.associateBy({ it[ChapterTable.url] }, { it })
}
@@ -126,7 +124,8 @@ object Chapter {
}
val map: Cache<Int, Mutex> =
CacheBuilder.newBuilder()
CacheBuilder
.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build()
@@ -173,7 +172,8 @@ object Chapter {
val chaptersInDb =
transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }
ChapterTable
.select { ChapterTable.manga eq mangaId }
.map { ChapterTable.toDataClass(it) }
.toList()
}
@@ -259,39 +259,40 @@ object Chapter {
transaction {
if (chaptersToInsert.isNotEmpty()) {
ChapterTable.batchInsert(chaptersToInsert) { chapter ->
this[ChapterTable.url] = chapter.url
this[ChapterTable.name] = chapter.name
this[ChapterTable.date_upload] = chapter.uploadDate
this[ChapterTable.chapter_number] = chapter.chapterNumber
this[ChapterTable.scanlator] = chapter.scanlator
this[ChapterTable.sourceOrder] = chapter.index
this[ChapterTable.fetchedAt] = chapter.fetchedAt
this[ChapterTable.manga] = chapter.mangaId
this[ChapterTable.realUrl] = chapter.realUrl
this[ChapterTable.isRead] = false
this[ChapterTable.isBookmarked] = false
this[ChapterTable.isDownloaded] = false
ChapterTable
.batchInsert(chaptersToInsert) { chapter ->
this[ChapterTable.url] = chapter.url
this[ChapterTable.name] = chapter.name
this[ChapterTable.date_upload] = chapter.uploadDate
this[ChapterTable.chapter_number] = chapter.chapterNumber
this[ChapterTable.scanlator] = chapter.scanlator
this[ChapterTable.sourceOrder] = chapter.index
this[ChapterTable.fetchedAt] = chapter.fetchedAt
this[ChapterTable.manga] = chapter.mangaId
this[ChapterTable.realUrl] = chapter.realUrl
this[ChapterTable.isRead] = false
this[ChapterTable.isBookmarked] = false
this[ChapterTable.isDownloaded] = false
// is recognized chapter number
if (chapter.chapterNumber >= 0f && chapter.chapterNumber in deletedChapterNumbers) {
this[ChapterTable.isRead] = chapter.chapterNumber in deletedReadChapterNumbers
this[ChapterTable.isBookmarked] = chapter.chapterNumber in deletedBookmarkedChapterNumbers
// is recognized chapter number
if (chapter.chapterNumber >= 0f && chapter.chapterNumber in deletedChapterNumbers) {
this[ChapterTable.isRead] = chapter.chapterNumber in deletedReadChapterNumbers
this[ChapterTable.isBookmarked] = chapter.chapterNumber in deletedBookmarkedChapterNumbers
// only preserve download status for chapters of the same scanlator, otherwise,
// the downloaded files won't be found anyway
val downloadedChapterInfo = deletedDownloadedChapterNumberInfoMap[chapter.chapterNumber]
val pageCount = downloadedChapterInfo?.get(chapter.scanlator)
if (pageCount != null) {
this[ChapterTable.isDownloaded] = true
this[ChapterTable.pageCount] = pageCount
// only preserve download status for chapters of the same scanlator, otherwise,
// the downloaded files won't be found anyway
val downloadedChapterInfo = deletedDownloadedChapterNumberInfoMap[chapter.chapterNumber]
val pageCount = downloadedChapterInfo?.get(chapter.scanlator)
if (pageCount != null) {
this[ChapterTable.isDownloaded] = true
this[ChapterTable.pageCount] = pageCount
}
// Try to use the fetch date of the original entry to not pollute 'Updates' tab
deletedChapterNumberDateFetchMap[chapter.chapterNumber]?.let {
this[ChapterTable.fetchedAt] = it
}
}
// Try to use the fetch date of the original entry to not pollute 'Updates' tab
deletedChapterNumberDateFetchMap[chapter.chapterNumber]?.let {
this[ChapterTable.fetchedAt] = it
}
}
}.forEach { insertedChapters.add(ChapterTable.toDataClass(it)) }
}.forEach { insertedChapters.add(ChapterTable.toDataClass(it)) }
}
if (chaptersToUpdate.isNotEmpty()) {
@@ -531,7 +532,8 @@ object Chapter {
if (isRead == true) {
val mangaIds =
transaction {
ChapterTable.select { condition }
ChapterTable
.select { condition }
.map { it[ChapterTable.manga].value }
.toSet()
}
@@ -539,21 +541,21 @@ object Chapter {
}
}
fun getChaptersMetaMaps(chapterIds: List<EntityID<Int>>): Map<EntityID<Int>, Map<String, String>> {
return transaction {
ChapterMetaTable.select { ChapterMetaTable.ref inList chapterIds }
fun getChaptersMetaMaps(chapterIds: List<EntityID<Int>>): Map<EntityID<Int>, Map<String, String>> =
transaction {
ChapterMetaTable
.select { ChapterMetaTable.ref inList chapterIds }
.groupBy { it[ChapterMetaTable.ref] }
.mapValues { it.value.associate { it[ChapterMetaTable.key] to it[ChapterMetaTable.value] } }
.withDefault { emptyMap<String, String>() }
}
}
fun getChapterMetaMap(chapter: EntityID<Int>): Map<String, String> {
return transaction {
ChapterMetaTable.select { ChapterMetaTable.ref eq chapter }
fun getChapterMetaMap(chapter: EntityID<Int>): Map<String, String> =
transaction {
ChapterMetaTable
.select { ChapterMetaTable.ref eq chapter }
.associate { it[ChapterMetaTable.key] to it[ChapterMetaTable.value] }
}
}
fun modifyChapterMeta(
mangaId: Int,
@@ -563,8 +565,10 @@ object Chapter {
) {
transaction {
val chapterId =
ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder eq chapterIndex) }
.first()[ChapterTable.id].value
ChapterTable
.select { (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder eq chapterIndex) }
.first()[ChapterTable.id]
.value
modifyChapterMeta(chapterId, key, value)
}
}
@@ -576,7 +580,8 @@ object Chapter {
) {
transaction {
val meta =
ChapterMetaTable.select { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
ChapterMetaTable
.select { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) }
.firstOrNull()
if (meta == null) {
@@ -599,8 +604,10 @@ object Chapter {
) {
transaction {
val chapterId =
ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder eq chapterIndex) }
.first()[ChapterTable.id].value
ChapterTable
.select { (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder eq chapterIndex) }
.first()[ChapterTable.id]
.value
ChapterDownloadHelper.delete(mangaId, chapterId)
@@ -619,7 +626,8 @@ object Chapter {
} else if (input.chapterIndexes != null && mangaId != null) {
transaction {
val chapterIds =
ChapterTable.slice(ChapterTable.manga, ChapterTable.id)
ChapterTable
.slice(ChapterTable.manga, ChapterTable.id)
.select { (ChapterTable.sourceOrder inList input.chapterIndexes) and (ChapterTable.manga eq mangaId) }
.map { row ->
val chapterId = row[ChapterTable.id].value
@@ -637,7 +645,8 @@ object Chapter {
fun deleteChapters(chapterIds: List<Int>) {
transaction {
ChapterTable.slice(ChapterTable.manga, ChapterTable.id)
ChapterTable
.slice(ChapterTable.manga, ChapterTable.id)
.select { ChapterTable.id inList chapterIds }
.forEach { row ->
val chapterMangaId = row[ChapterTable.manga].value
@@ -651,8 +660,8 @@ object Chapter {
}
}
fun getRecentChapters(pageNum: Int): PaginatedList<MangaChapterDataClass> {
return paginatedFrom(pageNum) {
fun getRecentChapters(pageNum: Int): PaginatedList<MangaChapterDataClass> =
paginatedFrom(pageNum) {
transaction {
(ChapterTable innerJoin MangaTable)
.select { (MangaTable.inLibrary eq true) and (ChapterTable.fetchedAt greater MangaTable.inLibraryAt) }
@@ -665,5 +674,4 @@ object Chapter {
}
}
}
}
}

View File

@@ -16,16 +16,12 @@ object ChapterDownloadHelper {
mangaId: Int,
chapterId: Int,
index: Int,
): Pair<InputStream, String> {
return provider(mangaId, chapterId).getImage().execute(index)
}
): Pair<InputStream, String> = provider(mangaId, chapterId).getImage().execute(index)
fun delete(
mangaId: Int,
chapterId: Int,
): Boolean {
return provider(mangaId, chapterId).delete()
}
): Boolean = provider(mangaId, chapterId).delete()
suspend fun download(
mangaId: Int,
@@ -33,9 +29,7 @@ object ChapterDownloadHelper {
download: DownloadChapter,
scope: CoroutineScope,
step: suspend (DownloadChapter?, Boolean) -> Unit,
): Boolean {
return provider(mangaId, chapterId).download().execute(download, scope, step)
}
): Boolean = provider(mangaId, chapterId).download().execute(download, scope, step)
// return the appropriate provider based on how the download was saved. For the logic is simple but will evolve when new types of downloads are available
private fun provider(

View File

@@ -30,9 +30,10 @@ object Library {
if (!manga.inLibrary) {
transaction {
val defaultCategories =
CategoryTable.select {
(CategoryTable.isDefault eq true) and (CategoryTable.id neq Category.DEFAULT_CATEGORY_ID)
}.toList()
CategoryTable
.select {
(CategoryTable.isDefault eq true) and (CategoryTable.id neq Category.DEFAULT_CATEGORY_ID)
}.toList()
val existingCategories = CategoryMangaTable.select { CategoryMangaTable.manga eq mangaId }.toList()
MangaTable.update({ MangaTable.id eq manga.id }) {

View File

@@ -64,13 +64,12 @@ object Manga {
private fun truncate(
text: String?,
maxLength: Int,
): String? {
return if (text?.length ?: 0 > maxLength) {
): String? =
if (text?.length ?: 0 > maxLength) {
text?.take(maxLength - 3) + "..."
} else {
text
}
}
suspend fun getManga(
mangaId: Int,
@@ -227,12 +226,12 @@ object Manga {
trackers = Track.getTrackRecordsByMangaId(mangaId),
)
fun getMangaMetaMap(mangaId: Int): Map<String, String> {
return transaction {
MangaMetaTable.select { MangaMetaTable.ref eq mangaId }
fun getMangaMetaMap(mangaId: Int): Map<String, String> =
transaction {
MangaMetaTable
.select { MangaMetaTable.ref eq mangaId }
.associate { it[MangaMetaTable.key] to it[MangaMetaTable.value] }
}
}
fun modifyMangaMeta(
mangaId: Int,
@@ -241,7 +240,8 @@ object Manga {
) {
transaction {
val meta =
MangaMetaTable.select { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) }
MangaMetaTable
.select { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) }
.firstOrNull()
if (meta == null) {
@@ -286,9 +286,10 @@ object Manga {
} ?: throw NullPointerException("No thumbnail found")
return try {
source.client.newCall(
GET(thumbnailUrl, source.headers, cache = CacheControl.FORCE_NETWORK),
).awaitSuccess()
source.client
.newCall(
GET(thumbnailUrl, source.headers, cache = CacheControl.FORCE_NETWORK),
).awaitSuccess()
} catch (e: HttpException) {
val tryToRefreshUrl =
!refreshUrl &&
@@ -341,9 +342,10 @@ object Manga {
val thumbnailUrl =
mangaEntry[MangaTable.thumbnail_url]
?: throw NullPointerException("No thumbnail found")
network.client.newCall(
GET(thumbnailUrl, cache = CacheControl.FORCE_NETWORK),
).await()
network.client
.newCall(
GET(thumbnailUrl, cache = CacheControl.FORCE_NETWORK),
).await()
}
else -> throw IllegalArgumentException("Unknown source")
@@ -372,19 +374,18 @@ object Manga {
clearCachedImage(applicationDirs.thumbnailDownloadsRoot, fileName)
}
fun getLatestChapter(mangaId: Int): ChapterDataClass? {
return transaction {
fun getLatestChapter(mangaId: Int): ChapterDataClass? =
transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }.maxByOrNull { it[ChapterTable.sourceOrder] }
}?.let { ChapterTable.toDataClass(it) }
}
fun getUnreadChapters(mangaId: Int): List<ChapterDataClass> {
return transaction {
ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.isRead eq false) }
fun getUnreadChapters(mangaId: Int): List<ChapterDataClass> =
transaction {
ChapterTable
.select { (ChapterTable.manga eq mangaId) and (ChapterTable.isRead eq false) }
.orderBy(ChapterTable.sourceOrder to SortOrder.DESC)
.map { ChapterTable.toDataClass(it) }
}
}
fun isInIncludedDownloadCategory(
logContext: KLogger = logger,

View File

@@ -21,9 +21,7 @@ import suwayomi.tachidesk.manga.model.table.toDataClass
import java.time.Instant
object MangaList {
fun proxyThumbnailUrl(mangaId: Int): String {
return "/api/v1/manga/$mangaId/thumbnail"
}
fun proxyThumbnailUrl(mangaId: Int): String = "/api/v1/manga/$mangaId/thumbnail"
suspend fun getMangaList(
sourceId: Long,
@@ -47,41 +45,44 @@ object MangaList {
return mangasPage.processEntries(sourceId)
}
fun MangasPage.insertOrUpdate(sourceId: Long): List<Int> {
return transaction {
fun MangasPage.insertOrUpdate(sourceId: Long): List<Int> =
transaction {
val existingMangaUrlsToId =
MangaTable.select {
(MangaTable.sourceReference eq sourceId) and (MangaTable.url inList mangas.map { it.url })
}.associateBy { it[MangaTable.url] }
MangaTable
.select {
(MangaTable.sourceReference eq sourceId) and (MangaTable.url inList mangas.map { it.url })
}.associateBy { it[MangaTable.url] }
val existingMangaUrls = existingMangaUrlsToId.map { it.key }
val mangasToInsert = mangas.filter { !existingMangaUrls.contains(it.url) }
val insertedMangaUrlsToId =
MangaTable.batchInsert(mangasToInsert) {
this[MangaTable.url] = it.url
this[MangaTable.title] = it.title
MangaTable
.batchInsert(mangasToInsert) {
this[MangaTable.url] = it.url
this[MangaTable.title] = it.title
this[MangaTable.artist] = it.artist
this[MangaTable.author] = it.author
this[MangaTable.description] = it.description
this[MangaTable.genre] = it.genre
this[MangaTable.status] = it.status
this[MangaTable.thumbnail_url] = it.thumbnail_url
this[MangaTable.updateStrategy] = it.update_strategy.name
this[MangaTable.artist] = it.artist
this[MangaTable.author] = it.author
this[MangaTable.description] = it.description
this[MangaTable.genre] = it.genre
this[MangaTable.status] = it.status
this[MangaTable.thumbnail_url] = it.thumbnail_url
this[MangaTable.updateStrategy] = it.update_strategy.name
this[MangaTable.sourceReference] = sourceId
}.associate { Pair(it[MangaTable.url], it[MangaTable.id].value) }
this[MangaTable.sourceReference] = sourceId
}.associate { Pair(it[MangaTable.url], it[MangaTable.id].value) }
// delete thumbnail in case cached data still exists
insertedMangaUrlsToId.forEach { (_, id) -> Manga.clearThumbnail(id) }
val mangaToUpdate =
mangas.mapNotNull { sManga ->
existingMangaUrlsToId[sManga.url]?.let { sManga to it }
}.filterNot { (_, resultRow) ->
resultRow[MangaTable.inLibrary]
}
mangas
.mapNotNull { sManga ->
existingMangaUrlsToId[sManga.url]?.let { sManga to it }
}.filterNot { (_, resultRow) ->
resultRow[MangaTable.inLibrary]
}
if (mangaToUpdate.isNotEmpty()) {
BatchUpdateStatement(MangaTable).apply {
@@ -116,7 +117,6 @@ object MangaList {
?: throw Exception("MangaList::insertOrGet($sourceId): Something went wrong inserting browsed source mangas")
}
}
}
fun MangasPage.processEntries(sourceId: Long): PagedMangaListDataClass {
val mangasPage = this

View File

@@ -51,17 +51,20 @@ object Page {
val source = getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
val chapterEntry =
transaction {
ChapterTable.select {
(ChapterTable.sourceOrder eq chapterIndex) and (ChapterTable.manga eq mangaId)
}.first()
ChapterTable
.select {
(ChapterTable.sourceOrder eq chapterIndex) and (ChapterTable.manga eq mangaId)
}.first()
}
val chapterId = chapterEntry[ChapterTable.id].value
val pageEntry =
transaction {
PageTable.select { (PageTable.chapter eq chapterId) }
PageTable
.select { (PageTable.chapter eq chapterId) }
.orderBy(PageTable.index to SortOrder.ASC)
.limit(1, index.toLong()).first()
.limit(1, index.toLong())
.first()
}
val tachiyomiPage =
Page(
@@ -114,7 +117,5 @@ object Page {
}
/** converts 0 to "001" */
fun getPageName(index: Int): String {
return String.format("%03d", index + 1)
}
fun getPageName(index: Int): String = String.format("%03d", index + 1)
}

View File

@@ -95,7 +95,10 @@ object Search {
private fun Filter.Select<*>.getValuesType(): String = values::class.java.componentType!!.simpleName
class SerializableGroup(name: String, state: List<FilterObject>) : Filter<List<FilterObject>>(name, state)
class SerializableGroup(
name: String,
state: List<FilterObject>,
) : Filter<List<FilterObject>>(name, state)
data class FilterObject(
val type: String,

View File

@@ -97,11 +97,10 @@ object Source {
/**
* Gets a source's PreferenceScreen, puts the result into [preferenceScreenMap]
*/
fun getSourcePreferences(sourceId: Long): List<PreferenceObject> {
return getSourcePreferencesRaw(sourceId).map {
fun getSourcePreferences(sourceId: Long): List<PreferenceObject> =
getSourcePreferencesRaw(sourceId).map {
PreferenceObject(it::class.java.simpleName, it)
}
}
fun getSourcePreferencesRaw(sourceId: Long): List<Preference> {
val source = getCatalogueSourceOrStub(sourceId)

View File

@@ -4,20 +4,12 @@ import suwayomi.tachidesk.manga.impl.download.fileProvider.impl.ThumbnailFilePro
import java.io.InputStream
object ThumbnailDownloadHelper {
fun getImage(mangaId: Int): Pair<InputStream, String> {
return provider(mangaId).getImage().execute()
}
fun getImage(mangaId: Int): Pair<InputStream, String> = provider(mangaId).getImage().execute()
fun delete(mangaId: Int): Boolean {
return provider(mangaId).delete()
}
fun delete(mangaId: Int): Boolean = provider(mangaId).delete()
suspend fun download(mangaId: Int): Boolean {
return provider(mangaId).download().execute()
}
suspend fun download(mangaId: Int): Boolean = provider(mangaId).download().execute()
// return the appropriate provider based on how the download was saved. For the logic is simple but will evolve when new types of downloads are available
private fun provider(mangaId: Int): ThumbnailFileProvider {
return ThumbnailFileProvider(mangaId)
}
private fun provider(mangaId: Int): ThumbnailFileProvider = ThumbnailFileProvider(mangaId)
}

View File

@@ -5,7 +5,9 @@ package suwayomi.tachidesk.manga.impl.backup.models
import eu.kanade.tachiyomi.source.model.SChapter
import java.io.Serializable
interface Chapter : SChapter, Serializable {
interface Chapter :
SChapter,
Serializable {
var id: Long?
var manga_id: Long?

View File

@@ -36,7 +36,5 @@ class ChapterImpl : Chapter {
return id == chapter.id
}
override fun hashCode(): Int {
return url.hashCode() + id.hashCode()
}
override fun hashCode(): Int = url.hashCode() + id.hashCode()
}

View File

@@ -41,13 +41,9 @@ interface Manga : SManga {
setChapterFlags(order, CHAPTER_SORT_MASK)
}
fun sortDescending(): Boolean {
return chapter_flags and CHAPTER_SORT_MASK == CHAPTER_SORT_DESC
}
fun sortDescending(): Boolean = chapter_flags and CHAPTER_SORT_MASK == CHAPTER_SORT_DESC
fun getGenres(): List<String>? {
return genre?.split(", ")?.map { it.trim() }
}
fun getGenres(): List<String>? = genre?.split(", ")?.map { it.trim() }
private fun setChapterFlags(
flag: Int,

View File

@@ -63,7 +63,5 @@ open class MangaImpl : Manga {
return id == manga.id
}
override fun hashCode(): Int {
return url.hashCode() + id.hashCode()
}
override fun hashCode(): Int = url.hashCode() + id.hashCode()
}

View File

@@ -93,10 +93,15 @@ object ProtoBackupExport : ProtoBackupBase() {
}
}
val (hour, minute) = serverConfig.backupTime.value.split(":").map { it.toInt() }
val (hour, minute) =
serverConfig.backupTime.value
.split(":")
.map { it.toInt() }
val backupHour = hour.coerceAtLeast(0).coerceAtMost(23)
val backupMinute = minute.coerceAtLeast(0).coerceAtMost(59)
val backupInterval = serverConfig.backupInterval.value.days.coerceAtLeast(1.days)
val backupInterval =
serverConfig.backupInterval.value.days
.coerceAtLeast(1.days)
// trigger last backup in case the server wasn't running on the scheduled time
val lastAutomatedBackup = preferences.getLong(LAST_AUTOMATED_BACKUP_KEY, 0)
@@ -161,7 +166,10 @@ object ProtoBackupExport : ProtoBackupBase() {
val lastAccessTime = file.lastModified()
val isTTLReached =
System.currentTimeMillis() - lastAccessTime >= serverConfig.backupTTL.value.days.coerceAtLeast(1.days).inWholeMilliseconds
System.currentTimeMillis() - lastAccessTime >=
serverConfig.backupTTL.value.days
.coerceAtLeast(1.days)
.inWholeMilliseconds
if (isTTLReached) {
file.delete()
}
@@ -185,7 +193,11 @@ object ProtoBackupExport : ProtoBackupBase() {
val byteArray = parser.encodeToByteArray(BackupSerializer, backup)
val byteStream = ByteArrayOutputStream()
byteStream.sink().gzip().buffer().use { it.write(byteArray) }
byteStream
.sink()
.gzip()
.buffer()
.use { it.write(byteArray) }
return byteStream.toByteArray().inputStream()
}
@@ -193,8 +205,8 @@ object ProtoBackupExport : ProtoBackupBase() {
private fun backupManga(
databaseManga: Query,
flags: BackupFlags,
): List<BackupManga> {
return databaseManga.map { mangaRow ->
): List<BackupManga> =
databaseManga.map { mangaRow ->
val backupManga =
BackupManga(
source = mangaRow[MangaTable.sourceReference],
@@ -216,7 +228,8 @@ object ProtoBackupExport : ProtoBackupBase() {
if (flags.includeChapters) {
val chapters =
transaction {
ChapterTable.select { ChapterTable.manga eq mangaId }
ChapterTable
.select { ChapterTable.manga eq mangaId }
.orderBy(ChapterTable.sourceOrder to SortOrder.DESC)
.map {
ChapterTable.toDataClass(it)
@@ -277,22 +290,23 @@ object ProtoBackupExport : ProtoBackupBase() {
backupManga
}
}
private fun backupCategories(): List<BackupCategory> {
return CategoryTable.selectAll().orderBy(CategoryTable.order to SortOrder.ASC).map {
CategoryTable.toDataClass(it)
}.map {
BackupCategory(
it.name,
it.order,
0, // not supported in Tachidesk
)
}
}
private fun backupCategories(): List<BackupCategory> =
CategoryTable
.selectAll()
.orderBy(CategoryTable.order to SortOrder.ASC)
.map {
CategoryTable.toDataClass(it)
}.map {
BackupCategory(
it.name,
it.order,
0, // not supported in Tachidesk
)
}
private fun backupExtensionInfo(mangas: Query): List<BackupSource> {
return mangas
private fun backupExtensionInfo(mangas: Query): List<BackupSource> =
mangas
.asSequence()
.map { it[MangaTable.sourceReference] }
.distinct()
@@ -302,7 +316,5 @@ object ProtoBackupExport : ProtoBackupBase() {
sourceRow?.get(SourceTable.name) ?: "",
it,
)
}
.toList()
}
}.toList()
}

View File

@@ -74,18 +74,22 @@ object ProtoBackupImport : ProtoBackupBase() {
data object Failure : BackupRestoreState()
data class RestoringCategories(val totalManga: Int) : BackupRestoreState()
data class RestoringCategories(
val totalManga: Int,
) : BackupRestoreState()
data class RestoringManga(val current: Int, val totalManga: Int, val title: String) : BackupRestoreState()
data class RestoringManga(
val current: Int,
val totalManga: Int,
val title: String,
) : BackupRestoreState()
}
private val backupRestoreIdToState = mutableMapOf<String, BackupRestoreState>()
val notifyFlow = MutableSharedFlow<Unit>(extraBufferCapacity = 1, onBufferOverflow = DROP_OLDEST)
fun getRestoreState(id: String): BackupRestoreState? {
return backupRestoreIdToState[id]
}
fun getRestoreState(id: String): BackupRestoreState? = backupRestoreIdToState[id]
private fun updateRestoreState(
id: String,
@@ -131,8 +135,8 @@ object ProtoBackupImport : ProtoBackupBase() {
suspend fun restoreLegacy(
sourceStream: InputStream,
restoreId: String = "legacy",
): ValidationResult {
return backupMutex.withLock {
): ValidationResult =
backupMutex.withLock {
try {
logger.info { "restore($restoreId): restoring..." }
performRestore(restoreId, sourceStream)
@@ -151,13 +155,17 @@ object ProtoBackupImport : ProtoBackupBase() {
cleanupRestoreState(restoreId)
}
}
}
private fun performRestore(
id: String,
sourceStream: InputStream,
): ValidationResult {
val backupString = sourceStream.source().gzip().buffer().use { it.readByteArray() }
val backupString =
sourceStream
.source()
.gzip()
.buffer()
.use { it.readByteArray() }
val backup = parser.decodeFromByteArray(BackupSerializer, backupString)
val validationResult = validate(backup)
@@ -174,7 +182,8 @@ object ProtoBackupImport : ProtoBackupBase() {
transaction {
backup.backupCategories.associate {
val dbCategory =
CategoryTable.select { CategoryTable.name eq it.name }
CategoryTable
.select { CategoryTable.name eq it.name }
.firstOrNull()
val categoryId =
dbCategory?.let { categoryResultRow ->
@@ -265,7 +274,8 @@ object ProtoBackupImport : ProtoBackupBase() {
) {
val dbManga =
transaction {
MangaTable.select { (MangaTable.url eq manga.url) and (MangaTable.sourceReference eq manga.source) }
MangaTable
.select { (MangaTable.url eq manga.url) and (MangaTable.sourceReference eq manga.source) }
.firstOrNull()
}
@@ -274,26 +284,27 @@ object ProtoBackupImport : ProtoBackupBase() {
transaction {
// insert manga to database
val mangaId =
MangaTable.insertAndGetId {
it[url] = manga.url
it[title] = manga.title
MangaTable
.insertAndGetId {
it[url] = manga.url
it[title] = manga.title
it[artist] = manga.artist
it[author] = manga.author
it[description] = manga.description
it[genre] = manga.genre
it[status] = manga.status
it[thumbnail_url] = manga.thumbnail_url
it[updateStrategy] = manga.update_strategy.name
it[artist] = manga.artist
it[author] = manga.author
it[description] = manga.description
it[genre] = manga.genre
it[status] = manga.status
it[thumbnail_url] = manga.thumbnail_url
it[updateStrategy] = manga.update_strategy.name
it[sourceReference] = manga.source
it[sourceReference] = manga.source
it[initialized] = manga.description != null
it[initialized] = manga.description != null
it[inLibrary] = manga.favorite
it[inLibrary] = manga.favorite
it[inLibraryAt] = TimeUnit.MILLISECONDS.toSeconds(manga.date_added)
}.value
it[inLibraryAt] = TimeUnit.MILLISECONDS.toSeconds(manga.date_added)
}.value
// delete thumbnail in case cached data still exists
clearThumbnail(mangaId)
@@ -394,34 +405,36 @@ object ProtoBackupImport : ProtoBackupBase() {
}
val dbTrackRecordsByTrackerId =
Tracker.getTrackRecordsByMangaId(mangaId)
Tracker
.getTrackRecordsByMangaId(mangaId)
.mapNotNull { it.record?.toTrack() }
.associateBy { it.sync_id }
val (existingTracks, newTracks) =
tracks.mapNotNull { backupTrack ->
val track = backupTrack.toTrack(mangaId)
tracks
.mapNotNull { backupTrack ->
val track = backupTrack.toTrack(mangaId)
val isUnsupportedTracker = TrackerManager.getTracker(track.sync_id) == null
if (isUnsupportedTracker) {
return@mapNotNull null
}
val isUnsupportedTracker = TrackerManager.getTracker(track.sync_id) == null
if (isUnsupportedTracker) {
return@mapNotNull null
}
val dbTrack =
dbTrackRecordsByTrackerId[backupTrack.syncId]
?: // new track
return@mapNotNull track
val dbTrack =
dbTrackRecordsByTrackerId[backupTrack.syncId]
?: // new track
return@mapNotNull track
if (track.toTrackRecordDataClass().forComparison() == dbTrack.toTrackRecordDataClass().forComparison()) {
return@mapNotNull null
}
if (track.toTrackRecordDataClass().forComparison() == dbTrack.toTrackRecordDataClass().forComparison()) {
return@mapNotNull null
}
dbTrack.also {
it.media_id = track.media_id
it.library_id = track.library_id
it.last_chapter_read = max(dbTrack.last_chapter_read, track.last_chapter_read)
}
}.partition { (it.id ?: -1) > 0 }
dbTrack.also {
it.media_id = track.media_id
it.library_id = track.library_id
it.last_chapter_read = max(dbTrack.last_chapter_read, track.last_chapter_read)
}
}.partition { (it.id ?: -1) > 0 }
existingTracks.forEach(Tracker::updateTrackRecord)
newTracks.forEach(Tracker::insertTrackRecord)

View File

@@ -64,7 +64,12 @@ object ProtoBackupValidator {
}
fun validate(sourceStream: InputStream): ValidationResult {
val backupString = sourceStream.source().gzip().buffer().use { it.readByteArray() }
val backupString =
sourceStream
.source()
.gzip()
.buffer()
.use { it.readByteArray() }
val backup = ProtoBackupImport.parser.decodeFromByteArray(BackupSerializer, backupString)
return validate(backup)

View File

@@ -14,10 +14,9 @@ data class Backup(
@ProtoNumber(100) var brokenBackupSources: List<BrokenBackupSource> = emptyList(),
@ProtoNumber(101) var backupSources: List<BackupSource> = emptyList(),
) {
fun getSourceMap(): Map<Long, String> {
return (brokenBackupSources.map { BackupSource(it.name, it.sourceId) } + backupSources)
fun getSourceMap(): Map<Long, String> =
(brokenBackupSources.map { BackupSource(it.name, it.sourceId) } + backupSources)
.associate { it.sourceId to it.name }
}
companion object {
fun getBasename(name: String = ""): String {

View File

@@ -21,8 +21,8 @@ data class BackupChapter(
@ProtoNumber(9) var chapterNumber: Float = 0F,
@ProtoNumber(10) var sourceOrder: Int = 0,
) {
fun toChapterImpl(): ChapterImpl {
return ChapterImpl().apply {
fun toChapterImpl(): ChapterImpl =
ChapterImpl().apply {
url = this@BackupChapter.url
name = this@BackupChapter.name
chapter_number = this@BackupChapter.chapterNumber
@@ -34,5 +34,4 @@ data class BackupChapter(
date_upload = this@BackupChapter.dateUpload
source_order = this@BackupChapter.sourceOrder
}
}
}

View File

@@ -39,8 +39,8 @@ data class BackupManga(
@ProtoNumber(104) var history: List<BackupHistory> = emptyList(),
@ProtoNumber(105) var updateStrategy: UpdateStrategy = UpdateStrategy.ALWAYS_UPDATE,
) {
fun getMangaImpl(): MangaImpl {
return MangaImpl().apply {
fun getMangaImpl(): MangaImpl =
MangaImpl().apply {
url = this@BackupManga.url
title = this@BackupManga.title
artist = this@BackupManga.artist
@@ -56,23 +56,20 @@ data class BackupManga(
chapter_flags = this@BackupManga.chapterFlags
update_strategy = this@BackupManga.updateStrategy
}
}
fun getChaptersImpl(): List<ChapterImpl> {
return chapters.map {
fun getChaptersImpl(): List<ChapterImpl> =
chapters.map {
it.toChapterImpl()
}
}
fun getTrackingImpl(): List<TrackImpl> {
return tracking.map {
fun getTrackingImpl(): List<TrackImpl> =
tracking.map {
it.getTrackingImpl()
}
}
companion object {
fun copyFrom(manga: Manga): BackupManga {
return BackupManga(
fun copyFrom(manga: Manga): BackupManga =
BackupManga(
url = manga.url,
title = manga.title,
artist = manga.artist,
@@ -88,6 +85,5 @@ data class BackupManga(
viewer_flags = manga.viewer_flags,
chapterFlags = manga.chapter_flags,
)
}
}
}

View File

@@ -16,11 +16,10 @@ data class BackupSource(
@ProtoNumber(2) var sourceId: Long,
) {
companion object {
fun copyFrom(source: Source): BackupSource {
return BackupSource(
fun copyFrom(source: Source): BackupSource =
BackupSource(
name = source.name,
sourceId = source.id,
)
}
}
}

View File

@@ -28,8 +28,8 @@ data class BackupTracking(
@ProtoNumber(11) var finishedReadingDate: Long = 0,
@ProtoNumber(100) var mediaId: Long = 0,
) {
fun getTrackingImpl(): TrackImpl {
return TrackImpl().apply {
fun getTrackingImpl(): TrackImpl =
TrackImpl().apply {
sync_id = this@BackupTracking.syncId
media_id =
if (this@BackupTracking.mediaIdInt != 0) {
@@ -48,11 +48,10 @@ data class BackupTracking(
finished_reading_date = this@BackupTracking.finishedReadingDate
tracking_url = this@BackupTracking.trackingUrl
}
}
companion object {
fun copyFrom(track: Track): BackupTracking {
return BackupTracking(
fun copyFrom(track: Track): BackupTracking =
BackupTracking(
syncId = track.sync_id,
mediaId = track.media_id,
// forced not null so its compatible with 1.x backup system
@@ -67,6 +66,5 @@ data class BackupTracking(
finishedReadingDate = track.finished_reading_date,
trackingUrl = track.tracking_url,
)
}
}
}

View File

@@ -37,16 +37,12 @@ suspend fun getChapterDownloadReady(
return chapter.asDownloadReady()
}
suspend fun getChapterDownloadReadyById(chapterId: Int): ChapterDataClass {
return getChapterDownloadReady(chapterId = chapterId)
}
suspend fun getChapterDownloadReadyById(chapterId: Int): ChapterDataClass = getChapterDownloadReady(chapterId = chapterId)
suspend fun getChapterDownloadReadyByIndex(
chapterIndex: Int,
mangaId: Int,
): ChapterDataClass {
return getChapterDownloadReady(chapterIndex = chapterIndex, mangaId = mangaId)
}
): ChapterDataClass = getChapterDownloadReady(chapterIndex = chapterIndex, mangaId = mangaId)
private class ChapterForDownload(
optChapterId: Int? = null,
@@ -101,15 +97,16 @@ private class ChapterForDownload(
optChapterIndex: Int? = null,
optMangaId: Int? = null,
) = transaction {
ChapterTable.select {
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()
ChapterTable
.select {
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()
}
private suspend fun fetchPageList(): List<Page> {
@@ -166,12 +163,11 @@ private class ChapterForDownload(
}
}
private fun firstPageExists(): Boolean {
return try {
private fun firstPageExists(): Boolean =
try {
ChapterDownloadHelper.getImage(mangaId, chapterId, 0).first.close()
true
} catch (e: Exception) {
false
}
}
}

View File

@@ -63,12 +63,17 @@ object DownloadManager {
private val sharedPreferences =
Injekt.get<Application>().getSharedPreferences(DownloadManager::class.jvmName, Context.MODE_PRIVATE)
private fun loadDownloadQueue(): List<Int> {
return sharedPreferences.getStringSet(DOWNLOAD_QUEUE_KEY, emptySet())?.mapNotNull { it.toInt() }.orEmpty()
}
private fun loadDownloadQueue(): List<Int> =
sharedPreferences
.getStringSet(DOWNLOAD_QUEUE_KEY, emptySet())
?.mapNotNull {
it.toInt()
}.orEmpty()
private fun saveDownloadQueue() {
sharedPreferences.edit().putStringSet(DOWNLOAD_QUEUE_KEY, downloadQueue.map { it.chapter.id.toString() }.toSet())
sharedPreferences
.edit()
.putStringSet(DOWNLOAD_QUEUE_KEY, downloadQueue.map { it.chapter.id.toString() }.toSet())
.apply()
}
@@ -159,8 +164,8 @@ object DownloadManager {
}
}
private fun getStatus(): DownloadStatus {
return DownloadStatus(
private fun getStatus(): DownloadStatus =
DownloadStatus(
if (downloadQueue.none { it.state == Downloading }) {
Status.Stopped
} else {
@@ -168,7 +173,6 @@ object DownloadManager {
},
downloadQueue.toList(),
)
}
private val downloaderWatch = MutableSharedFlow<Unit>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
@@ -201,13 +205,13 @@ object DownloadManager {
}
if (runningDownloaders.size < serverConfig.maxSourcesInParallel.value) {
availableDownloads.asSequence()
availableDownloads
.asSequence()
.map { it.manga.sourceId }
.distinct()
.minus(
runningDownloaders.map { it.sourceId }.toSet(),
)
.take(serverConfig.maxSourcesInParallel.value - runningDownloaders.size)
).take(serverConfig.maxSourcesInParallel.value - runningDownloaders.size)
.map { getDownloader(it) }
.forEach {
it.start()
@@ -271,7 +275,8 @@ object DownloadManager {
val mangas =
transaction {
chapters.distinctBy { chapter -> chapter[MangaTable.id] }
chapters
.distinctBy { chapter -> chapter[MangaTable.id] }
.map { MangaTable.toDataClass(it) }
.associateBy { it.id }
}
@@ -420,11 +425,12 @@ object DownloadManager {
logger.debug { "stop" }
coroutineScope {
downloaders.map { (_, downloader) ->
async {
downloader.stop()
}
}.awaitAll()
downloaders
.map { (_, downloader) ->
async {
downloader.stop()
}
}.awaitAll()
}
notifyAllClients()
}
@@ -439,7 +445,9 @@ object DownloadManager {
}
}
enum class DownloaderState(val state: Int) {
enum class DownloaderState(
val state: Int,
) {
Stopped(0),
Running(1),
Paused(2),

View File

@@ -69,16 +69,17 @@ class Downloader(
fun start() {
if (!isActive) {
job =
scope.launch {
run()
}.also { job ->
job.invokeOnCompletion {
if (it !is CancellationException) {
logger.debug { "completed" }
onComplete()
scope
.launch {
run()
}.also { job ->
job.invokeOnCompletion {
if (it !is CancellationException) {
logger.debug { "completed" }
onComplete()
}
}
}
}
logger.debug { "started" }
notifier(false)
}

View File

@@ -23,12 +23,16 @@ import java.io.File
import java.io.InputStream
sealed class FileType {
data class RegularFile(val file: File) : FileType()
data class RegularFile(
val file: File,
) : FileType()
data class ZipFile(val entry: ZipArchiveEntry) : FileType()
data class ZipFile(
val entry: ZipArchiveEntry,
) : FileType()
fun getName(): String {
return when (this) {
fun getName(): String =
when (this) {
is FileType.RegularFile -> {
this.file.name
}
@@ -36,10 +40,9 @@ sealed class FileType {
this.entry.name
}
}
}
fun getExtension(): String {
return when (this) {
fun getExtension(): String =
when (this) {
is FileType.RegularFile -> {
this.file.extension
}
@@ -47,13 +50,15 @@ sealed class FileType {
this.entry.name.substringAfterLast(".")
}
}
}
}
/*
* Base class for downloaded chapter files provider, example: Folder, Archive
*/
abstract class ChaptersFilesProvider<Type : FileType>(val mangaId: Int, val chapterId: Int) : DownloadedFilesProvider {
abstract class ChaptersFilesProvider<Type : FileType>(
val mangaId: Int,
val chapterId: Int,
) : DownloadedFilesProvider {
protected abstract fun getImageFiles(): List<Type>
protected abstract fun getImageInputStream(image: Type): InputStream
@@ -71,9 +76,7 @@ abstract class ChaptersFilesProvider<Type : FileType>(val mangaId: Int, val chap
return Pair(getImageInputStream(image).buffered(), "image/$imageFileType")
}
override fun getImage(): RetrieveFile1Args<Int> {
return RetrieveFile1Args(::getImageImpl)
}
override fun getImage(): RetrieveFile1Args<Int> = RetrieveFile1Args(::getImageImpl)
/**
* Extract the existing download to the base download folder (see [getChapterDownloadPath])
@@ -110,21 +113,22 @@ abstract class ChaptersFilesProvider<Type : FileType>(val mangaId: Int, val chap
}
try {
Page.getPageImage(
mangaId = download.mangaId,
chapterIndex = download.chapterIndex,
index = pageNum,
) { flow ->
pageProgressJob =
flow
.sample(100)
.distinctUntilChanged()
.onEach {
download.progress = (pageNum.toFloat() + (it.toFloat() * 0.01f)) / pageCount
step(null, false) // don't throw on canceled download here since we can't do anything
}
.launchIn(scope)
}.first.close()
Page
.getPageImage(
mangaId = download.mangaId,
chapterIndex = download.chapterIndex,
index = pageNum,
) { flow ->
pageProgressJob =
flow
.sample(100)
.distinctUntilChanged()
.onEach {
download.progress = (pageNum.toFloat() + (it.toFloat() * 0.01f)) / pageCount
step(null, false) // don't throw on canceled download here since we can't do anything
}.launchIn(scope)
}.first
.close()
} finally {
// always cancel the page progress job even if it throws an exception to avoid memory leaks
pageProgressJob?.cancel()
@@ -151,9 +155,8 @@ abstract class ChaptersFilesProvider<Type : FileType>(val mangaId: Int, val chap
return true
}
override fun download(): FileDownload3Args<DownloadChapter, CoroutineScope, suspend (DownloadChapter?, Boolean) -> Unit> {
return FileDownload3Args(::downloadImpl)
}
override fun download(): FileDownload3Args<DownloadChapter, CoroutineScope, suspend (DownloadChapter?, Boolean) -> Unit> =
FileDownload3Args(::downloadImpl)
abstract override fun delete(): Boolean
}

View File

@@ -1,5 +1,7 @@
package suwayomi.tachidesk.manga.impl.download.fileProvider
interface DownloadedFilesProvider : FileDownloader, FileRetriever {
interface DownloadedFilesProvider :
FileDownloader,
FileRetriever {
fun delete(): Boolean
}

View File

@@ -7,9 +7,7 @@ fun interface FileDownload {
fun interface FileDownload0Args : FileDownload {
suspend fun execute(): Boolean
override suspend fun executeDownload(vararg args: Any): Boolean {
return execute()
}
override suspend fun executeDownload(vararg args: Any): Boolean = execute()
}
@Suppress("UNCHECKED_CAST")
@@ -20,9 +18,7 @@ fun interface FileDownload3Args<A, B, C> : FileDownload {
c: C,
): Boolean
override suspend fun executeDownload(vararg args: Any): Boolean {
return execute(args[0] as A, args[1] as B, args[2] as C)
}
override suspend fun executeDownload(vararg args: Any): Boolean = execute(args[0] as A, args[1] as B, args[2] as C)
}
fun interface FileDownloader {

View File

@@ -9,18 +9,14 @@ fun interface RetrieveFile {
fun interface RetrieveFile0Args : RetrieveFile {
fun execute(): Pair<InputStream, String>
override fun executeGetImage(vararg args: Any): Pair<InputStream, String> {
return execute()
}
override fun executeGetImage(vararg args: Any): Pair<InputStream, String> = execute()
}
@Suppress("UNCHECKED_CAST")
fun interface RetrieveFile1Args<A> : RetrieveFile {
fun execute(a: A): Pair<InputStream, String>
override fun executeGetImage(vararg args: Any): Pair<InputStream, String> {
return execute(args[0] as A)
}
override fun executeGetImage(vararg args: Any): Pair<InputStream, String> = execute(args[0] as A)
}
fun interface FileRetriever {

View File

@@ -21,15 +21,21 @@ import java.io.InputStream
private val applicationDirs by DI.global.instance<ApplicationDirs>()
class ArchiveProvider(mangaId: Int, chapterId: Int) : ChaptersFilesProvider<FileType.ZipFile>(mangaId, chapterId) {
class ArchiveProvider(
mangaId: Int,
chapterId: Int,
) : ChaptersFilesProvider<FileType.ZipFile>(mangaId, chapterId) {
override fun getImageFiles(): List<FileType.ZipFile> {
val zipFile = ZipFile(getChapterCbzPath(mangaId, chapterId))
val zipFile = ZipFile.builder().setFile(getChapterCbzPath(mangaId, chapterId)).get()
return zipFile.entries.toList().map { FileType.ZipFile(it) }
}
override fun getImageInputStream(image: FileType.ZipFile): InputStream {
return ZipFile(getChapterCbzPath(mangaId, chapterId)).getInputStream(image.entry)
}
override fun getImageInputStream(image: FileType.ZipFile): InputStream =
ZipFile
.builder()
.setFile(getChapterCbzPath(mangaId, chapterId))
.get()
.getInputStream(image.entry)
override fun extractExistingDownload() {
val outputFile = File(getChapterCbzPath(mangaId, chapterId))

View File

@@ -17,7 +17,10 @@ private val applicationDirs by DI.global.instance<ApplicationDirs>()
/*
* Provides downloaded files when pages were downloaded into folders
* */
class FolderProvider(mangaId: Int, chapterId: Int) : ChaptersFilesProvider<RegularFile>(mangaId, chapterId) {
class FolderProvider(
mangaId: Int,
chapterId: Int,
) : ChaptersFilesProvider<RegularFile>(mangaId, chapterId) {
override fun getImageFiles(): List<RegularFile> {
val chapterFolder = File(getChapterDownloadPath(mangaId, chapterId))
@@ -25,12 +28,14 @@ class FolderProvider(mangaId: Int, chapterId: Int) : ChaptersFilesProvider<Regul
throw Exception("download folder does not exist")
}
return chapterFolder.listFiles().orEmpty().toList().map(::RegularFile)
return chapterFolder
.listFiles()
.orEmpty()
.toList()
.map(::RegularFile)
}
override fun getImageInputStream(image: RegularFile): FileInputStream {
return FileInputStream(image.file)
}
override fun getImageInputStream(image: RegularFile): FileInputStream = FileInputStream(image.file)
override fun extractExistingDownload() {
// nothing to do

View File

@@ -18,7 +18,9 @@ class MissingThumbnailException : Exception("No thumbnail found")
private val applicationDirs by DI.global.instance<ApplicationDirs>()
class ThumbnailFileProvider(val mangaId: Int) : DownloadedFilesProvider {
class ThumbnailFileProvider(
val mangaId: Int,
) : DownloadedFilesProvider {
private fun getFilePath(): String? {
val thumbnailDir = applicationDirs.thumbnailDownloadsRoot
val fileName = mangaId.toString()
@@ -36,9 +38,7 @@ class ThumbnailFileProvider(val mangaId: Int) : DownloadedFilesProvider {
return getCachedImageResponse(filePath, filePathWithoutExt)
}
override fun getImage(): RetrieveFile0Args {
return RetrieveFile0Args(::getImageImpl)
}
override fun getImage(): RetrieveFile0Args = RetrieveFile0Args(::getImageImpl)
private suspend fun downloadImpl(): Boolean {
val isExistingFile = getFilePath() != null
@@ -55,9 +55,7 @@ class ThumbnailFileProvider(val mangaId: Int) : DownloadedFilesProvider {
return true
}
override fun download(): FileDownload0Args {
return FileDownload0Args(::downloadImpl)
}
override fun download(): FileDownload0Args = FileDownload0Args(::downloadImpl)
override fun delete(): Boolean {
val filePath = getFilePath()

View File

@@ -20,7 +20,6 @@ class DownloadChapter(
var progress: Float = 0f,
var tries: Int = 0,
) {
override fun toString(): String {
return "${manga.title} ($mangaId) - ${chapter.name} (${chapter.id}) | state= $state, tries= $tries, progress= $progress"
}
override fun toString(): String =
"${manga.title} ($mangaId) - ${chapter.name} (${chapter.id}) | state= $state, tries= $tries, progress= $progress"
}

View File

@@ -7,7 +7,9 @@ package suwayomi.tachidesk.manga.impl.download.model
* 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/. */
enum class DownloadState(val state: Int) {
enum class DownloadState(
val state: Int,
) {
Queued(0),
Downloading(1),
Finished(2),

View File

@@ -78,8 +78,8 @@ object Extension {
suspend fun installExternalExtension(
inputStream: InputStream,
apkName: String,
): Int {
return installAPK(true) {
): Int =
installAPK(true) {
val savePath = "${applicationDirs.extensionsRoot}/$apkName"
logger.debug { "Saving apk at $apkName" }
// download apk file
@@ -92,7 +92,6 @@ object Extension {
}
savePath
}
}
suspend fun installAPK(
forceReinstall: Boolean = false,
@@ -174,7 +173,10 @@ object Extension {
else -> "all"
}
val extensionName = packageInfo.applicationInfo.nonLocalizedLabel.toString().substringAfter("Tachiyomi: ")
val extensionName =
packageInfo.applicationInfo.nonLocalizedLabel
.toString()
.substringAfter("Tachiyomi: ")
// update extension info
transaction {
@@ -277,9 +279,10 @@ object Extension {
savePath: String,
) {
val response =
network.client.newCall(
GET(url, cache = CacheControl.FORCE_NETWORK),
).await()
network.client
.newCall(
GET(url, cache = CacheControl.FORCE_NETWORK),
).await()
val downloadedFile = File(savePath)
downloadedFile.sink().buffer().use { sink ->
@@ -355,13 +358,12 @@ object Extension {
val cacheSaveDir = "${applicationDirs.extensionsRoot}/icon"
return getImageResponse(cacheSaveDir, apkName) {
network.client.newCall(
GET(iconUrl, cache = CacheControl.FORCE_NETWORK),
).await()
network.client
.newCall(
GET(iconUrl, cache = CacheControl.FORCE_NETWORK),
).await()
}
}
fun getExtensionIconUrl(apkName: String): String {
return "/api/v1/extension/icon/$apkName"
}
fun getExtensionIconUrl(apkName: String): String = "/api/v1/extension/icon/$apkName"
}

View File

@@ -39,13 +39,14 @@ object ExtensionsList {
// update if 60 seconds has passed or requested offline and database is empty
val extensions =
serverConfig.extensionRepos.value.map { repo ->
kotlin.runCatching {
ExtensionGithubApi.findExtensions(repo.repoUrlReplace())
}.onFailure {
logger.warn(it) {
"Failed to fetch extensions for repo: $repo"
kotlin
.runCatching {
ExtensionGithubApi.findExtensions(repo.repoUrlReplace())
}.onFailure {
logger.warn(it) {
"Failed to fetch extensions for repo: $repo"
}
}
}
}
val foundExtensions = extensions.mapNotNull { it.getOrNull() }.flatten()
updateExtensionDatabase(foundExtensions)
@@ -94,12 +95,15 @@ object ExtensionsList {
updateExtensionDatabaseMutex.withLock {
transaction {
val uniqueExtensions =
foundExtensions.groupBy { it.pkgName }.mapValues {
(_, extension) ->
extension.maxBy { it.versionCode }
}.values
foundExtensions
.groupBy { it.pkgName }
.mapValues { (_, extension) ->
extension.maxBy { it.versionCode }
}.values
val installedExtensions =
ExtensionTable.selectAll().toList()
ExtensionTable
.selectAll()
.toList()
.associateBy { it[ExtensionTable.pkgName] }
val extensionsToUpdate = mutableListOf<Pair<OnlineExtension, ResultRow>>()
val extensionsToInsert = mutableListOf<OnlineExtension>()
@@ -189,7 +193,8 @@ object ExtensionsList {
// deal with obsolete extensions
val extensionsToRemove =
extensionsToDelete.groupBy { it[ExtensionTable.isInstalled] }
extensionsToDelete
.groupBy { it[ExtensionTable.isInstalled] }
.mapValues { (_, extensions) -> extensions.map { it[ExtensionTable.pkgName] } }
// not in the repo, so these extensions are obsolete
val obsoleteExtensions = extensionsToRemove[true].orEmpty()
@@ -207,8 +212,8 @@ object ExtensionsList {
}
}
private fun String.repoUrlReplace(): String {
return if (contains("github")) {
private fun String.repoUrlReplace(): String =
if (contains("github")) {
replace(repoMatchRegex) {
"https://raw.githubusercontent.com/${it.groupValues[2]}/${it.groupValues[3]}/" +
(it.groupValues.getOrNull(4)?.ifBlank { null } ?: "repo") +
@@ -218,7 +223,6 @@ object ExtensionsList {
} else {
this
}
}
private val repoMatchRegex =
(

View File

@@ -58,29 +58,27 @@ object ExtensionGithubApi {
fun getApkUrl(
repo: String,
apkName: String,
): String {
return "${repo}apk/$apkName"
}
): String = "${repo}apk/$apkName"
private val client by lazy {
val network: NetworkHelper by injectLazy()
network.client.newBuilder()
network.client
.newBuilder()
.addNetworkInterceptor { chain ->
val originalResponse = chain.proceed(chain.request())
originalResponse.newBuilder()
originalResponse
.newBuilder()
.header("Content-Type", "application/json")
.build()
}
.build()
}.build()
}
private fun List<ExtensionJsonObject>.toExtensions(repo: String): List<OnlineExtension> {
return this
private fun List<ExtensionJsonObject>.toExtensions(repo: String): List<OnlineExtension> =
this
.filter {
val libVersion = it.version.substringBeforeLast('.').toDouble()
libVersion in LIB_VERSION_MIN..LIB_VERSION_MAX
}
.map {
}.map {
OnlineExtension(
repo = repo,
name = it.name.substringAfter("Tachiyomi: "),
@@ -96,10 +94,9 @@ object ExtensionGithubApi {
iconUrl = "${repo}icon/${it.pkg}.png",
)
}
}
private fun List<ExtensionSourceJsonObject>.toExtensionSources(): List<OnlineExtensionSource> {
return this.map {
private fun List<ExtensionSourceJsonObject>.toExtensionSources(): List<OnlineExtensionSource> =
this.map {
OnlineExtensionSource(
name = it.name,
lang = it.lang,
@@ -107,5 +104,4 @@ object ExtensionGithubApi {
baseUrl = it.baseUrl,
)
}
}
}

View File

@@ -63,9 +63,7 @@ object Track {
tracker.logout()
}
fun proxyThumbnailUrl(trackerId: Int): String {
return "/api/v1/track/$trackerId/thumbnail"
}
fun proxyThumbnailUrl(trackerId: Int): String = "/api/v1/track/$trackerId/thumbnail"
fun getTrackerThumbnail(trackerId: Int): Pair<InputStream, String> {
val tracker = TrackerManager.getTracker(trackerId)!!
@@ -76,7 +74,8 @@ object Track {
fun getTrackRecordsByMangaId(mangaId: Int): List<MangaTrackerDataClass> {
val recordMap =
transaction {
TrackRecordTable.select { TrackRecordTable.mangaId eq mangaId }
TrackRecordTable
.select { TrackRecordTable.mangaId eq mangaId }
.map { it.toTrackRecordDataClass() }
}.associateBy { it.trackerId }
@@ -138,10 +137,12 @@ object Track {
) {
val track =
transaction {
TrackSearchTable.select {
TrackSearchTable.trackerId eq trackerId and
(TrackSearchTable.remoteId eq remoteId)
}.first().toTrack(mangaId)
TrackSearchTable
.select {
TrackSearchTable.trackerId eq trackerId and
(TrackSearchTable.remoteId eq remoteId)
}.first()
.toTrack(mangaId)
}
val tracker = TrackerManager.getTracker(trackerId)!!
@@ -160,10 +161,10 @@ object Track {
if (track.started_reading_date <= 0) {
val oldestChapter =
transaction {
ChapterTable.select {
(ChapterTable.manga eq mangaId) and (ChapterTable.isRead eq true)
}
.orderBy(ChapterTable.lastReadAt to SortOrder.ASC)
ChapterTable
.select {
(ChapterTable.manga eq mangaId) and (ChapterTable.isRead eq true)
}.orderBy(ChapterTable.lastReadAt to SortOrder.ASC)
.limit(1)
.firstOrNull()
}
@@ -290,14 +291,14 @@ object Track {
}
}
private fun queryMaxReadChapter(mangaId: Int): ResultRow? {
return transaction {
ChapterTable.select { (ChapterTable.manga eq mangaId) and (ChapterTable.isRead eq true) }
private fun queryMaxReadChapter(mangaId: Int): ResultRow? =
transaction {
ChapterTable
.select { (ChapterTable.manga eq mangaId) and (ChapterTable.isRead eq true) }
.orderBy(ChapterTable.chapter_number to SortOrder.DESC)
.limit(1)
.firstOrNull()
}
}
private suspend fun trackChapter(
mangaId: Int,
@@ -305,7 +306,8 @@ object Track {
) {
val records =
transaction {
TrackRecordTable.select { TrackRecordTable.mangaId eq mangaId }
TrackRecordTable
.select { TrackRecordTable.mangaId eq mangaId }
.toList()
}
@@ -313,7 +315,8 @@ object Track {
try {
trackChapterForTracker(it, chapterNumber)
} catch (e: Exception) {
KotlinLogging.logger("${logger.name}::trackChapter(mangaId= $mangaId, chapterNumber= $chapterNumber)")
KotlinLogging
.logger("${logger.name}::trackChapter(mangaId= $mangaId, chapterNumber= $chapterNumber)")
.error(e) { "failed due to" }
}
}
@@ -358,14 +361,14 @@ object Track {
}
}
fun upsertTrackRecord(track: Track): Int {
return transaction {
fun upsertTrackRecord(track: Track): Int =
transaction {
val existingRecord =
TrackRecordTable.select {
(TrackRecordTable.mangaId eq track.manga_id) and
(TrackRecordTable.trackerId eq track.sync_id)
}
.singleOrNull()
TrackRecordTable
.select {
(TrackRecordTable.mangaId eq track.manga_id) and
(TrackRecordTable.trackerId eq track.sync_id)
}.singleOrNull()
if (existingRecord != null) {
updateTrackRecord(track)
@@ -374,7 +377,6 @@ object Track {
insertTrackRecord(track)
}
}
}
fun updateTrackRecord(track: Track): Int =
transaction {
@@ -399,20 +401,21 @@ object Track {
fun insertTrackRecord(track: Track): Int =
transaction {
TrackRecordTable.insertAndGetId {
it[mangaId] = track.manga_id
it[trackerId] = track.sync_id
it[remoteId] = track.media_id
it[libraryId] = track.library_id
it[title] = track.title
it[lastChapterRead] = track.last_chapter_read.toDouble()
it[totalChapters] = track.total_chapters
it[status] = track.status
it[score] = track.score.toDouble()
it[remoteUrl] = track.tracking_url
it[startDate] = track.started_reading_date
it[finishDate] = track.finished_reading_date
}.value
TrackRecordTable
.insertAndGetId {
it[mangaId] = track.manga_id
it[trackerId] = track.sync_id
it[remoteId] = track.media_id
it[libraryId] = track.library_id
it[title] = track.title
it[lastChapterRead] = track.last_chapter_read.toDouble()
it[totalChapters] = track.total_chapters
it[status] = track.status
it[score] = track.score.toDouble()
it[remoteUrl] = track.tracking_url
it[startDate] = track.started_reading_date
it[finishDate] = track.finished_reading_date
}.value
}
@Serializable

Some files were not shown because too many files have changed in this diff Show More