mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-12 21:27:43 +02:00
cleanup
This commit is contained in:
@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.youtube.layout.etc.branding.icon.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.resources.IconHelper.customIcon
|
||||
import app.revanced.util.resources.ResourceHelper.updatePatchStatusIcon
|
||||
|
||||
@Patch(false)
|
||||
@Name("custom-branding-icon-afn-blue")
|
||||
@Description("Changes the YouTube launcher icon (Afn / Blue).")
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CustomBrandingIconBluePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
context.customIcon("blue")
|
||||
context.updatePatchStatusIcon("blue")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.youtube.layout.etc.branding.icon.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.resources.IconHelper.customIcon
|
||||
import app.revanced.util.resources.ResourceHelper.updatePatchStatusIcon
|
||||
|
||||
@Patch
|
||||
@Name("custom-branding-icon-afn-red")
|
||||
@Description("Changes the YouTube launcher icon (Afn / Red).")
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CustomBrandingIconRedPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
context.customIcon("red")
|
||||
context.updatePatchStatusIcon("red")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.youtube.layout.etc.branding.icon.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.resources.IconHelper.customIcon
|
||||
import app.revanced.util.resources.ResourceHelper.updatePatchStatusIcon
|
||||
|
||||
@Patch(false)
|
||||
@Name("custom-branding-icon-revancify")
|
||||
@Description("Changes the YouTube launcher icon (Revancify).")
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CustomBrandingIconRevancifyPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
context.customIcon("revancify")
|
||||
context.updatePatchStatusIcon("revancify")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package app.revanced.patches.youtube.layout.etc.branding.name.patch
|
||||
|
||||
import app.revanced.extensions.startsWithAny
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.options.PatchOptions
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.resources.ResourceHelper.updatePatchStatusLabel
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Patch
|
||||
@Name("custom-branding-name")
|
||||
@DependsOn(
|
||||
[
|
||||
PatchOptions::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@Description("Changes the YouTube launcher name to your choice (defaults to ReVanced Extended).")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class CustomBrandingNamePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
// App name
|
||||
val resourceFileNames = arrayOf("strings.xml")
|
||||
val appName = PatchOptions.YouTubeAppName
|
||||
|
||||
context.forEach {
|
||||
if (!it.name.startsWithAny(*resourceFileNames)) return@forEach
|
||||
|
||||
// for each file in the "layouts" directory replace all necessary attributes content
|
||||
context.xmlEditor[it.absolutePath].use { editor ->
|
||||
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
|
||||
|
||||
for (i in 0 until resourcesNode.childNodes.length) {
|
||||
val node = resourcesNode.childNodes.item(i)
|
||||
if (node !is Element) continue
|
||||
|
||||
val element = resourcesNode.childNodes.item(i) as Element
|
||||
element.textContent = when (element.getAttribute("name")) {
|
||||
"application_name" -> "$appName"
|
||||
else -> continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.updatePatchStatusLabel("$appName")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package app.revanced.patches.youtube.layout.etc.forceheader.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import kotlin.io.path.exists
|
||||
|
||||
@Patch(false)
|
||||
@Name("force-premium-heading")
|
||||
@Description("Forces premium heading on the home screen.")
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class PremiumHeadingPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
val resDirectory = context["res"]
|
||||
if (!resDirectory.isDirectory) return PatchResultError("The res folder can not be found.")
|
||||
|
||||
val (original, replacement) = "yt_premium_wordmark_header" to "yt_wordmark_header"
|
||||
val modes = arrayOf("light", "dark")
|
||||
|
||||
arrayOf("xxxhdpi", "xxhdpi", "xhdpi", "hdpi", "mdpi").forEach { size ->
|
||||
val headingDirectory = resDirectory.resolve("drawable-$size")
|
||||
modes.forEach { mode ->
|
||||
val fromPath = headingDirectory.resolve("${original}_$mode.png").toPath()
|
||||
val toPath = headingDirectory.resolve("${replacement}_$mode.png").toPath()
|
||||
|
||||
if (!fromPath.exists())
|
||||
return PatchResultError("The file $fromPath does not exist in the resources. Therefore, this patch can not succeed.")
|
||||
Files.copy(
|
||||
fromPath,
|
||||
toPath,
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val prefs = context["res/xml/revanced_prefs.xml"]
|
||||
prefs.writeText(
|
||||
prefs.readText()
|
||||
.replace(
|
||||
"HEADER_SWITCH",
|
||||
"FORCE_PREMIUM_HEADER"
|
||||
).replace(
|
||||
"header-switch",
|
||||
"force-premium-heading"
|
||||
)
|
||||
)
|
||||
|
||||
SettingsPatch.updatePatchStatus("force-premium-heading")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package app.revanced.patches.youtube.layout.etc.materialyou.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.layout.etc.theme.bytecode.patch.GeneralThemePatch
|
||||
import app.revanced.patches.youtube.layout.etc.theme.bytecode.patch.GeneralThemePatch.Companion.isMonetPatchIncluded
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.resources.ResourceHelper.updatePatchStatusTheme
|
||||
import app.revanced.util.resources.ResourceUtils.copyXmlNode
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
@Patch(false)
|
||||
@Name("materialyou")
|
||||
@Description("Enables MaterialYou theme for Android 12+")
|
||||
@DependsOn(
|
||||
[
|
||||
GeneralThemePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class MaterialYouPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
val drawables1 = "drawable-night-v31" to arrayOf(
|
||||
"new_content_dot_background.xml"
|
||||
)
|
||||
|
||||
val drawables2 = "drawable-v31" to arrayOf(
|
||||
"new_content_count_background.xml",
|
||||
"new_content_dot_background.xml"
|
||||
)
|
||||
|
||||
val layout1 = "layout-v31" to arrayOf(
|
||||
"new_content_count.xml"
|
||||
)
|
||||
|
||||
arrayOf(drawables1, drawables2, layout1).forEach { (path, resourceNames) ->
|
||||
Files.createDirectory(context["res"].resolve(path).toPath())
|
||||
resourceNames.forEach { name ->
|
||||
val monetPath = "$path/$name"
|
||||
|
||||
Files.copy(
|
||||
this.javaClass.classLoader.getResourceAsStream("youtube/materialyou/$monetPath")!!,
|
||||
context["res"].resolve(monetPath).toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val sourcePath = this.javaClass.classLoader.getResourceAsStream("youtube/materialyou/host/values-v31/colors.xml")!!
|
||||
val relativePath = context.xmlEditor["res/values-v31/colors.xml"]
|
||||
|
||||
"resources".copyXmlNode(
|
||||
context.xmlEditor[sourcePath],
|
||||
relativePath
|
||||
)
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
context.updatePatchStatusTheme("materialyou")
|
||||
|
||||
isMonetPatchIncluded = true
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package app.revanced.patches.youtube.layout.etc.optimize.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
|
||||
@Patch
|
||||
@Name("optimize-resource")
|
||||
@DependsOn(
|
||||
[
|
||||
RedundantResourcePatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@Description("Removes duplicate resources from YouTube.")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OptimizeResourcePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
SettingsPatch.updatePatchStatus("optimize-resource")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
package app.revanced.patches.youtube.layout.etc.optimize.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
@Name("remove-duplicate-resource-patch")
|
||||
@Description("Removes duplicate resources from YouTube.")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class RedundantResourcePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
// Convert universal APK to anti-split APK
|
||||
arrayOf(
|
||||
WHITELIST_MDPI,
|
||||
WHITELIST_HDPI,
|
||||
WHITELIST_XHDPI,
|
||||
WHITELIST_XXXHDPI
|
||||
).forEach { (path, array) ->
|
||||
val tmpDirectory = path + "-v21"
|
||||
Files.createDirectory(context["res"].resolve(tmpDirectory).toPath())
|
||||
|
||||
(WHITELIST_GENERAL + array).forEach { name ->
|
||||
try {
|
||||
Files.copy(
|
||||
context["res"].resolve("$path/$name").toPath(),
|
||||
context["res"].resolve("$tmpDirectory/$name").toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
} catch (_: Exception) {}
|
||||
}
|
||||
val directoryPath = context["res"].resolve(path)
|
||||
|
||||
Files.walk(directoryPath.toPath())
|
||||
.map(Path::toFile)
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.forEach(File::delete)
|
||||
|
||||
Files.move(
|
||||
context["res"].resolve(tmpDirectory).toPath(),
|
||||
context["res"].resolve(path).toPath()
|
||||
)
|
||||
}
|
||||
|
||||
context.copyResources(
|
||||
"youtube/resource",
|
||||
ResourceUtils.ResourceGroup(
|
||||
"raw",
|
||||
"third_party_licenses",
|
||||
"third_party_license_metadata"
|
||||
)
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val WHITELIST_GENERAL = arrayOf(
|
||||
"product_logo_youtube_color_24.png",
|
||||
"product_logo_youtube_color_36.png",
|
||||
"product_logo_youtube_color_144.png",
|
||||
"product_logo_youtube_color_192.png",
|
||||
"yt_outline_audio_black_24.png",
|
||||
"yt_outline_bag_black_24.png",
|
||||
"yt_outline_fashion_black_24.png",
|
||||
"yt_outline_film_strip_black_24.png",
|
||||
"yt_outline_fire_black_24.png",
|
||||
"yt_outline_gaming_black_24.png",
|
||||
"yt_outline_lightbulb_black_24.png",
|
||||
"yt_outline_news_black_24.png",
|
||||
"yt_outline_radar_live_black_24.png",
|
||||
"yt_outline_trophy_black_24.png",
|
||||
"yt_premium_wordmark_header_dark.png",
|
||||
"yt_premium_wordmark_header_light.png"
|
||||
)
|
||||
|
||||
val WHITELIST_MDPI = "drawable-mdpi" to arrayOf(
|
||||
"ic_searchable.webp",
|
||||
"generic_dark_x1.png",
|
||||
"generic_light_x1.png"
|
||||
)
|
||||
|
||||
val WHITELIST_HDPI = "drawable-hdpi" to arrayOf(
|
||||
"transition.png"
|
||||
)
|
||||
|
||||
val WHITELIST_XHDPI = "drawable-xhdpi" to arrayOf(
|
||||
"action_bar_logo_release.png",
|
||||
"ad_feed_call_to_action_arrow.webp",
|
||||
"ad_skip.png",
|
||||
"alert_error.png",
|
||||
"api_btn_cc_off.png",
|
||||
"api_btn_cc_on.png",
|
||||
"api_btn_hd_off.png",
|
||||
"api_btn_hd_on.png",
|
||||
"api_btn_hq_off.png",
|
||||
"api_btn_hq_on.png",
|
||||
"api_btn_next.png",
|
||||
"api_btn_pause.png",
|
||||
"api_btn_play.png",
|
||||
"api_btn_prev.png",
|
||||
"api_btn_replay.png",
|
||||
"api_btn_unavailable.png",
|
||||
"api_ic_full_screen.png",
|
||||
"api_ic_full_screen_selected.png",
|
||||
"api_ic_live.9.png",
|
||||
"api_ic_options.png",
|
||||
"api_ic_options_selected.png",
|
||||
"api_ic_small_screen.png",
|
||||
"api_ic_small_screen_selected.png",
|
||||
"api_player_bar.9.png",
|
||||
"api_player_buffered.9.png",
|
||||
"api_player_menu_bar.9.png",
|
||||
"api_player_track.9.png",
|
||||
"api_play_on_you_tube.png",
|
||||
"api_scrubber.png",
|
||||
"api_scrubber_selected.png",
|
||||
"box_shadow.9.png",
|
||||
"btn_play_all.9.png",
|
||||
"card_frame_bottom.9.png",
|
||||
"card_frame_middle.9.png",
|
||||
"circle_shadow.9.png",
|
||||
"common_full_open_on_phone.png",
|
||||
"compat_selector_disabled.9.png",
|
||||
"compat_selector_focused.9.png",
|
||||
"compat_selector_longpressed.9.png",
|
||||
"compat_selector_pressed.9.png",
|
||||
"ic_account_switcher_alert.png",
|
||||
"ic_annotation_close.png",
|
||||
"ic_api_youtube_logo.png",
|
||||
"ic_api_youtube_logo_pressed.png",
|
||||
"ic_api_youtube_watermark.png",
|
||||
"ic_notification_error.png",
|
||||
"ic_notification_error_small.webp",
|
||||
"ic_playlist_icon.png",
|
||||
"ic_unavailable_common.webp",
|
||||
"ic_youtube_logo.png",
|
||||
"lc_editbox_dropdown_background_dark.9.png",
|
||||
"star_empty.webp",
|
||||
"star_filled.webp",
|
||||
"survey_checked.png",
|
||||
"survey_unchecked.png",
|
||||
"textfield_default_mtrl_alpha.9.png",
|
||||
"youtube_lozenge_logo.png",
|
||||
"youtube_lozenge_logo_dni.png"
|
||||
)
|
||||
|
||||
val WHITELIST_XXXHDPI = "drawable-xxxhdpi" to arrayOf(
|
||||
"ic_group_collapse_00.png",
|
||||
"ic_group_collapse_01.png",
|
||||
"ic_group_collapse_02.png",
|
||||
"ic_group_collapse_03.png",
|
||||
"ic_group_collapse_04.png",
|
||||
"ic_group_collapse_05.png",
|
||||
"ic_group_collapse_06.png",
|
||||
"ic_group_collapse_07.png",
|
||||
"ic_group_collapse_08.png",
|
||||
"ic_group_collapse_09.png",
|
||||
"ic_group_collapse_10.png",
|
||||
"ic_group_collapse_11.png",
|
||||
"ic_group_collapse_12.png",
|
||||
"ic_group_collapse_13.png",
|
||||
"ic_group_collapse_14.png",
|
||||
"ic_group_collapse_15.png",
|
||||
"ic_group_expand_00.png",
|
||||
"ic_group_expand_01.png",
|
||||
"ic_group_expand_02.png",
|
||||
"ic_group_expand_03.png",
|
||||
"ic_group_expand_04.png",
|
||||
"ic_group_expand_05.png",
|
||||
"ic_group_expand_06.png",
|
||||
"ic_group_expand_07.png",
|
||||
"ic_group_expand_08.png",
|
||||
"ic_group_expand_09.png",
|
||||
"ic_group_expand_10.png",
|
||||
"ic_group_expand_11.png",
|
||||
"ic_group_expand_12.png",
|
||||
"ic_group_expand_13.png",
|
||||
"ic_group_expand_14.png",
|
||||
"ic_group_expand_15.png"
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package app.revanced.patches.youtube.layout.etc.pipnotification.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object PrimaryPiPFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IPUT_BOOLEAN
|
||||
),
|
||||
strings = listOf("honeycomb.Shell\$HomeActivity")
|
||||
)
|
@ -0,0 +1,20 @@
|
||||
package app.revanced.patches.youtube.layout.etc.pipnotification.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object SecondaryPiPFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET_OBJECT
|
||||
),
|
||||
strings = listOf("honeycomb.Shell\$HomeActivity")
|
||||
)
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.etc.pipnotification.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.layout.etc.pipnotification.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
|
||||
@Patch
|
||||
@Name("hide-pip-notification")
|
||||
@Description("Disable pip notification when you first launch pip mode.")
|
||||
@DependsOn([SettingsPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class PiPNotificationPatch : BytecodePatch(
|
||||
listOf(
|
||||
PrimaryPiPFingerprint,
|
||||
SecondaryPiPFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
arrayOf(
|
||||
PrimaryPiPFingerprint,
|
||||
SecondaryPiPFingerprint
|
||||
).map {
|
||||
it.result ?: return it.toErrorResult()
|
||||
}.forEach {
|
||||
val index = it.scanResult.patternScanResult!!.startIndex + 1
|
||||
it.mutableMethod.addInstruction(index, "return-void")
|
||||
}
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
SettingsPatch.updatePatchStatus("hide-pip-notification")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package app.revanced.patches.youtube.layout.etc.theme.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object LithoThemeFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
access = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
customFingerprint = { it.name == "onBoundsChange" }
|
||||
)
|
@ -0,0 +1,48 @@
|
||||
package app.revanced.patches.youtube.layout.etc.theme.bytecode.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.layout.etc.theme.bytecode.fingerprints.LithoThemeFingerprint
|
||||
import app.revanced.patches.youtube.layout.etc.theme.resource.patch.GeneralThemeResourcePatch
|
||||
import app.revanced.util.integrations.Constants.UTILS_PATH
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
||||
@Name("general-theme")
|
||||
@DependsOn([GeneralThemeResourcePatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class GeneralThemePatch : BytecodePatch(
|
||||
listOf(
|
||||
LithoThemeFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
LithoThemeFingerprint.result?.let {
|
||||
with (it.mutableMethod) {
|
||||
val insertIndex = it.scanResult.patternScanResult!!.endIndex - 1
|
||||
val register = (implementation!!.instructions[insertIndex] as Instruction35c).registerD
|
||||
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static { v$register }, $UTILS_PATH/LithoThemePatch;->applyLithoTheme(I)I
|
||||
move-result v$register
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return LithoThemeFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
internal companion object {
|
||||
var isMonetPatchIncluded: Boolean = false
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package app.revanced.patches.youtube.layout.etc.theme.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Name("general-theme-resource-patch")
|
||||
@Version("0.0.1")
|
||||
class GeneralThemeResourcePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
// edit the resource files to change the splash screen color
|
||||
val attrsPath = "res/values/attrs.xml"
|
||||
val stylesPaths: List<String> = listOf(
|
||||
"res/values/styles.xml", // Android 11 (and below)
|
||||
"res/values-v31/styles.xml", // Android 12 (and above)
|
||||
)
|
||||
|
||||
context.xmlEditor[attrsPath].use { editor ->
|
||||
val file = editor.file
|
||||
|
||||
(file.getElementsByTagName("resources").item(0) as Element).appendChild(
|
||||
file.createElement("attr").apply {
|
||||
setAttribute("format", "reference")
|
||||
setAttribute("name", "splashScreenColor")
|
||||
}
|
||||
)
|
||||
}
|
||||
stylesPaths.forEachIndexed { pathIndex, stylesPath ->
|
||||
context.xmlEditor[stylesPath].use { editor ->
|
||||
val file = editor.file
|
||||
|
||||
val childNodes = (file.getElementsByTagName("resources").item(0) as Element).childNodes
|
||||
|
||||
for (i in 0 until childNodes.length) {
|
||||
val node = childNodes.item(i) as? Element ?: continue
|
||||
val nodeAttributeName = node.getAttribute("name")
|
||||
|
||||
file.createElement("item").apply {
|
||||
setAttribute(
|
||||
"name",
|
||||
when (pathIndex) {
|
||||
0 -> "splashScreenColor"
|
||||
1 -> "android:windowSplashScreenBackground"
|
||||
else -> "null"
|
||||
}
|
||||
)
|
||||
|
||||
appendChild(
|
||||
file.createTextNode(
|
||||
when (pathIndex) {
|
||||
0 -> when (nodeAttributeName) {
|
||||
"Base.Theme.YouTube.Launcher.Dark" -> "@color/yt_black1"
|
||||
"Base.Theme.YouTube.Launcher.Light" -> "@color/yt_white1"
|
||||
else -> "null"
|
||||
}
|
||||
1 -> when (nodeAttributeName) {
|
||||
"Base.Theme.YouTube.Launcher" -> "?attr/splashScreenColor"
|
||||
else -> "null"
|
||||
}
|
||||
else -> "null"
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
if (this.textContent != "null")
|
||||
node.appendChild(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayOf("drawable", "drawable-sw600dp").forEach { quantumLaunchscreenPath ->
|
||||
context.xmlEditor["res/$quantumLaunchscreenPath/quantum_launchscreen_youtube.xml"].use { editor ->
|
||||
val resourcesNode = editor.file.getElementsByTagName("item").item(0) as Element
|
||||
|
||||
if (resourcesNode.attributes.getNamedItem("android:drawable") != null)
|
||||
resourcesNode.setAttribute("android:drawable", "?attr/splashScreenColor")
|
||||
}
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package app.revanced.patches.youtube.layout.etc.theme.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.options.PatchOptions
|
||||
import app.revanced.patches.youtube.layout.etc.theme.bytecode.patch.GeneralThemePatch
|
||||
import app.revanced.patches.youtube.layout.etc.theme.bytecode.patch.GeneralThemePatch.Companion.isMonetPatchIncluded
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.resources.ResourceHelper.updatePatchStatusTheme
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Patch
|
||||
@Name("theme")
|
||||
@Description("Applies a custom theme (default: amoled).")
|
||||
@DependsOn(
|
||||
[
|
||||
GeneralThemePatch::class,
|
||||
PatchOptions::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ThemePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
arrayOf("values", "values-v31").forEach {
|
||||
context.setTheme(it)
|
||||
}
|
||||
|
||||
val currentTheme = if (isMonetPatchIncluded) "mix" else "amoled"
|
||||
|
||||
context.updatePatchStatusTheme(currentTheme)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
private companion object {
|
||||
private fun ResourceContext.setTheme(valuesPath: String) {
|
||||
this.xmlEditor["res/$valuesPath/colors.xml"].use { editor ->
|
||||
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
|
||||
|
||||
for (i in 0 until resourcesNode.childNodes.length) {
|
||||
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
|
||||
|
||||
node.textContent = when (node.getAttribute("name")) {
|
||||
"yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3",
|
||||
"yt_black4", "yt_status_bar_background_dark", "material_grey_850" -> PatchOptions.darkThemeBackgroundColor!!
|
||||
|
||||
else -> continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package app.revanced.patches.youtube.layout.etc.tooltip.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object TooltipContentViewFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
customFingerprint = { methodDef ->
|
||||
methodDef.implementation?.instructions?.any {
|
||||
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.tooltipLabelId
|
||||
} == true
|
||||
}
|
||||
)
|
@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.etc.tooltip.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.layout.etc.tooltip.fingerprints.TooltipContentViewFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
|
||||
@Patch
|
||||
@Name("hide-tooltip-content")
|
||||
@Description("Hides the tooltip box that appears on first install.")
|
||||
@DependsOn(
|
||||
[
|
||||
SettingsPatch::class,
|
||||
SharedResourcdIdPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class TooltipContentViewBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
TooltipContentViewFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
TooltipContentViewFingerprint.result?.mutableMethod?.addInstruction(
|
||||
0,
|
||||
"return-void"
|
||||
) ?: return TooltipContentViewFingerprint.toErrorResult()
|
||||
|
||||
/*
|
||||
add settings
|
||||
*/
|
||||
SettingsPatch.updatePatchStatus("hide-tooltip-content")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user