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