mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-04 03:14:40 -05:00
add Local Source
This commit is contained in:
@@ -75,7 +75,7 @@ object Manga {
|
||||
|
||||
transaction {
|
||||
MangaTable.update({ MangaTable.id eq mangaId }) {
|
||||
|
||||
it[MangaTable.title] = fetchedManga.title
|
||||
it[MangaTable.initialized] = true
|
||||
|
||||
it[MangaTable.artist] = fetchedManga.artist
|
||||
@@ -86,7 +86,11 @@ object Manga {
|
||||
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url.orEmpty().isNotEmpty())
|
||||
it[MangaTable.thumbnail_url] = fetchedManga.thumbnail_url
|
||||
|
||||
it[MangaTable.realUrl] = try { source.mangaDetailsRequest(sManga).url.toString() } catch (e: Exception) { null }
|
||||
it[MangaTable.realUrl] = try {
|
||||
source.mangaDetailsRequest(sManga).url.toString()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,14 +155,20 @@ object Manga {
|
||||
val fileName = mangaId.toString()
|
||||
|
||||
return getCachedImageResponse(saveDir, fileName) {
|
||||
getManga(mangaId) // make sure is initialized
|
||||
|
||||
val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }
|
||||
|
||||
val sourceId = mangaEntry[MangaTable.sourceReference]
|
||||
val source = getHttpSource(sourceId)
|
||||
|
||||
val thumbnailUrl = mangaEntry[MangaTable.thumbnail_url]!!
|
||||
val thumbnailUrl: String = mangaEntry[MangaTable.thumbnail_url]
|
||||
?: if (!mangaEntry[MangaTable.initialized]) {
|
||||
// initialize then try again
|
||||
getManga(mangaId)
|
||||
transaction { MangaTable.select { MangaTable.id eq mangaId }.first() }[MangaTable.thumbnail_url]!!
|
||||
} else {
|
||||
// source provides no thumbnail url for this manga
|
||||
throw NullPointerException()
|
||||
}
|
||||
|
||||
source.client.newCall(
|
||||
GET(thumbnailUrl, source.headers)
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.getPreferenceKey
|
||||
import mu.KotlinLogging
|
||||
import org.jetbrains.exposed.sql.select
|
||||
@@ -45,7 +46,8 @@ object Source {
|
||||
getExtensionIconUrl(sourceExtension[ExtensionTable.apkName]),
|
||||
httpSource.supportsLatest,
|
||||
httpSource is ConfigurableSource,
|
||||
it[SourceTable.isNsfw]
|
||||
it[SourceTable.isNsfw],
|
||||
httpSource.toString(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -53,6 +55,11 @@ object Source {
|
||||
|
||||
fun getSource(sourceId: Long): SourceDataClass { // all the data extracted fresh form the source instance
|
||||
return transaction {
|
||||
if (sourceId == LocalSource.ID) {
|
||||
// initialize local source
|
||||
getHttpSource(sourceId)
|
||||
}
|
||||
|
||||
val source = SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()
|
||||
val httpSource = source?.let { getHttpSource(sourceId) }
|
||||
val extension = source?.let {
|
||||
@@ -70,7 +77,8 @@ object Source {
|
||||
},
|
||||
httpSource?.supportsLatest,
|
||||
httpSource?.let { it is ConfigurableSource },
|
||||
source?.get(SourceTable.isNsfw)
|
||||
source?.get(SourceTable.isNsfw),
|
||||
httpSource?.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,8 +268,8 @@ object Extension {
|
||||
}
|
||||
|
||||
suspend fun getExtensionIcon(apkName: String): Pair<InputStream, String> {
|
||||
val iconUrl =
|
||||
transaction { ExtensionTable.select { ExtensionTable.apkName eq apkName }.first() }[ExtensionTable.iconUrl]
|
||||
val iconUrl = if (apkName == "localSource") ""
|
||||
else transaction { ExtensionTable.select { ExtensionTable.apkName eq apkName }.first() }[ExtensionTable.iconUrl]
|
||||
|
||||
val saveDir = "${applicationDirs.extensionsRoot}/icon"
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ package suwayomi.tachidesk.manga.impl.extension
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import mu.KotlinLogging
|
||||
import org.jetbrains.exposed.sql.deleteWhere
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
@@ -46,7 +47,7 @@ object ExtensionsList {
|
||||
}
|
||||
|
||||
fun extensionTableAsDataClass() = transaction {
|
||||
ExtensionTable.selectAll().map {
|
||||
ExtensionTable.selectAll().filter { it[ExtensionTable.name] != LocalSource.EXTENSION_NAME }.map {
|
||||
ExtensionDataClass(
|
||||
it[ExtensionTable.apkName],
|
||||
getExtensionIconUrl(it[ExtensionTable.apkName]),
|
||||
|
||||
@@ -7,6 +7,7 @@ package suwayomi.tachidesk.manga.impl.util
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
@@ -35,6 +36,10 @@ object GetHttpSource {
|
||||
SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()!!
|
||||
}
|
||||
|
||||
if (sourceId == LocalSource.ID) {
|
||||
return LocalSource()
|
||||
}
|
||||
|
||||
val extensionId = sourceRecord[SourceTable.extension]
|
||||
val extensionRecord = transaction {
|
||||
ExtensionTable.select { ExtensionTable.id eq extensionId }.first()
|
||||
|
||||
@@ -23,4 +23,6 @@ data class SourceDataClass(
|
||||
|
||||
/** The Source class has a @Nsfw annotation */
|
||||
val isNsfw: Boolean?,
|
||||
|
||||
val displayName: String?,
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ object ExtensionTable : IntIdTable() {
|
||||
val pkgName = varchar("pkg_name", 128)
|
||||
val versionName = varchar("version_name", 16)
|
||||
val versionCode = integer("version_code")
|
||||
val lang = varchar("lang", 10)
|
||||
val lang = varchar("lang", 32)
|
||||
val isNsfw = bool("is_nsfw")
|
||||
|
||||
val isInstalled = bool("is_installed").default(false)
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.jetbrains.exposed.dao.id.IdTable
|
||||
object SourceTable : IdTable<Long>() {
|
||||
override val id = long("id").entityId()
|
||||
val name = varchar("name", 128)
|
||||
val lang = varchar("lang", 10)
|
||||
val lang = varchar("lang", 32)
|
||||
val extension = reference("extension", ExtensionTable)
|
||||
val isNsfw = bool("is_nsfw").default(false)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package suwayomi.tachidesk.server
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import mu.KotlinLogging
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.bind
|
||||
@@ -33,6 +34,7 @@ class ApplicationDirs(
|
||||
val mangaThumbnailsRoot = "$dataRoot/manga-thumbnails"
|
||||
val animeThumbnailsRoot = "$dataRoot/anime-thumbnails"
|
||||
val mangaRoot = "$dataRoot/manga"
|
||||
val localMangaRoot = "$dataRoot/manga-local"
|
||||
val webUIRoot = "$dataRoot/webUI"
|
||||
}
|
||||
|
||||
@@ -63,6 +65,8 @@ fun applicationSetup() {
|
||||
applicationDirs.extensionsRoot + "/icon",
|
||||
applicationDirs.mangaThumbnailsRoot,
|
||||
applicationDirs.animeThumbnailsRoot,
|
||||
applicationDirs.mangaRoot,
|
||||
applicationDirs.localMangaRoot,
|
||||
).forEach {
|
||||
File(it).mkdirs()
|
||||
}
|
||||
@@ -96,11 +100,27 @@ fun applicationSetup() {
|
||||
logger.error("Exception while creating initial server.conf:\n", e)
|
||||
}
|
||||
|
||||
// copy local source icon
|
||||
try {
|
||||
val localSourceIconFile = File("${applicationDirs.extensionsRoot}/icon/localSource.png")
|
||||
if (!localSourceIconFile.exists()) {
|
||||
JavalinSetup::class.java.getResourceAsStream("/icon/localSource.png").use { input ->
|
||||
localSourceIconFile.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("Exception while creating initial server.conf:\n", e)
|
||||
}
|
||||
|
||||
// fixes #119 , ref: https://github.com/Suwayomi/Tachidesk-Server/issues/119#issuecomment-894681292 , source Id calculation depends on String.lowercase()
|
||||
Locale.setDefault(Locale.ENGLISH)
|
||||
|
||||
databaseUp()
|
||||
|
||||
LocalSource.addDbRecords()
|
||||
|
||||
// create system tray
|
||||
if (serverConfig.systemTrayEnabled) {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package suwayomi.tachidesk.server.database.migration
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import de.neonew.exposed.migrations.helpers.SQLMigration
|
||||
|
||||
@Suppress("ClassName", "unused")
|
||||
class M0015_SourceAndExtensionLangAddLengthLimit : SQLMigration() {
|
||||
override val sql = """
|
||||
ALTER TABLE SOURCE ALTER COLUMN LANG VARCHAR(32);
|
||||
ALTER TABLE EXTENSION ALTER COLUMN LANG VARCHAR(32);
|
||||
""".trimIndent()
|
||||
}
|
||||
Reference in New Issue
Block a user