feat: switch to the new api (#75)

This commit is contained in:
Ax333l 2023-08-07 11:03:50 +02:00 committed by GitHub
parent d666ece4a8
commit 1630668360
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 142 additions and 148 deletions

View File

@ -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)

View File

@ -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()
)
}
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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()
}

View File

@ -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()

View File

@ -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")

View File

@ -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,
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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")
}
}
}
}

View File

@ -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),

View File

@ -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
)
}
}
}

View File

@ -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
}