mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-04 11:24:35 -05:00
Improve Extensions List (#753)
* Use new extension icon path * Improve Extension list performance
This commit is contained in:
@@ -9,11 +9,13 @@ package suwayomi.tachidesk.manga.impl.extension
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.source.local.LocalSource
|
import eu.kanade.tachiyomi.source.local.LocalSource
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.dao.id.EntityID
|
||||||
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
|
||||||
|
import org.jetbrains.exposed.sql.batchInsert
|
||||||
import org.jetbrains.exposed.sql.deleteWhere
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
import org.jetbrains.exposed.sql.insert
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
|
import org.jetbrains.exposed.sql.statements.BatchUpdateStatement
|
||||||
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 suwayomi.tachidesk.manga.impl.extension.Extension.getExtensionIconUrl
|
import suwayomi.tachidesk.manga.impl.extension.Extension.getExtensionIconUrl
|
||||||
@@ -69,68 +71,100 @@ object ExtensionsList {
|
|||||||
|
|
||||||
private fun updateExtensionDatabase(foundExtensions: List<OnlineExtension>) {
|
private fun updateExtensionDatabase(foundExtensions: List<OnlineExtension>) {
|
||||||
transaction {
|
transaction {
|
||||||
foundExtensions.forEach { foundExtension ->
|
val installedExtensions =
|
||||||
val extensionRecord = ExtensionTable.select { ExtensionTable.pkgName eq foundExtension.pkgName }.firstOrNull()
|
ExtensionTable.selectAll().toList()
|
||||||
if (extensionRecord != null) {
|
.associateBy { it[ExtensionTable.pkgName] }
|
||||||
if (extensionRecord[ExtensionTable.isInstalled]) {
|
val extensionsToUpdate = mutableListOf<Pair<OnlineExtension, ResultRow>>()
|
||||||
when {
|
val extensionsToInsert = mutableListOf<OnlineExtension>()
|
||||||
foundExtension.versionCode > extensionRecord[ExtensionTable.versionCode] -> {
|
val extensionsToDelete =
|
||||||
// there is an update
|
installedExtensions.mapNotNull { (pkgName, extension) ->
|
||||||
ExtensionTable.update({ ExtensionTable.pkgName eq foundExtension.pkgName }) {
|
extension.takeUnless { foundExtensions.any { it.pkgName == pkgName } }
|
||||||
it[hasUpdate] = true
|
}
|
||||||
}
|
foundExtensions.forEach {
|
||||||
updateMap.putIfAbsent(foundExtension.pkgName, foundExtension)
|
val extension = installedExtensions[it.pkgName]
|
||||||
}
|
if (extension != null) {
|
||||||
foundExtension.versionCode < extensionRecord[ExtensionTable.versionCode] -> {
|
extensionsToUpdate.add(it to extension)
|
||||||
// somehow the user installed an invalid version
|
|
||||||
ExtensionTable.update({ ExtensionTable.pkgName eq foundExtension.pkgName }) {
|
|
||||||
it[isObsolete] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} 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 {
|
} else {
|
||||||
// insert new record
|
extensionsToInsert.add(it)
|
||||||
ExtensionTable.insert {
|
}
|
||||||
it[name] = foundExtension.name
|
}
|
||||||
it[pkgName] = foundExtension.pkgName
|
if (extensionsToUpdate.isNotEmpty()) {
|
||||||
it[versionName] = foundExtension.versionName
|
val extensionsInstalled =
|
||||||
it[versionCode] = foundExtension.versionCode
|
extensionsToUpdate
|
||||||
it[lang] = foundExtension.lang
|
.groupBy { it.second[ExtensionTable.isInstalled] }
|
||||||
it[isNsfw] = foundExtension.isNsfw
|
val installedExtensionsToUpdate = extensionsInstalled[true].orEmpty()
|
||||||
it[apkName] = foundExtension.apkName
|
if (installedExtensionsToUpdate.isNotEmpty()) {
|
||||||
it[iconUrl] = foundExtension.iconUrl
|
BatchUpdateStatement(ExtensionTable).apply {
|
||||||
|
installedExtensionsToUpdate.forEach { (foundExtension, extensionRecord) ->
|
||||||
|
addBatch(EntityID(extensionRecord[ExtensionTable.id].value, ExtensionTable))
|
||||||
|
// Always update icon url
|
||||||
|
this[ExtensionTable.iconUrl] = foundExtension.iconUrl
|
||||||
|
|
||||||
|
// add these because batch updates need matching columns
|
||||||
|
this[ExtensionTable.hasUpdate] = extensionRecord[ExtensionTable.hasUpdate]
|
||||||
|
this[ExtensionTable.isObsolete] = extensionRecord[ExtensionTable.isObsolete]
|
||||||
|
when {
|
||||||
|
foundExtension.versionCode > extensionRecord[ExtensionTable.versionCode] -> {
|
||||||
|
// there is an update
|
||||||
|
this[ExtensionTable.hasUpdate] = true
|
||||||
|
updateMap.putIfAbsent(foundExtension.pkgName, foundExtension)
|
||||||
|
}
|
||||||
|
foundExtension.versionCode < extensionRecord[ExtensionTable.versionCode] -> {
|
||||||
|
// somehow the user installed an invalid version
|
||||||
|
this[ExtensionTable.isObsolete] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
execute(this@transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val extensionsToFullyUpdate = extensionsInstalled[false].orEmpty()
|
||||||
|
if (extensionsToFullyUpdate.isNotEmpty()) {
|
||||||
|
BatchUpdateStatement(ExtensionTable).apply {
|
||||||
|
extensionsToFullyUpdate.forEach { (foundExtension, extensionRecord) ->
|
||||||
|
addBatch(EntityID(extensionRecord[ExtensionTable.id].value, ExtensionTable))
|
||||||
|
// extension is not installed, so we can overwrite the data without a care
|
||||||
|
this[ExtensionTable.name] = foundExtension.name
|
||||||
|
this[ExtensionTable.versionName] = foundExtension.versionName
|
||||||
|
this[ExtensionTable.versionCode] = foundExtension.versionCode
|
||||||
|
this[ExtensionTable.lang] = foundExtension.lang
|
||||||
|
this[ExtensionTable.isNsfw] = foundExtension.isNsfw
|
||||||
|
this[ExtensionTable.apkName] = foundExtension.apkName
|
||||||
|
this[ExtensionTable.iconUrl] = foundExtension.iconUrl
|
||||||
|
}
|
||||||
|
execute(this@transaction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extensionsToInsert.isNotEmpty()) {
|
||||||
|
ExtensionTable.batchInsert(extensionsToInsert) { foundExtension ->
|
||||||
|
this[ExtensionTable.name] = foundExtension.name
|
||||||
|
this[ExtensionTable.pkgName] = foundExtension.pkgName
|
||||||
|
this[ExtensionTable.versionName] = foundExtension.versionName
|
||||||
|
this[ExtensionTable.versionCode] = foundExtension.versionCode
|
||||||
|
this[ExtensionTable.lang] = foundExtension.lang
|
||||||
|
this[ExtensionTable.isNsfw] = foundExtension.isNsfw
|
||||||
|
this[ExtensionTable.apkName] = foundExtension.apkName
|
||||||
|
this[ExtensionTable.iconUrl] = foundExtension.iconUrl
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// deal with obsolete extensions
|
// deal with obsolete extensions
|
||||||
ExtensionTable.selectAll().forEach { extensionRecord ->
|
val extensionsToRemove =
|
||||||
val foundExtension = foundExtensions.find { it.pkgName == extensionRecord[ExtensionTable.pkgName] }
|
extensionsToDelete.groupBy { it[ExtensionTable.isInstalled] }
|
||||||
if (foundExtension == null) {
|
.mapValues { (_, extensions) -> extensions.map { it[ExtensionTable.pkgName] } }
|
||||||
// not in the repo, so these extensions are obsolete
|
// not in the repo, so these extensions are obsolete
|
||||||
if (extensionRecord[ExtensionTable.isInstalled]) {
|
val obsoleteExtensions = extensionsToRemove[true].orEmpty()
|
||||||
// is installed so we should mark it as obsolete
|
if (obsoleteExtensions.isNotEmpty()) {
|
||||||
ExtensionTable.update({ ExtensionTable.pkgName eq extensionRecord[ExtensionTable.pkgName] }) {
|
ExtensionTable.update({ ExtensionTable.pkgName inList obsoleteExtensions }) {
|
||||||
it[isObsolete] = true
|
it[isObsolete] = true
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// is not installed, so we can remove the record without a care
|
|
||||||
ExtensionTable.deleteWhere { ExtensionTable.pkgName eq extensionRecord[ExtensionTable.pkgName] }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// is not installed, so we can remove the record without a care
|
||||||
|
val removeExtensions = extensionsToRemove[false].orEmpty()
|
||||||
|
if (removeExtensions.isNotEmpty()) {
|
||||||
|
ExtensionTable.deleteWhere { ExtensionTable.pkgName inList removeExtensions }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ object ExtensionGithubApi {
|
|||||||
hasChangelog = it.hasChangelog == 1,
|
hasChangelog = it.hasChangelog == 1,
|
||||||
sources = it.sources?.toExtensionSources() ?: emptyList(),
|
sources = it.sources?.toExtensionSources() ?: emptyList(),
|
||||||
apkName = it.apk,
|
apkName = it.apk,
|
||||||
iconUrl = "${REPO_URL_PREFIX}icon/${it.apk.replace(".apk", ".png")}",
|
iconUrl = "${REPO_URL_PREFIX}icon/${it.pkg}.png",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user