mirror of
https://github.com/revanced/revanced-manager
synced 2024-05-14 13:56:57 +02:00
feat: switch to the new api (#75)
This commit is contained in:
parent
7e3c31c4b2
commit
3f059d7748
@ -4,14 +4,13 @@ import app.revanced.manager.data.platform.FileSystem
|
||||
import app.revanced.manager.data.platform.NetworkInfo
|
||||
import app.revanced.manager.domain.repository.*
|
||||
import app.revanced.manager.domain.worker.WorkerRepository
|
||||
import app.revanced.manager.network.api.ManagerAPI
|
||||
import app.revanced.manager.network.api.ReVancedAPI
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val repositoryModule = module {
|
||||
singleOf(::ReVancedRepository)
|
||||
singleOf(::ReVancedAPI)
|
||||
singleOf(::GithubRepository)
|
||||
singleOf(::ManagerAPI)
|
||||
singleOf(::FileSystem)
|
||||
singleOf(::NetworkInfo)
|
||||
singleOf(::PatchBundlePersistenceRepository)
|
||||
|
@ -2,20 +2,18 @@ package app.revanced.manager.domain.bundles
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import app.revanced.manager.data.room.bundles.VersionInfo
|
||||
import app.revanced.manager.domain.bundles.APIPatchBundle.Companion.toBundleAsset
|
||||
import app.revanced.manager.domain.repository.Assets
|
||||
import app.revanced.manager.domain.repository.PatchBundlePersistenceRepository
|
||||
import app.revanced.manager.domain.repository.ReVancedRepository
|
||||
import app.revanced.manager.network.dto.Asset
|
||||
import app.revanced.manager.network.api.ReVancedAPI
|
||||
import app.revanced.manager.network.api.ReVancedAPI.Extensions.findAssetByType
|
||||
import app.revanced.manager.network.dto.BundleAsset
|
||||
import app.revanced.manager.network.dto.BundleInfo
|
||||
import app.revanced.manager.network.service.HttpService
|
||||
import app.revanced.manager.network.utils.getOrThrow
|
||||
import app.revanced.manager.util.ghIntegrations
|
||||
import app.revanced.manager.util.ghPatches
|
||||
import app.revanced.manager.util.APK_MIMETYPE
|
||||
import app.revanced.manager.util.JAR_MIMETYPE
|
||||
import io.ktor.client.request.url
|
||||
import io.ktor.http.Url
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
@ -57,7 +55,11 @@ sealed class RemotePatchBundle(name: String, id: Int, directory: File, val endpo
|
||||
|
||||
suspend fun update(): Boolean = withContext(Dispatchers.IO) {
|
||||
val info = getLatestInfo()
|
||||
if (hasInstalled() && VersionInfo(info.patches.version, info.integrations.version) == currentVersion()) {
|
||||
if (hasInstalled() && VersionInfo(
|
||||
info.patches.version,
|
||||
info.integrations.version
|
||||
) == currentVersion()
|
||||
) {
|
||||
return@withContext false
|
||||
}
|
||||
|
||||
@ -94,18 +96,24 @@ class JsonPatchBundle(name: String, id: Int, directory: File, endpoint: String)
|
||||
|
||||
class APIPatchBundle(name: String, id: Int, directory: File, endpoint: String) :
|
||||
RemotePatchBundle(name, id, directory, endpoint) {
|
||||
private val api: ReVancedRepository by inject()
|
||||
private val api: ReVancedAPI by inject()
|
||||
|
||||
override suspend fun getLatestInfo() = api.getAssets().toBundleInfo()
|
||||
|
||||
private companion object {
|
||||
fun Assets.toBundleInfo(): BundleInfo {
|
||||
val patches = find(ghPatches, ".jar")
|
||||
val integrations = find(ghIntegrations, ".apk")
|
||||
|
||||
return BundleInfo(patches.toBundleAsset(), integrations.toBundleAsset())
|
||||
override suspend fun getLatestInfo() = coroutineScope {
|
||||
fun getAssetAsync(repo: String, mime: String) = async(Dispatchers.IO) {
|
||||
api
|
||||
.getRelease(repo)
|
||||
.getOrThrow()
|
||||
.let {
|
||||
BundleAsset(it.metadata.tag, it.findAssetByType(mime).downloadUrl)
|
||||
}
|
||||
}
|
||||
|
||||
fun Asset.toBundleAsset() = BundleAsset(version, downloadUrl)
|
||||
val patches = getAssetAsync("revanced-patches", JAR_MIMETYPE)
|
||||
val integrations = getAssetAsync("revanced-integrations", APK_MIMETYPE)
|
||||
|
||||
BundleInfo(
|
||||
patches.await(),
|
||||
integrations.await()
|
||||
)
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ class PreferencesManager(
|
||||
val dynamicColor = booleanPreference("dynamic_color", true)
|
||||
val theme = enumPreference("theme", Theme.SYSTEM)
|
||||
|
||||
val api = stringPreference("api_url", "https://releases.revanced.app")
|
||||
val api = stringPreference("api_url", "https://api.revanced.app")
|
||||
|
||||
val allowExperimental = booleanPreference("allow_experimental", false)
|
||||
|
||||
|
@ -2,6 +2,7 @@ package app.revanced.manager.domain.repository
|
||||
|
||||
import app.revanced.manager.network.service.GithubService
|
||||
|
||||
// TODO: delete this when the revanced api adds download count.
|
||||
class GithubRepository(private val service: GithubService) {
|
||||
suspend fun getChangelog(repo: String) = service.getChangelog(repo)
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package app.revanced.manager.domain.repository
|
||||
|
||||
import app.revanced.manager.domain.manager.PreferencesManager
|
||||
import app.revanced.manager.network.api.MissingAssetException
|
||||
import app.revanced.manager.network.dto.Asset
|
||||
import app.revanced.manager.network.dto.ReVancedReleases
|
||||
import app.revanced.manager.network.service.ReVancedService
|
||||
import app.revanced.manager.network.utils.getOrThrow
|
||||
|
||||
class ReVancedRepository(
|
||||
private val service: ReVancedService,
|
||||
private val prefs: PreferencesManager
|
||||
) {
|
||||
private suspend fun apiUrl() = prefs.api.get()
|
||||
|
||||
suspend fun getContributors() = service.getContributors(apiUrl())
|
||||
|
||||
suspend fun getAssets() = Assets(service.getAssets(apiUrl()).getOrThrow())
|
||||
}
|
||||
|
||||
class Assets(private val releases: ReVancedReleases): List<Asset> by releases.tools {
|
||||
fun find(repo: String, file: String) = find { asset ->
|
||||
asset.name.contains(file) && asset.repository.contains(repo)
|
||||
} ?: throw MissingAssetException()
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package app.revanced.manager.network.api
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import app.revanced.manager.domain.repository.Assets
|
||||
import app.revanced.manager.domain.repository.ReVancedRepository
|
||||
import app.revanced.manager.network.dto.Asset
|
||||
import app.revanced.manager.network.service.HttpService
|
||||
import app.revanced.manager.util.*
|
||||
import io.ktor.client.plugins.onDownload
|
||||
import io.ktor.client.request.url
|
||||
import java.io.File
|
||||
|
||||
// TODO: merge ReVancedRepository into this class
|
||||
class ManagerAPI(
|
||||
private val http: HttpService,
|
||||
private val revancedRepository: ReVancedRepository
|
||||
) {
|
||||
var downloadProgress: Float? by mutableStateOf(null)
|
||||
var downloadedSize: Long? by mutableStateOf(null)
|
||||
var totalSize: Long? by mutableStateOf(null)
|
||||
|
||||
private suspend fun downloadAsset(asset: Asset, saveLocation: File) {
|
||||
http.download(saveLocation) {
|
||||
url(asset.downloadUrl)
|
||||
onDownload { bytesSentTotal, contentLength ->
|
||||
downloadProgress = (bytesSentTotal.toFloat() / contentLength.toFloat())
|
||||
downloadedSize = bytesSentTotal
|
||||
totalSize = contentLength
|
||||
}
|
||||
}
|
||||
downloadProgress = null
|
||||
}
|
||||
|
||||
suspend fun downloadManager(location: File) {
|
||||
val managerAsset = revancedRepository.getAssets().find(ghManager, ".apk")
|
||||
downloadAsset(managerAsset, location)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MissingAssetException : Exception()
|
@ -0,0 +1,26 @@
|
||||
package app.revanced.manager.network.api
|
||||
|
||||
import app.revanced.manager.domain.manager.PreferencesManager
|
||||
import app.revanced.manager.network.dto.Asset
|
||||
import app.revanced.manager.network.dto.ReVancedLatestRelease
|
||||
import app.revanced.manager.network.dto.ReVancedRelease
|
||||
import app.revanced.manager.network.service.ReVancedService
|
||||
import app.revanced.manager.network.utils.getOrThrow
|
||||
import app.revanced.manager.network.utils.transform
|
||||
|
||||
class ReVancedAPI(
|
||||
private val service: ReVancedService,
|
||||
private val prefs: PreferencesManager
|
||||
) {
|
||||
private suspend fun apiUrl() = prefs.api.get()
|
||||
|
||||
suspend fun getContributors() = service.getContributors(apiUrl()).transform { it.repositories }
|
||||
|
||||
suspend fun getRelease(name: String) = service.getRelease(apiUrl(), name).transform { it.release }
|
||||
|
||||
companion object Extensions {
|
||||
fun ReVancedRelease.findAssetByType(mime: String) = assets.singleOrNull { it.contentType == mime } ?: throw MissingAssetException(mime)
|
||||
}
|
||||
}
|
||||
|
||||
class MissingAssetException(type: String) : Exception("No asset with type $type")
|
@ -4,18 +4,18 @@ import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class ReVancedRepositories(
|
||||
@SerialName("repositories") val repositories: List<ReVancedRepository>,
|
||||
data class ReVancedGitRepositories(
|
||||
val repositories: List<ReVancedGitRepository>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class ReVancedRepository(
|
||||
@SerialName("name") val name: String,
|
||||
@SerialName("contributors") val contributors: List<ReVancedContributor>,
|
||||
data class ReVancedGitRepository(
|
||||
val name: String,
|
||||
val contributors: List<ReVancedContributor>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class ReVancedContributor(
|
||||
@SerialName("login") val username: String,
|
||||
data class ReVancedContributor(
|
||||
val username: String,
|
||||
@SerialName("avatar_url") val avatarUrl: String,
|
||||
)
|
||||
|
@ -0,0 +1,32 @@
|
||||
package app.revanced.manager.network.dto
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ReVancedLatestRelease(
|
||||
val release: ReVancedRelease,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedRelease(
|
||||
val metadata: ReVancedReleaseMeta,
|
||||
val assets: List<Asset>
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReVancedReleaseMeta(
|
||||
@SerialName("tag_name") val tag: String,
|
||||
val name: String,
|
||||
val draft: Boolean,
|
||||
val prerelease: Boolean,
|
||||
@SerialName("created_at") val createdAt: String,
|
||||
@SerialName("published_at") val publishedAt: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Asset(
|
||||
val name: String,
|
||||
@SerialName("browser_download_url") val downloadUrl: String,
|
||||
@SerialName("content_type") val contentType: String
|
||||
)
|
@ -1,20 +0,0 @@
|
||||
package app.revanced.manager.network.dto
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class ReVancedReleases(
|
||||
@SerialName("tools") val tools: List<Asset>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class Asset(
|
||||
@SerialName("repository") val repository: String,
|
||||
@SerialName("version") val version: String,
|
||||
@SerialName("timestamp") val timestamp: String,
|
||||
@SerialName("name") val name: String,
|
||||
@SerialName("size") val size: String?,
|
||||
@SerialName("browser_download_url") val downloadUrl: String,
|
||||
@SerialName("content_type") val content_type: String
|
||||
)
|
@ -1,11 +1,8 @@
|
||||
package app.revanced.manager.network.service
|
||||
|
||||
import app.revanced.manager.network.api.MissingAssetException
|
||||
import app.revanced.manager.network.dto.Asset
|
||||
import app.revanced.manager.network.dto.ReVancedReleases
|
||||
import app.revanced.manager.network.dto.ReVancedRepositories
|
||||
import app.revanced.manager.network.dto.ReVancedLatestRelease
|
||||
import app.revanced.manager.network.dto.ReVancedGitRepositories
|
||||
import app.revanced.manager.network.utils.APIResponse
|
||||
import app.revanced.manager.network.utils.getOrThrow
|
||||
import io.ktor.client.request.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -13,20 +10,17 @@ import kotlinx.coroutines.withContext
|
||||
class ReVancedService(
|
||||
private val client: HttpService,
|
||||
) {
|
||||
suspend fun getAssets(api: String): APIResponse<ReVancedReleases> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
suspend fun getRelease(api: String, repo: String): APIResponse<ReVancedLatestRelease> =
|
||||
withContext(Dispatchers.IO) {
|
||||
client.request {
|
||||
url("$api/tools")
|
||||
url("$api/v2/$repo/releases/latest")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getContributors(api: String): APIResponse<ReVancedRepositories> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
suspend fun getContributors(api: String): APIResponse<ReVancedGitRepositories> =
|
||||
withContext(Dispatchers.IO) {
|
||||
client.request {
|
||||
url("$api/contributors")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -56,7 +56,7 @@ fun UpdateProgressScreen(
|
||||
), style = MaterialTheme.typography.headlineMedium
|
||||
)
|
||||
LinearProgressIndicator(
|
||||
progress = vm.downloadProgress / 100f,
|
||||
progress = vm.downloadProgress,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 16.dp)
|
||||
.fillMaxWidth()
|
||||
@ -66,7 +66,7 @@ fun UpdateProgressScreen(
|
||||
vm.totalSize.div(
|
||||
1000000
|
||||
)
|
||||
} MB (${vm.downloadProgress.toInt()}%)" else stringResource(R.string.installing_message),
|
||||
} MB (${vm.downloadProgress.times(100).toInt()}%)" else stringResource(R.string.installing_message),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.outline,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
|
@ -3,22 +3,21 @@ package app.revanced.manager.ui.viewmodel
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.revanced.manager.domain.repository.ReVancedRepository
|
||||
import app.revanced.manager.network.api.ReVancedAPI
|
||||
import app.revanced.manager.network.dto.ReVancedGitRepository
|
||||
import app.revanced.manager.network.utils.getOrNull
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ContributorViewModel(private val repository: ReVancedRepository): ViewModel() {
|
||||
val repositories = mutableStateListOf<app.revanced.manager.network.dto.ReVancedRepository>()
|
||||
class ContributorViewModel(private val reVancedAPI: ReVancedAPI) : ViewModel() {
|
||||
val repositories = mutableStateListOf<ReVancedGitRepository>()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val repos = repository.getContributors().getOrNull()?.repositories
|
||||
withContext(Dispatchers.Main) {
|
||||
if (repos != null) { repositories.addAll(repos) }
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.IO) { reVancedAPI.getContributors().getOrNull() }?.let(
|
||||
repositories::addAll
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -8,24 +8,36 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.network.api.ManagerAPI
|
||||
import app.revanced.manager.network.api.ReVancedAPI
|
||||
import app.revanced.manager.network.api.ReVancedAPI.Extensions.findAssetByType
|
||||
import app.revanced.manager.network.service.HttpService
|
||||
import app.revanced.manager.network.utils.getOrThrow
|
||||
import app.revanced.manager.util.APK_MIMETYPE
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import app.revanced.manager.util.PM
|
||||
import app.revanced.manager.util.uiSafe
|
||||
import io.ktor.client.plugins.onDownload
|
||||
import io.ktor.client.request.url
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
class UpdateProgressViewModel(
|
||||
app: Application,
|
||||
private val managerAPI: ManagerAPI,
|
||||
private val reVancedAPI: ReVancedAPI,
|
||||
private val http: HttpService,
|
||||
private val pm: PM
|
||||
) : ViewModel() {
|
||||
var downloadedSize by mutableStateOf(0L)
|
||||
private set
|
||||
var totalSize by mutableStateOf(0L)
|
||||
private set
|
||||
val downloadProgress by derivedStateOf {
|
||||
if (downloadedSize == 0L || totalSize == 0L) return@derivedStateOf 0f
|
||||
|
||||
val downloadProgress by derivedStateOf { managerAPI.downloadProgress?.times(100) ?: 0f }
|
||||
val downloadedSize by derivedStateOf { managerAPI.downloadedSize ?: 0L }
|
||||
val totalSize by derivedStateOf { managerAPI.totalSize ?: 0L }
|
||||
val isInstalling by derivedStateOf { downloadProgress >= 100 }
|
||||
downloadedSize.toFloat() / totalSize.toFloat()
|
||||
}
|
||||
val isInstalling by derivedStateOf { downloadProgress >= 1 }
|
||||
var finished by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
@ -33,7 +45,18 @@ class UpdateProgressViewModel(
|
||||
private val job = viewModelScope.launch {
|
||||
uiSafe(app, R.string.download_manager_failed, "Failed to download manager") {
|
||||
withContext(Dispatchers.IO) {
|
||||
managerAPI.downloadManager(location)
|
||||
val asset = reVancedAPI
|
||||
.getRelease("revanced-manager")
|
||||
.getOrThrow()
|
||||
.findAssetByType(APK_MIMETYPE)
|
||||
|
||||
http.download(location) {
|
||||
url(asset.downloadUrl)
|
||||
onDownload { bytesSentTotal, contentLength ->
|
||||
downloadedSize = bytesSentTotal
|
||||
totalSize = contentLength
|
||||
}
|
||||
}
|
||||
}
|
||||
finished = true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user