Files
revanced-library/src/main/kotlin/app/revanced/library/Options.kt
2023-12-07 15:14:59 +01:00

121 lines
3.9 KiB
Kotlin

@file:Suppress("MemberVisibilityCanBePrivate")
package app.revanced.library
import app.revanced.library.Options.Patch.Option
import app.revanced.patcher.PatchSet
import app.revanced.patcher.patch.options.PatchOptionException
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import java.io.File
import java.util.logging.Logger
@Suppress("unused")
object Options {
private val logger = Logger.getLogger(Options::class.java.name)
private val mapper = jacksonObjectMapper()
/**
* Serializes the options for a set of patches.
*
* @param patches The set of patches to serialize.
* @param prettyPrint Whether to pretty print the JSON.
* @return The JSON string containing the options.
*/
fun serialize(
patches: PatchSet,
prettyPrint: Boolean = false,
): String =
patches
.filter { it.options.any() }
.map { patch ->
Patch(
patch.name!!,
patch.options.values.map { option ->
val optionValue =
try {
option.value
} catch (e: PatchOptionException) {
logger.warning("Using default option value for the ${patch.name} patch: ${e.message}")
option.default
}
Option(option.key, optionValue)
},
)
}
// See https://github.com/revanced/revanced-patches/pull/2434/commits/60e550550b7641705e81aa72acfc4faaebb225e7.
.distinctBy { it.patchName }
.let {
if (prettyPrint) {
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(it)
} else {
mapper.writeValueAsString(it)
}
}
/**
* Deserializes the options to a set of patches.
*
* @param json The JSON string containing the options.
* @return A set of [Patch]s.
* @see Patch
*/
fun deserialize(json: String): Array<Patch> = mapper.readValue(json, Array<Patch>::class.java)
/**
* Sets the options for a set of patches.
*
* @param json The JSON string containing the options.
*/
fun PatchSet.setOptions(json: String) {
filter { it.options.any() }.let { patches ->
if (patches.isEmpty()) return
val jsonPatches =
deserialize(json).associate {
it.patchName to it.options.associate { option -> option.key to option.value }
}
patches.forEach { patch ->
jsonPatches[patch.name]?.let { jsonPatchOptions ->
jsonPatchOptions.forEach { (option, value) ->
try {
patch.options[option] = value
} catch (e: PatchOptionException) {
logger.warning("Could not set option value for the ${patch.name} patch: ${e.message}")
}
}
}
}
}
}
/**
* Sets the options for a set of patches.
*
* @param file The file containing the JSON string containing the options.
* @see setOptions
*/
fun PatchSet.setOptions(file: File) = setOptions(file.readText())
/**
* Data class for a patch and its [Option]s.
*
* @property patchName The name of the patch.
* @property options The [Option]s for the patch.
*/
class Patch internal constructor(
val patchName: String,
val options: List<Option>,
) {
/**
* Data class for patch option.
*
* @property key The name of the option.
* @property value The value of the option.
*/
class Option internal constructor(val key: String, val value: Any?)
}
}