Allow extension stores to have separate extension list file (#3454)

This commit is contained in:
AntsyLich
2026-06-22 00:26:38 +06:00
committed by GitHub
parent eb5f57a48c
commit 5f5a034112
9 changed files with 64 additions and 30 deletions
@@ -13,6 +13,7 @@ class BackupExtensionStore(
@ProtoNumber(4) var contactWebsite: String,
@ProtoNumber(6) var contactDiscord: String?,
@ProtoNumber(7) var isLegacy: Boolean?,
@ProtoNumber(8) var extensionListUrl: String?,
)
val backupExtensionStoreMapper = { store: ExtensionStore ->
@@ -24,5 +25,6 @@ val backupExtensionStoreMapper = { store: ExtensionStore ->
contactWebsite = store.contact.website,
contactDiscord = store.contact.discord,
isLegacy = store.isLegacy,
extensionListUrl = store.extensionListUrl,
)
}
@@ -20,6 +20,7 @@ class ExtensionStoreRestorer(
contactWebsite = backupStore.contactWebsite,
contactDiscord = backupStore.contactDiscord,
isLegacy = backupStore.isLegacy ?: true,
extensionListUrl = backupStore.extensionListUrl,
)
}
}
@@ -4,7 +4,10 @@ import android.annotation.SuppressLint
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames
import kotlinx.serialization.protobuf.ProtoNumber
import mihon.data.extension.model.NetworkExtensionStore.ContentRating
import mihon.data.extension.model.NetworkExtensionStore.ExtensionList
import mihon.domain.extension.model.ExtensionStore
import eu.kanade.tachiyomi.extension.model.Extension as TachiyomiExtension
@SuppressLint("UnsafeOptInUsageError")
@Serializable
@@ -13,7 +16,8 @@ data class NetworkExtensionStore(
@ProtoNumber(2) val badgeLabel: String,
@ProtoNumber(3) val signingKey: String,
@ProtoNumber(4) val contact: Contact,
@ProtoNumber(5) val extensions: List<Extension>,
@ProtoNumber(101) val extensionList: ExtensionList?,
@ProtoNumber(102) val extensionListUrl: String?,
) : BaseNetworkExtensionStore {
@Serializable
data class Contact(
@@ -21,6 +25,9 @@ data class NetworkExtensionStore(
@ProtoNumber(2) val discord: String?,
)
@Serializable
data class ExtensionList(@ProtoNumber(1) val extensions: List<Extension>)
@Serializable
data class Extension(
@ProtoNumber(1) val name: String,
@@ -79,13 +86,15 @@ data class NetworkExtensionStore(
discord = contact.discord,
),
isLegacy = false,
extensionListUrl = extensionListUrl,
)
}
}
fun toAvailableExtensions(store: ExtensionStore): List<eu.kanade.tachiyomi.extension.model.Extension.Available> {
fun ExtensionList.toAvailableExtensions(store: ExtensionStore): List<TachiyomiExtension.Available> {
return extensions.map { extension ->
val lang = extension.sources.map { it.language }.toSet()
eu.kanade.tachiyomi.extension.model.Extension.Available(
TachiyomiExtension.Available(
name = extension.name,
pkgName = extension.packageName,
apkUrl = extension.resources.apkUrl,
@@ -96,7 +105,7 @@ data class NetworkExtensionStore(
lang = if (lang.size == 1) lang.first() else "all",
isNsfw = extension.sources.maxOfOrNull { it.contentRating } == ContentRating.PORNOGRAPHIC,
sources = extension.sources.map { source ->
eu.kanade.tachiyomi.extension.model.Extension.Available.Source(
TachiyomiExtension.Available.Source(
id = source.id,
name = source.name,
lang = source.language,
@@ -107,4 +116,3 @@ data class NetworkExtensionStore(
)
}
}
}
@@ -31,6 +31,7 @@ data class NetworkLegacyExtensionRepo(
discord = null,
),
isLegacy = true,
extensionListUrl = null,
)
}
}
@@ -32,6 +32,7 @@ class ExtensionStoreRepositoryImpl(
contactWebsite = indexUrl,
contactDiscord = null,
isLegacy = false,
extensionListUrl = null,
)
}
@@ -67,6 +68,7 @@ class ExtensionStoreRepositoryImpl(
contactWebsite = store.contact.website,
contactDiscord = store.contact.discord,
isLegacy = store.isLegacy,
extensionListUrl = store.extensionListUrl,
)
}
@@ -117,6 +119,7 @@ class ExtensionStoreRepositoryImpl(
contactWebsite: String,
contactDiscord: String?,
isLegacy: Boolean,
extensionListUrl: String?,
): ExtensionStore = ExtensionStore(
indexUrl = indexUrl,
name = name,
@@ -127,5 +130,6 @@ class ExtensionStoreRepositoryImpl(
discord = contactDiscord,
),
isLegacy = isLegacy,
extensionListUrl = extensionListUrl,
)
}
@@ -12,6 +12,7 @@ import logcat.LogPriority
import mihon.data.extension.model.NetworkExtensionStore
import mihon.data.extension.model.NetworkLegacyExtension
import mihon.data.extension.model.NetworkLegacyExtensionRepo
import mihon.data.extension.model.toAvailableExtensions
import mihon.domain.extension.model.ExtensionStore
import okio.BufferedSource
import okio.buffer
@@ -68,7 +69,19 @@ class ExtensionStoreService(
suspend fun getExtensions(store: ExtensionStore): Result<List<Extension.Available>> {
return try {
val extensions = if (!store.isLegacy) {
val extensions = if (store.extensionListUrl != null) {
val response = network.client.newCall(GET(store.extensionListUrl!!)).awaitSuccess()
response.body.source().decompressIfGzipped().use { source ->
when (source.peek().readByte()) {
// "{..."
0x7B.toByte() -> json.decodeFromBufferedSource<NetworkExtensionStore.ExtensionList>(source)
else -> protoBuf.decodeFromByteArray<NetworkExtensionStore.ExtensionList>(
source.readByteArray(),
)
}
.toAvailableExtensions(store)
}
} else if (!store.isLegacy) {
val response = network.client.newCall(GET(store.indexUrl)).awaitSuccess()
response.body.source().decompressIfGzipped().use { source ->
when (source.peek().readByte()) {
@@ -76,6 +89,7 @@ class ExtensionStoreService(
0x7B.toByte() -> json.decodeFromBufferedSource<NetworkExtensionStore>(source)
else -> protoBuf.decodeFromByteArray<NetworkExtensionStore>(source.readByteArray())
}
.extensionList!!
.toAvailableExtensions(store)
}
} else {
@@ -7,7 +7,8 @@ CREATE TABLE extension_store(
signing_key TEXT NOT NULL,
contact_website TEXT NOT NULL,
contact_discord TEXT,
is_legacy INTEGER AS Boolean NOT NULL
is_legacy INTEGER AS Boolean NOT NULL,
extension_list_url TEXT
);
get:
@@ -24,8 +25,8 @@ SELECT COUNT(*)
FROM extension_store;
upsert:
INSERT INTO extension_store(index_url, name, badge_label, signing_key, contact_website, contact_discord, is_legacy)
VALUES (:indexUrl, :name, :badgeLabel, :signingKey, :contactWebsite, :contactDiscord, :isLegacy)
INSERT INTO extension_store(index_url, name, badge_label, signing_key, contact_website, contact_discord, is_legacy, extension_list_url)
VALUES (:indexUrl, :name, :badgeLabel, :signingKey, :contactWebsite, :contactDiscord, :isLegacy, :extensionListUrl)
ON CONFLICT(index_url)
DO UPDATE
SET
@@ -34,7 +35,8 @@ SET
signing_key =: signingKey,
contact_website = :contactWebsite,
contact_discord = :contactDiscord,
is_legacy = :isLegacy
is_legacy = :isLegacy,
extension_list_url = :extensionListUrl
WHERE index_url = :indexUrl;
delete:
@@ -0,0 +1 @@
ALTER TABLE extension_store ADD COLUMN extension_list_url TEXT;
@@ -7,6 +7,7 @@ data class ExtensionStore(
val signingKey: String,
val contact: Contact,
val isLegacy: Boolean,
val extensionListUrl: String?,
) {
data class Contact(
val website: String,