mirror of
https://github.com/revanced/revanced-manager
synced 2024-05-14 13:56:57 +02:00
refactor(downloaders): improve file system code (#1379)
This commit is contained in:
parent
56a4a7043d
commit
8f6d720454
@ -2,7 +2,7 @@
|
|||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "5515d164bc8f713201506d42a02d337f",
|
"identityHash": "371c7a84b122a2de8b660b35e6e9ce14",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "patch_bundles",
|
"tableName": "patch_bundles",
|
||||||
@ -160,7 +160,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "downloaded_app",
|
"tableName": "downloaded_app",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `version` TEXT NOT NULL, `file` TEXT NOT NULL, PRIMARY KEY(`package_name`, `version`))",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `version` TEXT NOT NULL, `directory` TEXT NOT NULL, PRIMARY KEY(`package_name`, `version`))",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "packageName",
|
"fieldPath": "packageName",
|
||||||
@ -175,8 +175,8 @@
|
|||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "file",
|
"fieldPath": "directory",
|
||||||
"columnName": "file",
|
"columnName": "directory",
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
}
|
}
|
||||||
@ -300,7 +300,7 @@
|
|||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5515d164bc8f713201506d42a02d337f')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '371c7a84b122a2de8b660b35e6e9ce14')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,5 +16,5 @@ class Converters {
|
|||||||
fun fileFromString(value: String) = File(value)
|
fun fileFromString(value: String) = File(value)
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun fileToString(file: File): String = file.absolutePath
|
fun fileToString(file: File): String = file.path
|
||||||
}
|
}
|
@ -11,5 +11,5 @@ import java.io.File
|
|||||||
data class DownloadedApp(
|
data class DownloadedApp(
|
||||||
@ColumnInfo(name = "package_name") val packageName: String,
|
@ColumnInfo(name = "package_name") val packageName: String,
|
||||||
@ColumnInfo(name = "version") val version: String,
|
@ColumnInfo(name = "version") val version: String,
|
||||||
@ColumnInfo(name = "file") val file: File,
|
@ColumnInfo(name = "directory") val directory: File,
|
||||||
)
|
)
|
@ -1,34 +1,61 @@
|
|||||||
package app.revanced.manager.domain.repository
|
package app.revanced.manager.domain.repository
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
import app.revanced.manager.data.room.AppDatabase
|
import app.revanced.manager.data.room.AppDatabase
|
||||||
|
import app.revanced.manager.data.room.AppDatabase.Companion.generateUid
|
||||||
import app.revanced.manager.data.room.apps.downloaded.DownloadedApp
|
import app.revanced.manager.data.room.apps.downloaded.DownloadedApp
|
||||||
|
import app.revanced.manager.network.downloader.AppDownloader
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class DownloadedAppRepository(
|
class DownloadedAppRepository(
|
||||||
|
app: Application,
|
||||||
db: AppDatabase
|
db: AppDatabase
|
||||||
) {
|
) {
|
||||||
|
private val dir = app.getDir("downloaded-apps", Context.MODE_PRIVATE)
|
||||||
private val dao = db.downloadedAppDao()
|
private val dao = db.downloadedAppDao()
|
||||||
|
|
||||||
fun getAll() = dao.getAllApps().distinctUntilChanged()
|
fun getAll() = dao.getAllApps().distinctUntilChanged()
|
||||||
|
|
||||||
suspend fun get(packageName: String, version: String) = dao.get(packageName, version)
|
fun getApkFileForApp(app: DownloadedApp): File = getApkFileForDir(dir.resolve(app.directory))
|
||||||
|
private fun getApkFileForDir(directory: File) = directory.listFiles()!!.first()
|
||||||
|
|
||||||
suspend fun add(
|
suspend fun download(
|
||||||
packageName: String,
|
app: AppDownloader.App,
|
||||||
version: String,
|
preferSplits: Boolean,
|
||||||
file: File
|
onDownload: suspend (downloadProgress: Pair<Float, Float>?) -> Unit = {},
|
||||||
) = dao.insert(
|
): File {
|
||||||
DownloadedApp(
|
this.get(app.packageName, app.version)?.let { downloaded ->
|
||||||
packageName = packageName,
|
return getApkFileForApp(downloaded)
|
||||||
version = version,
|
}
|
||||||
file = file
|
|
||||||
)
|
// Converted integers cannot contain / or .. unlike the package name or version, so they are safer to use here.
|
||||||
)
|
val relativePath = File(generateUid().toString())
|
||||||
|
val savePath = dir.resolve(relativePath).also { it.mkdirs() }
|
||||||
|
|
||||||
|
try {
|
||||||
|
app.download(savePath, preferSplits, onDownload)
|
||||||
|
|
||||||
|
dao.insert(DownloadedApp(
|
||||||
|
packageName = app.packageName,
|
||||||
|
version = app.version,
|
||||||
|
directory = relativePath,
|
||||||
|
))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
savePath.deleteRecursively()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the Apk file.
|
||||||
|
return getApkFileForDir(savePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun get(packageName: String, version: String) = dao.get(packageName, version)
|
||||||
|
|
||||||
suspend fun delete(downloadedApps: Collection<DownloadedApp>) {
|
suspend fun delete(downloadedApps: Collection<DownloadedApp>) {
|
||||||
downloadedApps.forEach {
|
downloadedApps.forEach {
|
||||||
it.file.deleteRecursively()
|
dir.resolve(it.directory).deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
dao.delete(downloadedApps)
|
dao.delete(downloadedApps)
|
||||||
|
@ -171,7 +171,7 @@ class APKMirror : AppDownloader, KoinComponent {
|
|||||||
saveDirectory: File,
|
saveDirectory: File,
|
||||||
preferSplit: Boolean,
|
preferSplit: Boolean,
|
||||||
onDownload: suspend (downloadProgress: Pair<Float, Float>?) -> Unit
|
onDownload: suspend (downloadProgress: Pair<Float, Float>?) -> Unit
|
||||||
): File {
|
) {
|
||||||
val variants = httpClient.getHtml { url(apkMirror + downloadLink) }
|
val variants = httpClient.getHtml { url(apkMirror + downloadLink) }
|
||||||
.div {
|
.div {
|
||||||
withClass = "variants-table"
|
withClass = "variants-table"
|
||||||
@ -246,18 +246,10 @@ class APKMirror : AppDownloader, KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val saveLocation = if (variant.apkType == APKType.BUNDLE)
|
val targetFile = saveDirectory.resolve("base.apk")
|
||||||
saveDirectory.resolve(version).also { it.mkdirs() }
|
|
||||||
else
|
|
||||||
saveDirectory.resolve("$version.apk")
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val downloadLocation = if (variant.apkType == APKType.BUNDLE)
|
httpClient.download(targetFile) {
|
||||||
saveLocation.resolve("temp.zip")
|
|
||||||
else
|
|
||||||
saveLocation
|
|
||||||
|
|
||||||
httpClient.download(downloadLocation) {
|
|
||||||
url(apkMirror + downloadLink)
|
url(apkMirror + downloadLink)
|
||||||
onDownload { bytesSentTotal, contentLength ->
|
onDownload { bytesSentTotal, contentLength ->
|
||||||
onDownload(bytesSentTotal.div(100000).toFloat().div(10) to contentLength.div(100000).toFloat().div(10))
|
onDownload(bytesSentTotal.div(100000).toFloat().div(10) to contentLength.div(100000).toFloat().div(10))
|
||||||
@ -267,16 +259,11 @@ class APKMirror : AppDownloader, KoinComponent {
|
|||||||
if (variant.apkType == APKType.BUNDLE) {
|
if (variant.apkType == APKType.BUNDLE) {
|
||||||
// TODO: Extract temp.zip
|
// TODO: Extract temp.zip
|
||||||
|
|
||||||
downloadLocation.delete()
|
targetFile.delete()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
saveLocation.deleteRecursively()
|
|
||||||
throw e
|
|
||||||
} finally {
|
} finally {
|
||||||
onDownload(null)
|
onDownload(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
return saveLocation
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ interface AppDownloader {
|
|||||||
saveDirectory: File,
|
saveDirectory: File,
|
||||||
preferSplit: Boolean,
|
preferSplit: Boolean,
|
||||||
onDownload: suspend (downloadProgress: Pair<Float, Float>?) -> Unit = {}
|
onDownload: suspend (downloadProgress: Pair<Float, Float>?) -> Unit = {}
|
||||||
): File
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -190,19 +190,11 @@ class PatcherWorker(
|
|||||||
|
|
||||||
val inputFile = when (val selectedApp = args.input) {
|
val inputFile = when (val selectedApp = args.input) {
|
||||||
is SelectedApp.Download -> {
|
is SelectedApp.Download -> {
|
||||||
val savePath = applicationContext.filesDir.resolve("downloaded-apps")
|
downloadedAppRepository.download(
|
||||||
.resolve(args.input.packageName).also { it.mkdirs() }
|
selectedApp.app,
|
||||||
|
|
||||||
selectedApp.app.download(
|
|
||||||
savePath,
|
|
||||||
prefs.preferSplits.get(),
|
prefs.preferSplits.get(),
|
||||||
onDownload = { downloadProgress.emit(it) }
|
onDownload = { downloadProgress.emit(it) }
|
||||||
).also {
|
).also {
|
||||||
downloadedAppRepository.add(
|
|
||||||
args.input.packageName,
|
|
||||||
args.input.version,
|
|
||||||
it
|
|
||||||
)
|
|
||||||
args.setInputFile(it)
|
args.setInputFile(it)
|
||||||
updateProgress() // Downloading
|
updateProgress() // Downloading
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ class VersionSelectorViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val downloadedVersions = downloadedAppRepository.getAll().map { downloadedApps ->
|
val downloadedVersions = downloadedAppRepository.getAll().map { downloadedApps ->
|
||||||
downloadedApps.filter { it.packageName == packageName }.map { SelectedApp.Local(it.packageName, it.version, it.file, false) }
|
downloadedApps.filter { it.packageName == packageName }.map { SelectedApp.Local(it.packageName, it.version, downloadedAppRepository.getApkFileForApp(it), false) }
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
Loading…
Reference in New Issue
Block a user