feat(YouTube Music): Support patching on Android 5-7 (#140)

* feat(YouTube Music): Support patching on Android 5-7

* Improve comments
This commit is contained in:
kitadai31 2025-02-12 09:55:37 +09:00 committed by GitHub
parent 325b43e394
commit 967776a484
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 78 additions and 40 deletions

View File

@ -11,6 +11,7 @@ import app.revanced.patches.music.utils.playservice.versionCheckPatch
import app.revanced.patches.music.utils.settings.ResourceUtils.setIconType
import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus
import app.revanced.patches.music.utils.settings.settingsPatch
import app.revanced.util.FilesCompat
import app.revanced.util.ResourceGroup
import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.copyAdaptiveIcon
@ -20,7 +21,6 @@ import app.revanced.util.underBarOrThrow
import app.revanced.util.valueOrThrow
import org.w3c.dom.Element
import java.io.File
import java.nio.file.Files
private const val ADAPTIVE_ICON_BACKGROUND_FILE_NAME =
"adaptiveproduct_youtube_music_background_color_108"
@ -155,9 +155,9 @@ val customBrandingIconPatch = resourcePatch(
val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName)
group.resources.forEach { iconFileName ->
Files.write(
toDirectory.resolve(iconFileName).toPath(),
fromDirectory.resolve(iconFileName).readBytes()
FilesCompat.copy(
fromDirectory.resolve(iconFileName),
toDirectory.resolve(iconFileName)
)
}
}

View File

@ -1,8 +1,8 @@
package app.revanced.patches.shared.materialyou
import app.revanced.patcher.patch.ResourcePatchContext
import app.revanced.util.FilesCompat
import org.w3c.dom.Element
import java.nio.file.Files
private fun ResourcePatchContext.patchXmlFile(
fromDir: String,
@ -17,7 +17,7 @@ private fun ResourcePatchContext.patchXmlFile(
val fromDirectory = resourceDirectory.resolve(fromDir)
val toDirectory = resourceDirectory.resolve(toDir)
if (!toDirectory.isDirectory) Files.createDirectories(toDirectory.toPath())
if (!toDirectory.isDirectory) toDirectory.mkdirs()
val fromXmlFile = fromDirectory.resolve(xmlFileName)
val toXmlFile = toDirectory.resolve(xmlFileName)
@ -27,9 +27,9 @@ private fun ResourcePatchContext.patchXmlFile(
}
if (!toXmlFile.exists()) {
Files.copy(
fromXmlFile.toPath(),
toXmlFile.toPath()
FilesCompat.copy(
fromXmlFile,
toXmlFile
)
}

View File

@ -2,13 +2,12 @@ package app.revanced.patches.shared.translations
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.ResourcePatchContext
import app.revanced.util.FilesCompat
import app.revanced.util.doRecursively
import app.revanced.util.inputStreamFromBundledResource
import org.w3c.dom.Element
import org.w3c.dom.Node
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
@ -173,12 +172,11 @@ private fun ResourcePatchContext.copyStringsXml(
)?.let { inputStream ->
val directory = "values-$language-v21"
val valuesV21Directory = resourceDirectory.resolve(directory)
if (!valuesV21Directory.isDirectory) Files.createDirectories(valuesV21Directory.toPath())
if (!valuesV21Directory.isDirectory) valuesV21Directory.mkdirs()
Files.copy(
FilesCompat.copy(
inputStream,
resourceDirectory.resolve("$directory/strings.xml").toPath(),
StandardCopyOption.REPLACE_EXISTING
resourceDirectory.resolve("$directory/strings.xml")
)
}
}

View File

@ -0,0 +1,53 @@
package app.revanced.util
import java.io.File
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.StandardCopyOption
/**
* Provides java.nio.file.Files compatible functions.
*
* This is needed for the ReVanced Manager running on Android 5.0-7.1
* because Android 7.1 and below does not support the Java NIO2 Files API.
*/
internal object FilesCompat {
private val useCompat = try {
// Check for the existence of java.nio.file.Files class
Class.forName("java.nio.file.Files")
false
} catch (_ : ClassNotFoundException) {
// Under Android 8.0
true
}
/**
* Copy a file to a target file.
*
* If the `target` file already exists, replace an existing file.
*/
fun copy(source: File, target: File) {
if (useCompat) {
source.copyTo(target, overwrite = true)
} else {
Files.copy(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
}
/**
* Copies all bytes from an input stream to a file.
*
* If the `target` file already exists, replace an existing file.
*/
fun copy(source: InputStream, target: File) {
if (useCompat) {
source.use { inputStream ->
target.outputStream().use { outputStream ->
inputStream.copyTo(outputStream)
}
}
} else {
Files.copy(source, target.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
}
}

View File

@ -11,8 +11,6 @@ import org.w3c.dom.Node
import org.w3c.dom.NodeList
import java.io.File
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.StandardCopyOption
private val classLoader = object {}.javaClass.classLoader
@ -115,14 +113,9 @@ fun ResourcePatchContext.copyAdaptiveIcon(
if (oldIconResourceFile != newIconResourceFile) {
mipmapDirectories.forEach {
val mipmapDirectory = get("res").resolve(it)
Files.copy(
mipmapDirectory
.resolve("$oldIconResourceFile.png")
.toPath(),
mipmapDirectory
.resolve("$newIconResourceFile.png")
.toPath(),
StandardCopyOption.REPLACE_EXISTING
FilesCompat.copy(
mipmapDirectory.resolve("$oldIconResourceFile.png"),
mipmapDirectory.resolve("$newIconResourceFile.png")
)
}
}
@ -132,14 +125,9 @@ fun ResourcePatchContext.copyAdaptiveIcon(
adaptiveIconMonoChromeFileName != getAdaptiveIconMonoChromeResourceFile()
) {
val drawableDirectory = get("res").resolve("drawable")
Files.copy(
drawableDirectory
.resolve("$adaptiveIconMonoChromeFileName.xml")
.toPath(),
drawableDirectory
.resolve("${getAdaptiveIconMonoChromeResourceFile()}.xml")
.toPath(),
StandardCopyOption.REPLACE_EXISTING
FilesCompat.copy(
drawableDirectory.resolve("$adaptiveIconMonoChromeFileName.xml"),
drawableDirectory.resolve("${getAdaptiveIconMonoChromeResourceFile()}.xml")
)
}
}
@ -201,9 +189,9 @@ fun ResourcePatchContext.copyFile(
val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName)
group.resources.forEach { iconFileName ->
Files.write(
toDirectory.resolve(iconFileName).toPath(),
fromDirectory.resolve(iconFileName).readBytes()
FilesCompat.copy(
fromDirectory.resolve(iconFileName),
toDirectory.resolve(iconFileName)
)
}
}
@ -307,16 +295,15 @@ fun ResourcePatchContext.copyResources(
resourceGroup.resources.forEach { resource ->
val resourceDirectoryName = resourceGroup.resourceDirectoryName
val targetDirectory = resourceDirectory.resolve(resourceDirectoryName)
if (!targetDirectory.isDirectory) Files.createDirectories(targetDirectory.toPath())
if (!targetDirectory.isDirectory) targetDirectory.mkdirs()
val resourceFile = "$resourceDirectoryName/$resource"
inputStreamFromBundledResource(
sourceResourceDirectory,
resourceFile
)?.let { inputStream ->
Files.copy(
FilesCompat.copy(
inputStream,
resourceDirectory.resolve(resourceFile).toPath(),
StandardCopyOption.REPLACE_EXISTING,
resourceDirectory.resolve(resourceFile),
)
}
}