mirror of
https://github.com/revanced/revanced-manager-compose-old.git
synced 2025-04-30 06:24:28 +02:00
feat: API
This commit is contained in:
parent
bd2424611d
commit
1211fc42a9
@ -114,7 +114,7 @@ dependencies {
|
||||
val ktorVersion = "2.0.3"
|
||||
implementation("io.ktor:ktor-client-core:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-android:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-cio:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
|
||||
|
||||
|
@ -1,42 +1,25 @@
|
||||
package app.revanced.manager.api
|
||||
|
||||
import android.util.Log
|
||||
import app.revanced.manager.dto.github.APIRelease
|
||||
import app.revanced.manager.dto.github.Assets
|
||||
import app.revanced.manager.preferences.PreferencesManager
|
||||
import app.revanced.manager.repository.GitHubRepository
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.android.*
|
||||
import io.ktor.client.plugins.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.util.cio.*
|
||||
import io.ktor.utils.io.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
|
||||
val client = HttpClient(Android) {
|
||||
BrowserUserAgent()
|
||||
install(ContentNegotiation) {
|
||||
json(Json {
|
||||
encodeDefaults = true
|
||||
isLenient = true
|
||||
ignoreUnknownKeys = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class API(private val repository: GitHubRepository, private val prefs: PreferencesManager) {
|
||||
class API(private val repository: GitHubRepository, private val prefs: PreferencesManager, val client: HttpClient) {
|
||||
|
||||
suspend fun findAsset(repo: String, file: String): PatchesAsset {
|
||||
val release = repository.getLatestRelease(repo)
|
||||
val asset = release.assets.findAsset(file) ?: throw MissingAssetException()
|
||||
return PatchesAsset(release, asset)
|
||||
val asset = repository.fetchAssets().tools.findAsset(repo, file) ?: throw MissingAssetException()
|
||||
return PatchesAsset(asset)
|
||||
}
|
||||
|
||||
private fun List<APIRelease.Asset>.findAsset(file: String) = find { asset ->
|
||||
(asset.name.contains(file) && !asset.name.contains("-sources") && !asset.name.contains("-javadoc"))
|
||||
private fun List<Assets>.findAsset(repo: String, file: String) = find { asset ->
|
||||
(asset.name.contains(file) && asset.repository.contains(repo))
|
||||
}
|
||||
|
||||
suspend fun downloadPatchBundle(workdir: File): File {
|
||||
@ -61,28 +44,26 @@ class API(private val repository: GitHubRepository, private val prefs: Preferenc
|
||||
|
||||
suspend fun downloadAsset(
|
||||
workdir: File,
|
||||
patchesAsset: PatchesAsset
|
||||
assets: PatchesAsset
|
||||
): Pair<PatchesAsset, File> {
|
||||
val (release, asset) = patchesAsset
|
||||
val out = workdir.resolve("${release.tagName}-${asset.name}")
|
||||
val out = workdir.resolve("${assets.asset.version}-${assets.asset.name}")
|
||||
if (out.exists()) {
|
||||
Log.d(
|
||||
"ReVanced Manager",
|
||||
"Skipping downloading asset ${asset.name} because it exists in cache!"
|
||||
"Skipping downloading asset ${assets.asset.name} because it exists in cache!"
|
||||
)
|
||||
return patchesAsset to out
|
||||
return assets to out
|
||||
}
|
||||
Log.d("ReVanced Manager", "Downloading asset ${asset.name}")
|
||||
client.get(asset.downloadUrl)
|
||||
Log.d("ReVanced Manager", "Downloading asset ${assets.asset.name}")
|
||||
client.get(assets.asset.downloadUrl)
|
||||
.bodyAsChannel()
|
||||
.copyAndClose(out.writeChannel())
|
||||
|
||||
return patchesAsset to out
|
||||
return assets to out
|
||||
}
|
||||
}
|
||||
data class PatchesAsset(
|
||||
val release: APIRelease,
|
||||
val asset: APIRelease.Asset
|
||||
val asset: Assets
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,16 +1,29 @@
|
||||
package app.revanced.manager.di
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.cio.*
|
||||
import io.ktor.client.engine.okhttp.*
|
||||
import io.ktor.client.plugins.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Dns
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
import java.net.Inet4Address
|
||||
import java.net.InetAddress
|
||||
|
||||
val httpModule = module {
|
||||
fun provideHttpClient() = HttpClient(CIO) {
|
||||
fun provideHttpClient() = HttpClient(OkHttp) {
|
||||
engine {
|
||||
config {
|
||||
dns(object : Dns {
|
||||
override fun lookup(hostname: String): List<InetAddress> {
|
||||
val addresses = Dns.SYSTEM.lookup(hostname)
|
||||
return addresses.filterIsInstance<Inet4Address>()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
BrowserUserAgent()
|
||||
install(ContentNegotiation) {
|
||||
json(Json {
|
||||
|
@ -1,22 +0,0 @@
|
||||
package app.revanced.manager.dto.github
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class APICommit(
|
||||
val sha: String,
|
||||
val commit: Object
|
||||
) {
|
||||
@Serializable
|
||||
class Object(
|
||||
val message: String,
|
||||
val author: Author,
|
||||
val committer: Author
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class Author(
|
||||
val name: String,
|
||||
val date: String
|
||||
)
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package app.revanced.manager.dto.github
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class APIContributor(
|
||||
@SerialName("login") val username: String,
|
||||
@SerialName("avatar_url") val avatarUrl: String,
|
||||
@SerialName("html_url") val profileUrl: String,
|
||||
)
|
@ -1,19 +0,0 @@
|
||||
package app.revanced.manager.dto.github
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class APIRelease(
|
||||
@SerialName("tag_name") val tagName: String,
|
||||
@SerialName("published_at") val publishedAt: String,
|
||||
val prerelease: Boolean,
|
||||
val assets: List<Asset>,
|
||||
val body: String
|
||||
) {
|
||||
@Serializable
|
||||
data class Asset(
|
||||
@SerialName("browser_download_url") val downloadUrl: String,
|
||||
val name: String
|
||||
)
|
||||
}
|
@ -1,32 +1,27 @@
|
||||
package app.revanced.manager.repository
|
||||
|
||||
import app.revanced.manager.dto.github.APICommit
|
||||
import app.revanced.manager.dto.github.APIContributor
|
||||
import app.revanced.manager.dto.github.APIRelease
|
||||
import app.revanced.manager.dto.github.Tools
|
||||
import app.revanced.manager.dto.github.Repositories
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class GitHubRepository(private val client: HttpClient) {
|
||||
suspend fun getLatestRelease(repo: String) = withContext(Dispatchers.IO) {
|
||||
val res: List<APIRelease> = client.get("$baseUrl/$repo/releases") {
|
||||
class GitHubRepository(val client: HttpClient) {
|
||||
|
||||
|
||||
suspend fun fetchAssets() = withContext(Dispatchers.IO) {
|
||||
client.get("$apiUrl/tools") {
|
||||
parameter("per_page", 1)
|
||||
}.body()
|
||||
res.first()
|
||||
}
|
||||
suspend fun getLatestCommit(repo: String, ref: String) = withContext(Dispatchers.IO) {
|
||||
client.get("$baseUrl/$repo/commits/$ref") {
|
||||
parameter("per_page", 1)
|
||||
}.body() as APICommit
|
||||
}.body() as Tools
|
||||
}
|
||||
|
||||
suspend fun getContributors(org: String, repo: String) = withContext(Dispatchers.IO) {
|
||||
client.get("$baseUrl/$org/$repo/contributors").body() as List<APIContributor>
|
||||
suspend fun fetchContributors() = withContext(Dispatchers.IO) {
|
||||
client.get("$apiUrl/contributors").body() as Repositories
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val baseUrl = "https://api.github.com/repos"
|
||||
private const val apiUrl = "https://revanced-releases-api.afterst0rm.xyz"
|
||||
}
|
||||
}
|
@ -1,40 +1,63 @@
|
||||
package app.revanced.manager.ui.viewmodel
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.format.DateUtils
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.revanced.manager.dto.github.Assets
|
||||
import app.revanced.manager.repository.GitHubRepository
|
||||
import app.revanced.manager.util.ghManager
|
||||
import app.revanced.manager.util.ghPatcher
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import app.revanced.manager.util.tag
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class DashboardViewModel(private val repository: GitHubRepository) : ViewModel() {
|
||||
var patcherCommitDate by mutableStateOf("")
|
||||
private set
|
||||
var managerCommitDate by mutableStateOf("")
|
||||
private set
|
||||
private var _latestPatcherCommit: Assets? by mutableStateOf(null)
|
||||
val patcherCommitDate: String
|
||||
get() = _latestPatcherCommit?.commitDate ?: "unknown"
|
||||
|
||||
private var _latestManagerCommit: Assets? by mutableStateOf(null)
|
||||
val managerCommitDate: String
|
||||
get() = _latestManagerCommit?.commitDate ?: "unknown"
|
||||
|
||||
init {
|
||||
runBlocking {
|
||||
patcherCommitDate = commitDateOf(ghPatcher)
|
||||
managerCommitDate = commitDateOf(ghManager)
|
||||
fetchLastCommit()
|
||||
}
|
||||
|
||||
private fun fetchLastCommit() {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val repo = repository.fetchAssets()
|
||||
for (asset in repo.tools) {
|
||||
when (asset.repository) {
|
||||
ghPatcher -> {
|
||||
_latestPatcherCommit = asset
|
||||
}
|
||||
ghManager -> {
|
||||
_latestManagerCommit = asset
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(tag, "Failed to fetch latest patcher release", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun commitDateOf(repo: String, ref: String = "HEAD"): String {
|
||||
val commit = repository.getLatestCommit(repo, ref).commit
|
||||
return DateUtils.getRelativeTimeSpanString(
|
||||
formatter.parse(commit.committer.date)!!.time,
|
||||
private val Assets.commitDate: String
|
||||
get() = DateUtils.getRelativeTimeSpanString(
|
||||
formatter.parse(timestamp)!!.time,
|
||||
Calendar.getInstance().timeInMillis,
|
||||
DateUtils.MINUTE_IN_MILLIS
|
||||
).toString()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
@SuppressLint("ConstantLocale")
|
||||
val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault())
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user