diff --git a/CHANGELOG.md b/CHANGELOG.md index b524ea54b..66935c974 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +# [5.43.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.3...v5.43.0-dev.4) (2025-10-14) + + +### Bug Fixes + +* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](https://github.com/ReVanced/revanced-patches/commit/0c19dbaf30bcb95a29448d98b028ebeea54cc7d3)) + +# [5.43.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.2...v5.43.0-dev.3) (2025-10-14) + + +### Bug Fixes + +* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](https://github.com/ReVanced/revanced-patches/commit/95eee59a87a680e212a3ba06e1afefee8d91ee9d)) + +# [5.43.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.1...v5.43.0-dev.2) (2025-10-14) + + +### Bug Fixes + +* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](https://github.com/ReVanced/revanced-patches/commit/10ea250d4a91f8ab3b7f865612a403fc93a857b5)) + +# [5.43.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.3...v5.43.0-dev.1) (2025-10-11) + + +### Features + +* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](https://github.com/ReVanced/revanced-patches/commit/50f0b9c5eee95ff5f9974e344802e1d2a4aab47b)) + +## [5.42.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.2...v5.42.2-dev.3) (2025-10-11) + + +### Bug Fixes + +* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](https://github.com/ReVanced/revanced-patches/commit/6555f6e6f8b52c2f1ddab1f52c6704cd2d8cfc12)) + +## [5.42.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.1...v5.42.2-dev.2) (2025-10-10) + + +### Bug Fixes + +* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](https://github.com/ReVanced/revanced-patches/commit/54846253d748f4e7e30b2bba427c7d2fb9c341e2)) + +## [5.42.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.42.2-dev.1) (2025-10-09) + + +### Bug Fixes + +* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](https://github.com/ReVanced/revanced-patches/commit/be2b144cc9c4108ec37e16f3dd20573d88ffaa2b)) + ## [5.42.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.0...v5.42.1) (2025-10-08) diff --git a/extensions/music/src/main/java/app/revanced/extension/music/settings/preference/MusicPreferenceFragment.java b/extensions/music/src/main/java/app/revanced/extension/music/settings/preference/MusicPreferenceFragment.java index 1ebae16df..86e517342 100644 --- a/extensions/music/src/main/java/app/revanced/extension/music/settings/preference/MusicPreferenceFragment.java +++ b/extensions/music/src/main/java/app/revanced/extension/music/settings/preference/MusicPreferenceFragment.java @@ -5,8 +5,10 @@ import android.preference.PreferenceScreen; import android.widget.Toolbar; import app.revanced.extension.music.settings.MusicActivityHook; +import app.revanced.extension.shared.GmsCoreSupport; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; +import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment; /** @@ -30,6 +32,17 @@ public class MusicPreferenceFragment extends ToolbarPreferenceFragment { preferenceScreen = getPreferenceScreen(); Utils.sortPreferenceGroups(preferenceScreen); setPreferenceScreenToolbar(preferenceScreen); + + // Clunky work around until preferences are custom classes that manage themselves. + // Custom branding only works with non-root install. But the preferences must be + // added during patched because of difficulties detecting during patching if it's + // a root install. So instead the non-functional preferences are removed during + // runtime if the app is mount (root) installation. + if (GmsCoreSupport.isPackageNameOriginal()) { + removePreferences( + BaseSettings.CUSTOM_BRANDING_ICON.key, + BaseSettings.CUSTOM_BRANDING_NAME.key); + } } catch (Exception ex) { Logger.printException(() -> "initialize failure", ex); } diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CustomBrandingPatch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CustomBrandingPatch.java index 79a4d5484..c6cf761ca 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CustomBrandingPatch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CustomBrandingPatch.java @@ -1,11 +1,14 @@ package app.revanced.extension.shared.patches; +import android.app.Notification; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; +import android.graphics.Color; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import app.revanced.extension.shared.GmsCoreSupport; import app.revanced.extension.shared.Logger; @@ -29,28 +32,56 @@ public class CustomBrandingPatch { // The most that can be done is to hide a theme from the UI and keep the alias with dummy data. public enum BrandingTheme { /** - * Original unpatched icon. Must be first enum. + * Original unpatched icon. */ - ORIGINAL("revanced_original"), - ROUNDED("revanced_rounded"), - MINIMAL("revanced_minimal"), - SCALED("revanced_scaled"), + ORIGINAL, + ROUNDED, + MINIMAL, + SCALED, /** - * User provided custom icon. Must be the last enum. + * User provided custom icon. */ - CUSTOM("revanced_custom"); - - public final String themeAlias; - - BrandingTheme(String themeAlias) { - this.themeAlias = themeAlias; - } + CUSTOM; private String packageAndNameIndexToClassAlias(String packageName, int appIndex) { if (appIndex <= 0) { throw new IllegalArgumentException("App index starts at index 1"); } - return packageName + '.' + themeAlias + '_' + appIndex; + return packageName + ".revanced_" + name().toLowerCase(Locale.US) + '_' + appIndex; + } + } + + private static final int notificationSmallIcon; + + static { + BrandingTheme branding = BaseSettings.CUSTOM_BRANDING_ICON.get(); + if (branding == BrandingTheme.ORIGINAL) { + notificationSmallIcon = 0; + } else { + // Original icon is quantum_ic_video_youtube_white_24 + String iconName = "revanced_notification_icon"; + if (branding == BrandingTheme.CUSTOM) { + iconName += "_custom"; + } + + notificationSmallIcon = Utils.getResourceIdentifier(iconName, "drawable"); + if (notificationSmallIcon == 0) { + Logger.printException(() -> "Could not load notification small icon"); + } + } + } + + /** + * Injection point. + */ + public static void setNotificationIcon(Notification.Builder builder) { + try { + if (notificationSmallIcon != 0) { + builder.setSmallIcon(notificationSmallIcon) + .setColor(Color.TRANSPARENT); // Remove YT red tint. + } + } catch (Exception ex) { + Logger.printException(() -> "setNotificationIcon failure", ex); } } diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ToolbarPreferenceFragment.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ToolbarPreferenceFragment.java index 8f1d0975a..e299613dc 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ToolbarPreferenceFragment.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ToolbarPreferenceFragment.java @@ -6,6 +6,7 @@ import android.graphics.Insets; import android.graphics.drawable.Drawable; import android.os.Build; import android.preference.Preference; +import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.util.TypedValue; import android.view.ViewGroup; @@ -22,6 +23,24 @@ import app.revanced.extension.shared.settings.BaseActivityHook; @SuppressWarnings({"deprecation", "NewApi"}) public class ToolbarPreferenceFragment extends AbstractPreferenceFragment { + + /** + * Removes the list of preferences from this fragment, if they exist. + * @param keys Preference keys. + */ + protected void removePreferences(String ... keys) { + for (String key : keys) { + Preference pref = findPreference(key); + if (pref != null) { + PreferenceGroup parent = pref.getParent(); + if (parent != null) { + Logger.printDebug(() -> "Removing preference: " + key); + parent.removePreference(pref); + } + } + } + } + /** * Sets toolbar for all nested preference screens. */ diff --git a/extensions/twitter/src/main/java/app/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch.java b/extensions/twitter/src/main/java/app/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch.java index f4f4a107d..e5a41e028 100644 --- a/extensions/twitter/src/main/java/app/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch.java +++ b/extensions/twitter/src/main/java/app/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch.java @@ -2,22 +2,19 @@ package app.revanced.twitter.patches.links; @SuppressWarnings("unused") public final class ChangeLinkSharingDomainPatch { - private static final String DOMAIN_NAME = "https://fxtwitter.com"; private static final String LINK_FORMAT = "%s/%s/status/%s"; /** - * Injection point. + * Method is modified during patching. Do not change. */ - public static String formatResourceLink(Object... formatArgs) { - String username = (String) formatArgs[0]; - String tweetId = (String) formatArgs[1]; - return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId); + private static String getShareDomain() { + return ""; } /** * Injection point. */ public static String formatLink(long tweetId, String username) { - return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId); + return String.format(LINK_FORMAT, getShareDomain(), username, tweetId); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/YouTubePreferenceFragment.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/YouTubePreferenceFragment.java index 1cd1c80c4..aec00487b 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/YouTubePreferenceFragment.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/YouTubePreferenceFragment.java @@ -4,8 +4,10 @@ import android.app.Dialog; import android.preference.PreferenceScreen; import android.widget.Toolbar; +import app.revanced.extension.shared.GmsCoreSupport; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; +import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment; import app.revanced.extension.youtube.settings.YouTubeActivityHook; @@ -30,6 +32,17 @@ public class YouTubePreferenceFragment extends ToolbarPreferenceFragment { preferenceScreen = getPreferenceScreen(); Utils.sortPreferenceGroups(preferenceScreen); setPreferenceScreenToolbar(preferenceScreen); + + // Clunky work around until preferences are custom classes that manage themselves. + // Custom branding only works with non-root install. But the preferences must be + // added during patched because of difficulties detecting during patching if it's + // a root install. So instead the non-functional preferences are removed during + // runtime if the app is mount (root) installation. + if (GmsCoreSupport.isPackageNameOriginal()) { + removePreferences( + BaseSettings.CUSTOM_BRANDING_ICON.key, + BaseSettings.CUSTOM_BRANDING_NAME.key); + } } catch (Exception ex) { Logger.printException(() -> "initialize failure", ex); } diff --git a/gradle.properties b/gradle.properties index e85d947af..340876409 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M org.gradle.parallel = true android.useAndroidX = true kotlin.code.style = official -version = 5.42.1 +version = 5.43.0-dev.4 diff --git a/patches/api/patches.api b/patches/api/patches.api index 15b955acb..dfc890bf2 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -269,7 +269,7 @@ public final class app/revanced/patches/instagram/feed/LimitFeedToFollowedProfil } public final class app/revanced/patches/instagram/hide/explore/HideExploreFeedKt { - public static final fun getHideExportFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch; + public static final fun getHideExploreFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } public final class app/revanced/patches/instagram/hide/navigation/HideNavigationButtonsKt { @@ -280,6 +280,10 @@ public final class app/revanced/patches/instagram/hide/stories/HideStoriesKt { public static final fun getHideStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/instagram/hide/suggestions/HideSuggestedContentKt { + public static final fun getHideSuggestedContent ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/instagram/misc/devmenu/EnableDeveloperMenuPatchKt { public static final fun getEnableDeveloperMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/Fingerprints.kt index 63402788b..a85e8eb30 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/Fingerprints.kt @@ -3,7 +3,9 @@ package app.revanced.patches.instagram.hide.explore import app.revanced.patcher.fingerprint +internal const val EXPLORE_KEY_TO_BE_HIDDEN = "sectional_items" + internal val exploreResponseJsonParserFingerprint = fingerprint { - strings("sectional_items", "ExploreTopicalFeedResponse") + strings(EXPLORE_KEY_TO_BE_HIDDEN, "ExploreTopicalFeedResponse") custom { method, _ -> method.name == "parseFromJson" } } diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/HideExploreFeed.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/HideExploreFeed.kt index 25ff17907..a2c7d5ba5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/HideExploreFeed.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/explore/HideExploreFeed.kt @@ -1,33 +1,39 @@ package app.revanced.patches.instagram.hide.explore +import app.revanced.patcher.Fingerprint import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.bytecodePatch import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +context(BytecodePatchContext) +internal fun Fingerprint.replaceJsonFieldWithBogus( + key: String, +) { + val targetStringIndex = stringMatches!!.first { match -> match.string == key }.index + val targetStringRegister = method.getInstruction(targetStringIndex).registerA + + /** + * Replacing the JSON key we want to skip with a random string that is not a valid JSON key. + * This way the feeds array will never be populated. + * Received JSON keys that are not handled are simply ignored, so there are no side effects. + */ + method.replaceInstruction( + targetStringIndex, + "const-string v$targetStringRegister, \"BOGUS\"", + ) +} + @Suppress("unused") -val hideExportFeedPatch = bytecodePatch( +val hideExploreFeedPatch = bytecodePatch( name = "Hide explore feed", description = "Hides posts and reels from the explore/search page.", - use = false + use = false, ) { compatibleWith("com.instagram.android") execute { - exploreResponseJsonParserFingerprint.method.apply { - val sectionalItemStringIndex = exploreResponseJsonParserFingerprint.stringMatches!!.first().index - val sectionalItemStringRegister = getInstruction(sectionalItemStringIndex).registerA - - /** - * Replacing the JSON key we want to skip with a random string that is not a valid JSON key. - * This way the feeds array will never be populated. - * Received JSON keys that are not handled are simply ignored, so there are no side effects. - */ - replaceInstruction( - sectionalItemStringIndex, - "const-string v$sectionalItemStringRegister, \"BOGUS\"" - ) - } + exploreResponseJsonParserFingerprint.replaceJsonFieldWithBogus(EXPLORE_KEY_TO_BE_HIDDEN) } } - diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/Fingerprints.kt new file mode 100644 index 000000000..0f731b4f4 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/Fingerprints.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.instagram.hide.suggestions + +import app.revanced.patcher.fingerprint + +internal val FEED_ITEM_KEYS_TO_BE_HIDDEN = arrayOf( + "clips_netego", + "stories_netego", + "in_feed_survey", + "bloks_netego", + "suggested_igd_channels", + "suggested_top_accounts", + "suggested_users", +) + +internal val feedItemParseFromJsonFingerprint = fingerprint { + strings(*FEED_ITEM_KEYS_TO_BE_HIDDEN, "FeedItem") +} diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContent.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContent.kt new file mode 100644 index 000000000..0c2501411 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/suggestions/HideSuggestedContent.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.instagram.hide.suggestions + +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.instagram.hide.explore.replaceJsonFieldWithBogus + +@Suppress("unused") +val hideSuggestedContent = bytecodePatch( + name = "Hide suggested content", + description = "Hides suggested stories, reels, threads and survey from feed (Suggested posts will still be shown).", + use = false, +) { + compatibleWith("com.instagram.android") + + execute { + FEED_ITEM_KEYS_TO_BE_HIDDEN.forEach { key -> + feedItemParseFromJsonFingerprint.replaceJsonFieldWithBogus(key) + } + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/misc/share/domain/ChangeLinkSharingDomainPatch.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/misc/share/domain/ChangeLinkSharingDomainPatch.kt index 1e476b73b..430d2d7b7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/misc/share/domain/ChangeLinkSharingDomainPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/misc/share/domain/ChangeLinkSharingDomainPatch.kt @@ -19,14 +19,14 @@ val changeLinkSharingDomainPatch = bytecodePatch( dependsOn(sharedExtensionPatch) - execute { - val customDomainHost by stringOption( - key = "domainName", - default = "imginn.com", - title = "Domain name", - description = "The domain name to use when sharing links." - ) + val customDomainHost by stringOption( + key = "domainName", + default = "imginn.com", + title = "Domain name", + description = "The domain name to use when sharing links." + ) + execute { getCustomShareDomainFingerprint.method.returnEarly(customDomainHost!!) editShareLinksPatch { index, register -> diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/branding/CustomBrandingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/branding/CustomBrandingPatch.kt index 6f0f46026..7f7b49ca9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/branding/CustomBrandingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/branding/CustomBrandingPatch.kt @@ -4,6 +4,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.music.misc.extension.sharedExtensionPatch import app.revanced.patches.music.misc.gms.Constants.MUSIC_MAIN_ACTIVITY_NAME import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint @@ -60,7 +61,7 @@ val customBrandingPatch = baseCustomBrandingPatch( originalLauncherIconName = "ic_launcher_release", originalAppName = "@string/app_launcher_name", originalAppPackageName = MUSIC_PACKAGE_NAME, - copyExistingIntentsToAliases = false, + isYouTubeMusic = true, numberOfPresetAppNames = 5, mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint, mainActivityName = MUSIC_MAIN_ACTIVITY_NAME, @@ -68,7 +69,7 @@ val customBrandingPatch = baseCustomBrandingPatch( preferenceScreen = PreferenceScreen.GENERAL, block = { - dependsOn(disableSplashAnimationPatch) + dependsOn(sharedExtensionPatch, disableSplashAnimationPatch) compatibleWith( "com.google.android.apps.youtube.music"( diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatch.kt index 8130cbe71..f5f170d54 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatch.kt @@ -27,7 +27,7 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch( ) ) }, - fixUseLocalizedAudioTrackFlag = is_8_10_or_greater, + fixUseLocalizedAudioTrackFlag = { is_8_10_or_greater }, mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint, subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR, preferenceScreen = PreferenceScreen.MISC, diff --git a/patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt index b14d6b659..d923c954f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt @@ -4,14 +4,17 @@ package app.revanced.patches.music.playservice import app.revanced.patcher.patch.resourcePatch import app.revanced.util.findPlayStoreServicesVersion +import kotlin.properties.Delegates -var is_7_33_or_greater = false +// Use notNull delegate so an exception is thrown if these fields are accessed before they are set. + +var is_7_33_or_greater: Boolean by Delegates.notNull() private set -var is_8_10_or_greater = false +var is_8_10_or_greater: Boolean by Delegates.notNull() private set -var is_8_11_or_greater = false +var is_8_11_or_greater: Boolean by Delegates.notNull() private set -var is_8_15_or_greater = false +var is_8_15_or_greater: Boolean by Delegates.notNull() private set val versionCheckPatch = resourcePatch( diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/BaseCustomBrandingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/BaseCustomBrandingPatch.kt index d8356aee0..5381131f2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/BaseCustomBrandingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/BaseCustomBrandingPatch.kt @@ -2,6 +2,7 @@ package app.revanced.patches.shared.layout.branding import app.revanced.patcher.Fingerprint import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.ResourcePatchBuilder @@ -12,16 +13,25 @@ import app.revanced.patcher.patch.stringOption import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.util.ResourceGroup import app.revanced.util.Utils.trimIndentMultiline +import app.revanced.util.addInstructionsAtControlFlowLabel import app.revanced.util.copyResources import app.revanced.util.findElementByAttributeValueOrThrow +import app.revanced.util.findInstructionIndicesReversedOrThrow +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.removeFromParent import app.revanced.util.returnEarly +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference +import com.android.tools.smali.dexlib2.iface.reference.TypeReference import org.w3c.dom.Element -import org.w3c.dom.Node import org.w3c.dom.NodeList import java.io.File import java.util.logging.Logger @@ -48,13 +58,15 @@ private const val LAUNCHER_RESOURCE_NAME_PREFIX = "revanced_launcher_" private const val LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX = "revanced_adaptive_background_" private const val LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX = "revanced_adaptive_foreground_" private const val LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX = "revanced_adaptive_monochrome_" +private const val NOTIFICATION_ICON_NAME = "revanced_notification_icon" private val USER_CUSTOM_ADAPTIVE_FILE_NAMES = arrayOf( "$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png", "$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png" ) -private const val USER_CUSTOM_MONOCHROME_NAME = "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml" +private const val USER_CUSTOM_MONOCHROME_FILE_NAME = "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml" +private const val USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME = "${NOTIFICATION_ICON_NAME}_$CUSTOM_USER_ICON_STYLE_NAME.xml" internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/shared/patches/CustomBrandingPatch;" @@ -66,7 +78,7 @@ internal fun baseCustomBrandingPatch( originalLauncherIconName: String, originalAppName: String, originalAppPackageName: String, - copyExistingIntentsToAliases: Boolean, + isYouTubeMusic: Boolean, numberOfPresetAppNames: Int, mainActivityOnCreateFingerprint: Fingerprint, mainActivityName: String, @@ -97,8 +109,9 @@ internal fun baseCustomBrandingPatch( Each of the folders must contain all of the following files: ${USER_CUSTOM_ADAPTIVE_FILE_NAMES.joinToString("\n")} - Optionally, the path can contain a 'drawable' folder with the monochrome icon file: - $USER_CUSTOM_MONOCHROME_NAME + Optionally, the path contains a 'drawable' folder with any of the monochrome icon files: + $USER_CUSTOM_MONOCHROME_FILE_NAME + $USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME """.trimIndentMultiline() ) @@ -106,6 +119,7 @@ internal fun baseCustomBrandingPatch( dependsOn( addResourcesPatch, + resourceMappingPatch, bytecodePatch { execute { mainActivityOnCreateFingerprint.method.addInstruction( @@ -114,25 +128,68 @@ internal fun baseCustomBrandingPatch( ) numberOfPresetAppNamesExtensionFingerprint.method.returnEarly(numberOfPresetAppNames) + + notificationFingerprint.method.apply { + val getBuilderIndex = if (isYouTubeMusic) { + // YT Music the field is not a plain object type. + indexOfFirstInstructionOrThrow { + getReference()?.type == "Landroid/app/Notification\$Builder;" + } + } else { + // Find the field name of the notification builder. Field is an Object type. + val builderCastIndex = indexOfFirstInstructionOrThrow { + val reference = getReference() + opcode == Opcode.CHECK_CAST && + reference?.type == "Landroid/app/Notification\$Builder;" + } + indexOfFirstInstructionReversedOrThrow(builderCastIndex) { + getReference()?.type == "Ljava/lang/Object;" + } + } + + val builderFieldName = getInstruction(getBuilderIndex) + .getReference() + + findInstructionIndicesReversedOrThrow( + Opcode.RETURN_VOID + ).forEach { index -> + addInstructionsAtControlFlowLabel( + index, + """ + move-object/from16 v0, p0 + iget-object v0, v0, $builderFieldName + check-cast v0, Landroid/app/Notification${'$'}Builder; + invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->setNotificationIcon(Landroid/app/Notification${'$'}Builder;)V + """ + ) + } + } } - } + }, ) finalize { - val useCustomName = customName != null - val useCustomIcon = customIcon != null - - if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) { - if (useCustomName || useCustomIcon) { + // Can only check if app is root installation by checking if change package name patch is in use. + // and can only do that in the finalize block here. + // The UI preferences cannot be selectively added here, because the settings finalize block + // may have already run and the settings are already wrote to file. + // Instead, show a warning if any patch option was used (A rooted device launcher ignores the manifest changes), + // and the non-functional in-app settings are removed on app startup by extension code. + if (customName != null || customIcon != null) { + if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) { Logger.getLogger(this::class.java.name).warning( "Custom branding does not work with root installation. No changes applied." ) } - return@finalize } + } + + execute { + addResources("shared", "layout.branding.baseCustomBrandingPatch") + addResources(addResourcePatchName, "layout.branding.customBrandingPatch") preferenceScreen.addPreferences( - if (useCustomName) { + if (customName != null ) { ListPreference( key = "revanced_custom_branding_name", entriesKey = "revanced_custom_branding_name_custom_entries", @@ -141,7 +198,7 @@ internal fun baseCustomBrandingPatch( } else { ListPreference("revanced_custom_branding_name") }, - if (useCustomIcon) { + if (customIcon != null) { ListPreference( key = "revanced_custom_branding_icon", entriesKey = "revanced_custom_branding_icon_custom_entries", @@ -151,11 +208,6 @@ internal fun baseCustomBrandingPatch( ListPreference("revanced_custom_branding_icon") } ) - } - - execute { - addResources("shared", "layout.branding.baseCustomBrandingPatch") - addResources(addResourcePatchName, "layout.branding.customBrandingPatch") val useCustomName = customName != null val useCustomIcon = customIcon != null @@ -167,7 +219,7 @@ internal fun baseCustomBrandingPatch( "drawable", "$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$style.xml", "$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$style.xml", - "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$style.xml" + "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$style.xml", ), ResourceGroup( "mipmap-anydpi", @@ -176,20 +228,27 @@ internal fun baseCustomBrandingPatch( ) } - // Copy template user icon, because the aliases must be added even if no user icon is provided. copyResources( "custom-branding", - ResourceGroup( - "mipmap-anydpi", - "$LAUNCHER_RESOURCE_NAME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml", - ), + // Push notification 'small' icon. ResourceGroup( "drawable", - "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml", + "$NOTIFICATION_ICON_NAME.xml" + ), + + // Copy template user icon, because the aliases must be added even if no user icon is provided. + ResourceGroup( + "drawable", + USER_CUSTOM_MONOCHROME_FILE_NAME, + USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME + ), + ResourceGroup( + "mipmap-anydpi", + "$LAUNCHER_RESOURCE_NAME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml" ) ) - // Copy template icon png files. + // Copy template icon files. mipmapDirectories.forEach { dpi -> copyResources( "custom-branding", @@ -201,68 +260,6 @@ internal fun baseCustomBrandingPatch( ) } - if (useCustomIcon) { - // Copy user provided files - val iconPathFile = File(customIcon!!.trim()) - - if (!iconPathFile.exists()) { - throw PatchException( - "The custom icon path cannot be found: " + iconPathFile.absolutePath - ) - } - - if (!iconPathFile.isDirectory) { - throw PatchException( - "The custom icon path must be a folder: " + iconPathFile.absolutePath - ) - } - - val sourceFolders = iconPathFile.listFiles { file -> file.isDirectory } - ?: throw PatchException("The custom icon path contains no subfolders: " + - iconPathFile.absolutePath) - - val resourceDirectory = get("res") - var copiedFiles = false - - // For each source folder, copy the files to the target resource directories. - sourceFolders.forEach { dpiSourceFolder -> - val targetDpiFolder = resourceDirectory.resolve(dpiSourceFolder.name) - if (!targetDpiFolder.exists()) return@forEach - - val customFiles = dpiSourceFolder.listFiles { file -> - file.isFile && file.name in USER_CUSTOM_ADAPTIVE_FILE_NAMES - }!! - - if (customFiles.size > 0 && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) { - throw PatchException("Must include all required icon files " + - "but only found " + customFiles.map { it.name }) - } - - customFiles.forEach { imgSourceFile -> - val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name) - imgSourceFile.copyTo(target = imgTargetFile, overwrite = true) - - copiedFiles = true - } - } - - // Copy monochrome if it provided. - val monochromeRelativePath = "drawable/$USER_CUSTOM_MONOCHROME_NAME" - val monochromeFile = iconPathFile.resolve(monochromeRelativePath) - if (monochromeFile.exists()) { - monochromeFile.copyTo( - target = resourceDirectory.resolve(monochromeRelativePath), - overwrite = true - ) - copiedFiles = true - } - - if (!copiedFiles) { - throw PatchException("Could not find any replacement images in " + - "patch option path: " + iconPathFile.absolutePath) - } - } - document("AndroidManifest.xml").use { document -> // Create launch aliases that can be programmatically selected in app. fun createAlias( @@ -294,13 +291,7 @@ internal fun baseCustomBrandingPatch( alias.setAttribute("android:targetActivity", mainActivityName) // Copy all intents from the original alias so long press actions still work. - if (copyExistingIntentsToAliases) { - for (i in 0 until intents.length) { - alias.appendChild( - intents.item(i).cloneNode(true) - ) - } - } else { + if (isYouTubeMusic) { val intentFilter = document.createElement("intent-filter").apply { val action = document.createElement("action") action.setAttribute("android:name", "android.intent.action.MAIN") @@ -311,17 +302,31 @@ internal fun baseCustomBrandingPatch( appendChild(category) } alias.appendChild(intentFilter) + } else { + for (i in 0 until intents.length) { + alias.appendChild( + intents.item(i).cloneNode(true) + ) + } } return alias } + val application = document.getElementsByTagName("application").item(0) as Element val intentFilters = document.childNodes.findElementByAttributeValueOrThrow( "android:name", activityAliasNameWithIntents ).childNodes - val application = document.getElementsByTagName("application").item(0) as Element + // The YT application name can appear in some places along side the system + // YouTube app, such as the settings app list and in the "open with" file picker. + // Because the YouTube app cannot be completely uninstalled and only disabled, + // use a custom name for this situation to disambiguate which app is which. + application.setAttribute( + "android:label", + "@string/revanced_custom_branding_name_entry_2" + ) for (appNameIndex in 1 .. numberOfPresetAppNames) { fun aliasName(name: String): String = ".revanced_" + name + '_' + appNameIndex @@ -382,6 +387,75 @@ internal fun baseCustomBrandingPatch( ).removeFromParent() } + // Copy custom icons last, so if the user enters an invalid icon path + // and an exception is thrown then the critical manifest changes are still made. + if (useCustomIcon) { + // Copy user provided files + val iconPathFile = File(customIcon!!.trim()) + + if (!iconPathFile.exists()) { + throw PatchException( + "The custom icon path cannot be found: " + iconPathFile.absolutePath + ) + } + + if (!iconPathFile.isDirectory) { + throw PatchException( + "The custom icon path must be a folder: " + iconPathFile.absolutePath + ) + } + + val sourceFolders = iconPathFile.listFiles { file -> file.isDirectory } + ?: throw PatchException("The custom icon path contains no subfolders: " + + iconPathFile.absolutePath) + + val resourceDirectory = get("res") + var copiedFiles = false + + // For each source folder, copy the files to the target resource directories. + sourceFolders.forEach { dpiSourceFolder -> + val targetDpiFolder = resourceDirectory.resolve(dpiSourceFolder.name) + if (!targetDpiFolder.exists()) return@forEach + + val customFiles = dpiSourceFolder.listFiles { file -> + file.isFile && file.name in USER_CUSTOM_ADAPTIVE_FILE_NAMES + }!! + + if (customFiles.size > 0 && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) { + throw PatchException("Must include all required icon files " + + "but only found " + customFiles.map { it.name }) + } + + customFiles.forEach { imgSourceFile -> + val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name) + imgSourceFile.copyTo(target = imgTargetFile, overwrite = true) + + copiedFiles = true + } + } + + // Copy monochrome and small notification icon if it provided. + arrayOf( + USER_CUSTOM_MONOCHROME_FILE_NAME, + USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME + ).forEach { fileName -> + val relativePath = "drawable/$fileName" + val file = iconPathFile.resolve(relativePath) + if (file.exists()) { + file.copyTo( + target = resourceDirectory.resolve(relativePath), + overwrite = true + ) + copiedFiles = true + } + } + + if (!copiedFiles) { + throw PatchException("Could not find any replacement images in " + + "patch option path: " + iconPathFile.absolutePath) + } + } + executeBlock() } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/Fingerprints.kt index c46cb1a88..8e99078d5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/Fingerprints.kt @@ -11,3 +11,11 @@ internal val numberOfPresetAppNamesExtensionFingerprint = fingerprint { method.name == "numberOfPresetAppNames" && classDef.type == EXTENSION_CLASS_DESCRIPTOR } } + +// A much simpler fingerprint exists that can set the small icon (contains string "414843287017"), +// but that has limited usage and this fingerprint allows changing any part of the notification. +internal val notificationFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) + parameters("L") + strings("key_action_priority") +} diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/audio/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/audio/Fingerprints.kt index 495ac4865..78cf1f284 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/audio/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/audio/Fingerprints.kt @@ -27,4 +27,3 @@ internal val selectAudioStreamFingerprint = fingerprint { && method.containsLiteralInstruction(AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG) } } - diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/audio/ForceOriginalAudioPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/audio/ForceOriginalAudioPatch.kt index 5c0d8c907..465ce8030 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/audio/ForceOriginalAudioPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/audio/ForceOriginalAudioPatch.kt @@ -34,7 +34,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR = internal fun forceOriginalAudioPatch( block: BytecodePatchBuilder.() -> Unit = {}, executeBlock: BytecodePatchContext.() -> Unit = {}, - fixUseLocalizedAudioTrackFlag: Boolean, + fixUseLocalizedAudioTrackFlag: () -> Boolean, mainActivityOnCreateFingerprint: Fingerprint, subclassExtensionClassDescriptor: String, preferenceScreen: BasePreferenceScreen.Screen @@ -64,7 +64,7 @@ internal fun forceOriginalAudioPatch( // Disable feature flag that ignores the default track flag // and instead overrides to the user region language. - if (fixUseLocalizedAudioTrackFlag) { + if (fixUseLocalizedAudioTrackFlag()) { selectAudioStreamFingerprint.method.insertLiteralOverride( AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG, "$EXTENSION_CLASS_DESCRIPTOR->ignoreDefaultAudioStream(Z)Z" diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt index db33e715b..106d8abe6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt @@ -1,33 +1,59 @@ package app.revanced.patches.twitter.misc.links import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.stringOption import app.revanced.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN import app.revanced.patches.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN -import app.revanced.patches.shared.misc.mapping.get -import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch -import app.revanced.util.indexOfFirstLiteralInstructionOrThrow -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import app.revanced.util.findElementByAttributeValueOrThrow +import app.revanced.util.returnEarly +import java.net.InetAddress +import java.net.UnknownHostException +import java.util.logging.Logger -internal var tweetShareLinkTemplateId = -1L - private set +internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;" -internal val changeLinkSharingDomainResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - - execute { - tweetShareLinkTemplateId = resourceMappings["string", "tweet_share_link"] +internal val domainNameOption by stringOption( + key = "domainName", + default = "https://fxtwitter.com", + title = "Domain name", + description = "The domain name to use when sharing links.", + required = true, +) { + // Do a courtesy check if the host can be resolved. + // If it does not resolve, then print a warning but use the host anyway. + // Unresolvable hosts should not be rejected, since the patching environment + // may not allow network connections or the network may be down. + try { + InetAddress.getByName(it) + } catch (e: UnknownHostException) { + Logger.getLogger(this::class.java.name).warning( + "Host \"$it\" did not resolve to any domain." + ) } + true } -private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;" +internal val changeLinkSharingDomainResourcePatch = resourcePatch { + execute { + val domainName = domainNameOption!! + + val shareLinkTemplate = if (domainName.endsWith("/")) { + "$domainName%1\$s/status/%2\$s" + } else { + "$domainName/%1\$s/status/%2\$s" + } + + document("res/values/strings.xml").use { document -> + document.documentElement.childNodes.findElementByAttributeValueOrThrow( + "name", + "tweet_share_link" + ).textContent = shareLinkTemplate + } + } +} @Suppress("unused") val changeLinkSharingDomainPatch = bytecodePatch( @@ -46,26 +72,11 @@ val changeLinkSharingDomainPatch = bytecodePatch( ) ) - val domainName by stringOption( - key = "domainName", - default = "fxtwitter.com", - title = "Domain name", - description = "The domain name to use when sharing links.", - required = true, - ) - execute { - linkSharingDomainFingerprint.let { - val replacementIndex = it.stringMatches!!.first().index - val domainRegister = it.method.getInstruction( - replacementIndex - ).registerA + val domainName = domainNameOption!! - it.method.replaceInstruction( - replacementIndex, - "const-string v$domainRegister, \"https://$domainName\"", - ) - } + // Replace the domain name in the link sharing extension methods. + linkSharingDomainHelperFingerprint.method.returnEarly(domainName) // Replace the domain name when copying a link with "Copy link" button. linkBuilderFingerprint.method.addInstructions( @@ -76,20 +87,5 @@ val changeLinkSharingDomainPatch = bytecodePatch( return-object p0 """ ) - - // Used in the Share via... dialog. - linkResourceGetterFingerprint.method.apply { - val templateIdConstIndex = indexOfFirstLiteralInstructionOrThrow(tweetShareLinkTemplateId) - - // Format the link with the new domain name register (1 instruction below the const). - val formatLinkCallIndex = templateIdConstIndex + 1 - val register = getInstruction(formatLinkCallIndex).registerE - - // Replace the original method call with the new method call. - replaceInstruction( - formatLinkCallIndex, - "invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->formatResourceLink([Ljava/lang/Object;)Ljava/lang/String;", - ) - } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/Fingerprints.kt index 0d5d0e6f8..9dbd7aeb1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/Fingerprints.kt @@ -1,8 +1,6 @@ package app.revanced.patches.twitter.misc.links import app.revanced.patcher.fingerprint -import app.revanced.util.literal -import com.android.tools.smali.dexlib2.AccessFlags internal val openLinkFingerprint = fingerprint { returns("V") @@ -19,13 +17,8 @@ internal val linkBuilderFingerprint = fingerprint { strings("/%1\$s/status/%2\$d") } -// Gets Resource string for share link view available by pressing "Share via" button. -internal val linkResourceGetterFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - parameters("Landroid/content/res/Resources;") - literal { tweetShareLinkTemplateId } -} - -internal val linkSharingDomainFingerprint = fingerprint { - strings("https://fxtwitter.com") +internal val linkSharingDomainHelperFingerprint = fingerprint { + custom { method, classDef -> + method.name == "getShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR + } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt index 2294ef9b2..09ca7481d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt @@ -13,7 +13,7 @@ val customBrandingPatch = baseCustomBrandingPatch( originalLauncherIconName = "ic_launcher", originalAppName = "@string/application_name", originalAppPackageName = YOUTUBE_PACKAGE_NAME, - copyExistingIntentsToAliases = true, + isYouTubeMusic = false, numberOfPresetAppNames = 5, mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint, mainActivityName = YOUTUBE_MAIN_ACTIVITY_NAME, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt index fd713626d..133beddfb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt @@ -4,72 +4,75 @@ package app.revanced.patches.youtube.misc.playservice import app.revanced.patcher.patch.resourcePatch import app.revanced.util.findPlayStoreServicesVersion +import kotlin.properties.Delegates + +// Use notNull delegate so an exception is thrown if these fields are accessed before they are set. @Deprecated("19.34.42 is the lowest supported version") -var is_19_03_or_greater = false +var is_19_03_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_04_or_greater = false +var is_19_04_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_16_or_greater = false +var is_19_16_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_17_or_greater = false +var is_19_17_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_18_or_greater = false +var is_19_18_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_23_or_greater = false +var is_19_23_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_25_or_greater = false +var is_19_25_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_26_or_greater = false +var is_19_26_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_29_or_greater = false +var is_19_29_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_32_or_greater = false +var is_19_32_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_33_or_greater = false +var is_19_33_or_greater : Boolean by Delegates.notNull() private set @Deprecated("19.34.42 is the lowest supported version") -var is_19_34_or_greater = false +var is_19_34_or_greater : Boolean by Delegates.notNull() private set -var is_19_35_or_greater = false +var is_19_35_or_greater : Boolean by Delegates.notNull() private set -var is_19_36_or_greater = false +var is_19_36_or_greater : Boolean by Delegates.notNull() private set -var is_19_41_or_greater = false +var is_19_41_or_greater : Boolean by Delegates.notNull() private set -var is_19_43_or_greater = false +var is_19_43_or_greater : Boolean by Delegates.notNull() private set -var is_19_46_or_greater = false +var is_19_46_or_greater : Boolean by Delegates.notNull() private set -var is_19_47_or_greater = false +var is_19_47_or_greater : Boolean by Delegates.notNull() private set -var is_19_49_or_greater = false +var is_19_49_or_greater : Boolean by Delegates.notNull() private set -var is_20_02_or_greater = false +var is_20_02_or_greater : Boolean by Delegates.notNull() private set -var is_20_03_or_greater = false +var is_20_03_or_greater : Boolean by Delegates.notNull() private set -var is_20_05_or_greater = false +var is_20_05_or_greater : Boolean by Delegates.notNull() private set -var is_20_07_or_greater = false +var is_20_07_or_greater : Boolean by Delegates.notNull() private set -var is_20_09_or_greater = false +var is_20_09_or_greater : Boolean by Delegates.notNull() private set -var is_20_10_or_greater = false +var is_20_10_or_greater : Boolean by Delegates.notNull() private set -var is_20_14_or_greater = false +var is_20_14_or_greater : Boolean by Delegates.notNull() private set -var is_20_15_or_greater = false +var is_20_15_or_greater : Boolean by Delegates.notNull() private set val versionCheckPatch = resourcePatch( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt index 3b9097095..390fe6c4a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatch.kt @@ -29,7 +29,7 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch( ) ) }, - fixUseLocalizedAudioTrackFlag = is_20_07_or_greater, + fixUseLocalizedAudioTrackFlag = { is_20_07_or_greater }, mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint, subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR, preferenceScreen = PreferenceScreen.VIDEO, diff --git a/patches/src/main/resources/addresources/values-ar-rSA/strings.xml b/patches/src/main/resources/addresources/values-ar-rSA/strings.xml index d0db36d92..0c50680e1 100644 --- a/patches/src/main/resources/addresources/values-ar-rSA/strings.xml +++ b/patches/src/main/resources/addresources/values-ar-rSA/strings.xml @@ -26,10 +26,10 @@ Second \"item\" text" مخصص أيقونة التطبيق - أصلي + الأصلية ReVanced minimal - ReVanced مصغر + ReVanced scaled مخصص @@ -1619,14 +1619,14 @@ Second \"item\" text" تم تعطيل التمرير للتقديم أو الترجيع - السماح لـ Android VR AV1 + السماح بـ Android VR AV1 "برنامج ترميز الفيديو هو AVC (H.264) أو VP9 أو AV1 قد يحدث تقطيع أو فقدان للإطارات أثناء التشغيل" برنامج ترميز الفيديو هو AVC (H.264) أو VP9 - "قد يؤدي تمكين هذا الإعداد إلى استخدام فك ترميز AV1 برمجيًا. + "قد يؤدي تمكين هذا الإعداد إلى استخدام فك تشفير AV1 البرمجي. -قد يتلعثم تشغيل الفيديو بتقنية AV1 أو يفقد بعض الإطارات." +قد يتسبب تشغيل الفيديو باستخدام AV1 في التقطيع أو إسقاط الإطارات." التأثيرات الجانبية للتزييف • عميل تجريبي وقد يتوقف عن العمل في أي وقت • قد يتوقف الفيديو عند 1:00، أو قد لا يكون متاحًا في بعض المناطق diff --git a/patches/src/main/resources/addresources/values-az-rAZ/strings.xml b/patches/src/main/resources/addresources/values-az-rAZ/strings.xml index 0fe290e92..5c3bd1b87 100644 --- a/patches/src/main/resources/addresources/values-az-rAZ/strings.xml +++ b/patches/src/main/resources/addresources/values-az-rAZ/strings.xml @@ -25,10 +25,10 @@ Second \"item\" text" Tətbiq adı Fərdi - Tətbiq ikonu + Tətbiq simvolu Orijinal - Ən kiçik ReVanced + ReVanced ən kiçik ReVanced ölçüləndirilmiş Fərdi @@ -1619,13 +1619,13 @@ Məhdudiyyətlər: Android VR AV1-ə icazə ver - "Video kodek AVC (H.264), VP9 və ya AV1-dir + "Video kodlayıcı AVC (H.264), VP9 və ya AV1-dir -Oxutma kəsilə bilər və ya kadrlar atıla bilər" - Video kodek AVC (H.264) və ya VP9-dur - "Bu ayarı aktivləşdirmək proqram təminatı AV1 dekodlaşdırmasından istifadə edə bilər. +Oynatma ilişə bilər və ya kadrlar buraxıla bilər" + Video kodlayıcı AVC (H.264) və ya VP9-dur + "Bu tənzimləməni aktivləşdirmə proqram təminatlı AV1 kodlayıcı istifadə edə bilər. -AV1 ilə video oxutma kəsilə bilər və ya kadrlar atıla bilər." +Video oynatma AV1 ilə ilişə bilər və ya kadrlar buraxıla bilər." Saxtakarlıq yan təsirləri • Təcrübi qəbuledici və hər vaxt işləməyi dayandıra bilər • Video 01:00-da dayana bilər və ya bəzi bölgələrdə mövcud olmaya bilər diff --git a/patches/src/main/resources/addresources/values-fi-rFI/strings.xml b/patches/src/main/resources/addresources/values-fi-rFI/strings.xml index 6f75cd4d8..4e5ccb0f9 100644 --- a/patches/src/main/resources/addresources/values-fi-rFI/strings.xml +++ b/patches/src/main/resources/addresources/values-fi-rFI/strings.xml @@ -25,11 +25,11 @@ Second \"item\" text" Sovelluksen nimi Mukautettu - Sovelluksen kuvake + Sovelluskuvake Alkuperäinen - ReVanced-minimaalinen - ReVanced skaalattu + ReVanced, minimaalinen + ReVanced, skaalattu Mukautettu @@ -1430,7 +1430,7 @@ Minisoitin voidaan vetää pois näytöltä vasemmalle tai oikealle" Oletus Tavallinen - ReVanced-minimaalinen + ReVanced, minimaalinen Mukautettu @@ -1622,11 +1622,11 @@ Rajoitukset: Salli Android VR AV1 "Videokoodekki on AVC (H.264), VP9 tai AV1 -Toisto voi nykiä tai pudottaa kehyksiä" +Toisto saattaa pätkiä" Videokoodekki on AVC (H.264) tai VP9 - "Tämän asetuksen ottaminen käyttöön saattaa käyttää ohjelmistopohjaista AV1-dekoodausta. + "Tämän asetuksen käyttöönotto saattaa käyttää ohjelmistopohjaista AV1-dekoodausta. -AV1-videon toisto saattaa pätkiä tai pudottaa kuvia." +AV1-videon toisto saattaa pätkiä." Naamioimisen sivuvaikutukset • Kokeellinen asiakasohjelma, joka saattaa lakata toimimasta milloin tahansa • Video saattaa pysähtyä aikaan 1:00, tai ei välttämättä ole saatavilla joillakin alueilla diff --git a/patches/src/main/resources/addresources/values-fr-rFR/strings.xml b/patches/src/main/resources/addresources/values-fr-rFR/strings.xml index 53927546b..c4e413064 100644 --- a/patches/src/main/resources/addresources/values-fr-rFR/strings.xml +++ b/patches/src/main/resources/addresources/values-fr-rFR/strings.xml @@ -24,14 +24,14 @@ Second \"item\" text" Nom de l\'application - Personnalisé + Personnalisée Icône de l\'application - Original + Originale ReVanced minimaliste - ReVanced mis à l\'échelle + ReVanced mise à l\'échelle - Personnalisé + Personnalisée Les vérifications ont échoué @@ -1363,7 +1363,7 @@ Limitation : Il se peut que le bouton Retour dans la barre d'outils ne fonction Lecteur réduit - Modifier le style du lecteur réduit à l\'intérieur de l\'application + Modifiez le style du lecteur réduit intégré à l\'application Type de lecteur réduit Désactivé Par défaut @@ -1623,11 +1623,11 @@ Limitations : Autoriser Android VR AV1 "Le codec vidéo est AVC (H.264), VP9 ou AV1 -La lecture peut saccader ou perdre des images" +La lecture peut être saccadée et des images peuvent être perdues" Le codec vidéo est AVC (H.264) ou VP9 - "L'activation de ce paramètre peut utiliser le décodage AV1 logiciel. + "L'activation de ce paramètre permet l'utilisation du décodage AV1 logiciel. -La lecture vidéo avec AV1 peut saccader ou perdre des images." +La lecture vidéo avec AV1 peut être saccadée et des images peuvent être perdues." Effets secondaires de la falsification • Client expérimental, peut cesser de fonctionner à tout moment • Les vidéos sont susceptibles de s\'arrêter à 1:00, ou de ne pas être disponibles dans certaines régions diff --git a/patches/src/main/resources/addresources/values-ga-rIE/strings.xml b/patches/src/main/resources/addresources/values-ga-rIE/strings.xml index 5c844eb90..a5f4c5ac7 100644 --- a/patches/src/main/resources/addresources/values-ga-rIE/strings.xml +++ b/patches/src/main/resources/addresources/values-ga-rIE/strings.xml @@ -22,14 +22,14 @@ Second \"item\" text" - Ainm an fheidhmchláir + Ainm an aip Saincheaptha - Deilbhín an fheidhmchláir + Deilbhín aip Bunaidh ReVanced Íosmhéid - ReVanced Scálaithe + ReVanced scálaithe Saincheaptha @@ -266,18 +266,18 @@ Mar sin féin, logálfaidh sé seo roinnt sonraí úsáideora freisin, mar shamp Cnaipe \'Taispeáin níos mó\' sna torthaí cuardaigh thaispeánta Folaigh suirbhéanna Tá suirbhéanna i bhfolach - Tá suirbhéanna taispeánta + Taispeántar suirbhéanna Folaigh an seilf ticéad Tá an seilf ticéad i bhfolach - Taispeántar an seilf ticéad + Taispeántar seilf ticéad Folaigh lipéid mholtaí físeáin Tá lipéid \'D\'fhéach daoine freisin ar\' agus \'B\'fhéidir gur mhaith leat freisin\' sna torthaí cuardaigh i bhfolach - Tá lipéid \'D\'fhéach daoine freisin ar\' agus \'B\'fhéidir gur mhaith leat freisin\' sna torthaí cuardaigh taispeánta + Taispeántar lipéid ‘Daoine a d’fhéach freisin’ agus ‘B’fhéidir gur mhaith leat freisin’ i dtorthaí cuardaigh Folaigh YouTube Doodles - Beochan Doodles YouTube ar an lógó i bhfolach - Tá beochán YouTube Doodles ar an lógó ar taispeáint + Tá beochan YouTube Doodles ar an lógó i bhfolach + Taispeántar beochan YouTube Doodles ar an lógó "Taispeántar Doodles ó YouTube cúpla lá gach bliain. Má tá Doodle á thaispeáint faoi láthair i do réigiún agus má tá an tsuíomh seo a chumasc, ansin cuirfear an barra scagaire faoin bharra cuardaigh i bhfolach freisin." @@ -296,29 +296,29 @@ Má tá Doodle á thaispeáint faoi láthair i do réigiún agus má tá an tsu Folaigh cnaipe Ballraíochta - Cnaipe \'Glac páirt\' i bhfolach - Cnaipe \'Glac páirt\' taispeánta + Tá an cnaipe Glac páirt i bhfolach + Taispeántar an cnaipe Glac páirt Folaigh painéil leighis Tá painéil leighis i bhfolach Taispeántar painéil leighis Folaigh gníomhartha tapa Tá gníomhartha tapa sa scáileán iomlán i bhfolach - Tá gníomhartha tapa sa scáileán iomlán le feiceáil + Taispeántar gníomhartha tapa i lánscáileán Folaigh físeáin ghaolmhara Tá físeáin ghaolmhara i ngníomhartha tapa i bhfolach - Tá físeáin ghaolmhara i ngníomhartha tapa le feiceáil + Taispeántar físeáin ghaolmhara i ngníomhartha tapa Folaigh treoirlínte síntiúsóirí Tá treoirlínte pobail síntiúsóirí i bhfolach Taispeántar treoirlínte pobail do shíntiúsóirí - Folaigh frithghníomhartha ama - Tá frithghníomhartha ama i bhfolach - Taispeántar frithghníomhartha ama + Folaigh imoibrithe uainithe + Tá imoibrithe uainithe i bhfolach + Taispeántar imoibrithe uainithe Folaigh \'Achoimre físeáin arna giniúint ag AI\' Tá an chuid achoimre físe IS-ghinte i bhfolach - Tá an rannán achoimre físeán ginte ag AI taispeánta - Folaigh Fiafraigh - Tá rannóg na Fiafraí i bhfolach - Taispeántar rannóg na Fiafraí + Taispeántar an chuid achoimre físe a ghintear ag AI + Folaigh Iarr + Tá an rannán Iarratas i bhfolach + Taispeántar an rannán Iarratas Folaigh Tréithe Tá ailt d\'áiteanna sonracha, Cluichí, Ceol agus Daoine a luaitear i bhfolach Taispeántar ailt d\'áiteanna sonracha, Cluichí, Ceol agus Daoine a luaitear @@ -336,54 +336,54 @@ Má tá Doodle á thaispeáint faoi láthair i do réigiún agus má tá an tsu Taispeántar rannán cártaí faisnéise Folaigh \'Príomhchoincheapa\' Tá an chuid Príomhchoincheapa i bhfolach - Taispeántar an chuid Príomhchoincheapa + Taispeántar an chuid coincheapa lárnacha Folaigh Tras-scríbhinn Tá alt an tras-scríbhinn i bhfolach Taispeántar alt an tras-scríbhinn Cur síos físeán - Folaigh nó taispeáint comhpháirteanna tuairisc + Folaigh nó taispeáin comhpháirteanna cur síos físe Barra scagaire Folaigh nó taispeáin an barra scagaire i bhfothaí, físeáin ghaolmhara, torthaí cuardaigh, agus stair féachana Folaigh i bhfothaí I bhfolach i bhfothaí - Taispeánta i bhfothaí + Taispeántar i bhfothaí Folaigh i bhfíseáin gaolmhara I bhfolach i bhfíseáin ghaolmhara Taispeántar i bhfíseáin ghaolmhara Folaigh i dtorthaí cuardaigh Folaigh i dtorthaí cuardaigh - Taispeáin i dtorthaí cuardaigh + Taispeántar i dtorthaí cuardaigh Folaigh i stair faire I bhfolach i stair féachana - Taispeánta i stair faire + Taispeántar i stair faire Leathanach cainéil Folaigh nó taispeáin comhpháirteanna leathanach cainéil - Folaigh seilf \'Duit\' + Folaigh seilf \'Duitse\' Tá seilf \'Maidir Leat\' i bhfolach Tá seilf \'Maidir Leat\' le feiceáil - Folaigh réamhamharc ar naisc - Tá réamhamharc ar naisc i bhfolach - Tá réamhamharc ar naisc le feiceáil + Folaigh réamhamharc naisc + Tá réamhamharc naisc i bhfolach + Taispeántar réamhamharc naisc Folaigh seilf na mball Tá seilf na mball i bhfolach Taispeántar seilf na gcomhaltaí Folaigh cnaipe \"Tabhair cuairt ar an gComhphobal\" Tá cnaipe \"Tabhair cuairt ar an gComhphobal\" i bhfolach - Tá cnaipe \'Tabhair Cuairt ar an bPobal\' le feiceáil + Taispeántar an cnaipe Tabhair Cuairt ar an bPobal - Folaigh an cnaipe \'Tabhair cuairt ar an siopa\' ar leathanaigh chainéil + Folaigh an cnaipe \'Tabhair cuairt ar an siopa\' Tá cnaipe \'Tabhair Cuairt ar an Siopa\' i bhfolach - Tá cnaipe \'Tabhair Cuairt ar an Siopa\' le feiceáil + Taispeántar an cnaipe Tabhair cuairt ar an siopa Tráchtanna Folaigh nó taispeáin comhpháirteanna na rannóige tráchtanna Folaigh achoimre comhrá IS Tá achoimre comhrá IS i bhfolach - Tá achoimre comhrá IS taispeánta - Folaigh achoimre Tuairimí AI + Taispeántar achoimre ar chomhrá AI + Folaigh achoimre ar thráchtanna AI Tá achoimre tráchtanna IS i bhfolach - Tá achoimre tráchtanna IS taispeánta + Taispeántar achoimre ar thráchtanna IS Folaigh treoirlínte an chainéil Tá treoirlínte an chainéil i bhfolach Taispeántar treoirlínte an chainéil @@ -395,13 +395,13 @@ Má tá Doodle á thaispeáint faoi láthair i do réigiún agus má tá an tsu Taispeántar an chuid tuairimí Folaigh treoirlínte an chomhphobail Tá treoirlínte an phobail i bhfolach - Tá treoirlínte an phobail le feiceáil + Taispeántar treoirlínte an phobail Folaigh an cnaipe \'Cruthaigh Short\' Tá cnaipe Cruthaigh gearrscéal i bhfolach Taispeántar cnaipe Cruthaigh gearrscéal - Folaigh cnaipí Emoji agus Amscála - Tá cnaipí Emoji agus Amscála i bhfolach - Tá cnaipí Emoji agus Amscála taispeánta + Folaigh cnaipí Emoji agus Stampa Ama + Tá cnaipí Emoji agus Stampa Ama i bhfolach + Taispeántar cnaipí Emoji agus Stampa Ama Folaigh trácht réamhamharc Tá trácht réamhamhar i bhfolach Taispeántar trácht réamhamharc @@ -409,7 +409,7 @@ Má tá Doodle á thaispeáint faoi láthair i do réigiún agus má tá an tsu Tá cnaipe buíochas i bhfolach Taispeántar cnaipe buíochas Scagaire saincheaptha - Folaigh comhpháirteanna ag baint úsáide as + Folaigh comhpháirteanna ag baint úsáide as scagairí saincheaptha Cumasaigh scagaire saincheaptha Tá scagaire saincheaptha cumasaithe Tá scagaire saincheaptha míchumasaithe @@ -1624,9 +1624,9 @@ Teorainneacha: D'fhéadfadh go mbeadh fadhbanna le hathsheinm nó go gcaillfí frámaí" Is é an códac físeáin AVC (H.264) nó VP9 - "Má chumasaítear an socrú seo, d'fhéadfadh sé díchódú bogearraí AV1 a úsáid. + "D’fhéadfadh sé go n-úsáidfí díchódú bogearraí AV1 agus an socrú seo á chumasú. -D'fhéadfadh athsheinm físe AV1 leacadh nó frámaí a scaoileadh." +D’fhéadfadh sé go mbeadh stad nó go gcaillfí frámaí ag athsheinm físe le AV1." Fo-éifeachtaí a fhalsúa • Cliant turgnamhach é seo agus féadfaidh sé stop a chur ag obair ag am ar bith • Is féidir go stopfaidh an físeán ag 1:00, nó b\'fhéidir nach mbeidh sé ar fáil i réigiúin áirithe diff --git a/patches/src/main/resources/addresources/values-it-rIT/strings.xml b/patches/src/main/resources/addresources/values-it-rIT/strings.xml index 298999c84..d94d160be 100644 --- a/patches/src/main/resources/addresources/values-it-rIT/strings.xml +++ b/patches/src/main/resources/addresources/values-it-rIT/strings.xml @@ -40,13 +40,13 @@ Second \"item\" text" <h5>Quest\'app non sembra essere stata patchata da te.</h5><br>Quest\'app potrebbe non funzionare correttamente, <b>potrebbe essere dannosa o addirittura pericolosa</b>.<br><br>Questi controlli implicano che quest\'app sia pre-patchata o ottenuta da qualcun altro:<br><br><small>%1$s</small><br>Si consiglia vivamente di <b>disinstallare quest\'app</b> per assicurarsi di utilizzare un\'app valida e sicura.<p><br>Se ignorato, questo avviso verrà visualizzato solo due volte. Patchato su un altro dispositivo Non installato da ReVanced Manager - Patchato da più di 10 minuti fa + Patchato più di 10 minuti fa Patchato %s giorni fa La data di compilazione dell\'APK è corrotta Attenzione - La tua cronologia di visualizzazione non è stata salvata.<br><br>Questo è molto probabilmente dovuto da un blocco annunci DNS o da un proxy di rete.<br><br>Per risolvere questo problema, inserisci nella whitelist <b>s.youtube.com</b> o disattiva tutti i DNS bloccanti e proxy. + La tua cronologia di visualizzazione non sta venendo salvata.<br><br>Questo è molto probabilmente causato da un blocco annunci DNS o da un proxy di rete.<br><br>Per risolvere, inserisci nella whitelist <b>s.youtube.com</b> o disattiva tutti i blocchi DNS e proxy. Non mostrare più diff --git a/patches/src/main/resources/addresources/values-ja-rJP/strings.xml b/patches/src/main/resources/addresources/values-ja-rJP/strings.xml index 48ec4859a..94c67bc1f 100644 --- a/patches/src/main/resources/addresources/values-ja-rJP/strings.xml +++ b/patches/src/main/resources/addresources/values-ja-rJP/strings.xml @@ -29,7 +29,7 @@ Second \"item\" text" オリジナル ReVanced (シンプル) - ReVanced (シンボル大) + ReVanced (ロゴ拡大) カスタム @@ -135,8 +135,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が オリジナルの音声を強制的に使用 - オリジナルの音声トラック (言語) を使用します\n\nオートダビングを含む吹き替えの音声トラックは使用しません - アプリが選択した音声トラック (言語) を使用します\n\nオートダビングを含む吹き替えの音声トラックを使用する場合があります + オリジナルの音声トラック (言語) を使用します\n\nオートダビングを含む吹き替えの音声トラックは使用されません + アプリが選択した音声トラック (言語) を使用します\n\nオートダビングを含む吹き替えの音声トラックが使用される場合があります この機能を使用するには、「動画ストリームを偽装」のクライアントを Android Studio 以外の任意のクライアントに変更してください @@ -313,17 +313,17 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が 登録チャンネルのコミュニティ ガイドラインは非表示です 登録チャンネルのコミュニティ ガイドラインは表示されます Timed Reaction を非表示 - Timed Reaction とチャット欄のハートマーク アイコンは表示されません - Timed Reaction とチャット欄のハートマー ク アイコンは表示されます + Timed reaction は表示されません\n\nライブ配信のチャット欄に常駐するハート マーク ボタンが非表示になります + Timed reaction は表示されます\n\nライブ配信のチャット欄にハート マーク ボタンが常駐します 「AI 生成による動画の要約」を非表示 「AI 生成による動画の要約」セクションは表示されません 「AI 生成による動画の要約」セクションは表示されます - 質問セクションを非表示 - 質問セクションは表示されません - 質問セクションは表示されます + 「質問する」を非表示 + 「質問する」セクションは表示されません + 「質問する」セクションは表示されます 付随情報を非表示 - 注目の場所 / ゲーム / 音楽 / 言及されている人物セクションは表示されません - 注目の場所 / ゲーム / 音楽 / 言及されている人物セクションは表示されます + 注目の場所 / ゲーム / 音楽 / 人物セクションは表示されません + 注目の場所 / ゲーム / 音楽 / 人物セクションは表示されます チャプター セクションを非表示 チャプター セクションは表示されません チャプター セクションは表示されます @@ -456,12 +456,12 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が "ホーム / 登録チャンネル / 検索結果でキーワードに合致する動画を非表示にします 制限事項 -• ショート動画はチャンネル名で非表示にできない +• ショート動画はチャンネル名の合致では非表示にできない • 一部の UI コンポーネントが残ってしまう場合がある • キーワードを検索したとき、結果が表示されない場合がある" 単語全体で合致 - キーワードを二重引用符で囲むことで、動画のタイトルやチャンネル名の単語の一部とキーワードが合致しないようにできます<br><br>例えば、<br><b>\"ai\"</b>は、次の動画を非表示にします:<b>How does AI work?</b><br>しかし、次の動画は非表示にしません:<b>What does fair use mean?</b> + キーワードを二重引用符で囲むことで、動画のタイトルやチャンネル名に含まれる単語の一部分とキーワードが合致しないようにできます<br><br>例えば、<br><b>\"ai\"</b>は、次の動画を非表示にします:<b>How does AI work?</b><br>しかし、次の動画は非表示にしません:<b>What does fair use mean?</b> 使用できないキーワード: %s 二重引用符が必要なキーワード: %s @@ -741,7 +741,7 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が フライアウト メニュー - プレーヤー オーバーレイの歯車ボタンから呼び出されるフライアウト メニューの項目を表示または非表示にします + プレーヤー オーバーレイの歯車アイコンボタンから呼び出されるフライアウト メニューの項目を表示または非表示にします 「字幕」を非表示 「字幕」は表示されません @@ -967,7 +967,7 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が "終了画面の「関連動画」は表示されませんが、自動再生がオンの場合は関連動画が自動で再生されます 自動再生の設定は YouTube の設定で変更できます: -設定 → 再生 → 次の動画を自動再生" +[設定] → [再生] → [次の動画を自動再生]" 終了画面の「関連動画」は表示されます @@ -982,8 +982,8 @@ YouTube Premium ユーザーの場合、この設定は必要ない可能性が プレーヤー ポップアップ パネルを非表示 - プレーヤー ポップアップ パネルは表示されません\n\nプレイリストやチャット欄などを閉じた状態で動画を開きます - プレーヤー ポップアップ パネルは表示されます\n\nプレイリストやチャット欄などを展開した状態で動画を開きます + プレーヤー ポップアップ パネルは表示されません\n\nプレイリストやライブ配信のチャット欄などを閉じた状態で動画を開きます + プレーヤー ポップアップ パネルは表示されます\n\nプレイリストやライブ配信のチャット欄などを展開した状態で動画を開きます 再生終了時に全画面表示を解除 @@ -1366,23 +1366,23 @@ Automotive レイアウト ミニプレーヤー アプリ内に表示される小さな画面のプレーヤーのスタイルを変更します - ミニプレーヤーのタイプ + ミニプレーヤーの種類 無効 デフォルト - 横長 + 旧タイプ (横長) タブレット - モダン 1 - モダン 2 - モダン 3 - モダン 4 + 新タイプ 1 + 新タイプ 2 + 新タイプ 3 + 新タイプ 4 ミニプレーヤーを直角化 ミニプレーヤーの角は直角です ミニプレーヤーの角は丸角です ダブルタップとピンチによるサイズ変更を有効化 "ダブルタップとピンチによるサイズ変更は有効です -• ダブルタップすると、ミニプレーヤーのサイズが大きくなる -• もう一度ダブルタップすると、元のサイズに戻る" +• ダブルタップするとミニプレーヤーのサイズが大きくなる +• もう一度ダブルタップすると元のサイズに戻る" ダブルタップとピンチによるサイズ変更は無効です ドラッグ&ドロップを無効化 ドラッグ&ドロップは無効です diff --git a/patches/src/main/resources/addresources/values-ko-rKR/strings.xml b/patches/src/main/resources/addresources/values-ko-rKR/strings.xml index ca0df154b..62453711f 100644 --- a/patches/src/main/resources/addresources/values-ko-rKR/strings.xml +++ b/patches/src/main/resources/addresources/values-ko-rKR/strings.xml @@ -29,7 +29,7 @@ Second \"item\" text" 원본 ReVanced 최소화 - ReVanced 크기 조정 + ReVanced 스케일 사용자 정의 @@ -1507,10 +1507,10 @@ DeArrow에 대해 자세히 알아보려면 여기를 탭하세요" 기기 크기 정보 변경하기 "기기 크기 정보를 변경합니다 -이 설정을 활성화하면 더 높은 화질 동영상 값을 잠금 해제할 수 있지만, 동영상 재생이 끊기거나 배터리 수명이 단축될 수 있으며, 알려지지 않은 부작용도 발생할 수 있습니다" +이 설정을 활성화하면 더 높은 동영상 화질 값을 잠금 해제할 수 있지만, 동영상 재생이 끊기거나 배터리 수명이 단축될 수 있으며, 알려지지 않은 부작용도 발생할 수 있습니다" "기기 크기 정보를 변경하지 않습니다 -이 설정을 활성화하면 더 높은 화질 동영상 값을 잠금 해제할 수 있습니다" +이 설정을 활성화하면 더 높은 동영상 화질 값을 잠금 해제할 수 있습니다" 이 설정을 활성화하면 동영상 재생이 끊기거나 배터리 수명이 단축되고 알려지지 않은 부작용이 발생할 수 있습니다. diff --git a/patches/src/main/resources/addresources/values-ru-rRU/strings.xml b/patches/src/main/resources/addresources/values-ru-rRU/strings.xml index 3406e92de..95bf138cc 100644 --- a/patches/src/main/resources/addresources/values-ru-rRU/strings.xml +++ b/patches/src/main/resources/addresources/values-ru-rRU/strings.xml @@ -24,14 +24,14 @@ Second \"item\" text" Название приложения - Кастомный - Значок приложения - Оригинал + Кастомное + Иконка приложения + Оригинальная - ReVanced минимальный - ReVanced масштабированный + ReVanced минимальная + ReVanced масштабированная - Кастомный + Кастомная Проверки не удались @@ -1630,8 +1630,8 @@ Second \"item\" text" "Видеокодек: AVC (H.264), VP9 или AV1 Воспроизведение может зависать или пропускать кадры" - Видеокодек: AVC (H.264) или VP9 - "Включение этой настройки может использовать программное декодирование AV1. + Видеокодек AVC (H.264) или VP9 + "Включение этой опции может использовать программное декодирование AV1. Воспроизведение видео с AV1 может прерываться или пропускать кадры." Побочные эффекты подмены diff --git a/patches/src/main/resources/addresources/values-tr-rTR/strings.xml b/patches/src/main/resources/addresources/values-tr-rTR/strings.xml index f62f617f1..43a2fc154 100644 --- a/patches/src/main/resources/addresources/values-tr-rTR/strings.xml +++ b/patches/src/main/resources/addresources/values-tr-rTR/strings.xml @@ -1626,7 +1626,7 @@ Sınırlamalar: Kaydırarak sardırma etkin değil - Android VR AV1\'e İzin Ver + Android VR AV1\'e izin ver "Video kodeği AVC (H.264), VP9 veya AV1'dir Oynatma takılabilir veya kare atlayabilir" diff --git a/patches/src/main/resources/addresources/values-vi-rVN/strings.xml b/patches/src/main/resources/addresources/values-vi-rVN/strings.xml index 0df40a32f..35f29f3a5 100644 --- a/patches/src/main/resources/addresources/values-vi-rVN/strings.xml +++ b/patches/src/main/resources/addresources/values-vi-rVN/strings.xml @@ -378,12 +378,12 @@ Nếu cài đặt này được bật và Doodle đang hiển thị tại khu v Nút Chuyển đến cửa hàng được hiển thị Bình luận Ẩn hoặc hiện các thành phần bình luận - Ẩn tóm tắt cuộc trò chuyện AI - Tóm tắt cuộc trò chuyện AI đã bị ẩn - Tóm tắt cuộc trò chuyện AI được hiển thị - Ẩn tóm tắt bình luận AI - Tóm tắt bình luận AI đã bị ẩn - Tóm tắt bình luận AI được hiển thị + Ẩn tóm tắt cuộc trò chuyện do AI tạo + Tóm tắt cuộc trò chuyện do AI tạo đã bị ẩn + Tóm tắt cuộc trò chuyện do AI tạo được hiển thị + Ẩn tóm tắt bình luận do AI tạo + Tóm tắt bình luận do AI tạo đã bị ẩn + Tóm tắt bình luận do AI tạo được hiển thị Ẩn nguyên tắc kênh Nguyên tắc kênh đã bị ẩn Nguyên tắc kênh được hiển thị @@ -912,12 +912,12 @@ Nếu thay đổi cài đặt này không có hiệu lực, hãy thử chuyển Ẩn nút Sắp diễn ra Nút sắp diễn ra đã bị ẩn Nút sắp diễn ra được hiển thị - Ẩn nút \"Sử dụng âm thanh này\" - Nút \"Sử dụng âm thanh này\" đã bị ẩn - Nút \"Sử dụng âm thanh này\" được hiển thị - Ẩn nút \"Sử dụng mẫu này\" - Nút \"Sử dụng mẫu này\" đã bị ẩn - Nút \"Sử dụng mẫu này\" được hiển thị + Ẩn nút Dùng âm thanh này + Nút dùng âm thanh này đã bị ẩn + Nút dùng âm thanh này được hiển thị + Ẩn nút Sử dụng mẫu này + Nút sử dụng mẫu này đã bị ẩn + Nút sử dụng mẫu này được hiển thị Ẩn hiệu ứng đài phun nút Thích Hiệu ứng đài phun nút thích đã bị ẩn Hiệu ứng đài phun nút thích được hiển thị diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_minimal.xml b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_minimal.xml index a4b14512d..044733ee0 100644 --- a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_minimal.xml +++ b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_minimal.xml @@ -5,33 +5,39 @@ android:height="108dp" android:viewportWidth="256" android:viewportHeight="256"> - - - + - - - - - - - - - - + android:fillColor="#1B1B1B" + android:pathData="M0,0 L256,0 L256,256 L0,256 Z" /> + + + + + + + + + + + + diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_rounded.xml b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_rounded.xml index 1b4dcef31..a29891962 100644 --- a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_rounded.xml +++ b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_rounded.xml @@ -5,47 +5,59 @@ android:height="108dp" android:viewportWidth="800" android:viewportHeight="800"> - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_scaled.xml b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_scaled.xml index e64200344..9a5e7944a 100644 --- a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_scaled.xml +++ b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_foreground_scaled.xml @@ -5,33 +5,39 @@ android:height="108dp" android:viewportWidth="256" android:viewportHeight="256"> - - - + - - - - - - - - - - + android:fillColor="#000000" + android:pathData="M0,0 L256,0 L256,256 L0,256 Z" /> + + + + + + + + + + + + diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_custom.xml b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_custom.xml index a5eadebdc..30c8d01bd 100644 --- a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_custom.xml +++ b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_custom.xml @@ -4,15 +4,16 @@ android:height="108dp" android:viewportWidth="256" android:viewportHeight="256"> - - - - + + + + diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_minimal.xml b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_minimal.xml index a5eadebdc..30c8d01bd 100644 --- a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_minimal.xml +++ b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_minimal.xml @@ -4,15 +4,16 @@ android:height="108dp" android:viewportWidth="256" android:viewportHeight="256"> - - - - + + + + diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_rounded.xml b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_rounded.xml index 11979dd6a..116f2da5d 100644 --- a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_rounded.xml +++ b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_rounded.xml @@ -4,20 +4,21 @@ android:height="108dp" android:viewportWidth="800" android:viewportHeight="800"> - - - - - + + + + + diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_scaled.xml b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_scaled.xml index 41160d4ba..381c59c8c 100644 --- a/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_scaled.xml +++ b/patches/src/main/resources/custom-branding/drawable/revanced_adaptive_monochrome_scaled.xml @@ -4,15 +4,16 @@ android:height="108dp" android:viewportWidth="256" android:viewportHeight="256"> - - - - + + + + diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_notification_icon.xml b/patches/src/main/resources/custom-branding/drawable/revanced_notification_icon.xml new file mode 100644 index 000000000..97e377929 --- /dev/null +++ b/patches/src/main/resources/custom-branding/drawable/revanced_notification_icon.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/patches/src/main/resources/custom-branding/drawable/revanced_notification_icon_custom.xml b/patches/src/main/resources/custom-branding/drawable/revanced_notification_icon_custom.xml new file mode 100644 index 000000000..97e377929 --- /dev/null +++ b/patches/src/main/resources/custom-branding/drawable/revanced_notification_icon_custom.xml @@ -0,0 +1,13 @@ + + + + + + +