diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37d08cd70..35ff3b4e9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,16 +24,12 @@ jobs: java-version: '17' distribution: 'adopt' cache: gradle - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: "lts/*" - name: Setup Android SDK uses: android-actions/setup-android@v2 - name: Build with Gradle env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: ./gradlew build clean generateReadme + run: ./gradlew build clean - name: Install Android build-tools run: sdkmanager "build-tools;32.0.0" - name: Setup semantic-release diff --git a/README-template.md b/README-template.md index 1f988237c..40cc7cfaf 100644 --- a/README-template.md +++ b/README-template.md @@ -1,7 +1,72 @@ -# 🧩 ReVanced Patches +## 🧩 Patches -Official patches by ReVanced +The official Patch bundle provided by ReVanced and the community. -## 📜 List of available patches +> Looking for the JSON variant of this? [Click here](patches.json). {{ table }} + +## 📝 JSON Format + +This section explains the JSON format for the [patches.json](patches.json) file. + +The file contains an array of objects, each object representing a patch. The object contains the following properties: + +| key | description | +|-------------------------------|------------------------------------------------------------------------------------------------------------------| +| `name` | The name of the patch. | +| `description` | The description of the patch. | +| `version` | The version of the patch. | +| `excluded` | Whether a patch is excluded by default. If `true`, the patch must never be included by default. | +| `dependencies` | An array of dependencies, which are patch names. | +| `compatiblePackages` | An array of packages compatible with this patch. | +| `compatiblePackages.name` | The name of the package. | +| `compatiblePackages.versions` | An array of versions of the package compatible with this patch. If empty, all versions are seemingly compatible. | + +Example: + +```json +[ + { + "name": "remember-video-quality", + "description": "Adds the ability to remember the video quality you chose in the video quality flyout.", + "version": "0.0.1", + "excluded": false, + "dependencies": [ + "integrations", + "video-id-hook" + ], + "compatiblePackages": [ + { + "name": "com.google.android.youtube", + "versions": [ + "17.22.36", + "17.24.35", + "17.26.35", + "17.27.39", + "17.28.34", + "17.29.34", + "17.32.35" + ] + } + ] + }, + { + "name": "client-spoof", + "description": "Spoofs the YouTube or Vanced client to prevent playback issues.", + "version": "0.0.1", + "excluded": false, + "dependencies": [], + "compatiblePackages": [ + { + "name": "com.google.android.youtube", + "versions": [] + }, + { + "name": "com.vanced.android.youtube", + "versions": [] + } + ] + } +] +``` \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index d288793b1..12f28f4fa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,6 +24,9 @@ dependencies { implementation("app.revanced:revanced-patcher:3.3.3") implementation("app.revanced:multidexlib2:2.5.2.r2") + + // Required for meta + implementation("com.google.code.gson:gson:2.9.1") } tasks { @@ -48,12 +51,12 @@ tasks { } } } - register("generateReadme") { - description = "Generate README.md" + register("generateMeta") { + description = "Generate metadata for this bundle" dependsOn(build) classpath = sourceSets["main"].runtimeClasspath - mainClass.set("app.revanced.meta.readme.Generator") + mainClass.set("app.revanced.meta.Meta") } // Dummy task to fix the Gradle semantic-release plugin. // Remove this if you forked it to support building only. @@ -61,6 +64,6 @@ tasks { register("publish") { group = "publish" description = "Dummy task" - dependsOn(named("generateBundle"), named("generateReadme")) + dependsOn(named("generateBundle"), named("generateMeta")) } } diff --git a/src/main/kotlin/app/revanced/meta/Meta.kt b/src/main/kotlin/app/revanced/meta/Meta.kt new file mode 100644 index 000000000..b629c66d7 --- /dev/null +++ b/src/main/kotlin/app/revanced/meta/Meta.kt @@ -0,0 +1,27 @@ +package app.revanced.meta + +import app.revanced.meta.json.generateJson +import app.revanced.meta.readme.generateText +import app.revanced.patcher.data.Data +import app.revanced.patcher.patch.Patch +import app.revanced.patcher.util.patch.impl.JarPatchBundle +import java.io.File + +typealias Bundle = List>> + +object Meta { + @JvmStatic + fun main(args: Array) { + val patches = accumulatePatches() + if (patches.isEmpty()) throw IllegalStateException("No patches found") + + generateText(patches) + generateJson(patches) + } +} + +fun accumulatePatches() = JarPatchBundle( + File("build/libs/").listFiles()!!.first { + it.name.startsWith("revanced-patches-") && it.name.endsWith(".jar") + }.absolutePath +).loadPatches() \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/meta/json/Generator.kt b/src/main/kotlin/app/revanced/meta/json/Generator.kt new file mode 100644 index 000000000..3585c3b1b --- /dev/null +++ b/src/main/kotlin/app/revanced/meta/json/Generator.kt @@ -0,0 +1,33 @@ +package app.revanced.meta.json + +import app.revanced.meta.Bundle +import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages +import app.revanced.patcher.extensions.PatchExtensions.dependencies +import app.revanced.patcher.extensions.PatchExtensions.description +import app.revanced.patcher.extensions.PatchExtensions.include +import app.revanced.patcher.extensions.PatchExtensions.patchName +import app.revanced.patcher.extensions.PatchExtensions.version +import com.google.gson.Gson +import java.io.File + +private val gson = Gson() + +fun generateJson(bundle: Bundle) { + val patches = bundle.map { + JsonPatch( + it.patchName, + it.description ?: "This patch has no description.", + it.version ?: "0.0.0", + !it.include, + it.dependencies?.map { dep -> + dep.java.patchName + }?.toTypedArray() ?: emptyArray(), + it.compatiblePackages?.map { pkg -> + CompatiblePackage(pkg.name, pkg.versions) + }?.toTypedArray() ?: emptyArray() + ) + } + + val json = File("patches.json") + json.writeText(gson.toJson(patches)) +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/meta/json/JsonPatch.kt b/src/main/kotlin/app/revanced/meta/json/JsonPatch.kt new file mode 100644 index 000000000..04242cffd --- /dev/null +++ b/src/main/kotlin/app/revanced/meta/json/JsonPatch.kt @@ -0,0 +1,17 @@ +@file:Suppress("ArrayInDataClass") // We don't need it here. + +package app.revanced.meta.json + +data class JsonPatch( + val name: String, + val description: String, + val version: String, + val excluded: Boolean, + val dependencies: Array, + val compatiblePackages: Array, +) + +data class CompatiblePackage( + val name: String, + val versions: Array, +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/meta/readme/Extensions.kt b/src/main/kotlin/app/revanced/meta/readme/Extensions.kt index d767f7ad4..72779a009 100644 --- a/src/main/kotlin/app/revanced/meta/readme/Extensions.kt +++ b/src/main/kotlin/app/revanced/meta/readme/Extensions.kt @@ -4,8 +4,7 @@ import app.revanced.patcher.data.Data import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.patch.Patch -internal fun Class>.getLatestVersion(): SemanticVersion? = - this.compatiblePackages?.first()?.versions?.map { SemanticVersion.fromString(it) } - ?.maxWithOrNull( - SemanticVersionComparator - ) +internal fun Class>.getLatestVersion() = + this.compatiblePackages?.first()?.versions?.map { + SemanticVersion.fromString(it) + }?.maxWithOrNull(SemanticVersionComparator) diff --git a/src/main/kotlin/app/revanced/meta/readme/Generator.kt b/src/main/kotlin/app/revanced/meta/readme/Generator.kt index b6557d814..4224fd2aa 100644 --- a/src/main/kotlin/app/revanced/meta/readme/Generator.kt +++ b/src/main/kotlin/app/revanced/meta/readme/Generator.kt @@ -1,55 +1,44 @@ package app.revanced.meta.readme +import app.revanced.meta.Bundle import app.revanced.patcher.data.Data import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.description import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.patch.Patch -import app.revanced.patcher.util.patch.impl.JarPatchBundle import java.io.File -object Generator { - private const val TABLE_HEADER = - "| \uD83D\uDC8A Patch | \uD83D\uDCDC Description | \uD83C\uDFF9 Target Version |\n" + - "|:--------:|:--------------:|:-----------------:|" +private const val TABLE_HEADER = + "| \uD83D\uDC8A Patch | \uD83D\uDCDC Description | \uD83C\uDFF9 Target Version |\n" + "|:--------:|:--------------:|:-----------------:|" - @JvmStatic - fun main(args: Array) { - val buildDir = File("build/libs/") - val buildJar = - buildDir.listFiles()?.first { it.name.startsWith("revanced-patches-") && it.name.endsWith(".jar") }!! +private val TABLE_REGEX = Regex("\\{\\{\\s?table\\s?}}") - val bundle = JarPatchBundle(buildJar.absolutePath).loadPatches() +fun generateText(bundle: Bundle) { + val output = StringBuilder() + val packages = mutableMapOf>>>() - val output = StringBuilder() - - val packages = mutableMapOf>>>() - - bundle.map { - val packageName = it.compatiblePackages?.first()?.name!! - if (!packages.contains(packageName)) { - packages[packageName] = mutableListOf() - } - - packages[packageName]?.add(it) + bundle.map { + val packageName = it.compatiblePackages?.first()?.name!! + if (!packages.contains(packageName)) { + packages[packageName] = mutableListOf() } - for (pkg in packages) { - output.appendLine("### \uD83D\uDCE6 `${pkg.key}`") - output.appendLine("
\n") - - output.appendLine(TABLE_HEADER) - pkg.value.forEach { output.appendLine("| `${it.patchName}` | ${it.description} | ${it.getLatestVersion() ?: "all"} |") } - - output.appendLine("
\n") - } - - val readMeTemplateFile = File("README-template.md") - val readmeTemplate = Template(readMeTemplateFile.readText()) - - readmeTemplate.replaceVariable("table", output.toString()) - - val readme = File("README.md") - readme.writeText(readmeTemplate.toString()) + packages[packageName]?.add(it) } + + for (pkg in packages) { + output.appendLine("### \uD83D\uDCE6 `${pkg.key}`") + output.appendLine("
\n") + + output.appendLine(TABLE_HEADER) + pkg.value.forEach { output.appendLine("| `${it.patchName}` | ${it.description} | ${it.getLatestVersion() ?: "all"} |") } + + output.appendLine("
\n") + } + + val readmeTemplate = Template(File("README-template.md").readText()) + readmeTemplate.replaceVariable(TABLE_REGEX, output.toString()) + + val readme = File("README.md") + readme.writeText(readmeTemplate.toString()) } diff --git a/src/main/kotlin/app/revanced/meta/readme/SemanticVersion.kt b/src/main/kotlin/app/revanced/meta/readme/SemanticVersion.kt index 7940bd2b3..6c461f239 100644 --- a/src/main/kotlin/app/revanced/meta/readme/SemanticVersion.kt +++ b/src/main/kotlin/app/revanced/meta/readme/SemanticVersion.kt @@ -3,10 +3,8 @@ package app.revanced.meta.readme data class SemanticVersion(val major: Int, val minor: Int, val patch: Int) { companion object { fun fromString(version: String): SemanticVersion { - var parts = version.split(".") - + val parts = version.split(".") if (parts.count() != 3) throw IllegalArgumentException("Invalid semantic version") - val versionNumbers = parts.map { it.toInt() } return SemanticVersion(versionNumbers[0], versionNumbers[1], versionNumbers[2]) } diff --git a/src/main/kotlin/app/revanced/meta/readme/Template.kt b/src/main/kotlin/app/revanced/meta/readme/Template.kt index 648c985d7..3b952c9cb 100644 --- a/src/main/kotlin/app/revanced/meta/readme/Template.kt +++ b/src/main/kotlin/app/revanced/meta/readme/Template.kt @@ -1,12 +1,10 @@ package app.revanced.meta.readme class Template(template: String) { - val result: StringBuilder = StringBuilder(template) + val result = StringBuilder(template) - fun replaceVariable(name: String, value: String) { - val regex = Regex("\\{\\{\\s?$name\\s?}}") + fun replaceVariable(regex: Regex, value: String) { val range = regex.find(result)!!.range - result.replace(range.first, range.last + 1, value) }