Improve source handling, fix errors with uninitialized mangas in broken sources (#319)
This commit is contained in:
@@ -29,7 +29,7 @@ object SourceController {
|
||||
/** fetch source with id `sourceId` */
|
||||
fun retrieve(ctx: Context) {
|
||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||
ctx.json(Source.getSource(sourceId))
|
||||
ctx.json(Source.getSource(sourceId)!!)
|
||||
}
|
||||
|
||||
/** popular mangas from source with id `sourceId` */
|
||||
|
||||
@@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.local.LocalSource
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.select
|
||||
@@ -23,6 +24,7 @@ import suwayomi.tachidesk.manga.impl.MangaList.proxyThumbnailUrl
|
||||
import suwayomi.tachidesk.manga.impl.Source.getSource
|
||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||
import suwayomi.tachidesk.manga.impl.util.network.await
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrNull
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.clearCachedImage
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.getImageResponse
|
||||
@@ -50,30 +52,10 @@ object Manga {
|
||||
var mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
|
||||
|
||||
return if (mangaEntry[MangaTable.initialized] && !onlineFetch) {
|
||||
MangaDataClass(
|
||||
mangaId,
|
||||
mangaEntry[MangaTable.sourceReference].toString(),
|
||||
|
||||
mangaEntry[MangaTable.url],
|
||||
mangaEntry[MangaTable.title],
|
||||
proxyThumbnailUrl(mangaId),
|
||||
|
||||
true,
|
||||
|
||||
mangaEntry[MangaTable.artist],
|
||||
mangaEntry[MangaTable.author],
|
||||
mangaEntry[MangaTable.description],
|
||||
mangaEntry[MangaTable.genre].toGenreList(),
|
||||
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
|
||||
mangaEntry[MangaTable.inLibrary],
|
||||
mangaEntry[MangaTable.inLibraryAt],
|
||||
getSource(mangaEntry[MangaTable.sourceReference]),
|
||||
getMangaMetaMap(mangaId),
|
||||
mangaEntry[MangaTable.realUrl],
|
||||
false
|
||||
)
|
||||
getMangaDataClass(mangaId, mangaEntry)
|
||||
} else { // initialize manga
|
||||
val source = getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
val source = getCatalogueSourceOrNull(mangaEntry[MangaTable.sourceReference])
|
||||
?: return getMangaDataClass(mangaId, mangaEntry)
|
||||
val sManga = SManga.create().apply {
|
||||
url = mangaEntry[MangaTable.url]
|
||||
title = mangaEntry[MangaTable.title]
|
||||
@@ -135,6 +117,29 @@ object Manga {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMangaDataClass(mangaId: Int, mangaEntry: ResultRow) = MangaDataClass(
|
||||
mangaId,
|
||||
mangaEntry[MangaTable.sourceReference].toString(),
|
||||
|
||||
mangaEntry[MangaTable.url],
|
||||
mangaEntry[MangaTable.title],
|
||||
proxyThumbnailUrl(mangaId),
|
||||
|
||||
true,
|
||||
|
||||
mangaEntry[MangaTable.artist],
|
||||
mangaEntry[MangaTable.author],
|
||||
mangaEntry[MangaTable.description],
|
||||
mangaEntry[MangaTable.genre].toGenreList(),
|
||||
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
|
||||
mangaEntry[MangaTable.inLibrary],
|
||||
mangaEntry[MangaTable.inLibraryAt],
|
||||
getSource(mangaEntry[MangaTable.sourceReference]),
|
||||
getMangaMetaMap(mangaId),
|
||||
mangaEntry[MangaTable.realUrl],
|
||||
false
|
||||
)
|
||||
|
||||
fun getMangaMetaMap(manga: Int): Map<String, String> {
|
||||
return transaction {
|
||||
MangaMetaTable.select { MangaMetaTable.ref eq manga }
|
||||
|
||||
@@ -21,10 +21,9 @@ import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import suwayomi.tachidesk.manga.impl.extension.Extension.getExtensionIconUrl
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrNull
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.unregisterCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.StubSource
|
||||
import suwayomi.tachidesk.manga.model.dataclass.SourceDataClass
|
||||
import suwayomi.tachidesk.manga.model.table.ExtensionTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceTable
|
||||
@@ -38,8 +37,7 @@ object Source {
|
||||
fun getSourceList(): List<SourceDataClass> {
|
||||
return transaction {
|
||||
SourceTable.selectAll().mapNotNull {
|
||||
val catalogueSource = getCatalogueSourceOrStub(it[SourceTable.id].value)
|
||||
if (catalogueSource is StubSource) return@mapNotNull null
|
||||
val catalogueSource = getCatalogueSourceOrNull(it[SourceTable.id].value) ?: return@mapNotNull null
|
||||
val sourceExtension = ExtensionTable.select { ExtensionTable.id eq it[SourceTable.extension] }.first()
|
||||
|
||||
SourceDataClass(
|
||||
@@ -56,27 +54,23 @@ object Source {
|
||||
}
|
||||
}
|
||||
|
||||
fun getSource(sourceId: Long): SourceDataClass { // all the data extracted fresh form the source instance
|
||||
fun getSource(sourceId: Long): SourceDataClass? { // all the data extracted fresh form the source instance
|
||||
return transaction {
|
||||
val source = SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()
|
||||
val catalogueSource = source?.let { getCatalogueSource(sourceId) }
|
||||
val extension = source?.let {
|
||||
ExtensionTable.select { ExtensionTable.id eq source[SourceTable.extension] }.first()
|
||||
}
|
||||
val source = SourceTable.select { SourceTable.id eq sourceId }.firstOrNull() ?: return@transaction null
|
||||
val catalogueSource = getCatalogueSourceOrNull(sourceId) ?: return@transaction null
|
||||
val extension = ExtensionTable.select { ExtensionTable.id eq source[SourceTable.extension] }.first()
|
||||
|
||||
SourceDataClass(
|
||||
sourceId.toString(),
|
||||
source?.get(SourceTable.name),
|
||||
source?.get(SourceTable.lang),
|
||||
source?.let {
|
||||
getExtensionIconUrl(
|
||||
extension!![ExtensionTable.apkName]
|
||||
)
|
||||
},
|
||||
catalogueSource?.supportsLatest,
|
||||
catalogueSource?.let { it is ConfigurableSource },
|
||||
source?.get(SourceTable.isNsfw),
|
||||
catalogueSource?.toString()
|
||||
source[SourceTable.name],
|
||||
source[SourceTable.lang],
|
||||
getExtensionIconUrl(
|
||||
extension[ExtensionTable.apkName]
|
||||
),
|
||||
catalogueSource.supportsLatest,
|
||||
catalogueSource is ConfigurableSource,
|
||||
source[SourceTable.isNsfw],
|
||||
catalogueSource.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -26,7 +26,7 @@ object GetCatalogueSource {
|
||||
private val sourceCache = ConcurrentHashMap<Long, CatalogueSource>()
|
||||
private val applicationDirs by DI.global.instance<ApplicationDirs>()
|
||||
|
||||
fun getCatalogueSource(sourceId: Long): CatalogueSource? {
|
||||
private fun getCatalogueSource(sourceId: Long): CatalogueSource? {
|
||||
val cachedResult: CatalogueSource? = sourceCache[sourceId]
|
||||
if (cachedResult != null) {
|
||||
return cachedResult
|
||||
@@ -56,8 +56,12 @@ object GetCatalogueSource {
|
||||
return sourceCache[sourceId]!!
|
||||
}
|
||||
|
||||
fun getCatalogueSourceOrNull(sourceId: Long): CatalogueSource? {
|
||||
return runCatching { getCatalogueSource(sourceId) }.getOrNull()
|
||||
}
|
||||
|
||||
fun getCatalogueSourceOrStub(sourceId: Long): CatalogueSource {
|
||||
return runCatching { getCatalogueSource(sourceId) }.getOrNull() ?: StubSource(sourceId)
|
||||
return getCatalogueSourceOrNull(sourceId) ?: StubSource(sourceId)
|
||||
}
|
||||
|
||||
fun registerCatalogueSource(sourcePair: Pair<Long, CatalogueSource>) {
|
||||
|
||||
@@ -11,19 +11,19 @@ import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
|
||||
data class SourceDataClass(
|
||||
val id: String,
|
||||
val name: String?,
|
||||
val lang: String?,
|
||||
val iconUrl: String?,
|
||||
val name: String,
|
||||
val lang: String,
|
||||
val iconUrl: String,
|
||||
|
||||
/** The Source provides a latest listing */
|
||||
val supportsLatest: Boolean?,
|
||||
val supportsLatest: Boolean,
|
||||
|
||||
/** The Source implements [ConfigurableSource] */
|
||||
val isConfigurable: Boolean?,
|
||||
val isConfigurable: Boolean,
|
||||
|
||||
/** The Source class has a @Nsfw annotation */
|
||||
val isNsfw: Boolean?,
|
||||
val isNsfw: Boolean,
|
||||
|
||||
/** A nicer version of [name] */
|
||||
val displayName: String?,
|
||||
val displayName: String,
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@ import suwayomi.tachidesk.manga.impl.extension.Extension.uninstallExtension
|
||||
import suwayomi.tachidesk.manga.impl.extension.Extension.updateExtension
|
||||
import suwayomi.tachidesk.manga.impl.extension.ExtensionsList.getExtensionList
|
||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrNull
|
||||
import suwayomi.tachidesk.manga.model.dataclass.ExtensionDataClass
|
||||
import suwayomi.tachidesk.server.applicationSetup
|
||||
import suwayomi.tachidesk.test.BASE_PATH
|
||||
@@ -72,7 +72,7 @@ class TestExtensionCompatibility {
|
||||
}
|
||||
}
|
||||
}
|
||||
sources = getSourceList().map { getCatalogueSource(it.id.toLong())!! as HttpSource }
|
||||
sources = getSourceList().map { getCatalogueSourceOrNull(it.id.toLong())!! as HttpSource }
|
||||
}
|
||||
setLoggingEnabled(true)
|
||||
File("$BASE_PATH/sources.txt").writeText(sources.joinToString("\n") { "${it.name} - ${it.lang.uppercase()} - ${it.id}" })
|
||||
|
||||
Reference in New Issue
Block a user