mirror of
https://github.com/ReVanced/revanced-cli.git
synced 2026-01-24 19:51:05 +00:00
add: resource patcher
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
@@ -2,13 +2,13 @@ package app.revanced.utils
|
||||
|
||||
// TODO: make this a class with PACKAGE_NAME as argument, then use that everywhere.
|
||||
// make sure to remove the "const" from all the vals, they won't compile obviously.
|
||||
object Scripts {
|
||||
internal object Scripts {
|
||||
private const val PACKAGE_NAME = "com.google.android.apps.youtube.music"
|
||||
private const val DATA_PATH = "/data/adb/ReVanced"
|
||||
const val APK_PATH = "/sdcard/base.apk"
|
||||
const val SCRIPT_PATH = "/sdcard/mount.sh"
|
||||
internal const val APK_PATH = "/sdcard/base.apk"
|
||||
internal const val SCRIPT_PATH = "/sdcard/mount.sh"
|
||||
|
||||
val MOUNT_SCRIPT =
|
||||
internal val MOUNT_SCRIPT =
|
||||
"""
|
||||
base_path="$DATA_PATH/base.apk"
|
||||
stock_path=${'$'}{ pm path $PACKAGE_NAME | grep base | sed 's/package://g' }
|
||||
@@ -21,14 +21,15 @@ object Scripts {
|
||||
mount -o bind ${'$'}base_path ${'$'}stock_path
|
||||
""".trimIndent()
|
||||
|
||||
const val PIDOF_APP_COMMAND = "pidof -s $PACKAGE_NAME"
|
||||
internal const val PIDOF_APP_COMMAND = "pidof -s $PACKAGE_NAME"
|
||||
private const val PIDOF_APP = "\$($PIDOF_APP_COMMAND)"
|
||||
const val CREATE_DIR_COMMAND = "su -c \"mkdir -p $DATA_PATH/\""
|
||||
const val MV_MOUNT_COMMAND = "su -c \"mv /sdcard/mount.sh $DATA_PATH/\""
|
||||
const val CHMOD_MOUNT_COMMAND = "su -c \"chmod +x $DATA_PATH/mount.sh\""
|
||||
const val START_MOUNT_COMMAND = "su -c $DATA_PATH/mount.sh"
|
||||
const val UNMOUNT_COMMAND = "su -c \"umount -l $(pm path $PACKAGE_NAME | grep base | sed 's/package://g')\""
|
||||
const val LOGCAT_COMMAND = "su -c \"logcat -c && logcat --pid=$PIDOF_APP\""
|
||||
const val STOP_APP_COMMAND = "su -c \"kill $PIDOF_APP\""
|
||||
const val START_APP_COMMAND = "monkey -p $PACKAGE_NAME 1"
|
||||
internal const val CREATE_DIR_COMMAND = "su -c \"mkdir -p $DATA_PATH/\""
|
||||
internal const val MV_MOUNT_COMMAND = "su -c \"mv /sdcard/mount.sh $DATA_PATH/\""
|
||||
internal const val CHMOD_MOUNT_COMMAND = "su -c \"chmod +x $DATA_PATH/mount.sh\""
|
||||
internal const val START_MOUNT_COMMAND = "su -c $DATA_PATH/mount.sh"
|
||||
internal const val UNMOUNT_COMMAND =
|
||||
"su -c \"umount -l $(pm path $PACKAGE_NAME | grep base | sed 's/package://g')\""
|
||||
internal const val LOGCAT_COMMAND = "su -c \"logcat -c && logcat --pid=$PIDOF_APP\""
|
||||
internal const val STOP_APP_COMMAND = "su -c \"kill $PIDOF_APP\""
|
||||
internal const val START_APP_COMMAND = "monkey -p $PACKAGE_NAME 1"
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package app.revanced.utils.dex
|
||||
|
||||
import lanchon.multidexlib2.BasicDexFileNamer
|
||||
import org.jf.dexlib2.writer.io.MemoryDataStore
|
||||
import java.io.File
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Files
|
||||
|
||||
val NAMER = BasicDexFileNamer()
|
||||
|
||||
object DexReplacer {
|
||||
fun replaceDex(source: File, dexFiles: Map<String, MemoryDataStore>) {
|
||||
FileSystems.newFileSystem(
|
||||
source.toPath(),
|
||||
null
|
||||
).use { fs ->
|
||||
// Delete all classes?.dex files
|
||||
Files.walk(fs.rootDirectories.first()).forEach {
|
||||
if (
|
||||
it.toString().endsWith(".dex") &&
|
||||
NAMER.isValidName(it.fileName.toString())
|
||||
) Files.delete(it)
|
||||
}
|
||||
// Write new dex files
|
||||
dexFiles
|
||||
.forEach { (dexName, dexData) ->
|
||||
Files.write(fs.getPath("/$dexName"), dexData.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package app.revanced.utils.filesystem
|
||||
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.nio.file.FileSystem
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Files
|
||||
|
||||
internal class FileSystemUtils(
|
||||
file: File
|
||||
) : Closeable {
|
||||
private var fileSystem: FileSystem
|
||||
|
||||
init {
|
||||
fileSystem = FileSystems.newFileSystem(
|
||||
file.toPath(),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
private fun deleteDirectory(dirPath: String) {
|
||||
val files = Files.walk(fileSystem.getPath("$dirPath/"))
|
||||
|
||||
files
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.forEach {
|
||||
|
||||
Files.delete(it)
|
||||
}
|
||||
|
||||
files.close()
|
||||
}
|
||||
|
||||
|
||||
internal fun replaceDirectory(replacement: File) {
|
||||
if (!replacement.isDirectory) throw Exception("${replacement.name} is not a directory.")
|
||||
|
||||
// FIXME: make this delete the directory recursively
|
||||
//deleteDirectory(replacement.name)
|
||||
//val path = Files.createDirectory(fileSystem.getPath(replacement.name))
|
||||
|
||||
val excludeFromPath = replacement.path.removeSuffix(replacement.name)
|
||||
for (path in Files.walk(replacement.toPath())) {
|
||||
val file = path.toFile()
|
||||
if (file.isDirectory) {
|
||||
val relativePath = path.toString().removePrefix(excludeFromPath)
|
||||
val fileSystemPath = fileSystem.getPath(relativePath)
|
||||
if (!Files.exists(fileSystemPath)) Files.createDirectory(fileSystemPath)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
replaceFile(path.toString().removePrefix(excludeFromPath), file.readBytes())
|
||||
}
|
||||
}
|
||||
|
||||
internal fun replaceFile(sourceFile: String, content: ByteArray) {
|
||||
val path = fileSystem.getPath(sourceFile)
|
||||
Files.deleteIfExists(path)
|
||||
Files.write(path, content)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
fileSystem.close()
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package app.revanced.utils.patch
|
||||
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
|
||||
class PatchLoader {
|
||||
companion object {
|
||||
fun injectPatches(file: File) {
|
||||
// This function will fail on Java 9 and above.
|
||||
try {
|
||||
val url = file.toURI().toURL()
|
||||
val classLoader = Thread.currentThread().contextClassLoader as URLClassLoader
|
||||
val method = URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java)
|
||||
method.isAccessible = true
|
||||
method.invoke(classLoader, url)
|
||||
} catch (e: Exception) {
|
||||
throw Exception(
|
||||
"Failed to inject patches! The CLI does NOT work on Java 9 and above, please use Java 8!",
|
||||
e // propagate exception
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package app.revanced.utils.patch
|
||||
|
||||
import app.revanced.patches.Index
|
||||
|
||||
class Patches {
|
||||
companion object {
|
||||
// You may ask yourself, "why do this?".
|
||||
// We do it like this, because we don't want the Index class
|
||||
// to be loaded while the dependency hasn't been injected yet.
|
||||
// You can see this as "controlled class loading".
|
||||
// Whenever this class is loaded (because it is invoked), all the imports
|
||||
// will be loaded too. We don't want to do this until we've injected the class.
|
||||
fun loadPatches() = Index.patches
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user