mirror of
https://github.com/tachiyomiorg/tachiyomi-extensions-inspector.git
synced 2024-12-25 00:01:49 +01:00
refactor & support for extension update: Backend
This commit is contained in:
parent
b1b1abad1d
commit
077bbc3c38
@ -11,13 +11,14 @@ package eu.kanade.tachiyomi.extension.api
|
|||||||
// import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
// import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
||||||
import ir.armor.tachidesk.database.dataclass.ExtensionDataClass
|
import ir.armor.tachidesk.model.dataclass.ExtensionDataClass
|
||||||
// import kotlinx.coroutines.Dispatchers
|
// import kotlinx.coroutines.Dispatchers
|
||||||
// import kotlinx.coroutines.withContext
|
// import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.json.JsonArray
|
import kotlinx.serialization.json.JsonArray
|
||||||
import kotlinx.serialization.json.int
|
import kotlinx.serialization.json.int
|
||||||
import kotlinx.serialization.json.jsonObject
|
import kotlinx.serialization.json.jsonObject
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
|
||||||
// import uy.kohesive.injekt.injectLazy
|
// import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
internal class ExtensionGithubApi {
|
internal class ExtensionGithubApi {
|
||||||
@ -84,7 +85,9 @@ internal class ExtensionGithubApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val BASE_URL = "https://raw.githubusercontent.com/"
|
// const val BASE_URL = "https://raw.githubusercontent.com"
|
||||||
const val REPO_URL_PREFIX = "${BASE_URL}inorichi/tachiyomi-extensions/repo"
|
// const val REPO_URL_PREFIX = "${BASE_URL}/tachiyomiorg/tachiyomi-extensions/repo"
|
||||||
|
const val BASE_URL = "http://127.0.0.1:8000"
|
||||||
|
const val REPO_URL_PREFIX = "$BASE_URL/repo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ interface ExtensionGithubService {
|
|||||||
.addNetworkInterceptor { chain ->
|
.addNetworkInterceptor { chain ->
|
||||||
val originalResponse = chain.proceed(chain.request())
|
val originalResponse = chain.proceed(chain.request())
|
||||||
originalResponse.newBuilder()
|
originalResponse.newBuilder()
|
||||||
.header("Content-Encoding", "gzip")
|
// .header("Content-Encoding", "gzip")
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
@ -41,6 +41,7 @@ interface ExtensionGithubService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET("${ExtensionGithubApi.REPO_URL_PREFIX}/index.json.gz")
|
// @GET("${ExtensionGithubApi.REPO_URL_PREFIX}/index.json.gz")
|
||||||
|
@GET("${ExtensionGithubApi.REPO_URL_PREFIX}/index.json")
|
||||||
suspend fun getRepo(): JsonArray
|
suspend fun getRepo(): JsonArray
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
package ir.armor.tachidesk.database.entity
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 ir.armor.tachidesk.database.table.ExtensionTable
|
|
||||||
import org.jetbrains.exposed.dao.IntEntity
|
|
||||||
import org.jetbrains.exposed.dao.IntEntityClass
|
|
||||||
import org.jetbrains.exposed.dao.id.EntityID
|
|
||||||
|
|
||||||
class ExtensionEntity(id: EntityID<Int>) : IntEntity(id) {
|
|
||||||
companion object : IntEntityClass<ExtensionEntity>(ExtensionTable)
|
|
||||||
|
|
||||||
var name by ExtensionTable.name
|
|
||||||
var pkgName by ExtensionTable.pkgName
|
|
||||||
var versionName by ExtensionTable.versionName
|
|
||||||
var versionCode by ExtensionTable.versionCode
|
|
||||||
var lang by ExtensionTable.lang
|
|
||||||
var isNsfw by ExtensionTable.isNsfw
|
|
||||||
var apkName by ExtensionTable.apkName
|
|
||||||
var iconUrl by ExtensionTable.iconUrl
|
|
||||||
var installed by ExtensionTable.installed
|
|
||||||
var classFQName by ExtensionTable.classFQName
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package ir.armor.tachidesk.database.entity
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 ir.armor.tachidesk.database.table.MangaTable
|
|
||||||
import org.jetbrains.exposed.dao.IntEntity
|
|
||||||
import org.jetbrains.exposed.dao.IntEntityClass
|
|
||||||
import org.jetbrains.exposed.dao.id.EntityID
|
|
||||||
|
|
||||||
class MangaEntity(id: EntityID<Int>) : IntEntity(id) {
|
|
||||||
companion object : IntEntityClass<MangaEntity>(MangaTable)
|
|
||||||
|
|
||||||
var url by MangaTable.url
|
|
||||||
var title by MangaTable.title
|
|
||||||
var initialized by MangaTable.initialized
|
|
||||||
|
|
||||||
var artist by MangaTable.artist
|
|
||||||
var author by MangaTable.author
|
|
||||||
var description by MangaTable.description
|
|
||||||
var genre by MangaTable.genre
|
|
||||||
var status by MangaTable.status
|
|
||||||
var thumbnail_url by MangaTable.thumbnail_url
|
|
||||||
|
|
||||||
var sourceReference by MangaEntity referencedOn MangaTable.sourceReference
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package ir.armor.tachidesk.database.entity
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 ir.armor.tachidesk.database.table.SourceTable
|
|
||||||
import org.jetbrains.exposed.dao.EntityClass
|
|
||||||
import org.jetbrains.exposed.dao.LongEntity
|
|
||||||
import org.jetbrains.exposed.dao.id.EntityID
|
|
||||||
|
|
||||||
class SourceEntity(id: EntityID<Long>) : LongEntity(id) {
|
|
||||||
companion object : EntityClass<Long, SourceEntity>(SourceTable, null)
|
|
||||||
|
|
||||||
var sourceId by SourceTable.id
|
|
||||||
var name by SourceTable.name
|
|
||||||
var lang by SourceTable.lang
|
|
||||||
var extension by ExtensionEntity referencedOn SourceTable.extension
|
|
||||||
var partOfFactorySource by SourceTable.partOfFactorySource
|
|
||||||
var positionInFactorySource by SourceTable.positionInFactorySource
|
|
||||||
}
|
|
@ -7,10 +7,10 @@ package ir.armor.tachidesk.impl
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import ir.armor.tachidesk.database.dataclass.CategoryDataClass
|
import ir.armor.tachidesk.model.database.CategoryMangaTable
|
||||||
import ir.armor.tachidesk.database.table.CategoryMangaTable
|
import ir.armor.tachidesk.model.database.CategoryTable
|
||||||
import ir.armor.tachidesk.database.table.CategoryTable
|
import ir.armor.tachidesk.model.database.toDataClass
|
||||||
import ir.armor.tachidesk.database.table.toDataClass
|
import ir.armor.tachidesk.model.dataclass.CategoryDataClass
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.deleteWhere
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
import org.jetbrains.exposed.sql.insert
|
import org.jetbrains.exposed.sql.insert
|
||||||
|
@ -7,12 +7,12 @@ package ir.armor.tachidesk.impl
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import ir.armor.tachidesk.database.dataclass.CategoryDataClass
|
import ir.armor.tachidesk.model.database.CategoryMangaTable
|
||||||
import ir.armor.tachidesk.database.dataclass.MangaDataClass
|
import ir.armor.tachidesk.model.database.CategoryTable
|
||||||
import ir.armor.tachidesk.database.table.CategoryMangaTable
|
import ir.armor.tachidesk.model.database.MangaTable
|
||||||
import ir.armor.tachidesk.database.table.CategoryTable
|
import ir.armor.tachidesk.model.database.toDataClass
|
||||||
import ir.armor.tachidesk.database.table.MangaTable
|
import ir.armor.tachidesk.model.dataclass.CategoryDataClass
|
||||||
import ir.armor.tachidesk.database.table.toDataClass
|
import ir.armor.tachidesk.model.dataclass.MangaDataClass
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
import org.jetbrains.exposed.sql.deleteWhere
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
|
@ -9,10 +9,10 @@ package ir.armor.tachidesk.impl
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import ir.armor.tachidesk.database.dataclass.ChapterDataClass
|
import ir.armor.tachidesk.model.database.ChapterTable
|
||||||
import ir.armor.tachidesk.database.table.ChapterTable
|
import ir.armor.tachidesk.model.database.MangaTable
|
||||||
import ir.armor.tachidesk.database.table.MangaTable
|
import ir.armor.tachidesk.model.database.PageTable
|
||||||
import ir.armor.tachidesk.database.table.PageTable
|
import ir.armor.tachidesk.model.dataclass.ChapterDataClass
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
import org.jetbrains.exposed.sql.insert
|
import org.jetbrains.exposed.sql.insert
|
||||||
import org.jetbrains.exposed.sql.insertAndGetId
|
import org.jetbrains.exposed.sql.insertAndGetId
|
||||||
|
@ -15,9 +15,9 @@ import eu.kanade.tachiyomi.network.GET
|
|||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import ir.armor.tachidesk.database.table.ExtensionTable
|
|
||||||
import ir.armor.tachidesk.database.table.SourceTable
|
|
||||||
import ir.armor.tachidesk.impl.util.APKExtractor
|
import ir.armor.tachidesk.impl.util.APKExtractor
|
||||||
|
import ir.armor.tachidesk.model.database.ExtensionTable
|
||||||
|
import ir.armor.tachidesk.model.database.SourceTable
|
||||||
import ir.armor.tachidesk.server.applicationDirs
|
import ir.armor.tachidesk.server.applicationDirs
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
@ -71,10 +71,10 @@ private fun dex2jar(dexFile: String, jarFile: String, fileNameWithoutType: Strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun installAPK(apkName: String): Int {
|
fun installExtension(pkgName: String): Int {
|
||||||
logger.debug("Installing $apkName")
|
logger.debug("Installing $pkgName")
|
||||||
val extensionRecord = getExtensionList(true).first { it.apkName == apkName }
|
val extensionRecord = extensionTableAsDataClass().first { it.pkgName == pkgName }
|
||||||
val fileNameWithoutType = apkName.substringBefore(".apk")
|
val fileNameWithoutType = extensionRecord.apkName.substringBefore(".apk")
|
||||||
val dirPathWithoutType = "${applicationDirs.extensionsRoot}/$fileNameWithoutType"
|
val dirPathWithoutType = "${applicationDirs.extensionsRoot}/$fileNameWithoutType"
|
||||||
|
|
||||||
// check if we don't have the dex file already downloaded
|
// check if we don't have the dex file already downloaded
|
||||||
@ -145,7 +145,7 @@ fun installAPK(apkName: String): Int {
|
|||||||
// update extension info
|
// update extension info
|
||||||
transaction {
|
transaction {
|
||||||
ExtensionTable.update({ ExtensionTable.name eq extensionRecord.name }) {
|
ExtensionTable.update({ ExtensionTable.name eq extensionRecord.name }) {
|
||||||
it[installed] = true
|
it[isInstalled] = true
|
||||||
it[classFQName] = className
|
it[classFQName] = className
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,18 +168,18 @@ private fun downloadAPKFile(url: String, apkPath: String) {
|
|||||||
sink.close()
|
sink.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeExtension(apkName: String) {
|
fun removeExtension(pkgName: String) {
|
||||||
logger.debug("Uninstalling $apkName")
|
logger.debug("Uninstalling $pkgName")
|
||||||
|
|
||||||
val extensionRecord = getExtensionList(true).first { it.apkName == apkName }
|
val extensionRecord = extensionTableAsDataClass().first { it.pkgName == pkgName }
|
||||||
val fileNameWithoutType = apkName.substringBefore(".apk")
|
val fileNameWithoutType = extensionRecord.apkName.substringBefore(".apk")
|
||||||
val jarPath = "${applicationDirs.extensionsRoot}/$fileNameWithoutType.jar"
|
val jarPath = "${applicationDirs.extensionsRoot}/$fileNameWithoutType.jar"
|
||||||
transaction {
|
transaction {
|
||||||
val extensionId = ExtensionTable.select { ExtensionTable.name eq extensionRecord.name }.first()[ExtensionTable.id]
|
val extensionId = ExtensionTable.select { ExtensionTable.name eq extensionRecord.name }.first()[ExtensionTable.id]
|
||||||
|
|
||||||
SourceTable.deleteWhere { SourceTable.extension eq extensionId }
|
SourceTable.deleteWhere { SourceTable.extension eq extensionId }
|
||||||
ExtensionTable.update({ ExtensionTable.name eq extensionRecord.name }) {
|
ExtensionTable.update({ ExtensionTable.name eq extensionRecord.name }) {
|
||||||
it[ExtensionTable.installed] = false
|
it[isInstalled] = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,6 +188,24 @@ fun removeExtension(apkName: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateExtension(pkgName: String): Int {
|
||||||
|
val targetExtension = ExtensionListData.updateMap.remove(pkgName)!!
|
||||||
|
removeExtension(pkgName)
|
||||||
|
transaction {
|
||||||
|
ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) {
|
||||||
|
it[name] = targetExtension.name
|
||||||
|
it[versionName] = targetExtension.versionName
|
||||||
|
it[versionCode] = targetExtension.versionCode
|
||||||
|
it[lang] = targetExtension.lang
|
||||||
|
it[isNsfw] = targetExtension.isNsfw
|
||||||
|
it[apkName] = targetExtension.apkName
|
||||||
|
it[iconUrl] = targetExtension.iconUrl
|
||||||
|
it[hasUpdate] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return installExtension(pkgName)
|
||||||
|
}
|
||||||
|
|
||||||
val network: NetworkHelper by injectLazy()
|
val network: NetworkHelper by injectLazy()
|
||||||
|
|
||||||
fun getExtensionIcon(apkName: String): Pair<InputStream, String> {
|
fun getExtensionIcon(apkName: String): Pair<InputStream, String> {
|
||||||
|
@ -9,86 +9,122 @@ package ir.armor.tachidesk.impl
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
|
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import ir.armor.tachidesk.database.dataclass.ExtensionDataClass
|
import ir.armor.tachidesk.model.database.ExtensionTable
|
||||||
import ir.armor.tachidesk.database.table.ExtensionTable
|
import ir.armor.tachidesk.model.dataclass.ExtensionDataClass
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
import org.jetbrains.exposed.sql.insert
|
import org.jetbrains.exposed.sql.insert
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
|
|
||||||
private object Data {
|
object ExtensionListData {
|
||||||
var lastExtensionCheck: Long = 0
|
var lastUpdateCheck: Long = 0
|
||||||
|
var updateMap = ConcurrentHashMap<String, Extension.Available>()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extensionDatabaseIsEmtpy(): Boolean {
|
fun getExtensionList(): List<ExtensionDataClass> {
|
||||||
return transaction {
|
|
||||||
return@transaction ExtensionTable.selectAll().count() == 0L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getExtensionList(offline: Boolean = false): List<ExtensionDataClass> {
|
|
||||||
// update if 60 seconds has passed or requested offline and database is empty
|
// update if 60 seconds has passed or requested offline and database is empty
|
||||||
if (Data.lastExtensionCheck + 60 * 1000 < System.currentTimeMillis() || (offline && extensionDatabaseIsEmtpy())) {
|
if (ExtensionListData.lastUpdateCheck + 60 * 1000 < System.currentTimeMillis()) {
|
||||||
logger.debug("Getting extensions list from the internet")
|
logger.debug("Getting extensions list from the internet")
|
||||||
Data.lastExtensionCheck = System.currentTimeMillis()
|
ExtensionListData.lastUpdateCheck = System.currentTimeMillis()
|
||||||
var foundExtensions: List<Extension.Available>
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val api = ExtensionGithubApi()
|
val foundExtensions = ExtensionGithubApi().findExtensions()
|
||||||
foundExtensions = api.findExtensions()
|
updateExtensionDatabase(foundExtensions)
|
||||||
transaction {
|
|
||||||
foundExtensions.forEach { foundExtension ->
|
|
||||||
val extensionRecord = ExtensionTable.select { ExtensionTable.name eq foundExtension.name }.firstOrNull()
|
|
||||||
if (extensionRecord != null) {
|
|
||||||
// update the record
|
|
||||||
ExtensionTable.update({ ExtensionTable.name eq foundExtension.name }) {
|
|
||||||
it[name] = foundExtension.name
|
|
||||||
it[pkgName] = foundExtension.pkgName
|
|
||||||
it[versionName] = foundExtension.versionName
|
|
||||||
it[versionCode] = foundExtension.versionCode
|
|
||||||
it[lang] = foundExtension.lang
|
|
||||||
it[isNsfw] = foundExtension.isNsfw
|
|
||||||
it[apkName] = foundExtension.apkName
|
|
||||||
it[iconUrl] = foundExtension.iconUrl
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// insert new record
|
|
||||||
ExtensionTable.insert {
|
|
||||||
it[name] = foundExtension.name
|
|
||||||
it[pkgName] = foundExtension.pkgName
|
|
||||||
it[versionName] = foundExtension.versionName
|
|
||||||
it[versionCode] = foundExtension.versionCode
|
|
||||||
it[lang] = foundExtension.lang
|
|
||||||
it[isNsfw] = foundExtension.isNsfw
|
|
||||||
it[apkName] = foundExtension.apkName
|
|
||||||
it[iconUrl] = foundExtension.iconUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.debug("used cached extension list")
|
logger.debug("used cached extension list")
|
||||||
}
|
}
|
||||||
|
|
||||||
return transaction {
|
return extensionTableAsDataClass()
|
||||||
return@transaction ExtensionTable.selectAll().map {
|
}
|
||||||
ExtensionDataClass(
|
|
||||||
it[ExtensionTable.name],
|
fun extensionTableAsDataClass() = transaction {
|
||||||
it[ExtensionTable.pkgName],
|
return@transaction ExtensionTable.selectAll().map {
|
||||||
it[ExtensionTable.versionName],
|
ExtensionDataClass(
|
||||||
it[ExtensionTable.versionCode],
|
it[ExtensionTable.name],
|
||||||
it[ExtensionTable.lang],
|
it[ExtensionTable.pkgName],
|
||||||
it[ExtensionTable.isNsfw],
|
it[ExtensionTable.versionName],
|
||||||
it[ExtensionTable.apkName],
|
it[ExtensionTable.versionCode],
|
||||||
getExtensionIconUrl(it[ExtensionTable.apkName]),
|
it[ExtensionTable.lang],
|
||||||
it[ExtensionTable.installed],
|
it[ExtensionTable.isNsfw],
|
||||||
it[ExtensionTable.classFQName]
|
it[ExtensionTable.apkName],
|
||||||
)
|
getExtensionIconUrl(it[ExtensionTable.apkName]),
|
||||||
|
it[ExtensionTable.isInstalled],
|
||||||
|
it[ExtensionTable.hasUpdate],
|
||||||
|
it[ExtensionTable.isObsolete],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateExtensionDatabase(foundExtensions: List<Extension.Available>) {
|
||||||
|
transaction {
|
||||||
|
foundExtensions.forEach { foundExtension ->
|
||||||
|
val extensionRecord = ExtensionTable.select { ExtensionTable.pkgName eq foundExtension.pkgName }.firstOrNull()
|
||||||
|
if (extensionRecord != null) {
|
||||||
|
if (extensionRecord[ExtensionTable.isInstalled]) {
|
||||||
|
if (foundExtension.versionCode > extensionRecord[ExtensionTable.versionCode]) {
|
||||||
|
// there is an update
|
||||||
|
ExtensionTable.update({ ExtensionTable.pkgName eq foundExtension.pkgName }) {
|
||||||
|
it[hasUpdate] = true
|
||||||
|
}
|
||||||
|
ExtensionListData.updateMap.putIfAbsent(foundExtension.pkgName, foundExtension)
|
||||||
|
} else if (foundExtension.versionCode < extensionRecord[ExtensionTable.versionCode]) {
|
||||||
|
// some how the user installed an invalid version
|
||||||
|
ExtensionTable.update({ ExtensionTable.pkgName eq foundExtension.pkgName }) {
|
||||||
|
it[isObsolete] = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the two are equal
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// extension is not installed so we can overwrite the data without a care
|
||||||
|
ExtensionTable.update({ ExtensionTable.pkgName eq foundExtension.pkgName }) {
|
||||||
|
it[name] = foundExtension.name
|
||||||
|
it[versionName] = foundExtension.versionName
|
||||||
|
it[versionCode] = foundExtension.versionCode
|
||||||
|
it[lang] = foundExtension.lang
|
||||||
|
it[isNsfw] = foundExtension.isNsfw
|
||||||
|
it[apkName] = foundExtension.apkName
|
||||||
|
it[iconUrl] = foundExtension.iconUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// insert new record
|
||||||
|
ExtensionTable.insert {
|
||||||
|
it[name] = foundExtension.name
|
||||||
|
it[pkgName] = foundExtension.pkgName
|
||||||
|
it[versionName] = foundExtension.versionName
|
||||||
|
it[versionCode] = foundExtension.versionCode
|
||||||
|
it[lang] = foundExtension.lang
|
||||||
|
it[isNsfw] = foundExtension.isNsfw
|
||||||
|
it[apkName] = foundExtension.apkName
|
||||||
|
it[iconUrl] = foundExtension.iconUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// deal with obsolete extensions
|
||||||
|
ExtensionTable.selectAll().forEach { extensionRecord ->
|
||||||
|
val foundExtension = foundExtensions.find { it.pkgName == extensionRecord[ExtensionTable.pkgName] }
|
||||||
|
if (foundExtension == null) {
|
||||||
|
// this extensions is obsolete
|
||||||
|
if (extensionRecord[ExtensionTable.isInstalled]) {
|
||||||
|
// is installed so we should mark it as obsolete
|
||||||
|
ExtensionTable.update({ ExtensionTable.pkgName eq extensionRecord[ExtensionTable.pkgName] }) {
|
||||||
|
it[isObsolete] = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// is not installed so we can remove the record without a care
|
||||||
|
ExtensionTable.deleteWhere { ExtensionTable.pkgName eq extensionRecord[ExtensionTable.pkgName] }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@ package ir.armor.tachidesk.impl
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import ir.armor.tachidesk.database.dataclass.MangaDataClass
|
import ir.armor.tachidesk.model.database.CategoryMangaTable
|
||||||
import ir.armor.tachidesk.database.table.CategoryMangaTable
|
import ir.armor.tachidesk.model.database.MangaTable
|
||||||
import ir.armor.tachidesk.database.table.MangaTable
|
import ir.armor.tachidesk.model.database.toDataClass
|
||||||
import ir.armor.tachidesk.database.table.toDataClass
|
import ir.armor.tachidesk.model.dataclass.MangaDataClass
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
import org.jetbrains.exposed.sql.deleteWhere
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
|
@ -9,9 +9,9 @@ package ir.armor.tachidesk.impl
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import ir.armor.tachidesk.database.dataclass.MangaDataClass
|
import ir.armor.tachidesk.model.database.MangaStatus
|
||||||
import ir.armor.tachidesk.database.table.MangaStatus
|
import ir.armor.tachidesk.model.database.MangaTable
|
||||||
import ir.armor.tachidesk.database.table.MangaTable
|
import ir.armor.tachidesk.model.dataclass.MangaDataClass
|
||||||
import ir.armor.tachidesk.server.applicationDirs
|
import ir.armor.tachidesk.server.applicationDirs
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
@ -8,10 +8,10 @@ package ir.armor.tachidesk.impl
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import ir.armor.tachidesk.database.dataclass.MangaDataClass
|
import ir.armor.tachidesk.model.database.MangaStatus
|
||||||
import ir.armor.tachidesk.database.dataclass.PagedMangaListDataClass
|
import ir.armor.tachidesk.model.database.MangaTable
|
||||||
import ir.armor.tachidesk.database.table.MangaStatus
|
import ir.armor.tachidesk.model.dataclass.MangaDataClass
|
||||||
import ir.armor.tachidesk.database.table.MangaTable
|
import ir.armor.tachidesk.model.dataclass.PagedMangaListDataClass
|
||||||
import org.jetbrains.exposed.sql.insertAndGetId
|
import org.jetbrains.exposed.sql.insertAndGetId
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
@ -9,10 +9,10 @@ package ir.armor.tachidesk.impl
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import ir.armor.tachidesk.database.table.ChapterTable
|
import ir.armor.tachidesk.model.database.ChapterTable
|
||||||
import ir.armor.tachidesk.database.table.MangaTable
|
import ir.armor.tachidesk.model.database.MangaTable
|
||||||
import ir.armor.tachidesk.database.table.PageTable
|
import ir.armor.tachidesk.model.database.PageTable
|
||||||
import ir.armor.tachidesk.database.table.SourceTable
|
import ir.armor.tachidesk.model.database.SourceTable
|
||||||
import ir.armor.tachidesk.server.applicationDirs
|
import ir.armor.tachidesk.server.applicationDirs
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
|
@ -7,7 +7,7 @@ package ir.armor.tachidesk.impl
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import ir.armor.tachidesk.database.dataclass.PagedMangaListDataClass
|
import ir.armor.tachidesk.model.dataclass.PagedMangaListDataClass
|
||||||
|
|
||||||
fun sourceFilters(sourceId: Long) {
|
fun sourceFilters(sourceId: Long) {
|
||||||
val source = getHttpSource(sourceId)
|
val source = getHttpSource(sourceId)
|
||||||
|
@ -9,17 +9,14 @@ package ir.armor.tachidesk.impl
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import ir.armor.tachidesk.database.dataclass.SourceDataClass
|
import ir.armor.tachidesk.model.database.ExtensionTable
|
||||||
import ir.armor.tachidesk.database.entity.ExtensionEntity
|
import ir.armor.tachidesk.model.database.SourceTable
|
||||||
import ir.armor.tachidesk.database.entity.SourceEntity
|
import ir.armor.tachidesk.model.dataclass.SourceDataClass
|
||||||
import ir.armor.tachidesk.database.table.ExtensionTable
|
|
||||||
import ir.armor.tachidesk.database.table.SourceTable
|
|
||||||
import ir.armor.tachidesk.server.applicationDirs
|
import ir.armor.tachidesk.server.applicationDirs
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import java.lang.NullPointerException
|
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
|
|
||||||
@ -30,8 +27,8 @@ private val extensionCache = mutableListOf<Pair<String, Any>>()
|
|||||||
|
|
||||||
fun getHttpSource(sourceId: Long): HttpSource {
|
fun getHttpSource(sourceId: Long): HttpSource {
|
||||||
val sourceRecord = transaction {
|
val sourceRecord = transaction {
|
||||||
SourceEntity.findById(sourceId)
|
SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()!!
|
||||||
} ?: throw NullPointerException("Source with id $sourceId is not installed")
|
}
|
||||||
|
|
||||||
val cachedResult: Pair<Long, HttpSource>? = sourceCache.firstOrNull { it.first == sourceId }
|
val cachedResult: Pair<Long, HttpSource>? = sourceCache.firstOrNull { it.first == sourceId }
|
||||||
if (cachedResult != null) {
|
if (cachedResult != null) {
|
||||||
@ -40,10 +37,10 @@ fun getHttpSource(sourceId: Long): HttpSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val result: HttpSource = transaction {
|
val result: HttpSource = transaction {
|
||||||
val extensionId = sourceRecord.extension.id.value
|
val extensionId = sourceRecord[SourceTable.extension]
|
||||||
val extensionRecord = ExtensionEntity.findById(extensionId)!!
|
val extensionRecord = ExtensionTable.select { ExtensionTable.id eq extensionId }.firstOrNull()!!
|
||||||
val apkName = extensionRecord.apkName
|
val apkName = extensionRecord[ExtensionTable.apkName]
|
||||||
val className = extensionRecord.classFQName
|
val className = extensionRecord[ExtensionTable.classFQName]
|
||||||
val jarName = apkName.substringBefore(".apk") + ".jar"
|
val jarName = apkName.substringBefore(".apk") + ".jar"
|
||||||
val jarPath = "${applicationDirs.extensionsRoot}/$jarName"
|
val jarPath = "${applicationDirs.extensionsRoot}/$jarName"
|
||||||
|
|
||||||
@ -60,13 +57,15 @@ fun getHttpSource(sourceId: Long): HttpSource {
|
|||||||
val classToLoad = Class.forName(className, true, child)
|
val classToLoad = Class.forName(className, true, child)
|
||||||
classToLoad.newInstance()
|
classToLoad.newInstance()
|
||||||
}
|
}
|
||||||
if (sourceRecord.partOfFactorySource) {
|
if (sourceRecord[SourceTable.partOfFactorySource]) {
|
||||||
|
val positionInFactorySource = sourceRecord[SourceTable.positionInFactorySource]!!
|
||||||
return@transaction if (usedCached) {
|
return@transaction if (usedCached) {
|
||||||
(instance as List<HttpSource>)[sourceRecord.positionInFactorySource!!]
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
(instance as List<HttpSource>)[positionInFactorySource]
|
||||||
} else {
|
} else {
|
||||||
val list = (instance as SourceFactory).createSources()
|
val list = (instance as SourceFactory).createSources()
|
||||||
extensionCache.add(Pair(jarPath, list))
|
extensionCache.add(Pair(jarPath, list))
|
||||||
list[sourceRecord.positionInFactorySource!!] as HttpSource
|
list[positionInFactorySource] as HttpSource
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!usedCached)
|
if (!usedCached)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.table
|
package ir.armor.tachidesk.model.database
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.table
|
package ir.armor.tachidesk.model.database
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
@ -7,7 +7,7 @@ package ir.armor.tachidesk.database.table
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import ir.armor.tachidesk.database.dataclass.CategoryDataClass
|
import ir.armor.tachidesk.model.dataclass.CategoryDataClass
|
||||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.table
|
package ir.armor.tachidesk.model.database
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.table
|
package ir.armor.tachidesk.model.database
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
@ -19,6 +19,8 @@ object ExtensionTable : IntIdTable() {
|
|||||||
val apkName = varchar("apk_name", 1024)
|
val apkName = varchar("apk_name", 1024)
|
||||||
val iconUrl = varchar("icon_url", 2048)
|
val iconUrl = varchar("icon_url", 2048)
|
||||||
|
|
||||||
val installed = bool("installed").default(false)
|
val isInstalled = bool("is_installed").default(false)
|
||||||
|
val hasUpdate = bool("has_update").default(false)
|
||||||
|
val isObsolete = bool("is_obsolete").default(false)
|
||||||
val classFQName = varchar("class_name", 256).default("") // fully qualified name
|
val classFQName = varchar("class_name", 256).default("") // fully qualified name
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.table
|
package ir.armor.tachidesk.model.database
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
@ -8,8 +8,8 @@ package ir.armor.tachidesk.database.table
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import ir.armor.tachidesk.database.dataclass.MangaDataClass
|
|
||||||
import ir.armor.tachidesk.impl.proxyThumbnailUrl
|
import ir.armor.tachidesk.impl.proxyThumbnailUrl
|
||||||
|
import ir.armor.tachidesk.model.dataclass.MangaDataClass
|
||||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.table
|
package ir.armor.tachidesk.model.database
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.table
|
package ir.armor.tachidesk.model.database
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.dataclass
|
package ir.armor.tachidesk.model.dataclass
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.dataclass
|
package ir.armor.tachidesk.model.dataclass
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database
|
package ir.armor.tachidesk.model.dataclass
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
@ -7,13 +7,13 @@ package ir.armor.tachidesk.database
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import ir.armor.tachidesk.database.table.CategoryMangaTable
|
import ir.armor.tachidesk.model.database.CategoryMangaTable
|
||||||
import ir.armor.tachidesk.database.table.CategoryTable
|
import ir.armor.tachidesk.model.database.CategoryTable
|
||||||
import ir.armor.tachidesk.database.table.ChapterTable
|
import ir.armor.tachidesk.model.database.ChapterTable
|
||||||
import ir.armor.tachidesk.database.table.ExtensionTable
|
import ir.armor.tachidesk.model.database.ExtensionTable
|
||||||
import ir.armor.tachidesk.database.table.MangaTable
|
import ir.armor.tachidesk.model.database.MangaTable
|
||||||
import ir.armor.tachidesk.database.table.PageTable
|
import ir.armor.tachidesk.model.database.PageTable
|
||||||
import ir.armor.tachidesk.database.table.SourceTable
|
import ir.armor.tachidesk.model.database.SourceTable
|
||||||
import ir.armor.tachidesk.server.applicationDirs
|
import ir.armor.tachidesk.server.applicationDirs
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import org.jetbrains.exposed.sql.SchemaUtils
|
import org.jetbrains.exposed.sql.SchemaUtils
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.dataclass
|
package ir.armor.tachidesk.model.dataclass
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
@ -16,6 +16,7 @@ data class ExtensionDataClass(
|
|||||||
val isNsfw: Boolean,
|
val isNsfw: Boolean,
|
||||||
val apkName: String,
|
val apkName: String,
|
||||||
val iconUrl: String,
|
val iconUrl: String,
|
||||||
val installed: Boolean,
|
val isInstalled: Boolean,
|
||||||
val classFQName: String,
|
val hasUpdate: Boolean,
|
||||||
|
val isObsolete: Boolean,
|
||||||
)
|
)
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.dataclass
|
package ir.armor.tachidesk.model.dataclass
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
@ -7,7 +7,7 @@ package ir.armor.tachidesk.database.dataclass
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import ir.armor.tachidesk.database.table.MangaStatus
|
import ir.armor.tachidesk.model.database.MangaStatus
|
||||||
|
|
||||||
data class MangaDataClass(
|
data class MangaDataClass(
|
||||||
val id: Int,
|
val id: Int,
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.dataclass
|
package ir.armor.tachidesk.model.dataclass
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
@ -1,4 +1,4 @@
|
|||||||
package ir.armor.tachidesk.database.dataclass
|
package ir.armor.tachidesk.model.dataclass
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Contributors to the Suwayomi project
|
* Copyright (C) Contributors to the Suwayomi project
|
@ -19,7 +19,7 @@ import ir.armor.tachidesk.impl.getPageImage
|
|||||||
import ir.armor.tachidesk.impl.getSource
|
import ir.armor.tachidesk.impl.getSource
|
||||||
import ir.armor.tachidesk.impl.getSourceList
|
import ir.armor.tachidesk.impl.getSourceList
|
||||||
import ir.armor.tachidesk.impl.getThumbnail
|
import ir.armor.tachidesk.impl.getThumbnail
|
||||||
import ir.armor.tachidesk.impl.installAPK
|
import ir.armor.tachidesk.impl.installExtension
|
||||||
import ir.armor.tachidesk.impl.removeCategory
|
import ir.armor.tachidesk.impl.removeCategory
|
||||||
import ir.armor.tachidesk.impl.removeExtension
|
import ir.armor.tachidesk.impl.removeExtension
|
||||||
import ir.armor.tachidesk.impl.removeMangaFromCategory
|
import ir.armor.tachidesk.impl.removeMangaFromCategory
|
||||||
@ -29,6 +29,7 @@ import ir.armor.tachidesk.impl.sourceFilters
|
|||||||
import ir.armor.tachidesk.impl.sourceGlobalSearch
|
import ir.armor.tachidesk.impl.sourceGlobalSearch
|
||||||
import ir.armor.tachidesk.impl.sourceSearch
|
import ir.armor.tachidesk.impl.sourceSearch
|
||||||
import ir.armor.tachidesk.impl.updateCategory
|
import ir.armor.tachidesk.impl.updateCategory
|
||||||
|
import ir.armor.tachidesk.impl.updateExtension
|
||||||
import ir.armor.tachidesk.server.util.openInBrowser
|
import ir.armor.tachidesk.server.util.openInBrowser
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
|
|
||||||
@ -69,18 +70,26 @@ fun javalinSetup() {
|
|||||||
ctx.json(getExtensionList())
|
ctx.json(getExtensionList())
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get("/api/v1/extension/install/:apkName") { ctx ->
|
app.get("/api/v1/extension/install/:pkgName") { ctx ->
|
||||||
val apkName = ctx.pathParam("apkName")
|
val pkgName = ctx.pathParam("pkgName")
|
||||||
|
|
||||||
ctx.status(
|
ctx.status(
|
||||||
installAPK(apkName)
|
installExtension(pkgName)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get("/api/v1/extension/uninstall/:apkName") { ctx ->
|
app.get("/api/v1/extension/update/:pkgName") { ctx ->
|
||||||
val apkName = ctx.pathParam("apkName")
|
val pkgName = ctx.pathParam("pkgName")
|
||||||
|
|
||||||
removeExtension(apkName)
|
ctx.status(
|
||||||
|
updateExtension(pkgName)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get("/api/v1/extension/uninstall/:pkgName") { ctx ->
|
||||||
|
val pkgName = ctx.pathParam("pkgName")
|
||||||
|
|
||||||
|
removeExtension(pkgName)
|
||||||
ctx.status(200)
|
ctx.status(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ package ir.armor.tachidesk.server
|
|||||||
import ch.qos.logback.classic.Level
|
import ch.qos.logback.classic.Level
|
||||||
import eu.kanade.tachiyomi.App
|
import eu.kanade.tachiyomi.App
|
||||||
import ir.armor.tachidesk.Main
|
import ir.armor.tachidesk.Main
|
||||||
import ir.armor.tachidesk.database.makeDataBaseTables
|
import ir.armor.tachidesk.model.dataclass.makeDataBaseTables
|
||||||
import ir.armor.tachidesk.server.util.systemTray
|
import ir.armor.tachidesk.server.util.systemTray
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import net.harawata.appdirs.AppDirsFactory
|
import net.harawata.appdirs.AppDirsFactory
|
||||||
@ -40,7 +40,7 @@ val androidCompat by lazy { AndroidCompat() }
|
|||||||
fun applicationSetup() {
|
fun applicationSetup() {
|
||||||
// register server config
|
// register server config
|
||||||
GlobalConfigManager.registerModule(
|
GlobalConfigManager.registerModule(
|
||||||
ServerConfig.register(GlobalConfigManager.config)
|
ServerConfig.register(GlobalConfigManager.config)
|
||||||
)
|
)
|
||||||
|
|
||||||
// set application wide logging level
|
// set application wide logging level
|
||||||
@ -50,10 +50,10 @@ fun applicationSetup() {
|
|||||||
|
|
||||||
// make dirs we need
|
// make dirs we need
|
||||||
listOf(
|
listOf(
|
||||||
applicationDirs.dataRoot,
|
applicationDirs.dataRoot,
|
||||||
applicationDirs.extensionsRoot,
|
applicationDirs.extensionsRoot,
|
||||||
"${applicationDirs.extensionsRoot}/icon",
|
"${applicationDirs.extensionsRoot}/icon",
|
||||||
applicationDirs.thumbnailsRoot
|
applicationDirs.thumbnailsRoot
|
||||||
).forEach {
|
).forEach {
|
||||||
File(it).mkdirs()
|
File(it).mkdirs()
|
||||||
}
|
}
|
||||||
@ -99,5 +99,6 @@ fun applicationSetup() {
|
|||||||
System.getProperties()["proxySet"] = "true"
|
System.getProperties()["proxySet"] = "true"
|
||||||
System.getProperties()["socksProxyHost"] = serverConfig.socksProxyHost
|
System.getProperties()["socksProxyHost"] = serverConfig.socksProxyHost
|
||||||
System.getProperties()["socksProxyPort"] = serverConfig.socksProxyPort
|
System.getProperties()["socksProxyPort"] = serverConfig.socksProxyPort
|
||||||
|
logger.info("Socks Proxy is enabled to ${serverConfig.socksProxyHost}:${serverConfig.socksProxyPort}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ interface IProps {
|
|||||||
export default function ExtensionCard(props: IProps) {
|
export default function ExtensionCard(props: IProps) {
|
||||||
const {
|
const {
|
||||||
extension: {
|
extension: {
|
||||||
name, lang, versionName, installed, apkName, iconUrl,
|
name, lang, versionName, installed, pkgName, iconUrl,
|
||||||
},
|
},
|
||||||
notifyInstall,
|
notifyInstall,
|
||||||
} = props;
|
} = props;
|
||||||
@ -62,7 +62,7 @@ export default function ExtensionCard(props: IProps) {
|
|||||||
|
|
||||||
function install() {
|
function install() {
|
||||||
setInstalledState('installing');
|
setInstalledState('installing');
|
||||||
client.get(`/api/v1/extension/install/${apkName}`)
|
client.get(`/api/v1/extension/install/${pkgName}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setInstalledState('uninstall');
|
setInstalledState('uninstall');
|
||||||
notifyInstall();
|
notifyInstall();
|
||||||
@ -71,7 +71,7 @@ export default function ExtensionCard(props: IProps) {
|
|||||||
|
|
||||||
function uninstall() {
|
function uninstall() {
|
||||||
setInstalledState('uninstalling');
|
setInstalledState('uninstalling');
|
||||||
client.get(`/api/v1/extension/uninstall/${apkName}`)
|
client.get(`/api/v1/extension/uninstall/${pkgName}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// setInstalledState('install');
|
// setInstalledState('install');
|
||||||
notifyInstall();
|
notifyInstall();
|
||||||
|
14
webUI/react/src/typings.d.ts
vendored
14
webUI/react/src/typings.d.ts
vendored
@ -7,12 +7,16 @@
|
|||||||
|
|
||||||
interface IExtension {
|
interface IExtension {
|
||||||
name: string
|
name: string
|
||||||
lang: string
|
|
||||||
versionName: string
|
|
||||||
iconUrl: string
|
|
||||||
installed: boolean
|
|
||||||
apkName: string
|
|
||||||
pkgName: string
|
pkgName: string
|
||||||
|
versionName: string
|
||||||
|
versionCode: number
|
||||||
|
lang: string
|
||||||
|
isNsfw: boolean
|
||||||
|
apkName: string
|
||||||
|
iconUrl: string
|
||||||
|
isInstalled: boolean
|
||||||
|
hasUpdate: boolean
|
||||||
|
isObsolete: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISource {
|
interface ISource {
|
||||||
|
Loading…
Reference in New Issue
Block a user