From 0b1d2605555bfdf0a8744b9c551461fee5ba9981 Mon Sep 17 00:00:00 2001 From: KobeW50 <84587632+KobeW50@users.noreply.github.com> Date: Tue, 31 Dec 2024 03:07:32 -0500 Subject: [PATCH 01/65] fix: In app strings and patch descriptions (#114) * fix(YouTube Music -Spoof client): String grammar * fix(YouTube): Patch description grammar & clarity * Apply suggestion from review * Use consistent bullet point syntax * Minor wording clarification * chroe: Match with YouTube --------- Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com> --- .../app/revanced/patches/music/utils/patch/PatchList.kt | 2 +- .../app/revanced/patches/youtube/utils/patch/PatchList.kt | 6 +++--- .../main/resources/music/settings/host/values/strings.xml | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt index c814a7d97..5a9c71bbc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt @@ -23,7 +23,7 @@ internal enum class PatchList( ), CHANGE_SHARE_SHEET( "Change share sheet", - "Add option to change from in-app share sheet to system share sheet." + "Adds an option to change the in-app share sheet to the system share sheet." ), CHANGE_START_PAGE( "Change start page", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/patch/PatchList.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/patch/PatchList.kt index 5ebdc1893..2e944d1ba 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/patch/PatchList.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/patch/PatchList.kt @@ -23,7 +23,7 @@ internal enum class PatchList( ), CHANGE_SHARE_SHEET( "Change share sheet", - "Add option to change from in-app share sheet to system share sheet." + "Adds an option to change the in-app share sheet to the system share sheet." ), CHANGE_START_PAGE( "Change start page", @@ -147,7 +147,7 @@ internal enum class PatchList( ), HIDE_SHORTCUTS( "Hide shortcuts", - "Remove, at compile time, the app shortcuts that appears when app icon is long pressed." + "Remove, at compile time, the app shortcuts that appears when the app icon is long pressed." ), HOOK_YOUTUBE_MUSIC_ACTIONS( "Hook YouTube Music actions", @@ -235,7 +235,7 @@ internal enum class PatchList( ), TOOLBAR_COMPONENTS( "Toolbar components", - "Adds options to hide or change components located on the toolbar, such as toolbar buttons, search bar, and header." + "Adds options to hide or change components located on the toolbar, such as the search bar, header, and toolbar buttons." ), TRANSLATIONS_FOR_YOUTUBE( "Translations for YouTube", diff --git a/patches/src/main/resources/music/settings/host/values/strings.xml b/patches/src/main/resources/music/settings/host/values/strings.xml index d04d6e15b..8415983e2 100644 --- a/patches/src/main/resources/music/settings/host/values/strings.xml +++ b/patches/src/main/resources/music/settings/host/values/strings.xml @@ -451,11 +451,11 @@ Tap the continue button and allow optimization changes." Spoof client "Spoof the client to prevent playback issues. -※ When used with 'Spoofing streaming data', playback issues may occur." +• When used with 'Spoofing streaming data', playback issues may occur." Default client - "Defines a default client to spoofing. + "Defines a default client for spoofing. -※ When using the Android client, it is recommended to use it with 'Spoof app version'." +• When using the Android client, it is recommended to also use 'Spoof app version'." Android Music 4.27.53 Android Music 5.29.53 iOS Music 6.21 @@ -463,7 +463,7 @@ Tap the continue button and allow optimization changes." Spoof streaming data "Spoof the streaming data to prevent playback issues. -※ When used with 'Spoof client', playback issues may occur." +• When used with 'Spoof client', playback issues may occur." Default client Defines a default client that fetches streaming data. Show in Stats for nerds From c0d8745e08d6831911764679698149df6cfa1068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20Gia=20B=E1=BA=A3o?= <70064328+YT-Advanced@users.noreply.github.com> Date: Tue, 31 Dec 2024 18:20:58 +0700 Subject: [PATCH 02/65] fix(Hide Carousel Shelf): Your Movies is empty when turning on Hide Carousel Shelf options (#116) --- .../youtube/patches/components/CarouselShelfFilter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/components/CarouselShelfFilter.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/components/CarouselShelfFilter.java index 4dd9ace46..e565fe92c 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/components/CarouselShelfFilter.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/components/CarouselShelfFilter.java @@ -18,6 +18,7 @@ public final class CarouselShelfFilter extends Filter { private static final String BROWSE_ID_CLIP = "FEclips"; private static final String BROWSE_ID_HOME = "FEwhat_to_watch"; private static final String BROWSE_ID_LIBRARY = "FElibrary"; + private static final String BROWSE_ID_MOVIE = "FEstorefront"; private static final String BROWSE_ID_NOTIFICATION = "FEactivity"; private static final String BROWSE_ID_NOTIFICATION_INBOX = "FEnotifications_inbox"; private static final String BROWSE_ID_PLAYLIST = "VLPL"; @@ -32,9 +33,10 @@ public final class CarouselShelfFilter extends Filter { ); private static final Supplier> whitelistBrowseId = () -> Stream.of( - BROWSE_ID_LIBRARY, - BROWSE_ID_NOTIFICATION_INBOX, BROWSE_ID_CLIP, + BROWSE_ID_LIBRARY, + BROWSE_ID_MOVIE, + BROWSE_ID_NOTIFICATION_INBOX, BROWSE_ID_PREMIUM ); From e29a25fac2d0a26667c1debe7d72e5271944d449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20Gia=20B=E1=BA=A3o?= <70064328+YT-Advanced@users.noreply.github.com> Date: Tue, 31 Dec 2024 18:23:07 +0700 Subject: [PATCH 03/65] feat(YouTube - Change start page): Add more start page (#115) * ci: workflow to ping Discord users when patches are released (#72) * init: Workflow to notify discord users of releases * Rename workflow * chore (Background playback): Shorten description * Revert "chore (Background playback): Shorten description" This reverts commit 10661b870f0c9c670c5d522f9b2ca7cc82d32772. * Change message contents * Add `Courses` * Add to array * Add strings * Add more start page * Add to array * Rename `CLIPS` to `YOUR_CLIPS` * Add string --------- Co-authored-by: KobeW50 <84587632+KobeW50@users.noreply.github.com> Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com> --- .../youtube/patches/general/ChangeStartPagePatch.java | 3 +++ .../main/resources/youtube/settings/host/values/arrays.xml | 6 ++++++ .../main/resources/youtube/settings/host/values/strings.xml | 3 +++ 3 files changed, 12 insertions(+) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/ChangeStartPagePatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/ChangeStartPagePatch.java index 272eac1dd..759397604 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/ChangeStartPagePatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/ChangeStartPagePatch.java @@ -32,12 +32,15 @@ public final class ChangeStartPagePatch { HISTORY("FEhistory", TRUE), LIBRARY("FElibrary", TRUE), MOVIE("FEstorefront", TRUE), + NOTIFICATIONS("FEactivity", TRUE), SUBSCRIPTIONS("FEsubscriptions", TRUE), TRENDING("FEtrending", TRUE), + YOUR_CLIPS("FEclips", TRUE), /** * Channel id, this can be used as a browseId. */ + COURSES("UCtFRv9O2AHqOZjjynzrv-xg", TRUE), GAMING("UCOpNcN46UbXVtpKMrmU4Abg", TRUE), LIVE("UC4R8DWoMoI7CAwX8_LjQHig", TRUE), MUSIC("UC-9-kyTW8ZkZNDHQJ6FgpwQ", TRUE), diff --git a/patches/src/main/resources/youtube/settings/host/values/arrays.xml b/patches/src/main/resources/youtube/settings/host/values/arrays.xml index 8538bf654..3ae7d2bf4 100644 --- a/patches/src/main/resources/youtube/settings/host/values/arrays.xml +++ b/patches/src/main/resources/youtube/settings/host/values/arrays.xml @@ -42,11 +42,14 @@ @string/revanced_change_start_page_entry_shorts @string/revanced_change_start_page_entry_subscriptions @string/revanced_change_start_page_entry_explore + @string/revanced_change_start_page_entry_notifications @string/revanced_change_start_page_entry_library + @string/revanced_change_start_page_entry_your_clips @string/revanced_change_start_page_entry_liked_videos @string/revanced_change_start_page_entry_watch_later @string/revanced_change_start_page_entry_history @string/revanced_change_start_page_entry_trending + @string/revanced_change_start_page_entry_courses @string/revanced_change_start_page_entry_gaming @string/revanced_change_start_page_entry_live @string/revanced_change_start_page_entry_music @@ -62,11 +65,14 @@ SUBSCRIPTIONS EXPLORE + NOTIFICATIONS LIBRARY + YOUR_CLIPS LIKED_VIDEO WATCH_LATER HISTORY TRENDING + COURSES GAMING LIVE MUSIC diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index 57025c2a6..f8b1eed0e 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -320,6 +320,7 @@ If the layout of the player screen changes due to server-side changes, unintende Change start page Browse channels + Courses / Learning Default Explore Gaming @@ -329,12 +330,14 @@ If the layout of the player screen changes due to server-side changes, unintende Live Movies Music + Notifications Search Shorts Sports Subscriptions Trending Watch later + Your clips Change start page type "Start page always changes. From dd3c889062dfb59905c8d6ae588fe1fbcc111b4f Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 20:33:18 +0900 Subject: [PATCH 04/65] fix(YouTube - Disable haptic feedback): `Disable seek haptic feedback` doesn't work --- .../hapticfeedback/hapticFeedbackPatch.kt | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/hapticfeedback/hapticFeedbackPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/hapticfeedback/hapticFeedbackPatch.kt index 22888a480..373619800 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/hapticfeedback/hapticFeedbackPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/hapticfeedback/hapticFeedbackPatch.kt @@ -10,10 +10,12 @@ import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCR import app.revanced.patches.youtube.utils.patch.PatchList.DISABLE_HAPTIC_FEEDBACK import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch -import app.revanced.util.fingerprint.methodOrThrow -import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.fingerprint.matchOrThrow +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionReversedOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference @Suppress("unused") val hapticFeedbackPatch = bytecodePatch( @@ -26,23 +28,29 @@ val hapticFeedbackPatch = bytecodePatch( execute { fun Pair.hookHapticFeedback(methodName: String) = - methodOrThrow().apply { - var index = 0 - var register = 0 + matchOrThrow().let { + it.method.apply { + var index = 0 + var register = 0 - if (name == "run") { - index = indexOfFirstInstructionOrThrow(Opcode.SGET) - register = getInstruction(index).registerA - } + if (name == "run") { + val stringIndex = it.stringMatches!!.first().index + index = indexOfFirstInstructionReversedOrThrow(stringIndex) { + opcode == Opcode.SGET && + getReference()?.toString() == "Landroid/os/Build${'$'}VERSION;->SDK_INT:I" + } + register = getInstruction(index).registerA + } - addInstructionsWithLabels( - index, """ + addInstructionsWithLabels( + index, """ invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->$methodName()Z move-result v$register if-eqz v$register, :vibrate return-void """, ExternalLabel("vibrate", getInstruction(index)) - ) + ) + } } arrayOf( From 4b0e9504c978ab5b9f1aaf09f2e5a73286548b84 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 20:37:25 +0900 Subject: [PATCH 05/65] fix(YouTube - Swipe controls): Gestures are not disabled in the channel bar even though `Disable watch panel gestures` is turned on (YouTube 19.16.39+) --- .../youtube/swipe/controls/Fingerprints.kt | 25 ++++++++++++++++--- .../swipe/controls/SwipeControlsPatch.kt | 10 +++++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/swipe/controls/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/swipe/controls/Fingerprints.kt index 1447cc97c..e0a892c49 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/swipe/controls/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/swipe/controls/Fingerprints.kt @@ -3,6 +3,7 @@ package app.revanced.patches.youtube.swipe.controls import app.revanced.patches.youtube.utils.extension.Constants.EXTENSION_PATH import app.revanced.patches.youtube.utils.resourceid.autoNavScrollCancelPadding import app.revanced.patches.youtube.utils.resourceid.fullScreenEngagementOverlay +import app.revanced.util.containsLiteralInstruction import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags @@ -39,7 +40,7 @@ internal val swipeToSwitchVideoFingerprint = legacyFingerprint( literals = listOf(SWIPE_TO_SWITCH_VIDEO_FEATURE_FLAG), ) -internal const val WATCH_PANEL_GESTURES_FEATURE_FLAG = 45372793L +internal const val WATCH_PANEL_GESTURES_PRIMARY_FEATURE_FLAG = 45372793L /** * This fingerprint is compatible with YouTube v18.29.38 ~ v19.34.42 @@ -47,10 +48,28 @@ internal const val WATCH_PANEL_GESTURES_FEATURE_FLAG = 45372793L internal val watchPanelGesturesFingerprint = legacyFingerprint( name = "watchPanelGesturesFingerprint", returnType = "V", - literals = listOf(WATCH_PANEL_GESTURES_FEATURE_FLAG), + literals = listOf(WATCH_PANEL_GESTURES_PRIMARY_FEATURE_FLAG), ) internal val watchPanelGesturesAlternativeFingerprint = legacyFingerprint( name = "watchPanelGesturesAlternativeFingerprint", literals = listOf(autoNavScrollCancelPadding), -) \ No newline at end of file +) + +internal const val WATCH_PANEL_GESTURES_SECONDARY_FEATURE_FLAG = 45619395L + +/** + * Watch panel gestures in channel bar + * This fingerprint is compatible with YouTube v19.15.36 ~ + */ +internal val watchPanelGesturesChannelBarFingerprint = legacyFingerprint( + name = "watchPanelGesturesChannelBarFingerprint", + returnType = "Z", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("Landroid/view/MotionEvent;"), + customFingerprint = { method, _ -> + method.definingClass.endsWith("/NextGenWatchLayout;") && + method.name == "onInterceptTouchEvent" && + method.containsLiteralInstruction(WATCH_PANEL_GESTURES_SECONDARY_FEATURE_FLAG) + } +) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/swipe/controls/SwipeControlsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/swipe/controls/SwipeControlsPatch.kt index 3d404f4b7..5e459e855 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/swipe/controls/SwipeControlsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/swipe/controls/SwipeControlsPatch.kt @@ -16,6 +16,7 @@ import app.revanced.patches.youtube.utils.mainactivity.mainActivityResolvePatch import app.revanced.patches.youtube.utils.patch.PatchList.SWIPE_CONTROLS import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch import app.revanced.patches.youtube.utils.playservice.is_19_09_or_greater +import app.revanced.patches.youtube.utils.playservice.is_19_15_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_36_or_greater import app.revanced.patches.youtube.utils.playservice.versionCheckPatch @@ -146,7 +147,7 @@ val swipeControlsPatch = bytecodePatch( if (!is_19_36_or_greater) { watchPanelGesturesFingerprint.injectLiteralInstructionBooleanCall( - WATCH_PANEL_GESTURES_FEATURE_FLAG, + WATCH_PANEL_GESTURES_PRIMARY_FEATURE_FLAG, "$EXTENSION_SWIPE_CONTROLS_PATCH_CLASS_DESCRIPTOR->disableWatchPanelGestures()Z" ) } else { @@ -197,6 +198,13 @@ val swipeControlsPatch = bytecodePatch( } } + if (is_19_15_or_greater) { + watchPanelGesturesChannelBarFingerprint.injectLiteralInstructionBooleanCall( + WATCH_PANEL_GESTURES_SECONDARY_FEATURE_FLAG, + "$EXTENSION_SWIPE_CONTROLS_PATCH_CLASS_DESCRIPTOR->disableWatchPanelGestures()Z" + ) + } + // endregion // region copy resources From fd9670fcae125754fa688009d17bcb71403e8e24 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 20:39:52 +0900 Subject: [PATCH 06/65] fix(YouTube - Overlay buttons): Restrict the version that can use the patch options `Bottom margin` and `Wider between-buttons space` to YouTube 19.16.39 (Close https://github.com/inotia00/ReVanced_Extended/issues/2608) --- .../overlaybuttons/OverlayButtonsPatch.kt | 135 +++++++++++------- 1 file changed, 82 insertions(+), 53 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt index 5c023b1eb..a99186c66 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt @@ -15,12 +15,14 @@ import app.revanced.patches.youtube.utils.patch.PatchList.OVERLAY_BUTTONS import app.revanced.patches.youtube.utils.pip.pipStateHookPatch import app.revanced.patches.youtube.utils.playercontrols.hookBottomControlButton import app.revanced.patches.youtube.utils.playercontrols.playerControlsPatch +import app.revanced.patches.youtube.utils.playservice.is_19_17_or_greater import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.patches.youtube.video.information.videoEndMethod import app.revanced.patches.youtube.video.information.videoInformationPatch import app.revanced.util.ResourceGroup +import app.revanced.util.Utils.printWarn import app.revanced.util.copyResources import app.revanced.util.copyXmlNode import app.revanced.util.doRecursively @@ -99,7 +101,7 @@ val overlayButtonsPatch = resourcePatch( "Wider" to MARGIN_WIDER, ), title = "Bottom margin", - description = "The bottom margin for the overlay buttons and timestamp.", + description = "The bottom margin for the overlay buttons and timestamp. Supports from YouTube 18.29.38 to YouTube 19.16.39.", required = true ) @@ -107,7 +109,7 @@ val overlayButtonsPatch = resourcePatch( key = "widerButtonsSpace", default = false, title = "Wider between-buttons space", - description = "Prevent adjacent button presses by increasing the horizontal spacing between buttons.", + description = "Prevent adjacent button presses by increasing the horizontal spacing between buttons. Supports from YouTube 18.29.38 to YouTube 19.16.39.", required = true ) @@ -125,9 +127,19 @@ val overlayButtonsPatch = resourcePatch( val iconType = iconTypeOption .lowerCaseOrThrow() - val marginBottom = bottomMarginOption + var marginBottom = bottomMarginOption .lowerCaseOrThrow() + if (marginBottom != MARGIN_DEFAULT && is_19_17_or_greater) { + printWarn("\"Bottom margin\" is not supported in this version. Use YouTube 19.16.39 or earlier.") + marginBottom = MARGIN_DEFAULT + } + + if (widerButtonsSpace == true && is_19_17_or_greater) { + printWarn("\"Wider between-buttons space\" is not supported in this version. Use YouTube 19.16.39 or earlier.") + } + val useWiderButtonsSpace = widerButtonsSpace == true && !is_19_17_or_greater + // Inject hooks for overlay buttons. setOf( "AlwaysRepeat;", @@ -201,59 +213,76 @@ val overlayButtonsPatch = resourcePatch( "android.support.constraint.ConstraintLayout" ) - // Note: Do not modify fullscreen button and multiview button - document("res/layout/youtube_controls_bottom_ui_container.xml").use { document -> - document.doRecursively loop@{ node -> - if (node !is Element) return@loop + var xmlFiles = arrayOf( + "youtube_controls_bottom_ui_container.xml" + ) + if (!is_19_17_or_greater) { + xmlFiles += "youtube_controls_fullscreen_button.xml" + xmlFiles += "youtube_controls_cf_fullscreen_button.xml" + } - // Change the relationship between buttons - node.getAttributeNode("yt:layout_constraintRight_toLeftOf") - ?.let { attribute -> - if (attribute.textContent == "@id/fullscreen_button") { - attribute.textContent = "@+id/speed_dialog_button" + xmlFiles.forEach { xmlFile -> + val targetXml = get("res").resolve("layout").resolve(xmlFile) + if (targetXml.exists()) { + document("res/layout/$xmlFile").use { document -> + document.doRecursively loop@{ node -> + if (node !is Element) return@loop + + // Change the relationship between buttons + node.getAttributeNode("yt:layout_constraintRight_toLeftOf") + ?.let { attribute -> + if (attribute.textContent == "@id/fullscreen_button") { + attribute.textContent = "@+id/speed_dialog_button" + } + } + + val (id, height, width) = Triple( + node.getAttribute("android:id"), + node.getAttribute("android:layout_height"), + node.getAttribute("android:layout_width") + ) + val (heightIsNotZero, widthIsNotZero) = Pair( + height != "0.0dip", + width != "0.0dip", + ) + + val isButton = if (is_19_17_or_greater) + // Note: Do not modify fullscreen button and multiview button + id.endsWith("_button") && id != "@id/multiview_button" + else + id.endsWith("_button") || id == "@id/youtube_controls_fullscreen_button_stub" + + // Adjust TimeBar and Chapter bottom padding + val timBarItem = mutableMapOf( + "@id/time_bar_chapter_title" to "16.0dip", + "@id/timestamps_container" to "14.0dip" + ) + + val layoutHeightWidth = if (useWiderButtonsSpace) + "56.0dip" + else + "48.0dip" + + if (isButton) { + node.setAttribute("android:layout_marginBottom", marginBottom) + node.setAttribute("android:paddingLeft", "0.0dip") + node.setAttribute("android:paddingRight", "0.0dip") + node.setAttribute("android:paddingBottom", "22.0dip") + if (heightIsNotZero && widthIsNotZero) { + node.setAttribute("android:layout_height", layoutHeightWidth) + node.setAttribute("android:layout_width", layoutHeightWidth) + } + } else if (timBarItem.containsKey(id)) { + node.setAttribute("android:layout_marginBottom", marginBottom) + if (!useWiderButtonsSpace) { + node.setAttribute("android:paddingBottom", timBarItem.getValue(id)) + } + } + + if (!is_19_17_or_greater && id.equals("@id/youtube_controls_fullscreen_button_stub")) { + node.setAttribute("android:layout_width", layoutHeightWidth) } } - - val (id, height, width) = Triple( - node.getAttribute("android:id"), - node.getAttribute("android:layout_height"), - node.getAttribute("android:layout_width") - ) - val (heightIsNotZero, widthIsNotZero, isButton) = Triple( - height != "0.0dip", - width != "0.0dip", - id.endsWith("_button") && id != "@id/multiview_button" - ) - - // Adjust TimeBar and Chapter bottom padding - val timBarItem = mutableMapOf( - "@id/time_bar_chapter_title" to "16.0dip", - "@id/timestamps_container" to "14.0dip" - ) - - val layoutHeightWidth = if (widerButtonsSpace == true) - "56.0dip" - else - "48.0dip" - - if (isButton) { - node.setAttribute("android:layout_marginBottom", marginBottom) - node.setAttribute("android:paddingLeft", "0.0dip") - node.setAttribute("android:paddingRight", "0.0dip") - node.setAttribute("android:paddingBottom", "22.0dip") - if (heightIsNotZero && widthIsNotZero) { - node.setAttribute("android:layout_height", layoutHeightWidth) - node.setAttribute("android:layout_width", layoutHeightWidth) - } - } else if (timBarItem.containsKey(id)) { - node.setAttribute("android:layout_marginBottom", marginBottom) - if (widerButtonsSpace != true) { - node.setAttribute("android:paddingBottom", timBarItem.getValue(id)) - } - } - - if (id.equals("@id/youtube_controls_fullscreen_button_stub")) { - node.setAttribute("android:layout_width", layoutHeightWidth) } } } From 87a6aec1dc342b389a4dfef51467f52fb929fd31 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 20:41:02 +0900 Subject: [PATCH 07/65] fix(YouTube - Overlay buttons): Add missing dependency --- .../youtube/player/overlaybuttons/OverlayButtonsPatch.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt index a99186c66..ea6446abd 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt @@ -16,6 +16,7 @@ import app.revanced.patches.youtube.utils.pip.pipStateHookPatch import app.revanced.patches.youtube.utils.playercontrols.hookBottomControlButton import app.revanced.patches.youtube.utils.playercontrols.playerControlsPatch import app.revanced.patches.youtube.utils.playservice.is_19_17_or_greater +import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch @@ -77,6 +78,7 @@ val overlayButtonsPatch = resourcePatch( playerControlsPatch, sharedResourceIdPatch, settingsPatch, + versionCheckPatch, ) val iconTypeOption = stringOption( From 8d045bc6183bce54c4cee0b01b064774fc9b988d Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 20:43:57 +0900 Subject: [PATCH 08/65] fix(YouTube Music - Custom header): Not working on YouTube Music 7.25.53 https://github.com/inotia00/ReVanced_Extended/issues/2612 --- .../music/layout/header/ChangeHeaderPatch.kt | 33 +++++++++++++------ .../music/layout/header/Fingerprints.kt | 12 ------- .../utils/resourceid/SharedResourceIdPatch.kt | 25 ++++++++++++++ .../kotlin/app/revanced/util/BytecodeUtils.kt | 28 ++++++++++++++++ 4 files changed, 76 insertions(+), 22 deletions(-) delete mode 100644 patches/src/main/kotlin/app/revanced/patches/music/layout/header/Fingerprints.kt diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/header/ChangeHeaderPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/header/ChangeHeaderPatch.kt index db08f642f..8143cfddd 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/header/ChangeHeaderPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/header/ChangeHeaderPatch.kt @@ -5,6 +5,13 @@ import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.stringOption import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.music.utils.patch.PatchList.CUSTOM_HEADER_FOR_YOUTUBE_MUSIC +import app.revanced.patches.music.utils.playservice.is_7_06_or_greater +import app.revanced.patches.music.utils.playservice.versionCheckPatch +import app.revanced.patches.music.utils.resourceid.actionBarLogo +import app.revanced.patches.music.utils.resourceid.actionBarLogoRingo2 +import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch +import app.revanced.patches.music.utils.resourceid.ytmLogo +import app.revanced.patches.music.utils.resourceid.ytmLogoRingo2 import app.revanced.patches.music.utils.settings.ResourceUtils.getIconType import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus import app.revanced.patches.music.utils.settings.settingsPatch @@ -13,8 +20,7 @@ import app.revanced.util.Utils.printWarn import app.revanced.util.Utils.trimIndentMultiline import app.revanced.util.copyFile import app.revanced.util.copyResources -import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall -import app.revanced.util.fingerprint.resolvable +import app.revanced.util.replaceLiteralInstructionCall import app.revanced.util.underBarOrThrow import app.revanced.util.valueOrThrow @@ -100,24 +106,31 @@ private val getDescription = { private val changeHeaderBytecodePatch = bytecodePatch( description = "changeHeaderBytecodePatch" ) { + dependsOn( + sharedResourceIdPatch, + versionCheckPatch, + ) + execute { + /** * New Header has been added from YouTube Music v7.04.51. * - * The new header's file names are 'action_bar_logo_ringo2.png' and 'ytm_logo_ringo2.png'. + * The new header's file names are 'action_bar_logo_ringo2.png' and 'ytm_logo_ringo2.png'. * The only difference between the existing header and the new header is the dimensions of the image. * * The affected patch is [changeHeaderPatch]. - * - * TODO: Add a new header image file to [changeHeaderPatch] later. */ - if (!headerSwitchConfigFingerprint.resolvable()) { + if (!is_7_06_or_greater) { return@execute } - headerSwitchConfigFingerprint.injectLiteralInstructionBooleanCall( - 45617851L, - "0x0" - ) + + listOf( + actionBarLogoRingo2 to actionBarLogo, + ytmLogoRingo2 to ytmLogo, + ).forEach { (originalResource, replacementResource) -> + replaceLiteralInstructionCall(originalResource, replacementResource) + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/header/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/header/Fingerprints.kt deleted file mode 100644 index 866303d2f..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/header/Fingerprints.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.music.layout.header - -import app.revanced.util.fingerprint.legacyFingerprint -import app.revanced.util.or -import com.android.tools.smali.dexlib2.AccessFlags - -internal val headerSwitchConfigFingerprint = legacyFingerprint( - name = "headerSwitchConfigFingerprint", - returnType = "Z", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - literals = listOf(45617851L) -) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt index a3358901f..94d001193 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt @@ -4,6 +4,7 @@ import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.shared.mapping.ResourceType.BOOL import app.revanced.patches.shared.mapping.ResourceType.COLOR import app.revanced.patches.shared.mapping.ResourceType.DIMEN +import app.revanced.patches.shared.mapping.ResourceType.DRAWABLE import app.revanced.patches.shared.mapping.ResourceType.ID import app.revanced.patches.shared.mapping.ResourceType.LAYOUT import app.revanced.patches.shared.mapping.ResourceType.STRING @@ -14,6 +15,10 @@ import app.revanced.patches.shared.mapping.resourceMappings var accountSwitcherAccessibility = -1L private set +var actionBarLogo = -1L + private set +var actionBarLogoRingo2 = -1L + private set var bottomSheetRecyclerView = -1L private set var buttonContainer = -1L @@ -94,6 +99,10 @@ var trimSilenceSwitch = -1L private set var varispeedUnavailableTitle = -1L private set +var ytmLogo = -1L + private set +var ytmLogoRingo2 = -1L + private set internal val sharedResourceIdPatch = resourcePatch( description = "sharedResourceIdPatch" @@ -105,6 +114,14 @@ internal val sharedResourceIdPatch = resourcePatch( STRING, "account_switcher_accessibility_label", ] + actionBarLogo = resourceMappings[ + DRAWABLE, + "action_bar_logo", + ] + actionBarLogoRingo2 = resourceMappings[ + DRAWABLE, + "action_bar_logo_ringo2", + ] bottomSheetRecyclerView = resourceMappings[ LAYOUT, "bottom_sheet_recycler_view" @@ -265,5 +282,13 @@ internal val sharedResourceIdPatch = resourcePatch( STRING, "varispeed_unavailable_title" ] + ytmLogo = resourceMappings[ + DRAWABLE, + "ytm_logo", + ] + ytmLogoRingo2 = resourceMappings[ + DRAWABLE, + "ytm_logo_ringo2", + ] } } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index 9f9c0989d..cd58c6e34 100644 --- a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -263,6 +263,34 @@ fun MutableMethod.injectLiteralInstructionViewCall( ) } +fun BytecodePatchContext.replaceLiteralInstructionCall( + originalLiteral: Long, + replaceLiteral: Long +) { + classes.forEach { classDef -> + classDef.methods.forEach { method -> + method.implementation.apply { + this?.instructions?.forEachIndexed { _, instruction -> + if (instruction.opcode != Opcode.CONST) + return@forEachIndexed + if ((instruction as Instruction31i).wideLiteral != originalLiteral) + return@forEachIndexed + + proxy(classDef) + .mutableClass + .findMutableMethodOf(method).apply { + val index = indexOfFirstLiteralInstructionOrThrow(originalLiteral) + val register = + (instruction as OneRegisterInstruction).registerA + + replaceInstruction(index, "const v$register, $replaceLiteral") + } + } + } + } + } +} + fun BytecodePatchContext.replaceLiteralInstructionCall( literal: Long, smaliInstruction: String From 74d39ff034c06e985dd9e0a280cffcf0834cbcdc Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 20:47:37 +0900 Subject: [PATCH 09/65] fix(YouTube - Miniplayer): Patched app crashes after first launch or clearing data --- .../patches/general/MiniplayerPatch.java | 99 ++++++++++++------- 1 file changed, 62 insertions(+), 37 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/MiniplayerPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/MiniplayerPatch.java index b231f24d9..615d27e10 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/MiniplayerPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/MiniplayerPatch.java @@ -12,6 +12,8 @@ import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_26_OR_GRE import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_29_OR_GREATER; import static app.revanced.extension.youtube.utils.ExtendedUtils.validateValue; +import android.content.Context; +import android.content.res.Resources; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; @@ -82,49 +84,56 @@ public final class MiniplayerPatch { } } - private static final int MINIPLAYER_SIZE; + private static int MINIPLAYER_SIZE = 0; static { - // YT appears to use the device screen dip width, plus an unknown fixed horizontal padding size. - DisplayMetrics displayMetrics = Utils.getContext().getResources().getDisplayMetrics(); - final int deviceDipWidth = (int) (displayMetrics.widthPixels / displayMetrics.density); + setMiniPlayerSize(); + } - // YT seems to use a minimum height to calculate the minimum miniplayer width based on the video. - // 170 seems to be the smallest that can be used and using less makes no difference. - final int WIDTH_DIP_MIN = 170; // Seems to be the smallest that works. - final int HORIZONTAL_PADDING_DIP = 15; // Estimated padding. - // Round down to the nearest 5 pixels, to keep any error toasts easier to read. - final int estimatedWidthDipMax = 5 * ((deviceDipWidth - HORIZONTAL_PADDING_DIP) / 5); - // On some ultra low end devices the pixel width and density are the same number, - // which causes the estimate to always give a value of 1. - // Fix this by using a fixed size of double the min width. - final int WIDTH_DIP_MAX = estimatedWidthDipMax <= WIDTH_DIP_MIN - ? 2 * WIDTH_DIP_MIN - : estimatedWidthDipMax; - Logger.printDebug(() -> "Screen dip width: " + deviceDipWidth + " maxWidth: " + WIDTH_DIP_MAX); + private static void setMiniPlayerSize() { + try { + Context context = Utils.getContext(); + if (context == null) { + return; + } + Resources resources = context.getResources(); + if (resources == null) { + return; + } + // YT appears to use the device screen dip width, plus an unknown fixed horizontal padding size. + DisplayMetrics displayMetrics = resources.getDisplayMetrics(); + final int deviceDipWidth = (int) (displayMetrics.widthPixels / displayMetrics.density); - int dipWidth = Settings.MINIPLAYER_WIDTH_DIP.get(); + // YT seems to use a minimum height to calculate the minimum miniplayer width based on the video. + // 170 seems to be the smallest that can be used and using less makes no difference. + final int WIDTH_DIP_MIN = 170; // Seems to be the smallest that works. + final int HORIZONTAL_PADDING_DIP = 15; // Estimated padding. + // Round down to the nearest 5 pixels, to keep any error toasts easier to read. + final int estimatedWidthDipMax = 5 * ((deviceDipWidth - HORIZONTAL_PADDING_DIP) / 5); + // On some ultra low end devices the pixel width and density are the same number, + // which causes the estimate to always give a value of 1. + // Fix this by using a fixed size of double the min width. + final int WIDTH_DIP_MAX = estimatedWidthDipMax <= WIDTH_DIP_MIN + ? 2 * WIDTH_DIP_MIN + : estimatedWidthDipMax; + Logger.printDebug(() -> "Screen dip width: " + deviceDipWidth + " maxWidth: " + WIDTH_DIP_MAX); - if (dipWidth < WIDTH_DIP_MIN || dipWidth > WIDTH_DIP_MAX) { - Utils.showToastShort(str("revanced_miniplayer_width_dip_invalid_toast", - WIDTH_DIP_MIN, WIDTH_DIP_MAX)); - Utils.showToastShort(str("revanced_extended_reset_to_default_toast")); + int dipWidth = Settings.MINIPLAYER_WIDTH_DIP.get(); - // Instead of resetting, clamp the size at the bounds. - dipWidth = Math.max(WIDTH_DIP_MIN, Math.min(dipWidth, WIDTH_DIP_MAX)); - Settings.MINIPLAYER_WIDTH_DIP.save(dipWidth); + if (dipWidth < WIDTH_DIP_MIN || dipWidth > WIDTH_DIP_MAX) { + Utils.showToastShort(str("revanced_miniplayer_width_dip_invalid_toast", + WIDTH_DIP_MIN, WIDTH_DIP_MAX)); + Utils.showToastShort(str("revanced_extended_reset_to_default_toast")); + + // Instead of resetting, clamp the size at the bounds. + dipWidth = Math.max(WIDTH_DIP_MIN, Math.min(dipWidth, WIDTH_DIP_MAX)); + Settings.MINIPLAYER_WIDTH_DIP.save(dipWidth); + } + + MINIPLAYER_SIZE = dipWidth; + } catch (Exception ex) { + Logger.printException(() -> "setMiniPlayerSize failure", ex); } - - MINIPLAYER_SIZE = dipWidth; - - final int opacity = validateValue( - Settings.MINIPLAYER_OPACITY, - 0, - 100, - "revanced_miniplayer_opacity_invalid_toast" - ); - - OPACITY_LEVEL = (opacity * 255) / 100; } /** @@ -175,6 +184,17 @@ public final class MiniplayerPatch { private static final int OPACITY_LEVEL; + static { + final int opacity = validateValue( + Settings.MINIPLAYER_OPACITY, + 0, + 100, + "revanced_miniplayer_opacity_invalid_toast" + ); + + OPACITY_LEVEL = (opacity * 255) / 100; + } + public static final class MiniplayerHorizontalDragAvailability implements Setting.Availability { @Override public boolean isAvailable() { @@ -293,7 +313,12 @@ public final class MiniplayerPatch { */ public static int setMiniplayerDefaultSize(int original) { if (CURRENT_TYPE.isModern()) { - return MINIPLAYER_SIZE; + if (MINIPLAYER_SIZE == 0) { + setMiniPlayerSize(); + } + if (MINIPLAYER_SIZE != 0) { + return MINIPLAYER_SIZE; + } } return original; From 09c1d495eb2e1bb98a3326ed98a5629a4e1b517e Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 20:54:07 +0900 Subject: [PATCH 10/65] feat(YouTube - Navigation bar components): Remove settings `Disable translucent status bar`, `Disable light translucent bar` and `Disable dark translucent bar` --- .../extension/shared/utils/Utils.java | 10 ----- .../youtube/patches/general/GeneralPatch.java | 43 ------------------- .../extension/youtube/settings/Settings.java | 3 -- .../ReVancedSettingsPreference.java | 5 --- .../general/navigation/Fingerprints.kt | 30 ------------- .../NavigationBarComponentsPatch.kt | 32 -------------- .../youtube/settings/host/values/strings.xml | 9 ---- .../youtube/settings/xml/revanced_prefs.xml | 7 --- 8 files changed, 139 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java index d8e6a0afc..b0fbf2a62 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java @@ -462,16 +462,6 @@ public class Utils { return false; } - public static boolean isDarkModeEnabled() { - return isDarkModeEnabled(context); - } - - public static boolean isDarkModeEnabled(Context context) { - Configuration config = context.getResources().getConfiguration(); - final int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK; - return currentNightMode == Configuration.UI_MODE_NIGHT_YES; - } - /** * @return whether the device's API level is higher than a specific SDK version. */ diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java index 0893398fb..6dd7ceffe 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java @@ -5,7 +5,6 @@ import static app.revanced.extension.shared.utils.Utils.getChildView; import static app.revanced.extension.shared.utils.Utils.hideViewByLayoutParams; import static app.revanced.extension.shared.utils.Utils.hideViewGroupByMarginLayoutParams; import static app.revanced.extension.shared.utils.Utils.hideViewUnderCondition; -import static app.revanced.extension.shared.utils.Utils.isSDKAbove; import static app.revanced.extension.youtube.patches.utils.PatchStatus.ImageSearchButton; import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton; @@ -245,48 +244,6 @@ public class GeneralPatch { hideViewUnderCondition(Settings.HIDE_NAVIGATION_BAR.get(), view); } - public static boolean useTranslucentNavigationStatusBar(boolean original) { - try { - if (Settings.DISABLE_TRANSLUCENT_STATUS_BAR.get()) { - return false; - } - } catch (Exception ex) { - Logger.printException(() -> "Failed to load useTranslucentNavigationStatusBar", ex); - } - - return original; - } - - private static final Boolean DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT - = Settings.DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT.get(); - - private static final Boolean DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK - = Settings.DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK.get(); - - public static boolean useTranslucentNavigationButtons(boolean original) { - try { - // Feature requires Android 13+ - if (!isSDKAbove(33)) { - return original; - } - - if (!DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK && !DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT) { - return original; - } - - if (DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK && DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT) { - return false; - } - - return Utils.isDarkModeEnabled() - ? !DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK - : !DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT; - } catch (Exception ex) { - Logger.printException(() -> "Failed to load useTranslucentNavigationButtons", ex); - } - return original; - } - // endregion // region [Remove viewer discretion dialog] patch diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 9d593c8f5..223508b8a 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -147,7 +147,6 @@ public class Settings extends BaseSettings { new ChangeStartPagePatch.ChangeStartPageTypeAvailability()); public static final BooleanSetting DISABLE_AUTO_AUDIO_TRACKS = new BooleanSetting("revanced_disable_auto_audio_tracks", FALSE); public static final BooleanSetting DISABLE_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_splash_animation", FALSE, true); - public static final BooleanSetting DISABLE_TRANSLUCENT_STATUS_BAR = new BooleanSetting("revanced_disable_translucent_status_bar", FALSE, true); public static final BooleanSetting ENABLE_GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_enable_gradient_loading_screen", FALSE, true); public static final BooleanSetting HIDE_FLOATING_MICROPHONE = new BooleanSetting("revanced_hide_floating_microphone", TRUE, true); public static final BooleanSetting HIDE_GRAY_SEPARATOR = new BooleanSetting("revanced_hide_gray_separator", TRUE); @@ -190,8 +189,6 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_NAVIGATION_SUBSCRIPTIONS_BUTTON = new BooleanSetting("revanced_hide_navigation_subscriptions_button", FALSE, true); public static final BooleanSetting HIDE_NAVIGATION_LABEL = new BooleanSetting("revanced_hide_navigation_label", FALSE, true); public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true, "revanced_switch_create_with_notifications_button_user_dialog_message"); - public static final BooleanSetting DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT = new BooleanSetting("revanced_disable_translucent_navigation_bar_light", FALSE, true); - public static final BooleanSetting DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK = new BooleanSetting("revanced_disable_translucent_navigation_bar_dark", FALSE, true); public static final BooleanSetting HIDE_NAVIGATION_BAR = new BooleanSetting("revanced_hide_navigation_bar", FALSE, true); // PreferenceScreen: General - Override buttons diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java index d1dfbcdb4..02549cb77 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java @@ -203,11 +203,6 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment { Settings.REPLACE_TOOLBAR_CREATE_BUTTON, Settings.REPLACE_TOOLBAR_CREATE_BUTTON_TYPE ); - enableDisablePreferences( - !isSDKAbove(33), - Settings.DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT, - Settings.DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK - ); } /** diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/navigation/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/navigation/Fingerprints.kt index fd74a28bd..712ce9700 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/navigation/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/navigation/Fingerprints.kt @@ -73,33 +73,3 @@ internal val setEnumMapFingerprint = legacyFingerprint( name = "setEnumMapFingerprint", literals = listOf(ytFillBell), ) - -internal const val TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG = 45400535L - -internal val translucentNavigationStatusBarFeatureFlagFingerprint = legacyFingerprint( - name = "translucentNavigationStatusBarFeatureFlagFingerprint", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "Z", - literals = listOf(TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG) -) - -internal const val TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG = 45630927L - -internal val translucentNavigationButtonsFeatureFlagFingerprint = legacyFingerprint( - name = "translucentNavigationButtonsFeatureFlagFingerprint", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "V", - literals = listOf(TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG) -) - -/** - * The device on screen back/home/recent buttons. - */ -internal const val TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG = 45632194L - -internal val translucentNavigationButtonsSystemFeatureFlagFingerprint = legacyFingerprint( - name = "translucentNavigationButtonsSystemFeatureFlagFingerprint", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "Z", - literals = listOf(TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG) -) \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/navigation/NavigationBarComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/navigation/NavigationBarComponentsPatch.kt index 8e8d38987..4b709b5d4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/navigation/NavigationBarComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/navigation/NavigationBarComponentsPatch.kt @@ -82,38 +82,6 @@ val navigationBarComponentsPatch = bytecodePatch( "SETTINGS: HIDE_NAVIGATION_COMPONENTS" ) - // region patch for enable translucent navigation bar - - if (is_19_25_or_greater) { - arrayOf( - Triple( - translucentNavigationStatusBarFeatureFlagFingerprint, - TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG, - "useTranslucentNavigationStatusBar" - ), - Triple( - translucentNavigationButtonsFeatureFlagFingerprint, - TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG, - "useTranslucentNavigationButtons" - ), - Triple( - translucentNavigationButtonsSystemFeatureFlagFingerprint, - TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG, - "useTranslucentNavigationButtons" - ) - ).forEach { - it.first.injectLiteralInstructionBooleanCall( - it.second, - "$GENERAL_CLASS_DESCRIPTOR->${it.third}(Z)Z" - ) - } - - settingArray += "SETTINGS: DISABLE_TRANSLUCENT_STATUS_BAR" - settingArray += "SETTINGS: TRANSLUCENT_NAVIGATION_BAR" - } - - // endregion - // region patch for enable narrow navigation buttons arrayOf( diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index f8b1eed0e..e1472e106 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -352,9 +352,6 @@ Limitation: Back button on the toolbar may not work." Disable splash animation Splash animation is disabled. Splash animation is enabled. - Disable translucent status bar - Status bar is opaque. - Status bar is opaque or translucent. Enable gradient loading screen Gradient loading screen is enabled. Gradient loading screen is disabled. @@ -543,12 +540,6 @@ Also, ads will no longer be blocked in Shorts. If this setting do not take effect, try switching to Incognito mode." - Disable light translucent bar - Light mode navigation bar is opaque. - Light mode navigation bar is opaque or translucent. - Disable dark translucent bar - Dark mode navigation bar is opaque. - Dark mode navigation bar is opaque or translucent. Hide navigation bar Navigation bar is hidden. Navigation bar is shown. diff --git a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml index dbe7b8c0e..4ae2ad1ae 100644 --- a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -213,10 +213,6 @@ SETTINGS: HIDE_NAVIGATION_COMPONENTS --> - - @@ -282,9 +278,6 @@ - - From 5d79826f4eabf7a276b3fa09897f23d618848458 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 20:55:33 +0900 Subject: [PATCH 11/65] fix(YouTube Music - Spoof streaming data): Last selected value is not remembered in ListPreference Dialog --- .../music/settings/preference/ResettableListPreference.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ResettableListPreference.java b/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ResettableListPreference.java index b01f5bf2d..f0c68b46f 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ResettableListPreference.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ResettableListPreference.java @@ -8,7 +8,10 @@ import android.app.Activity; import androidx.annotation.NonNull; +import org.apache.commons.lang3.ArrayUtils; + import java.util.Arrays; +import java.util.Locale; import app.revanced.extension.shared.settings.EnumSetting; import app.revanced.extension.shared.settings.Setting; @@ -57,7 +60,7 @@ public class ResettableListPreference { final String[] mEntries = getStringArray(entryKey); final String[] mEntryValues = getStringArray(entryValueKey); - final int findIndex = Arrays.binarySearch(mEntryValues, setting.get().toString()); + final int findIndex = ArrayUtils.indexOf(mEntryValues, setting.get().toString().toUpperCase(Locale.ENGLISH)); mClickedDialogEntryIndex = findIndex >= 0 ? findIndex : defaultIndex; getDialogBuilder(mActivity) From 83f2d82d0a5b4c038424ebc87b2e0db088cc2351 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 21:06:47 +0900 Subject: [PATCH 12/65] feat(YouTube - Spoof streaming data): Remove `Use Android clients only` setting, restore `Force iOS AVC` setting --- .../extension/shared/patches/PatchStatus.java | 4 +- .../shared/patches/client/AppClient.java | 114 +++++++++--------- .../spoof/requests/StreamingDataRequest.java | 8 +- .../shared/settings/BaseSettings.java | 7 +- ...eamingDataDefaultClientListPreference.java | 87 ------------- ...oofStreamingDataSideEffectsPreference.java | 8 +- .../streamingdata/SpoofStreamingDataPatch.kt | 10 ++ .../streamingdata/SpoofStreamingDataPatch.kt | 10 -- .../youtube/settings/host/values/strings.xml | 12 +- .../youtube/settings/xml/revanced_prefs.xml | 4 +- 10 files changed, 90 insertions(+), 174 deletions(-) delete mode 100644 extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataDefaultClientListPreference.java diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java index f5bcef97f..468528831 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java @@ -11,8 +11,8 @@ public class PatchStatus { return false; } - public static boolean SpoofStreamingDataAndroidOnlyDefaultBoolean() { - // Replace this with true If the Spoof streaming data patch succeeds in YouTube + public static boolean SpoofStreamingDataMusic() { + // Replace this with true If the Spoof streaming data patch succeeds in YouTube Music return false; } } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java index 67eee0854..d8dc963e0 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java @@ -1,6 +1,6 @@ package app.revanced.extension.shared.patches.client; -import static app.revanced.extension.shared.utils.ResourceUtils.getString; +import static app.revanced.extension.shared.patches.PatchStatus.SpoofStreamingDataMusic; import android.os.Build; @@ -24,7 +24,9 @@ public class AppClient { * Store page of the YouTube app, in the {@code What’s New} section. *

*/ - private static final String CLIENT_VERSION_IOS = "19.29.1"; + private static final String CLIENT_VERSION_IOS = forceAVC() + ? "17.40.5" + : "19.29.1"; /** * The device machine id for the iPhone 15 Pro Max (iPhone16,2), used to get HDR with AV1 hardware decoding. * @@ -33,9 +35,15 @@ public class AppClient { * information. *

*/ - private static final String DEVICE_MODEL_IOS = "iPhone16,2"; - private static final String OS_VERSION_IOS = "17.7.2.21H221"; - private static final String USER_AGENT_VERSION_IOS = "17_7_2"; + private static final String DEVICE_MODEL_IOS = forceAVC() + ? "iPhone12,5" // 11 Pro Max. (last device with iOS 13) + : "iPhone16,2"; // 15 Pro Max. + private static final String OS_VERSION_IOS = forceAVC() + ? "13.7.17H35" // Last release of iOS 13. + : "17.7.2.21H221"; + private static final String USER_AGENT_VERSION_IOS = forceAVC() + ? "13_7" + : "17_7_2"; private static final String USER_AGENT_IOS = iOSUserAgent(PACKAGE_NAME_IOS, CLIENT_VERSION_IOS); @@ -55,7 +63,9 @@ public class AppClient { * Store page of the YouTube TV app, in the {@code What’s New} section. *

*/ - private static final String CLIENT_VERSION_IOS_UNPLUGGED = "8.33"; + private static final String CLIENT_VERSION_IOS_UNPLUGGED = forceAVC() + ? "6.45" + : "8.33"; private static final String USER_AGENT_IOS_UNPLUGGED = iOSUserAgent(PACKAGE_NAME_IOS_UNPLUGGED, CLIENT_VERSION_IOS_UNPLUGGED); @@ -140,20 +150,6 @@ public class AppClient { androidUserAgent(PACKAGE_NAME_ANDROID_UNPLUGGED, CLIENT_VERSION_ANDROID_UNPLUGGED, OS_VERSION_ANDROID_UNPLUGGED); - // ANDROID CREATOR - /** - * Video not playable: Livestream - * Note: Audio track is not available - */ - private static final String PACKAGE_NAME_ANDROID_CREATOR = "com.google.android.apps.youtube.creator"; - private static final String CLIENT_VERSION_ANDROID_CREATOR = "24.14.101"; - private static final String DEVICE_MODEL_ANDROID_CREATOR = Build.MODEL; - private static final String OS_VERSION_ANDROID_CREATOR = Build.VERSION.RELEASE; - private static final String ANDROID_SDK_VERSION_ANDROID_CREATOR = String.valueOf(Build.VERSION.SDK_INT); - private static final String USER_AGENT_ANDROID_CREATOR = - androidUserAgent(PACKAGE_NAME_ANDROID_CREATOR, CLIENT_VERSION_ANDROID_CREATOR, OS_VERSION_ANDROID_CREATOR); - - private AppClient() { } @@ -178,21 +174,14 @@ public class AppClient { } public enum ClientType { - IOS(5, - DEVICE_MODEL_IOS, - OS_VERSION_IOS, - USER_AGENT_IOS, - null, - CLIENT_VERSION_IOS, - false - ), ANDROID_VR(28, DEVICE_MODEL_ANDROID_VR, OS_VERSION_ANDROID_VR, USER_AGENT_ANDROID_VR, ANDROID_SDK_VERSION_ANDROID_VR, CLIENT_VERSION_ANDROID_VR, - true + true, + "Android VR" ), ANDROID_UNPLUGGED(29, DEVICE_MODEL_ANDROID_UNPLUGGED, @@ -200,15 +189,8 @@ public class AppClient { USER_AGENT_ANDROID_UNPLUGGED, ANDROID_SDK_VERSION_ANDROID_UNPLUGGED, CLIENT_VERSION_ANDROID_UNPLUGGED, - true - ), - ANDROID_CREATOR(14, - DEVICE_MODEL_ANDROID_CREATOR, - OS_VERSION_ANDROID_CREATOR, - USER_AGENT_ANDROID_CREATOR, - ANDROID_SDK_VERSION_ANDROID_CREATOR, - CLIENT_VERSION_ANDROID_CREATOR, - true + true, + "Android TV" ), IOS_UNPLUGGED(33, DEVICE_MODEL_IOS, @@ -216,7 +198,21 @@ public class AppClient { USER_AGENT_IOS_UNPLUGGED, null, CLIENT_VERSION_IOS_UNPLUGGED, - true + true, + forceAVC() + ? "iOS TV Force AVC" + : "iOS TV" + ), + IOS(5, + DEVICE_MODEL_IOS, + OS_VERSION_IOS, + USER_AGENT_IOS, + null, + CLIENT_VERSION_IOS, + false, + forceAVC() + ? "iOS Force AVC" + : "iOS" ), IOS_MUSIC( 26, @@ -225,7 +221,8 @@ public class AppClient { USER_AGENT_IOS_MUSIC, null, CLIENT_VERSION_IOS_MUSIC, - true + true, + "iOS Music" ); /** @@ -268,13 +265,19 @@ public class AppClient { */ public final boolean canLogin; + /** + * Friendly name displayed in stats for nerds. + */ + public final String friendlyName; + ClientType(int id, String deviceModel, String osVersion, String userAgent, @Nullable String androidSdkVersion, String clientVersion, - boolean canLogin + boolean canLogin, + String friendlyName ) { this.id = id; this.clientName = name(); @@ -284,30 +287,29 @@ public class AppClient { this.androidSdkVersion = androidSdkVersion; this.userAgent = userAgent; this.canLogin = canLogin; + this.friendlyName = friendlyName; } - private static final ClientType[] CLIENT_ORDER_TO_USE_ANDROID = { - ANDROID_VR, - ANDROID_UNPLUGGED, - ANDROID_CREATOR, - }; - - private static final ClientType[] CLIENT_ORDER_TO_USE_DEFAULT = { - IOS, + private static final ClientType[] CLIENT_ORDER_TO_USE_YOUTUBE = { ANDROID_VR, ANDROID_UNPLUGGED, IOS_UNPLUGGED, - IOS_MUSIC, + IOS, }; - public final String getFriendlyName() { - return getString("revanced_spoof_streaming_data_type_entry_" + name().toLowerCase()); - } + private static final ClientType[] CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC = { + ANDROID_VR, + IOS_MUSIC, + }; + } + + private static boolean forceAVC() { + return BaseSettings.SPOOF_STREAMING_DATA_IOS_FORCE_AVC.get(); } public static ClientType[] getAvailableClientTypes() { - return BaseSettings.SPOOF_STREAMING_DATA_ANDROID_ONLY.get() - ? ClientType.CLIENT_ORDER_TO_USE_ANDROID - : ClientType.CLIENT_ORDER_TO_USE_DEFAULT; + return SpoofStreamingDataMusic() + ? ClientType.CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC + : ClientType.CLIENT_ORDER_TO_USE_YOUTUBE; } } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java index a76c8a2df..fc9cf3bc8 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java @@ -6,6 +6,9 @@ import static app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes. import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.apache.commons.lang3.ArrayUtils; +import org.json.JSONObject; + import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -14,7 +17,6 @@ import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -78,14 +80,14 @@ public class StreamingDataRequest { public static String getLastSpoofedClientName() { return lastSpoofedClientType == null ? "Unknown" - : lastSpoofedClientType.getFriendlyName(); + : lastSpoofedClientType.friendlyName; } static { ClientType[] allClientTypes = getAvailableClientTypes(); ClientType preferredClient = BaseSettings.SPOOF_STREAMING_DATA_TYPE.get(); - if (Arrays.stream(allClientTypes).noneMatch(preferredClient::equals)) { + if (ArrayUtils.indexOf(allClientTypes, preferredClient) < 0) { CLIENT_ORDER_TO_USE = allClientTypes; } else { CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length]; diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java b/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java index 973550208..0e0c9dd39 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java @@ -3,7 +3,6 @@ package app.revanced.extension.shared.settings; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static app.revanced.extension.shared.patches.PatchStatus.HideFullscreenAdsDefaultBoolean; -import static app.revanced.extension.shared.patches.PatchStatus.SpoofStreamingDataAndroidOnlyDefaultBoolean; import app.revanced.extension.shared.patches.ReturnYouTubeUsernamePatch.DisplayFormat; import app.revanced.extension.shared.patches.client.AppClient.ClientType; @@ -37,9 +36,11 @@ public class BaseSettings { public static final StringSetting RETURN_YOUTUBE_USERNAME_YOUTUBE_DATA_API_V3_DEVELOPER_KEY = new StringSetting("revanced_return_youtube_username_youtube_data_api_v3_developer_key", "", true, false); public static final BooleanSetting SPOOF_STREAMING_DATA = new BooleanSetting("revanced_spoof_streaming_data", TRUE, true, "revanced_spoof_streaming_data_user_dialog_message"); - public static final EnumSetting SPOOF_STREAMING_DATA_TYPE = new EnumSetting<>("revanced_spoof_streaming_data_type", ClientType.ANDROID_VR, true); - public static final BooleanSetting SPOOF_STREAMING_DATA_ANDROID_ONLY = new BooleanSetting("revanced_spoof_streaming_data_android_only", SpoofStreamingDataAndroidOnlyDefaultBoolean(), true, "revanced_spoof_streaming_data_android_only_user_dialog_message"); + public static final BooleanSetting SPOOF_STREAMING_DATA_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_streaming_data_ios_force_avc", FALSE, true, + "revanced_spoof_streaming_data_ios_force_avc_user_dialog_message"); public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE); + // Client type must be last spoof setting due to cyclic references. + public static final EnumSetting SPOOF_STREAMING_DATA_TYPE = new EnumSetting<>("revanced_spoof_streaming_data_type", ClientType.ANDROID_VR, true); /** * @noinspection DeprecatedIsStillUsed diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataDefaultClientListPreference.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataDefaultClientListPreference.java deleted file mode 100644 index b3fabe111..000000000 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataDefaultClientListPreference.java +++ /dev/null @@ -1,87 +0,0 @@ -package app.revanced.extension.youtube.settings.preference; - -import static app.revanced.extension.shared.utils.ResourceUtils.getStringArray; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.ListPreference; -import android.preference.PreferenceManager; -import android.util.AttributeSet; - -import app.revanced.extension.shared.patches.client.AppClient.ClientType; -import app.revanced.extension.shared.settings.EnumSetting; -import app.revanced.extension.shared.settings.Setting; -import app.revanced.extension.shared.utils.Utils; -import app.revanced.extension.youtube.settings.Settings; - -@SuppressWarnings({"unused", "deprecation"}) -public class SpoofStreamingDataDefaultClientListPreference extends ListPreference { - - private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> { - // Because this listener may run before the ReVanced settings fragment updates Settings, - // this could show the prior config and not the current. - // - // Push this call to the end of the main run queue, - // so all other listeners are done and Settings is up to date. - Utils.runOnMainThread(this::updateUI); - }; - - public SpoofStreamingDataDefaultClientListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - public SpoofStreamingDataDefaultClientListPreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public SpoofStreamingDataDefaultClientListPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public SpoofStreamingDataDefaultClientListPreference(Context context) { - super(context); - } - - private void addChangeListener() { - Setting.preferences.preferences.registerOnSharedPreferenceChangeListener(listener); - } - - private void removeChangeListener() { - Setting.preferences.preferences.unregisterOnSharedPreferenceChangeListener(listener); - } - - @Override - protected void onAttachedToHierarchy(PreferenceManager preferenceManager) { - super.onAttachedToHierarchy(preferenceManager); - updateUI(); - addChangeListener(); - } - - @Override - protected void onPrepareForRemoval() { - super.onPrepareForRemoval(); - removeChangeListener(); - } - - private void updateUI() { - final boolean spoofStreamingDataAndroidOnly = Settings.SPOOF_STREAMING_DATA_ANDROID_ONLY.get(); - final String entryKey = spoofStreamingDataAndroidOnly - ? "revanced_spoof_streaming_data_type_android_entries" - : "revanced_spoof_streaming_data_type_android_ios_entries"; - final String entryValueKey = spoofStreamingDataAndroidOnly - ? "revanced_spoof_streaming_data_type_android_entry_values" - : "revanced_spoof_streaming_data_type_android_ios_entry_values"; - final String[] mEntries = getStringArray(entryKey); - final String[] mEntryValues = getStringArray(entryValueKey); - setEntries(mEntries); - setEntryValues(mEntryValues); - - final EnumSetting clientType = Settings.SPOOF_STREAMING_DATA_TYPE; - final boolean isAndroid = clientType.get().name().startsWith("ANDROID"); - if (spoofStreamingDataAndroidOnly && !isAndroid) { - clientType.resetToDefault(); - } - - setEnabled(Settings.SPOOF_STREAMING_DATA.get()); - } -} diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java index f8e062270..99958d018 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java @@ -63,13 +63,7 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference { private void updateUI() { final String clientName = Settings.SPOOF_STREAMING_DATA_TYPE.get().name().toLowerCase(); - String summaryTextKey = "revanced_spoof_streaming_data_side_effects_"; - - if (Settings.SPOOF_STREAMING_DATA_ANDROID_ONLY.get()) { - summaryTextKey += "android"; - } else { - summaryTextKey += clientName; - } + final String summaryTextKey = "revanced_spoof_streaming_data_side_effects_" + clientName; setSummary(str(summaryTextKey)); setEnabled(Settings.SPOOF_STREAMING_DATA.get()); diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatch.kt index a37eeeeb8..7bab56e59 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.music.utils.fix.streamingdata +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.music.utils.compatibility.Constants.YOUTUBE_MUSIC_PACKAGE_NAME import app.revanced.patches.music.utils.patch.PatchList.SPOOF_STREAMING_DATA @@ -8,8 +9,10 @@ import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus import app.revanced.patches.music.utils.settings.addPreferenceWithIntent import app.revanced.patches.music.utils.settings.addSwitchPreference import app.revanced.patches.music.utils.settings.settingsPatch +import app.revanced.patches.shared.extension.Constants.PATCHES_PATH import app.revanced.patches.shared.spoof.streamingdata.baseSpoofStreamingDataPatch import app.revanced.patches.shared.spoof.useragent.baseSpoofUserAgentPatch +import app.revanced.util.findMethodOrThrow @Suppress("unused") val spoofStreamingDataPatch = baseSpoofStreamingDataPatch( @@ -22,6 +25,13 @@ val spoofStreamingDataPatch = baseSpoofStreamingDataPatch( ) }, { + findMethodOrThrow("$PATCHES_PATH/PatchStatus;") { + name == "SpoofStreamingDataMusic" + }.replaceInstruction( + 0, + "const/4 v0, 0x1" + ) + addSwitchPreference( CategoryType.MISC, "revanced_spoof_streaming_data", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/streamingdata/SpoofStreamingDataPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/streamingdata/SpoofStreamingDataPatch.kt index c82bbb612..a2ba66890 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/streamingdata/SpoofStreamingDataPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/streamingdata/SpoofStreamingDataPatch.kt @@ -1,7 +1,5 @@ package app.revanced.patches.youtube.utils.fix.streamingdata -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction -import app.revanced.patches.shared.extension.Constants.PATCHES_PATH import app.revanced.patches.shared.spoof.streamingdata.baseSpoofStreamingDataPatch import app.revanced.patches.shared.spoof.useragent.baseSpoofUserAgentPatch import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE @@ -9,7 +7,6 @@ import app.revanced.patches.youtube.utils.compatibility.Constants.YOUTUBE_PACKAG import app.revanced.patches.youtube.utils.patch.PatchList.SPOOF_STREAMING_DATA import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch -import app.revanced.util.findMethodOrThrow val spoofStreamingDataPatch = baseSpoofStreamingDataPatch( { @@ -21,13 +18,6 @@ val spoofStreamingDataPatch = baseSpoofStreamingDataPatch( ) }, { - findMethodOrThrow("$PATCHES_PATH/PatchStatus;") { - name == "SpoofStreamingDataAndroidOnlyDefaultBoolean" - }.replaceInstruction( - 0, - "const/4 v0, 0x1" - ) - addPreference( arrayOf( "SETTINGS: SPOOF_STREAMING_DATA" diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index e1472e106..21e7dfcf6 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -1918,10 +1918,14 @@ Tap the continue button and allow optimization changes." "• Audio track menu is missing. • Stable volume is not available. • Disable forced auto audio tracks is not available." - Use Android clients only - Android clients are used to fetch streaming data. - Android and iOS clients are used to fetch streaming data. - Turning off this setting may cause video playback issues. + • There may be playback issues (Deprecated). + • Movies or paid videos may not play. + Force iOS AVC (H.264) + Video codec is forced to AVC (H.264). + Video codec is determined automatically. + "Enabling this might improve battery life and fix playback stuttering. + +AVC has a maximum resolution of 1080p, Opus audio codec is not available, and video playback will use more internet data than VP9 or AV1." Show in Stats for nerds Client used to fetch streaming data is shown in Stats for nerds. Client used to fetch streaming data is hidden in Stats for nerds. diff --git a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml index 4ae2ad1ae..396af8202 100644 --- a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -784,9 +784,9 @@ From 00fbd318e772863c2d6b8e806d07764627f62450 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 21:17:51 +0900 Subject: [PATCH 13/65] feat(YouTube - Spoof streaming data): Add setting to change `PoToken / Visitor Data` https://github.com/inotia00/ReVanced_Extended/issues/2630#issuecomment-2566310025 --- .../shared/patches/client/AppClient.java | 12 +++++ .../spoof/SpoofStreamingDataPatch.java | 26 ++++++++++- .../patches/spoof/requests/PlayerRoutes.java | 11 +---- .../spoof/requests/StreamingDataRequest.java | 44 ++++++++++++++----- .../shared/settings/BaseSettings.java | 3 ++ .../video/requests/PlaylistRequest.java | 5 ++- .../BaseSpoofStreamingDataPatch.kt | 19 ++++++++ .../spoof/streamingdata/Fingerprints.kt | 15 +++++++ .../youtube/settings/host/values/strings.xml | 13 ++++++ .../youtube/settings/xml/revanced_prefs.xml | 6 +++ 10 files changed, 132 insertions(+), 22 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java index d8dc963e0..c67094f29 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java @@ -181,6 +181,7 @@ public class AppClient { ANDROID_SDK_VERSION_ANDROID_VR, CLIENT_VERSION_ANDROID_VR, true, + false, "Android VR" ), ANDROID_UNPLUGGED(29, @@ -190,6 +191,7 @@ public class AppClient { ANDROID_SDK_VERSION_ANDROID_UNPLUGGED, CLIENT_VERSION_ANDROID_UNPLUGGED, true, + false, "Android TV" ), IOS_UNPLUGGED(33, @@ -199,6 +201,7 @@ public class AppClient { null, CLIENT_VERSION_IOS_UNPLUGGED, true, + false, forceAVC() ? "iOS TV Force AVC" : "iOS TV" @@ -210,6 +213,7 @@ public class AppClient { null, CLIENT_VERSION_IOS, false, + true, forceAVC() ? "iOS Force AVC" : "iOS" @@ -222,6 +226,7 @@ public class AppClient { null, CLIENT_VERSION_IOS_MUSIC, true, + false, "iOS Music" ); @@ -265,6 +270,11 @@ public class AppClient { */ public final boolean canLogin; + /** + * If a poToken should be used. + */ + public final boolean usePoToken; + /** * Friendly name displayed in stats for nerds. */ @@ -277,6 +287,7 @@ public class AppClient { @Nullable String androidSdkVersion, String clientVersion, boolean canLogin, + boolean usePoToken, String friendlyName ) { this.id = id; @@ -287,6 +298,7 @@ public class AppClient { this.androidSdkVersion = androidSdkVersion; this.userAgent = userAgent; this.canLogin = canLogin; + this.usePoToken = usePoToken; this.friendlyName = friendlyName; } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java index f1ca98e32..227f01435 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java @@ -4,7 +4,9 @@ import static app.revanced.extension.shared.patches.PatchStatus.SpoofStreamingDa import android.net.Uri; import android.text.TextUtils; +import android.util.Base64; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.nio.ByteBuffer; @@ -19,7 +21,11 @@ import app.revanced.extension.shared.utils.Utils; @SuppressWarnings("unused") public class SpoofStreamingDataPatch { - public static final boolean SPOOF_STREAMING_DATA = SpoofStreamingData() && BaseSettings.SPOOF_STREAMING_DATA.get(); + private static final boolean SPOOF_STREAMING_DATA = SpoofStreamingData() && BaseSettings.SPOOF_STREAMING_DATA.get(); + private static final String PO_TOKEN = + BaseSettings.SPOOF_STREAMING_DATA_PO_TOKEN.get(); + private static final String VISITOR_DATA = + BaseSettings.SPOOF_STREAMING_DATA_VISITOR_DATA.get(); /** * Any unreachable ip address. Used to intentionally fail requests. @@ -27,6 +33,9 @@ public class SpoofStreamingDataPatch { private static final String UNREACHABLE_HOST_URI_STRING = "https://127.0.0.0"; private static final Uri UNREACHABLE_HOST_URI = Uri.parse(UNREACHABLE_HOST_URI_STRING); + @NonNull + private static volatile String droidGuardPoToken = ""; + /** * Key: video id * Value: original video length [streamingData.formats.approxDurationMs] @@ -128,7 +137,7 @@ public class SpoofStreamingDataPatch { return; } - StreamingDataRequest.fetchRequest(id, requestHeaders); + StreamingDataRequest.fetchRequest(id, requestHeaders, VISITOR_DATA, PO_TOKEN, droidGuardPoToken); } } catch (Exception ex) { Logger.printException(() -> "buildRequest failure", ex); @@ -253,4 +262,17 @@ public class SpoofStreamingDataPatch { return videoFormat; } + + /** + * Injection point. + */ + public static void setDroidGuardPoToken(byte[] bytes) { + if (SPOOF_STREAMING_DATA && bytes.length > 20) { + final String poToken = Base64.encodeToString(bytes, Base64.URL_SAFE); + if (!droidGuardPoToken.equals(poToken)) { + Logger.printDebug(() -> "New droidGuardPoToken loaded:\n" + poToken); + droidGuardPoToken = poToken; + } + } + } } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java index 4eb16d20c..af2eb167c 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java @@ -37,11 +37,7 @@ public final class PlayerRoutes { private PlayerRoutes() { } - public static String createInnertubeBody(ClientType clientType) { - return createInnertubeBody(clientType, false); - } - - public static String createInnertubeBody(ClientType clientType, boolean playlistId) { + public static JSONObject createInnertubeBody(ClientType clientType) { JSONObject innerTubeBody = new JSONObject(); try { @@ -66,14 +62,11 @@ public final class PlayerRoutes { innerTubeBody.put("contentCheckOk", true); innerTubeBody.put("racyCheckOk", true); innerTubeBody.put("videoId", "%s"); - if (playlistId) { - innerTubeBody.put("playlistId", "%s"); - } } catch (JSONException e) { Logger.printException(() -> "Failed to create innerTubeBody", e); } - return innerTubeBody.toString(); + return innerTubeBody; } /** diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java index fc9cf3bc8..b4da8c61c 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java @@ -44,10 +44,11 @@ public class StreamingDataRequest { private static final ClientType[] CLIENT_ORDER_TO_USE; private static final String AUTHORIZATION_HEADER = "Authorization"; + private static final String VISITOR_ID_HEADER = "X-Goog-Visitor-Id"; private static final String[] REQUEST_HEADER_KEYS = { AUTHORIZATION_HEADER, // Available only to logged-in users. "X-GOOG-API-FORMAT-VERSION", - "X-Goog-Visitor-Id" + VISITOR_ID_HEADER }; private static ClientType lastSpoofedClientType; @@ -105,15 +106,17 @@ public class StreamingDataRequest { private final String videoId; private final Future future; - private StreamingDataRequest(String videoId, Map playerHeaders) { + private StreamingDataRequest(String videoId, Map playerHeaders, String visitorId, + String botGuardPoToken, String droidGuardPoToken) { Objects.requireNonNull(playerHeaders); this.videoId = videoId; - this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId, playerHeaders)); + this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId, playerHeaders, visitorId, botGuardPoToken, droidGuardPoToken)); } - public static void fetchRequest(String videoId, Map fetchHeaders) { + public static void fetchRequest(String videoId, Map fetchHeaders, String visitorId, + String botGuardPoToken, String droidGuardPoToken) { // Always fetch, even if there is an existing request for the same video. - cache.put(videoId, new StreamingDataRequest(videoId, fetchHeaders)); + cache.put(videoId, new StreamingDataRequest(videoId, fetchHeaders, visitorId, botGuardPoToken, droidGuardPoToken)); } @Nullable @@ -126,8 +129,8 @@ public class StreamingDataRequest { } @Nullable - private static HttpURLConnection send(ClientType clientType, String videoId, - Map playerHeaders) { + private static HttpURLConnection send(ClientType clientType, String videoId, Map playerHeaders, + String visitorId, String botGuardPoToken, String droidGuardPoToken) { Objects.requireNonNull(clientType); Objects.requireNonNull(videoId); Objects.requireNonNull(playerHeaders); @@ -149,12 +152,32 @@ public class StreamingDataRequest { continue; } } + if (key.equals(VISITOR_ID_HEADER) && + clientType.usePoToken && + !botGuardPoToken.isEmpty() && + !visitorId.isEmpty()) { + String originalVisitorId = value; + Logger.printDebug(() -> "Original visitor id:\n" + originalVisitorId); + Logger.printDebug(() -> "Replaced visitor id:\n" + visitorId); + value = visitorId; + } connection.setRequestProperty(key, value); } } - String innerTubeBody = String.format(PlayerRoutes.createInnertubeBody(clientType), videoId); + JSONObject innerTubeBodyJson = PlayerRoutes.createInnertubeBody(clientType); + if (clientType.usePoToken && !botGuardPoToken.isEmpty() && !visitorId.isEmpty()) { + JSONObject serviceIntegrityDimensions = new JSONObject(); + serviceIntegrityDimensions.put("poToken", botGuardPoToken); + innerTubeBodyJson.put("serviceIntegrityDimensions", serviceIntegrityDimensions); + if (!droidGuardPoToken.isEmpty()) { + Logger.printDebug(() -> "Original poToken (droidGuardPoToken):\n" + droidGuardPoToken); + } + Logger.printDebug(() -> "Replaced poToken (botGuardPoToken):\n" + botGuardPoToken); + } + + String innerTubeBody = String.format(innerTubeBodyJson.toString(), videoId); byte[] requestBody = innerTubeBody.getBytes(StandardCharsets.UTF_8); connection.setFixedLengthStreamingMode(requestBody.length); connection.getOutputStream().write(requestBody); @@ -180,12 +203,13 @@ public class StreamingDataRequest { return null; } - private static ByteBuffer fetch(String videoId, Map playerHeaders) { + private static ByteBuffer fetch(String videoId, Map playerHeaders, String visitorId, + String botGuardPoToken, String droidGuardPoToken) { lastSpoofedClientType = null; // Retry with different client if empty response body is received. for (ClientType clientType : CLIENT_ORDER_TO_USE) { - HttpURLConnection connection = send(clientType, videoId, playerHeaders); + HttpURLConnection connection = send(clientType, videoId, playerHeaders, visitorId, botGuardPoToken, droidGuardPoToken); if (connection != null) { try { // gzip encoding doesn't response with content length (-1), diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java b/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java index 0e0c9dd39..886852d2e 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java @@ -42,6 +42,9 @@ public class BaseSettings { // Client type must be last spoof setting due to cyclic references. public static final EnumSetting SPOOF_STREAMING_DATA_TYPE = new EnumSetting<>("revanced_spoof_streaming_data_type", ClientType.ANDROID_VR, true); + public static final StringSetting SPOOF_STREAMING_DATA_PO_TOKEN = new StringSetting("revanced_spoof_streaming_data_po_token", "", true); + public static final StringSetting SPOOF_STREAMING_DATA_VISITOR_DATA = new StringSetting("revanced_spoof_streaming_data_visitor_data", "", true); + /** * @noinspection DeprecatedIsStillUsed */ diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java index b7c69cd0a..db12d6d23 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java @@ -84,9 +84,12 @@ public class PlaylistRequest { try { HttpURLConnection connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(GET_PLAYLIST_PAGE, clientType); + JSONObject innerTubeBodyJson = PlayerRoutes.createInnertubeBody(clientType); + innerTubeBodyJson.put("playlistId", "%s"); + String innerTubeBody = String.format( Locale.ENGLISH, - PlayerRoutes.createInnertubeBody(clientType, true), + innerTubeBodyJson.toString(), videoId, "RD" + videoId ); diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt index 0ddda9abf..8c023ac2c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt @@ -21,6 +21,7 @@ import app.revanced.util.fingerprint.definingClassOrThrow import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.matchOrThrow import app.revanced.util.fingerprint.methodOrThrow +import app.revanced.util.fingerprint.mutableClassOrThrow import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow import com.android.tools.smali.dexlib2.AccessFlags @@ -362,6 +363,24 @@ fun baseSpoofStreamingDataPatch( // endregion + // region Set DroidGuard poToken. + + poTokenToStringFingerprint.mutableClassOrThrow().let { + val poTokenClass = it.fields.find { field -> + field.accessFlags == AccessFlags.PRIVATE.value && field.type.startsWith("L") + }!!.type + + findMethodOrThrow(poTokenClass) { + name == "" && + parameters == listOf("[B") + }.addInstruction( + 1, + "invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->setDroidGuardPoToken([B)V" + ) + } + + // endregion + findMethodOrThrow("$PATCHES_PATH/PatchStatus;") { name == "SpoofStreamingData" }.replaceInstruction( diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/Fingerprints.kt index 36ae9360b..c120b5d4e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/Fingerprints.kt @@ -197,3 +197,18 @@ internal val hlsCurrentTimeFingerprint = legacyFingerprint( parameters = listOf("Z", "L"), literals = listOf(HLS_CURRENT_TIME_FEATURE_FLAG), ) + +internal val poTokenToStringFingerprint = legacyFingerprint( + name = "poTokenToStringFingerprint", + returnType = "Ljava/lang/String;", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = emptyList(), + strings = listOf("UTF-8"), + customFingerprint = { method, classDef -> + method.name == "toString" && + classDef.fields.find { it.type == "[B" } != null && + // In YouTube, this field's type is 'Lcom/google/android/gms/potokens/PoToken;'. + // In YouTube Music, this class name is obfuscated. + classDef.fields.find { it.accessFlags == AccessFlags.PRIVATE.value && it.type.startsWith("L") } != null + }, +) diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index 21e7dfcf6..3aaf77a14 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -1930,6 +1930,19 @@ AVC has a maximum resolution of 1080p, Opus audio codec is not available, and vi Client used to fetch streaming data is shown in Stats for nerds. Client used to fetch streaming data is hidden in Stats for nerds. + + PoToken / VisitorData + PoToken to use + PoToken issued by BotGuard in a trusted browser. + VisitorData to use + VisitorData issued by BotGuard in a trusted browser. + About PoToken / VisitorData + "Some clients require PoToken and VisitorData to get a valid streaming data response. + +If you are trying to use iOS as the default client, you may need these values. + +Click to see more information." + Watch history Change settings related with watch history. diff --git a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml index 396af8202..15e79d88d 100644 --- a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -788,6 +788,12 @@ + + + + + + SETTINGS: SPOOF_STREAMING_DATA --> + + From 721f6043e9babef9e0cb983d624736d01d96851f Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 21:42:08 +0900 Subject: [PATCH 19/65] fix(YouTube - Custom branding icon): Restrict the version that can use the patch options `Change splash icons` to YouTube 19.16.39 (Close https://github.com/inotia00/ReVanced_Extended/issues/2605) --- .../branding/icon/CustomBrandingIconPatch.kt | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/CustomBrandingIconPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/CustomBrandingIconPatch.kt index ededd6ab4..797477de2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/CustomBrandingIconPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/CustomBrandingIconPatch.kt @@ -5,12 +5,14 @@ import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.stringOption import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.patch.PatchList.CUSTOM_BRANDING_ICON_FOR_YOUTUBE +import app.revanced.patches.youtube.utils.playservice.is_19_17_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_32_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusIcon import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.util.ResourceGroup +import app.revanced.util.Utils.printWarn import app.revanced.util.Utils.trimIndentMultiline import app.revanced.util.copyAdaptiveIcon import app.revanced.util.copyFile @@ -122,7 +124,7 @@ val customBrandingIconPatch = resourcePatch( key = "changeSplashIcon", default = true, title = "Change splash icons", - description = "Apply the custom branding icon to the splash screen.", + description = "Apply the custom branding icon to the splash screen. Supports from YouTube 18.29.38 to YouTube 19.16.39.", required = true ) @@ -171,29 +173,33 @@ val customBrandingIconPatch = resourcePatch( // Change splash icon. if (changeSplashIconOption == true) { - splashIconResourceGroups.let { resourceGroups -> - resourceGroups.forEach { - copyResources("$appIconResourcePath/splash", it) - } - } - - document("res/values/styles.xml").use { document -> - val resourcesNode = - document.getElementsByTagName("resources").item(0) as Element - val childNodes = resourcesNode.childNodes - - for (i in 0 until childNodes.length) { - val node = childNodes.item(i) as? Element ?: continue - val nodeAttributeName = node.getAttribute("name") - if (nodeAttributeName.startsWith("Theme.YouTube.Launcher")) { - val style = document.createElement("style") - style.setAttribute("name", nodeAttributeName) - style.setAttribute("parent", "@style/Base.Theme.YouTube.Launcher") - - resourcesNode.removeChild(node) - resourcesNode.appendChild(style) + if (!is_19_17_or_greater) { + splashIconResourceGroups.let { resourceGroups -> + resourceGroups.forEach { + copyResources("$appIconResourcePath/splash", it) } } + + document("res/values/styles.xml").use { document -> + val resourcesNode = + document.getElementsByTagName("resources").item(0) as Element + val childNodes = resourcesNode.childNodes + + for (i in 0 until childNodes.length) { + val node = childNodes.item(i) as? Element ?: continue + val nodeAttributeName = node.getAttribute("name") + if (nodeAttributeName.startsWith("Theme.YouTube.Launcher")) { + val style = document.createElement("style") + style.setAttribute("name", nodeAttributeName) + style.setAttribute("parent", "@style/Base.Theme.YouTube.Launcher") + + resourcesNode.removeChild(node) + resourcesNode.appendChild(style) + } + } + } + } else { + printWarn("\"Change splash icons\" is not supported in this version. Use YouTube 19.16.39 or earlier.") } } From f6a5ffd3ba5d79d440161a2ac11fdf8eae517348 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 21:47:07 +0900 Subject: [PATCH 20/65] feat(YouTube - Seekbar components): If the `Custom braning icon` patch is included and the patch option `Restore old splash animation` is enabled, it will not change the Seekbar color from the original splash animation (Lottie animation) --- .../player/seekbar/SeekbarComponentsPatch.kt | 40 +++++++++++-------- .../kotlin/app/revanced/util/ResourceUtils.kt | 4 ++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt index 49c3fb886..ada482215 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt @@ -11,12 +11,14 @@ import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.shared.drawable.addDrawableColorHook import app.revanced.patches.shared.drawable.drawableColorHookPatch import app.revanced.patches.shared.mainactivity.onCreateMethod +import app.revanced.patches.youtube.layout.branding.icon.customBrandingIconPatch import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.extension.Constants.PATCH_STATUS_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_PATH import app.revanced.patches.youtube.utils.flyoutmenu.flyoutMenuHookPatch import app.revanced.patches.youtube.utils.mainactivity.mainActivityResolvePatch +import app.revanced.patches.youtube.utils.patch.PatchList.CUSTOM_BRANDING_ICON_FOR_YOUTUBE import app.revanced.patches.youtube.utils.patch.PatchList.SEEKBAR_COMPONENTS import app.revanced.patches.youtube.utils.playerButtonsResourcesFingerprint import app.revanced.patches.youtube.utils.playerButtonsVisibilityFingerprint @@ -43,6 +45,7 @@ import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.matchOrThrow import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.resolvable +import app.revanced.util.getBooleanOptionValue import app.revanced.util.getReference import app.revanced.util.getWalkerMethod import app.revanced.util.indexOfFirstInstructionOrThrow @@ -116,6 +119,9 @@ val seekbarComponentsPatch = bytecodePatch( execute { + val restoreOldSplashAnimationIncluded = CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included == true && + customBrandingIconPatch.getBooleanOptionValue("restoreOldSplashAnimationOption").value == true + var settingArray = arrayOf( "PREFERENCE_SCREEN: PLAYER", "SETTINGS: SEEKBAR_COMPONENTS" @@ -257,25 +263,27 @@ val seekbarComponentsPatch = bytecodePatch( "invoke-static/range { p4 .. p5 }, $EXTENSION_SEEKBAR_COLOR_CLASS_DESCRIPTOR->setLinearGradient([I[F)V" ) - // Don't use the lotte splash screen layout if using custom seekbar. - arrayOf( - launchScreenLayoutTypeFingerprint.methodOrThrow(), - onCreateMethod - ).forEach { method -> - method.apply { - val literalIndex = - indexOfFirstLiteralInstructionOrThrow(launchScreenLayoutTypeLotteFeatureFlag) - val resultIndex = - indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT) - val register = getInstruction(resultIndex).registerA + if (!restoreOldSplashAnimationIncluded) { + // Don't use the lotte splash screen layout if using custom seekbar. + arrayOf( + launchScreenLayoutTypeFingerprint.methodOrThrow(), + onCreateMethod + ).forEach { method -> + method.apply { + val literalIndex = + indexOfFirstLiteralInstructionOrThrow(launchScreenLayoutTypeLotteFeatureFlag) + val resultIndex = + indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT) + val register = getInstruction(resultIndex).registerA - addInstructions( - resultIndex + 1, - """ + addInstructions( + resultIndex + 1, + """ invoke-static { v$register }, $EXTENSION_SEEKBAR_COLOR_CLASS_DESCRIPTOR->useLotteLaunchSplashScreen(Z)Z move-result v$register """ - ) + ) + } } } @@ -317,7 +325,7 @@ val seekbarComponentsPatch = bytecodePatch( scaleNode.replaceChild(replacementNode, shapeNode) } - if (is_19_25_or_greater) { + if (is_19_25_or_greater && !restoreOldSplashAnimationIncluded) { // Add attribute and styles for splash screen custom color. // Using a style is the only way to selectively change just the seekbar fill color. // diff --git a/patches/src/main/kotlin/app/revanced/util/ResourceUtils.kt b/patches/src/main/kotlin/app/revanced/util/ResourceUtils.kt index 89be81890..9f172b065 100644 --- a/patches/src/main/kotlin/app/revanced/util/ResourceUtils.kt +++ b/patches/src/main/kotlin/app/revanced/util/ResourceUtils.kt @@ -20,6 +20,10 @@ private val classLoader = object {}.javaClass.classLoader fun Patch<*>.getStringOptionValue(key: String) = options[key] as Option +@Suppress("UNCHECKED_CAST") +fun Patch<*>.getBooleanOptionValue(key: String) = + options[key] as Option + fun Option.valueOrThrow() = value ?: throw PatchException("Invalid patch option: $title.") From b105fc1f62d2fdd50fce225818fc4eb06771c8e9 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 21:49:35 +0900 Subject: [PATCH 21/65] chore: Lint code --- .../java/app/revanced/extension/music/shared/PlayerType.kt | 2 +- .../java/app/revanced/extension/music/shared/VideoType.kt | 2 +- .../extension/shared/patches/BaseSettingsMenuPatch.java | 2 ++ .../extension/youtube/shared/PlayerControlsVisibility.kt | 2 +- .../patches/youtube/utils/settings/SettingsPatch.kt | 6 +++--- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/shared/PlayerType.kt b/extensions/shared/src/main/java/app/revanced/extension/music/shared/PlayerType.kt index 5ca6ba944..9a274a6cf 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/shared/PlayerType.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/music/shared/PlayerType.kt @@ -18,7 +18,7 @@ enum class PlayerType { companion object { - private val nameToPlayerType = values().associateBy { it.name } + private val nameToPlayerType = entries.associateBy { it.name } @JvmStatic fun setFromString(enumName: String) { diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/shared/VideoType.kt b/extensions/shared/src/main/java/app/revanced/extension/music/shared/VideoType.kt index 87711a27e..af78d1945 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/shared/VideoType.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/music/shared/VideoType.kt @@ -19,7 +19,7 @@ enum class VideoType { companion object { - private val nameToVideoType = values().associateBy { it.name } + private val nameToVideoType = entries.associateBy { it.name } @JvmStatic fun setFromString(enumName: String) { diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BaseSettingsMenuPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BaseSettingsMenuPatch.java index 4ce7e63a8..04da5c224 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BaseSettingsMenuPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BaseSettingsMenuPatch.java @@ -1,5 +1,6 @@ package app.revanced.extension.shared.patches; +import android.annotation.SuppressLint; import android.util.Log; import androidx.preference.PreferenceScreen; @@ -10,6 +11,7 @@ public class BaseSettingsMenuPatch { /** * Rest of the implementation added by patch. */ + @SuppressLint("LongLogTag") public static void removePreference(PreferenceScreen mPreferenceScreen, String key) { Log.d("Extended: SettingsMenuPatch", "key: " + key); } diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibility.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibility.kt index e9d5468d4..e5c8e6639 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibility.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibility.kt @@ -14,7 +14,7 @@ enum class PlayerControlsVisibility { companion object { - private val nameToPlayerControlsVisibility = values().associateBy { it.name } + private val nameToPlayerControlsVisibility = entries.associateBy { it.name } @JvmStatic fun setFromString(enumName: String) { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt index 13e59bb69..caa5ebb0c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt @@ -54,9 +54,9 @@ private val settingsBytecodePatch = bytecodePatch( addInstructions( index + 1, """ - invoke-static {v$register}, $EXTENSION_THEME_METHOD_DESCRIPTOR - return-object v$register - """ + invoke-static {v$register}, $EXTENSION_THEME_METHOD_DESCRIPTOR + return-object v$register + """ ) removeInstruction(index) } From 41aaeafbe9b7ec334de453f6b67eec1e6f4ea6b7 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 21:51:39 +0900 Subject: [PATCH 22/65] fix(GmsCore support): Do not show battery optimization error on Android Automotive devices (Google built-in) --- .../extension/shared/patches/GmsCoreSupport.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/GmsCoreSupport.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/GmsCoreSupport.java index 3b5004d3b..f0c5cd391 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/GmsCoreSupport.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/GmsCoreSupport.java @@ -120,7 +120,11 @@ public class GmsCoreSupport { } // Check if GmsCore is whitelisted from battery optimizations. - if (batteryOptimizationsEnabled(mActivity)) { + if (isAndroidAutomotive(mActivity)) { + // Ignore Android Automotive devices (Google built-in), + // as there is no way to disable battery optimizations. + Logger.printDebug(() -> "Device is Android Automotive"); + } else if (batteryOptimizationsEnabled(mActivity)) { Logger.printInfo(() -> "GmsCore is not whitelisted from battery optimizations"); showBatteryOptimizationDialog(mActivity, "gms_core_dialog_not_whitelisted_using_battery_optimizations_message", @@ -220,6 +224,10 @@ public class GmsCoreSupport { return packageName; } + private static boolean isAndroidAutomotive(Context context) { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + private static String getGmsCoreDownload() { final String vendorGroupId = getGmsCoreVendorGroupId(); return switch (vendorGroupId) { From 9e496b1da3d0012bebdd361a78f81be8c11f21ff Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 22:00:54 +0900 Subject: [PATCH 23/65] fix(YouTube - NavigationBarHook): Increase nav button latch timeout. --- .../youtube/shared/NavigationBar.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/NavigationBar.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/NavigationBar.java index 0f3c07105..3c65e1d0c 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/NavigationBar.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/NavigationBar.java @@ -25,20 +25,21 @@ public final class NavigationBar { * How long to wait for the set nav button latch to be released. Maximum wait time must * be as small as possible while still allowing enough time for the nav bar to update. *

- * YT calls it's back button handlers out of order, - * and litho starts filtering before the navigation bar is updated. + * YT calls it's back button handlers out of order, and litho starts filtering before the + * navigation bar is updated. Fixing this situation and not needlessly waiting requires + * somehow detecting if a back button key/gesture will not change the active tab. *

- * Fixing this situation and not needlessly waiting requires somehow - * detecting if a back button key-press will cause a tab change. + * On average the time between pressing the back button and the first litho event is + * about 10-20ms. Waiting up to 75-150ms should be enough time to handle normal use cases + * and not be noticeable, since YT typically takes 100-200ms (or more) to update the view. *

- * Typically after pressing the back button, the time between the first litho event and - * when the nav button is updated is about 10-20ms. Using 50-100ms here should be enough time - * and not noticeable, since YT typically takes 100-200ms (or more) to update the view anyways. + * This delay is only noticeable when the device back button/gesture will not + * change the current navigation tab, such as backing out of the watch history. *

* This issue can also be avoided on a patch by patch basis, by avoiding calls to * {@link NavigationButton#getSelectedNavigationButton()} unless absolutely necessary. */ - private static final long LATCH_AWAIT_TIMEOUT_MILLISECONDS = 75; + private static final long LATCH_AWAIT_TIMEOUT_MILLISECONDS = 120; /** * Used as a workaround to fix the issue of YT calling back button handlers out of order. @@ -84,7 +85,8 @@ public final class NavigationBar { // The latch is released from the main thread, and waiting from the main thread will always timeout. // This situation has only been observed when navigating out of a submenu and not changing tabs. // and for that use case the nav bar does not change so it's safe to return here. - Logger.printDebug(() -> "Cannot block main thread waiting for nav button. Using last known navbar button status."); + Logger.printDebug(() -> "Cannot block main thread waiting for nav button. " + + "Using last known navbar button status."); return; } @@ -102,7 +104,9 @@ public final class NavigationBar { Logger.printDebug(() -> "Latch wait timed out"); } catch (InterruptedException ex) { - Logger.printException(() -> "Latch wait interrupted failure", ex); // Will never happen. + // Calling YouTube thread was interrupted. + Logger.printException(() -> "Latch wait interrupted", ex); + Thread.currentThread().interrupt(); // Restore interrupt status flag. } } @@ -256,8 +260,8 @@ public final class NavigationBar { *

* All code calling this method should handle a null return value. *

- * Due to issues with how YT processes physical back button events, - * this patch uses workarounds that can cause this method to take up to 75ms + * Due to issues with how YT processes physical back button/gesture events, + * this patch uses workarounds that can cause this method to take up to 120ms * if the device back button was recently pressed. * * @return The active navigation tab. From 255675443a55e9ef673d730803255f3e280b31aa Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 22:03:56 +0900 Subject: [PATCH 24/65] feat(Translations): Update translation --- .../music/translations/el-rGR/strings.xml | 3 - .../music/translations/es-rES/strings.xml | 20 ++ .../music/translations/hu-rHU/strings.xml | 5 +- .../music/translations/ja-rJP/strings.xml | 2 - .../music/translations/ko-rKR/strings.xml | 3 - .../music/translations/pl-rPL/strings.xml | 3 - .../music/translations/pt-rBR/strings.xml | 10 +- .../music/translations/ru-rRU/strings.xml | 10 +- .../music/translations/uk-rUA/strings.xml | 15 +- .../music/translations/vi-rVN/strings.xml | 11 +- .../music/translations/zh-rTW/strings.xml | 8 + .../youtube/translations/ar/strings.xml | 78 +++---- .../youtube/translations/bg-rBG/strings.xml | 3 +- .../youtube/translations/de-rDE/strings.xml | 201 +++++++++++++++++- .../youtube/translations/el-rGR/strings.xml | 23 +- .../youtube/translations/es-rES/strings.xml | 23 +- .../youtube/translations/fr-rFR/strings.xml | 23 +- .../youtube/translations/hu-rHU/strings.xml | 88 ++++---- .../youtube/translations/it-rIT/strings.xml | 24 +-- .../youtube/translations/ja-rJP/strings.xml | 50 ++--- .../youtube/translations/ko-rKR/strings.xml | 70 +++--- .../youtube/translations/pl-rPL/strings.xml | 24 +-- .../youtube/translations/pt-rBR/strings.xml | 18 +- .../youtube/translations/ru-rRU/strings.xml | 23 +- .../youtube/translations/tr-rTR/strings.xml | 1 + .../youtube/translations/uk-rUA/strings.xml | 23 +- .../youtube/translations/vi-rVN/strings.xml | 99 ++++----- .../youtube/translations/zh-rCN/strings.xml | 3 +- .../youtube/translations/zh-rTW/strings.xml | 20 +- 29 files changed, 484 insertions(+), 400 deletions(-) diff --git a/patches/src/main/resources/music/translations/el-rGR/strings.xml b/patches/src/main/resources/music/translations/el-rGR/strings.xml index e332009ef..d45e07ea8 100644 --- a/patches/src/main/resources/music/translations/el-rGR/strings.xml +++ b/patches/src/main/resources/music/translations/el-rGR/strings.xml @@ -418,9 +418,6 @@ Καθορισμός ενός προεπιλεγμένου προγράμματος-πελάτη για την λήψη δεδομένων ροής. Εμφάνιση στο «Στατιστικά για σπασίκλες» Εμφάνιση του προγράμματος πελάτη που χρησιμοποιείται για τη λήψη δεδομένων ροής στο μενού «Στατιστικά για σπασίκλες». - iOS - iOS Music - Android TV Android VR Καθαρισμός συνδέσμων κοινοποίησης Αφαίρεση των παραμέτρων παρακολούθησης από τις διευθύνσεις URL κατά την κοινοποίηση συνδέσμων. diff --git a/patches/src/main/resources/music/translations/es-rES/strings.xml b/patches/src/main/resources/music/translations/es-rES/strings.xml index dbc4586da..9e86a18fa 100644 --- a/patches/src/main/resources/music/translations/es-rES/strings.xml +++ b/patches/src/main/resources/music/translations/es-rES/strings.xml @@ -89,6 +89,7 @@ Esta función aún está en desarrollo, por lo que puede ser inestable."Ocultar menú de ir a episodios Ocultar menú de ir al podcast Ocultar menú Ayuda & Comentarios + Ocultar el pin al menú de marcación rápida Ocultar menú de reproducción siguiente Ocultar menú de calidad Ocultar menú de eliminar de la biblioteca @@ -103,6 +104,7 @@ Esta función aún está en desarrollo, por lo que puede ser inestable."Ocultar menú de Iniciar radio Ocultar menú Estadísticas para Nerds Ocultar menú Suscribirse / Desuscribirse + Ocultar Desfijar del menú de marcación rápida Ocultar menú de vista de créditos de canción Continuar viendo Continúa el vídeo desde el tiempo actual cuando se cambia a YouTube. @@ -368,6 +370,8 @@ Toca para ver cómo crear una clave de API." Cambia la hoja de compartir en la app a la hoja de compartir del sistema. Desactiva la animación Cairo Deshabilita la animación de bienvenida \"Cairo\" cuando se inicia la aplicación. + Desactivar audio DRC + Deshabilita DRC (Dynamic Range Compression) aplicado al audio. Activar registro de depuración Imprime el registro de depuración. Incluir búfer en registro de depuración @@ -395,6 +399,22 @@ Limitaciones: • Código de audio OPUS puede no ser compatible. • La miniatura de la barra de Seekbar puede no estar presente. • El historial de la vista no funciona con una cuenta de marca." + Cliente por defecto + "Define un cliente predeterminado a falsear. + +※ Al usar el cliente Android, se recomienda usarlo con 'Versión de aplicación Spoof'." + Android Music 4.27.53 + Android Music 5.29.53 + iOS Music 6.21 + Falsificar datos de transmisión + "Falsificar los datos de streaming para evitar problemas de reproducción. + +※ Cuando se utiliza con 'Cliente de spoof', problemas de reproducción pueden producirse." + Cliente por defecto + Define un cliente por defecto que obtiene datos de streaming. + Mostrar en estadísticas para nerds + Muestra el cliente utilizado para obtener datos de streaming en Estadísticas para nerds. + Android VR Desinfectar enlaces compartidos Elimina los parámetros de consulta de seguimiento de las URL al compartir enlaces. Abrir ajustes predeterminados de la app diff --git a/patches/src/main/resources/music/translations/hu-rHU/strings.xml b/patches/src/main/resources/music/translations/hu-rHU/strings.xml index ccac0dbb1..350a0b658 100644 --- a/patches/src/main/resources/music/translations/hu-rHU/strings.xml +++ b/patches/src/main/resources/music/translations/hu-rHU/strings.xml @@ -275,7 +275,7 @@ Előfordulhat, hogy egyes funkciók nem működnek megfelelően a régi lejátsz A nem tetszések százalékos arányát jeleníti meg a nem tetszések száma helyett. Kompakt kedvelés gomb Elrejti a kedvelés gomb elválasztóját. - Mutassa a becsült kedveléseket + Becsült kedvelések megjelenítése Megjeleníti a becsült kedvelések számát a videóknál. Köszöntő megjelenítése, ha az API nem elérhető Megjelenik egy üzenet, ha a YouTube nem tetszések visszaállítása API nem érhető el. @@ -417,9 +417,6 @@ Nyomj a folytatás gombra, és engedélyezd az optimalizálási módosításokat Meghatároz egy alapértelmezett klienst, amely streaming adatokat hív le. Megjelenik a statisztikák kockáknakban Megmutatja a streaming adatok lekérdezésére használt klienst a Statisztikák kockáknakban. - iOS - iOS Music - Android TV Android VR Megosztási linkek tisztítása Linkek megosztásakor eltávolítja a nyomkövetési paramétereket az URL-ekből. diff --git a/patches/src/main/resources/music/translations/ja-rJP/strings.xml b/patches/src/main/resources/music/translations/ja-rJP/strings.xml index c1300fea2..5b125cea7 100644 --- a/patches/src/main/resources/music/translations/ja-rJP/strings.xml +++ b/patches/src/main/resources/music/translations/ja-rJP/strings.xml @@ -392,8 +392,6 @@ API キーの発行方法については、ここをタップしてください • OPUSオーディオコーデックはサポートされていない可能性があります。 • シークバーのサムネイルが表示されない場合があります。 • 再生履歴はブランドアカウントでは動作しません。" - iOS - Android TV Android VR 共有リンクのクリーンアップ リンクを共有する際に、URL からトラッキングクエリパラメーターを削除します。 diff --git a/patches/src/main/resources/music/translations/ko-rKR/strings.xml b/patches/src/main/resources/music/translations/ko-rKR/strings.xml index 0ff9670d8..dbf1a0db1 100644 --- a/patches/src/main/resources/music/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/music/translations/ko-rKR/strings.xml @@ -419,9 +419,6 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요." 스트리밍 데이터를 가져오는 데 사용되는 기본 클라이언트를 정의할 수 있습니다. 동영상 통계에서 표시 \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 동영상 통계에서 표시됩니다. - iOS - iOS Music - Android TV Android VR 추적 쿼리를 제거한 링크 공유 링크를 공유할 때, URL에서 추적 쿼리 매개변수를 제거합니다. diff --git a/patches/src/main/resources/music/translations/pl-rPL/strings.xml b/patches/src/main/resources/music/translations/pl-rPL/strings.xml index b8b202749..ac8358637 100644 --- a/patches/src/main/resources/music/translations/pl-rPL/strings.xml +++ b/patches/src/main/resources/music/translations/pl-rPL/strings.xml @@ -421,9 +421,6 @@ Stuknij przycisk kontynuacji i zezwól na zmiany w optymalizacji." Denifiuje domyślnego klienta, z którego będzie przechwytywany strumień danych. Informacja w statystykach dla nerdów Pokazuje używanego klienta do przechwytywania strumienia danych w statystykach dla nerdów. - iOS - iOS Music - Android TV Android VR Oczyść udostępniane linki Usuwa parametry śledzących zapytań z adresów URL podczas udostępniania linków. diff --git a/patches/src/main/resources/music/translations/pt-rBR/strings.xml b/patches/src/main/resources/music/translations/pt-rBR/strings.xml index acbc47703..8f5ab4cbb 100644 --- a/patches/src/main/resources/music/translations/pt-rBR/strings.xml +++ b/patches/src/main/resources/music/translations/pt-rBR/strings.xml @@ -406,7 +406,12 @@ Toque no botão continuar e permita as alterações de otimização." ※ Quando usado com 'Dados de streaming falsos', podem ocorrer problemas de reprodução." Cliente padrão - "Define um cliente padrão para falsificar." + "Define um cliente padrão para falsificar. + +※ Ao usar o cliente Android, é recomendável usá-lo com 'Falsificar versão do aplicativo'." + Android Music 4.27.53 + Android Music 5.29.53 + iOS Music 6.21 Dados de streaming falsos "Falsifique os dados de streaming para evitar problemas de reprodução. @@ -415,9 +420,6 @@ Toque no botão continuar e permita as alterações de otimização." Define um cliente padrão que busca dados de streaming. Exibir em Estatísticas para nerds Exibir o cliente usado para buscar dados de streaming em estatísticas para nerds. - iOS - iOS Music - Android TV Android VR Limpar links compartilhados Remove os parâmetros de consulta de rastreamento das URLs ao compartilhar os links. diff --git a/patches/src/main/resources/music/translations/ru-rRU/strings.xml b/patches/src/main/resources/music/translations/ru-rRU/strings.xml index 00dea8b8d..81522a725 100644 --- a/patches/src/main/resources/music/translations/ru-rRU/strings.xml +++ b/patches/src/main/resources/music/translations/ru-rRU/strings.xml @@ -403,6 +403,13 @@ • Кодек OPUS может не работать. • Превью во время перемотки может отсутствовать. • История просмотра не работает при использовании аккаунта компании." + Клиент по умолчанию + "Определяет клиент по умолчанию для подмены. + +※ При использовании клиента Android рекомендуется использовать его вместе с \"Подмена версии приложения\"." + Android Music 4.27.53 + Android Music 5.29.53 + iOS Music 6.21 Подделка потоковых данных "Подделать потоковые данные, чтобы предотвратить проблемы с воспроизведением. @@ -411,9 +418,6 @@ Определяет клиент по умолчанию, получающий потоковые данные. Показывать в \"Статистике для сисадминов\" Показывает клиент, используемый для получения потоковых данных в Статистике для сисадминов. - iOS - iOS Music - Android TV Android VR Подчищать ссылки Убирает параметры отслеживания запросов из адресов при отправке ссылки. diff --git a/patches/src/main/resources/music/translations/uk-rUA/strings.xml b/patches/src/main/resources/music/translations/uk-rUA/strings.xml index 08b50da88..8fc60cdba 100644 --- a/patches/src/main/resources/music/translations/uk-rUA/strings.xml +++ b/patches/src/main/resources/music/translations/uk-rUA/strings.xml @@ -404,12 +404,14 @@ Підміна клієнта "Підробити клієнт, щоб запобігти проблемам із відтворенням. -Обмеження: -• Аудіокодек OPUS може не підтримуватися. -• Мініатюри перемотки можуть бути відсутніми. -• Історія переглядів не працює з обліковим записом бренду. +※ Під час використання разом з \"Підробка потокових даних\" можуть виникнути проблеми з відтворенням." + Клієнт за замовчуванням + "Визначає клієнт за замовчуванням для підробки. -※ Під час використання разом з \"Підміною клієнта\" можуть виникнути проблеми з відтворенням." +※ Під час використання клієнта Android рекомендується використовувати його разом з \"Підробити версію програми\"." + Android Music 4.27.53 + Android Music 5.29.53 + iOS Music 6.21 Підробка потокових даних "Підробити потокові дані, щоб запобігти проблемам із відтворенням. @@ -418,9 +420,6 @@ Визначає клієнт за замовчуванням, який отримує потокові дані. Показувати у \"Статистиці для сисадмінів\" Показує клієнт, який використовується для отримання потокових даних у \"Статистиці для сисадмінів\". - iOS - iOS Music - Android TV Android VR Обробляти поширення посилань Видаляє параметри запиту відстеження з URL-адрес під час обміну посиланнями. diff --git a/patches/src/main/resources/music/translations/vi-rVN/strings.xml b/patches/src/main/resources/music/translations/vi-rVN/strings.xml index 9814f38c7..29e533a6a 100644 --- a/patches/src/main/resources/music/translations/vi-rVN/strings.xml +++ b/patches/src/main/resources/music/translations/vi-rVN/strings.xml @@ -35,7 +35,7 @@ Ẩn tên nút Ẩn tên nút trong thanh thao tác. Ghi đè nút tải xuống - "Nút tải xuống sẽ mở trình tải xuống bên ngoài của bạn. + "Khi thao tác với nút tải xuống sẽ mở trình tải xuống bên ngoài của bạn. • Chỉ ghi đè lên nút Tải xuống trong trình phát. • Không ghi đè lên nút Tải xuống trong Trình đơn tuỳ chọn hoặc trong thẻ Thư viện." @@ -386,7 +386,7 @@ Cụ thể: • Các phiên bản YouTube Music mới nhất sử dụng codec OPUS như mặc định. • Điều này chỉ áp dụng cho người dùng giả mạo với các phiên bản ứng dụng rất cũ." GmsCore - Chuyển hướng tới cài đặt GmsCore và kích hoạt Cloud Messaging để nhận thông báo đẩy. + Chuyển hướng tới cài đặt MicroG và kích hoạt Cloud Messaging để nhận thông báo đẩy. GmsCore chưa được cài đặt. Hãy cài đặt nó đi nào. Hành động cần thiết "Hiện GmsCore không có quyền chạy nền. @@ -409,8 +409,8 @@ Nhấn vào Tiếp tục và cho phép thay đổi lựa chọn tối ưu hoá p "Xác định ứng dụng khách mặc định để giả mạo. ※ Khi sử dụng ứng dụng khách Android, tính năng này nên được sử dụng đồng thời với \"Giả mạo phiên bản ứng dụng\"." - Music Android 4.27.53 - Music Android 5.29.53 + Android Music 4.27.53 + Android Music 5.29.53 Music iOS 6.21 Giả mạo luồng dữ liệu trực tuyến "Giả mạo luồng dữ liệu trực tuyến nhằm khắc phục sự cố phát. @@ -420,9 +420,6 @@ Nhấn vào Tiếp tục và cho phép thay đổi lựa chọn tối ưu hoá p Xác định một ứng dụng khách mặc định để nạp luồng dữ liệu trực tuyến. Hiển thị trong Thống kê chi tiết Hiển thị ứng dụng khách được sử dụng để nạp luồng dữ liệu trực tuyến trong Thống kê chi tiết. - iOS - Music iOS - Android TV Android VR Liên kết sạch khi chia sẻ Loại bỏ các tham số truy vấn theo dõi khỏi URL khi chia sẻ liên kết. diff --git a/patches/src/main/resources/music/translations/zh-rTW/strings.xml b/patches/src/main/resources/music/translations/zh-rTW/strings.xml index 6ea62fa6d..49eed3d20 100644 --- a/patches/src/main/resources/music/translations/zh-rTW/strings.xml +++ b/patches/src/main/resources/music/translations/zh-rTW/strings.xml @@ -2,6 +2,7 @@ ReVanced 擴充功能 + 重設為預設值。 重新啟動以套用更改後的介面 套用並重新啟動 @@ -59,6 +60,8 @@ 隱藏 Premium 升級彈出選單 隱藏 Premium 續訂橫幅 隱藏 Premium 續訂橫幅 + Hide promotion alert banner + 隱藏促銷提醒橫幅。 彈出式選單 啟用精簡選單 @@ -86,6 +89,7 @@ 隱藏前往插曲選項 隱藏前往播客選項 隱藏說明& 回報問題選項 + 隱藏在快速播放專區中置頂選單 隱藏播放下一個選項 隱藏畫質選項 隱藏從媒體庫中移除選項 @@ -100,6 +104,7 @@ 隱藏開啟電台選項 隱藏資訊統計選項 隱藏訂閱/取消訂閱選項 + 隱藏從快速播放取消置頂選單 隱藏查看歌曲製作人員選項 繼續觀看 在Youtube上觀看時,從上次時間繼續觀看 @@ -171,6 +176,7 @@ 選擇欲偽裝的應用程式版本 4.27.53 - 在加拿大地區停用電台模式 6.11.52 - 停用即時歌詞 + 7.16.53 - 還原舊的動作欄 導覽列 啟用黑色導覽列 @@ -304,6 +310,7 @@ 列出除錯記錄檔 啟用解碼器覆寫 "播放音樂時啟用 250/251 opus 解碼器。" + Android VR 清理分享連結 分享連結時從 URL 中刪除追蹤參數。 匯入/匯出設定 @@ -318,5 +325,6 @@ 匯入失敗: %s 設定已重設為預設值 已匯入設定: %d + 重置 設定已複製到剪貼簿 diff --git a/patches/src/main/resources/youtube/translations/ar/strings.xml b/patches/src/main/resources/youtube/translations/ar/strings.xml index 9ff0df85f..8c2760391 100644 --- a/patches/src/main/resources/youtube/translations/ar/strings.xml +++ b/patches/src/main/resources/youtube/translations/ar/strings.xml @@ -66,7 +66,7 @@ DeArrow & اللقطات الثابتة اللقطات الثابتة DeArrow - "يوفر DeArrow مُصغَّرات فيديو من مصادر جماعية لمقاطع فيديو YouTube. غالبًا ما تكون مُصغَّرات فيديو هذه ذات صلة أكثر من تلك التي يقدمها موقع YouTube. + "يوفر DeArrow مُصغَّرات فيديو من مصادر جماعية لفيديوهات YouTube. غالبًا ما تكون مُصغَّرات الفيديو هذه ذات صلة أكثر من تلك التي يقدمها موقع YouTube. في حالة التمكين، سيتم إرسال عناوين URL للفيديو إلى خادم API ولن يتم إرسال أي بيانات أخرى. إذا لم يكن الفيديو يحتوي على مُصغَّرات لـ DeArrow، فسيتم عرض اللقطات الأصلية أو الثابتة. @@ -109,7 +109,7 @@ إخفاء رف الشرائح تم إخفاء رف الشرائح. يتم عرض رف الشرائح. - إخفاء الشريحة القابلة للتوسع تحت مقاطع الفيديو + إخفاء الشريحة القابلة للتوسع تحت الفيديوهات تم إخفاء الرقائق القابلة للتوسيع. يتم عرض الرقائق القابلة للتوسيع. إخفاء الرفوف القابلة للتوسع @@ -133,9 +133,9 @@ إخفاء آخر المشاركات تم إخفاء أحدث المشاركات. يتم عرض أحدث المشاركات. - إخفاء زر أحدث مقاطع الفيديو - تم إخفاء زر أحدث مقاطع الفيديو. - يتم عرض زر أحدث مقاطع الفيديو. + إخفاء زر أحدث الفيديوهات + تم إخفاء زر أحدث الفيديوهات. + يتم عرض زر أحدث الفيديوهات. إخفاء قوائم تشغيل التشكيلة تم إخفاء قوائم تشغيل التشكيلة. يتم عرض قوائم تشغيل التشكيلة. @@ -159,13 +159,13 @@ يتم عرض رفوف التذاكر. شريط الفئة - إخفاء شريط الفئة أو عرضه في الموجز والبحث ومقاطع الفيديو ذات الصلة. + إخفاء شريط الفئة أو عرضه في الموجز والبحث والفيديوهات ذات الصلة. إخفاء في الموجز مخفي في الموجز. يُعرض في الموجز. - إخفاء في مقاطع الفيديو ذات الصلة - مخفي في مقاطع الفيديو ذات الصلة. - يُعرض في مقاطع الفيديو ذات الصلة. + إخفاء في الفيديوهات ذات الصلة + مخفي في الفيديوهات ذات الصلة. + يُعرض في الفيديوهات ذات الصلة. إخفاء في نتائج البحث مخفي في نتائج البحث. يُعرض في نتائج البحث. @@ -252,12 +252,12 @@ الفيديو الموصى به إخفاء الفيديوهات الموصى بها - "يخفي مقاطع الفيديو الموصى بها التالية: + "يخفي الفيديوهات الموصى بها التالية: -• مقاطع الفيديو التي تحمل علامة للأعضاء فقط. -• مقاطع فيديو تحتوي على عبارات مثل 'شاهد الأشخاص أيضًا' أسفلها." +• الفيديوهات التي تحمل علامة للأعضاء فقط. +• فيديوهات تحتوي على عبارات مثل 'شاهد الأشخاص أيضًا' أسفلها." إخفاء فيديو المشاهدات المنخفضة - إخفاء مقاطع الفيديو التي حصلت على أقل من 1000 مشاهدة من موجز الصفحة الرئيسية التي تم تحميلها من القنوات غير المشترك بها. + إخفاء الفيديوهات التي حصلت على أقل من 1000 مشاهدة من موجز الصفحة الرئيسية التي تم تحميلها من القنوات غير المشترك بها. تصفية عدد المشاهدات إخفاء فيديوهات الصفحة الرئيسية حسب عدد المشاهدات @@ -277,10 +277,9 @@ حدد قالب اللغة الخاص بك لعدد مرات المشاهدة الموضحة أسفل كل فيديو في واجهة المستخدم. كل مفتاح (حرف/كلمة في لغتك) -> قيمة (معنى المفتاح) يجب أن يكون على سطر جديد. المفاتيح تذهب قبل علامة \"->\". إذا قمت بتغيير التطبيق أو لغة النظام، فستحتاج إلى إعادة تعيين هذا الإعداد.\n\nأمثلة:\nEnglish: 10K views = K -> 1000, views -> views\nSpanish: 10 K vistas = K -> 1000, vistas -> views K -> 1 000\nM -> 1 000 000\nB -> 1 000 000 000\nمشاهد -> مشاهد حول تصفية عدد المشاهدات - "الصفحة الرئيسية / الاشتراكات / تتم تصفية نتائج البحث لإخفاء مقاطع الفيديو التي حصلت على عدد مشاهدات أقل أو أكبر من عدد محدد. + "الصفحة الرئيسية / الاشتراكات / تتم تصفية نتائج البحث لإخفاء الفيديوهات التي حصلت على عدد مشاهدات أقل أو أكبر من عدد محدد. القيود: - • لا يمكن إخفاء فيديوهات Shorts. • لا تتم تصفية الفيديوهات التي حصلت على 0 مشاهدة." إخفاء الفيديوهات ذات الصلة @@ -323,9 +322,6 @@ تعطيل تأثيرات الحركة تم تعطيل تأثيرات الحركة. تم تمكين تأثيرات الحركة. - تعطيل شريط الحالة الشفاف - شريط الحالة غير شفاف. - شريط الحالة معتم أو شفاف. تمكين شاشة التحميل المتدرجة تم تمكين شاشة التحميل المتدرجة الملونة. تم تعطيل شاشة التحميل المتدرجة الملونة. @@ -497,12 +493,6 @@ كما لن يتم حظر الإعلانات في فيديوهات Shorts بعد الآن. إذا لم يتم تفعيل هذا الإعداد، فحاول التبديل إلى وضع التصفح المتخفي." - تعطيل الشريط الشفاف الفاتح - شريط التنقل في الوضع الفاتح غير شفاف. - شريط التنقل في الوضع الفاتح معتم او شفاف. - تعطيل الشريط الشفاف الداكن - شريط التنقل في الوضع الداكن غير شفاف. - شريط التنقل في الوضع الداكن معتم او شفاف. إخفاء شريط التنقل تم إخفاء شريط التنقل. يتم عرض شريط التنقل. @@ -748,7 +738,7 @@ تم تمكين وضع الإضاءة السينمائية في ملء الشاشة. شريط القناة - إخفاء أو عرض مكونات شريط القناة تحت مقاطع الفيديو. + إخفاء أو عرض مكونات شريط القناة تحت الفيديوهات. إخفاء زر الانضمام تم إخفاء زر الانضمام. يتم عرض زر الانضمام. @@ -873,8 +863,8 @@ تم إخفاء زر إعادة تشغيل المحادثات المباشرة.\n\nيظهر في وضع ملء الشاشة عند إغلاق المحادثات المباشرة. يتم عرض زر إعادة تشغيل المحادثات المباشرة.\n\nيظهر في وضع ملء الشاشة عند إغلاق المحادثات المباشرة. إخفاء تراكب الفيديو ذي الصلة - تم إخفاء قسم المزيد من مقاطع الفيديو في حاوية الإجراءات السريعة وواجهة الفيديو ذي الصلة. - يتم عرض قسم المزيد من مقاطع الفيديو في حاوية الإجراءات السريعة وواجهة الفيديو ذي الصلة. + تم إخفاء قسم المزيد من الفيديوهات في حاوية الإجراءات السريعة وواجهة الفيديو ذي الصلة. + يتم عرض قسم المزيد من الفيديوهات في حاوية الإجراءات السريعة وواجهة الفيديو ذي الصلة. الإجراءات السريعة إخفاء حاوية الإجراءات السريعة @@ -918,7 +908,7 @@ لا يملأ تراكب عناصر التحكم الشاشة الكاملة. يملأ تراكب عناصر التحكم الشاشة الكاملة. فرض ملء الشاشة - "سيتم تحويل مقاطع الفيديو إلى وضع ملء الشاشة في المواقف التالية: + "سيتم تحويل الفيديوهات إلى وضع ملء الشاشة في المواقف التالية: • عند بدء تشغيل الفيديو. • عندما يتم النقر على الطابع الزمني في التعليقات." @@ -1438,24 +1428,24 @@ تعطيل سرعة التشغيل للموسيقى "تم تعطيل سرعة التشغيل الافتراضية للموسيقى. -التقييد: قد لا ينطبق هذا الإعداد على مقاطع الفيديو التي لا تتضمن لافتة \"الاستماع على YouTube Music\"." +التقييد: قد لا ينطبق هذا الإعداد على الفيديوهات التي لا تتضمن لافتة \"الاستماع على YouTube Music\"." تم تمكين سرعة التشغيل الافتراضية للموسيقى. تمكين سرعة التشغيل الافتراضية لفيديوهات Shorts تنطبق سرعة التشغيل الافتراضية على Shorts. لا تنطبق سرعة التشغيل الافتراضية على Shorts. تم تخطي التخزين المؤقت الذي تم تحميله مسبقًا. تخطي التخزين المؤقت المحمل مسبقًا - "لتخطي التخزين المؤقت المحمل مسبقًا في بداية مقاطع الفيديو لتطبيق جودة الفيديو الافتراضية على الفور. + "لتخطي التخزين المؤقت المحمل مسبقًا في بداية الفيديوهات لتطبيق جودة الفيديو الافتراضية على الفور. • عند بَدْء تشغيل الفيديو، يكون هناك تأخير قدره 0.3 ثانية تقريبًا. -• لا ينطبق على مقاطع فيديو HDR, مقاطع فيديو البث المباشر, مقاطع الفيديو التي تقل مدتها عن 15 ثوانٍ." +• لا ينطبق على فيديوهات HDR, فيديوهات البث المباشر, الفيديوهات التي تقل مدتها عن 15 ثوانٍ." تشغيل هذا الإعداد قد يسبب مشاكل في تشغيل الفيديو. عرض ملاحظة عند التخطي يتم عرض الملاحظة. لا يتم عرض الملاحظة. إيهام أبعاد الجهاز "يوهم أبعاد الجهاز من أجل فتح جودة فيديو أعلى قد لا تكون متوفرة على جهازك. -قد يتم توفير الجودة العالية في بعض مقاطع الفيديو التي تتطلب أبعادًا عالية للجهاز، ولكن ليس كل مقاطع الفيديو." +قد يتم توفير الجودة العالية في بعض الفيديوهات التي تتطلب أبعادًا عالية للجهاز، ولكن ليس كل الفيديوهات." تعطيل ترميز VP9 "تم تعطيل برنامج ترميز VP9. @@ -1480,12 +1470,12 @@ تمكين Return YouTube Dislike يتم عرض لم يعجبني. لا يتم عرض لم يعجبني. - عرض لم يعجني في مقاطع Shorts - يتم عرض لم يعجني في مقاطع Shorts. + عرض لم يعجني في فيديوهات Shorts + يتم عرض لم يعجني في فيديوهات Shorts. "إبداءات لم يعجبني التي تظهر على فيديوهات Shorts. التقييد: قد لا تظهر إبداءات لم يعجبني إذا لم يقم المستخدم بتسجيل الدخول أو في وضع التصفح المتخفي." - تم إخفاء لم يعجني في مقاطع Shorts. + تم إخفاء لم يعجني في فيديوهات Shorts. لم يعجبني كــ نسبة مئوية يعرض عدد لم يعجبني كـ نسبة مئوية. يعرض عدد لم يعجبني كـ رَقَم. @@ -1501,7 +1491,7 @@ لمحة ReturnYouTubeDislike.com - يتم توفير بيانات لم يعجبني بمقاطع YouTube بواسطة the Return YouTube Dislike API. اضغط هنا لمعرفة المزيد. + يتم توفير بيانات لم يعجبني بفيديوهات YouTube بواسطة the Return YouTube Dislike API. اضغط هنا لمعرفة المزيد. لم يعجبني غير متوفر مؤقتًا (انتهت مهلة API). لم يعجبني غير متوفر (الحالة %d). لم يعجبني غير متوفر (تم الوصول إلى حد API العميل). @@ -1530,7 +1520,7 @@ SponsorBlock تمكين SponsorBlock - مانِع الرُعَاة هو نظام جماعي لتخطي الأجزاء المُمِلَّة في مقاطع YouTube. + مانِع الرُعَاة هو نظام جماعي لتخطي الأجزاء المُمِلَّة في فيديوهات YouTube. المظهر عرض زر التصويت @@ -1784,24 +1774,20 @@ "لا يتم تزييف بيانات البث. قد لا يعمل تشغيل الفيديو." إيقاف تشغيل هذا الإعداد قد يسبب مشاكل في تشغيل الفيديو. العميل الافتراضي - iOS - موسيقى iOS - iOS TV - Android Creator Android TV Android VR + iOS + iOS TV التأثيرات الجانبية للتزييف - • لم يتم العثور عليه بعد. - • قد لا يتم تشغيل الأفلام أو الفيديوهات المدفوعة. "• قائمة المقطع الصوتي مفقودة. • مستوى الصوت الثابت غير متاح. • تعطيل مقاطع الصوت التلقائية المفروضة غير متاح." - استخدام عملاء Android فقط - يتم استخدام عملاء Android لجلب البيانات المتدفقة. - يتم استخدام عملاء Android و iOS لجلب البيانات المتدفقة. + • لم يتم العثور عليه بعد. + • قد لا يتم تشغيل الأفلام أو الفيديوهات المدفوعة. عرض في إحصاءات تقنية يتم عرض العميل المستخدم لجلب بيانات البث في إحصاءات تقنية. تم إخفاء العميل المستخدم لجلب بيانات البث في إحصاءات تقنية. + سجل المشاهدة تغيير الإعدادات المتعلقة بسجل المشاهدة. diff --git a/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml b/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml index a9164629d..3876b20d3 100644 --- a/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml +++ b/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml @@ -1685,13 +1685,14 @@ "Данните за поточно предаване не са подправени. Възпроизвеждането на видео може да не работи." Изключването на тази настройка може да причини проблеми с възпроизвеждането на видео. Клиент по подразбиране - iOS Android TV Android VR + iOS Ефекти от замяната Показване в \"Разширени статистики\" Клиентът, използван за получаване на данни за потока, се показва в Статистика за системни администратори. Клиентът, използван за получаване на данни за поток, е скрит в Статистика за системни администратори. + История на гледане Променя настройките, за хронологията на гледане. diff --git a/patches/src/main/resources/youtube/translations/de-rDE/strings.xml b/patches/src/main/resources/youtube/translations/de-rDE/strings.xml index b42624280..11d811cfd 100644 --- a/patches/src/main/resources/youtube/translations/de-rDE/strings.xml +++ b/patches/src/main/resources/youtube/translations/de-rDE/strings.xml @@ -12,6 +12,8 @@ Neustarten um das Layout zu laden Aktualisieren und Neustarten Normal + Paketname des Video-Downloaders + Paketname der installierten externen Video-Downloader-App wie NewPipe oder YTDLnis. Externer Downloader Warnung "%1$s ist nicht installiert. @@ -109,6 +111,9 @@ Tippen Sie hier, um mehr über DeArrow zu erfahren." Erweiterbaren Chip unter Videos ausblenden Erweiterbare Chips sind versteckt Erweiterbare Chips werden angezeigt + Erweiterbare Regale ausblenden + Erweiterbare Regale sind ausgeblendet. + Erweiterbare Regale werden angezeigt. Verstecke \"Untertitel\" Schaltfläche Schaltfläche \"Untertitel\" ist versteckt. Schaltfläche \"Untertitel\" wird angezeigt. @@ -279,6 +284,7 @@ Beschränkungen: "Diese Einstellung begrenzt die maximale Anzahl von Layouts, die auf dem Wiedergabebildschirm geladen werden können. Wenn sich das Layout des Wiedergabebildschirms aufgrund serverseitiger Änderungen ändert, können unbeabsichtigte Layouts auf dem Wiedergabebildschirm ausgeblendet werden." + Offset Allgemein Startseite ändern @@ -375,17 +381,35 @@ Manche Komponenten könnten nicht versteckt werden." Hook Buttons Überschreibt die Klick-Aktion von In-App-Tasten. + Download-Button + Überschreibe Video-Download-Button + YouTube Musik-Button überschreiben + YouTube Music Button öffnet RVX Music. + YouTube Musik-Button öffnet die native App. + RVX Music Paketname + Paketname des installierten RVX Music. + RVX Music + Warnung + %s ist nicht installiert. Bitte installieren. + Voraussetzung Miniplayer Ändern Sie den Stil des in App minimierten Players. Miniplayer Typ + Deaktiviert Original Telefon Tablet Modern 1 Modern 2 Modern 3 + Abgerundete Ecken aktivieren + Ecken sind abgerundet. + Ecken sind nicht abgerundet. + Aktiviere doppeltes Tippen und Pinchen um die Größe zu ändern + Drag and Drop aktivieren + Drag and Drop ist deaktiviert. Ausklappen und Schließen der Tasten ausblenden Tasten sind ausgeblendet.\n(wischen Sie den Miniplayer zum erweitern oder schließen) Erweitern und Schließen Schaltflächen werden angezeigt. @@ -395,10 +419,15 @@ Manche Komponenten könnten nicht versteckt werden." Vorwärts- und Rückwärts-Buttons ausblenden Vorwärts springen und zurück sind versteckt. Vor- und zurückspringen wird angezeigt. + Initiale Größe + Initiale Bildschirmgröße (in Pixel). + Pixelgröße muss zwischen %1$s und %2$s liegen. Deckkraft der Überlagerung Deckkraft Wert zwischen 0-100, wobei 0 transparent ist. Die Transparenz des Miniplayers muss zwischen 0-100 liegen. Zurückgesetzt auf Standardwerte. + Navigationsleiste + Komponenten der Navigationsleiste ausblenden oder anzeigen. Aktiviere schmale Navigationstasten Der Abstand zwischen den Navigationstasten ist schmal. Abstand zwischen den Navigationstasten ist normal. @@ -424,12 +453,81 @@ Manche Komponenten könnten nicht versteckt werden." Navigationslabel ist versteckt Navigationslabel wird angezeigt Erstellungs- und Benachrichtigungs-Buttons tauschen + "Die Schaltfläche \"Erstellen\" wird mit der Schaltfläche \"Benachrichtigungen\" vertauscht. + +Hinweis: Durch Aktivieren dieser Option wird auch die Videowerbung zwangsweise ausgeblendet." + Erstellen-Button ist nicht mit Benachrichtigungs-Button getauscht. + "Das Deaktivieren kann mehr Werbung vom Server laden. + +Auch Werbung wird nicht mehr in Shorts blockiert. + +Wenn diese Einstellung nicht wirksam ist, versuchen Sie in den Inkognito-Modus zu wechseln." + Navigationsleiste verstecken + Navigationsleiste ist ausgeblendet. + Navigationsleiste wird angezeigt. Einstellungsmenü Elemente im YouTube-Einstellungsmenü verstecken - \"Im TV anschauen\"-Menü wird angezeigt. - + Familiencenter Menü ausblenden + Familiencenter Menü wird ausgeblendet. + Familiencenter Menü wird angezeigt. + Allgemein ausblenden + Allgemein wird ausgeblendet. + Allgemein wird angezeigt. + Konto ausblenden + Konto wird ausgeblendet. + Konto wird angezeigt. + \"Niedrigerer Datenverbrauch\" ausblenden + \"Niedrigerer Datenverbrauch\" wird ausgeblendet. + \"Niedrigerer Datenverbrauch\" wird angezeigt. + Autoplay ausblenden + Autoplay wird ausgeblendet. + Autoplay wird angezeigt. + Einstellungen für Videoqualität ausblenden + Einstellungen für Videoqualität wird ausgeblendet. + Einstellungen für Videoqualität wird angezeigt. + Hintergrundmenü ausblenden + Hintergrundmenü wird ausgeblendet. + Hintergrundmenü wird angezeigt. + \"Auf Fernseher ansehen\" ausblenden + Auf Fernseher ansehen wird ausgeblendet. + \"Auf Fernseher ansehen\" wird angezeigt. + \"Verlauf verwalten\" ausblenden + \"Verlauf verwalten\" wird ausgeblendet. + \"Verlauf verwalten\" wird angezeigt. + \"Meine Daten auf YouTube\" ausblenden + \"Meine Daten auf YouTube\" wird ausgeblendet. + \"Meine Daten auf YouTube\" wird angezeigt. + Datenschutz ausblenden + Datenschutz wird ausgeblendet. Privatsphäre-Menü wird angezeigt. + \"Neue Testfunktionen ausprobieren\" ausblenden + \"Neue Testfunktionen ausprobieren\" wird ausgeblendet. + \"Neue Testfunktionen ausprobieren\" wird angezeigt. + \"Käufe und Mitgliedschaften\" ausblenden + \"Käufe und Mitgliedschaften\" wird ausgeblendet. + \"Käufe und Mitgliedschaften\" wird angezeigt. + \"Abrechnung & Zahlungen\" ausblenden + \"Abrechnung & Zahlungen\" wird ausgeblendet. + \"Abrechnung & Zahlungen\" wird angezeigt. + Benachrichtigungen ausblenden + Benachrichtigungen wird ausgeblendet. + Benachrichtigungen wird angezeigt. + Verbundene Apps ausblenden + Verbundene Apps wird ausgeblendet. + Verbundene Apps wird angezeigt. + Livechat ausblenden + Livechat wird ausgeblendet. + Livechat wird angezeigt. + Untertitel ausblenden + Untertitel wird ausgeblendet. + Untertitel wird angezeigt. + Bedienungshilfen ausblenden + Bedienungshilfen wird ausgeblendet. + Bedienungshilfen wird angezeigt. + \"Über\" ausblenden + \"Über\" wird ausgeblendet. + \"Über\" wird angezeigt. Werkzeugleiste Verstecke oder ändere Toolbar-Komponenten, wie die Suchleiste, Buttons und Header. @@ -465,6 +563,12 @@ Sie Registerkarte > Kanal > Menü > Einstellungen." Sprachsuche ausblenden Sprachsuche ist ausgeblendet. Sprachsuche wird angezeigt. + YouTube Doodles ausblenden + YouTube Doodles sind versteckt. + YouTube Doodles werden angezeigt. + "YouTube Doodles erscheinen jedes Jahr ein paar Tage. + +Wenn ein YouTube Doodle gerade in deiner Region angezeigt wird und diese Einstellung aktiviert ist die Filterleiste unterhalb der Suchleiste wird ebenfalls ausgeblendet." Ersetze Erstellen-Schaltfläche Ersetzt die Erstellen-Schaltfläche mit Einstellungen. Aktionstyp zum Zuweisen der Taste @@ -480,6 +584,8 @@ Tippe und halte zum Öffnen der RVX-Einstellungen." Player-Popup-Panels deaktivieren Auto-Player-Popup-Panels sind deaktiviert. Auto-Player-Popup-Panels sind deaktiviert. + Mix-Playlists deaktivieren + Mix-Playlists sind deaktiviert. Geschwindigkeitsüberlagerung deaktivieren "Deaktiviere 'Abspielen mit 2x Geschwindigkeit' während du gedrückt hältst. @@ -625,6 +731,15 @@ Einstellungen → Autoplay → Nächstes Video automatisch abspielen" Flyout Menü Komponenten des Flyout-Menüs im Feed verstecken oder anzeigen. Toggle Typ ändern + 1080p Premium ausblenden + 1080p Premium wird ausgeblendet. + 1080p Premium wird angezeigt. + Audiospurmenü ausblenden + Audiospur-Menü ist ausgeblendet. + Audio-Track Menü wird angezeigt. + Untertitel-Menü verstecken + Untertitel-Menü ist versteckt. + Untertitel-Menü wird angezeigt. Captions menu footer is hidden. Captions menu footer is shown. Hide lock screen menu @@ -647,6 +762,9 @@ Einstellungen → Autoplay → Nächstes Video automatisch abspielen" Report menu is shown. Additional settings + Ambient-Modus ausblenden + Ambient-Modus ist versteckt. + Ambient-Modus wird angezeigt. Hide help & feedback menu Help & feedback menu is hidden. Help & feedback menu is shown. @@ -667,17 +785,25 @@ Einstellungen → Autoplay → Nächstes Video automatisch abspielen" Stable volume menu is hidden. Hide stats for nerds menu Stats for nerds menu is hidden. + \'In VR ansehen\'-Menü wird ausgeblendet. + \'In VR ansehen\'-Menü wird angezeigt. Vollbild Komponenten im Zusammenhang mit Vollbild ausblenden oder ändern. + Video-Titelbereich anzeigen + "Zeigt den Video-Titelbereich im Vollbild. + +Einschränkung: Videotitel verschwindet beim Klicken auf den Bildschirm." Autoplay-Vorschau-Container ausblenden Autoplay-Vorschau-Container wird ausgeblendet Autoplay-Vorschau-Container wird angezeigt Live-Chat Replay-Button ausblenden Der Live-Chat-Replay-Button ist verborgen.\n\nEr erscheint im Vollbild, wenn Live-Chat geschlossen wird. Der Live-Chat-Replay-Button ist verborgen.\n\nEr erscheint im Vollbild, wenn Live-Chat geschlossen wird. + Im Schnellaktionscontainer werden weitere Videos sowie die zugehörige Videoüberlagerung ausgeblendet. Im Schnellaktionscontainer werden weitere Videos angezeigt sowie die zugehörige Videoüberlagerung. + Schnelle Aktionen Verstecke \"Schnellaktionen\" Container \"Schnellaktionen\" Container wird versteckt \"Schnellaktionen\" Container wird angezeigt @@ -708,6 +834,7 @@ Einstellungen → Autoplay → Nächstes Video automatisch abspielen" Verstecke \"Teilen\" Schaltfläche Teilen-Schaltfläche ist versteckt. Teilen-Schaltfläche wird angezeigt. + Schnelle Aktionen oberer Rand Konfigurieren Sie den Abstand von der Suchleiste auf die Meta-Leiste zwischen 0-32. Der obere Rand der Schnellaktionen muss zwischen 0-32 liegen. Zurückgesetzt auf Standardwerte. @@ -725,6 +852,7 @@ Einstellungen → Autoplay → Nächstes Video automatisch abspielen" Querformat behalten Bewahrt den Querformat beim Ausschalten des Bildschirms im Vollbild. Timeout für den Wechsel zum Querformat + Die Anzahl der Millisekunden nach dem Einschalten des Bildschirms, nachdem Querformat erzwungen wird. Haptisches Feedback Haptisches Feedback aktivieren oder deaktivieren @@ -744,6 +872,23 @@ Einstellungen → Autoplay → Nächstes Video automatisch abspielen" Haptisches Feedback ist deaktiviert. Haptisches Feedback ist aktiviert. + Player Buttons + Verstecke oder zeige Buttons im Video-Player. + Verstecke Autoplay-Schaltfläche + Autoplay-Schaltfläche ist versteckt. + Autoplay-Schaltfläche wird angezeigt. + Verstecke \"Untertitel\" Schaltfläche + Schaltfläche \"Untertitel\" ist versteckt. + Schaltfläche \"Untertitel\" wird angezeigt. + Verstecke Cast-Schaltfläche + Die Cast-Schaltfläche ist versteckt. + Die Cast-Schaltfläche wird angezeigt. + Schaltfläche „Ausklappen” ausblenden + Schaltfläche \"Ausklappen\" wird ausgeblendet. + Schaltfläche \"Ausklappen\" wird angezeigt. + Vollbild-Schaltfläche ausblenden + Vollbild-Schaltfläche wird ausgeblendet. + Vollbild-Schaltfläche wird angezeigt. Hide previous & next button Buttons are hidden. Buttons are shown. @@ -761,6 +906,8 @@ Tap and hold to copy video URL with timestamp." Show copy timestamp URL button "Tap to copy video URL with timestamp. Tap and hold to copy video timestamp." + Stummschalten-Schaltfläche anzeigen + Tippen um Lautstärke des aktuellen Videos stumm zu schalten. Zum laut schalten erneut tippen. Show external download button Tap to launch external downloader. Zeige Geschwindigkeitsdialog Taste @@ -769,6 +916,7 @@ Tippen und halten um die Wiedergabegeschwindigkeit auf 1.0x zurückzusetzen. Hal Zeige Whitelist-Button \"Tippen, um den Whitelist-Dialog zu öffnen. Tippen und halten Sie, um den Einstellungsdialog für die Whitelist anzuzeigen. + \"Alle abspielen\"-Button anzeigen Kanal Whitelist Überprüfen oder die Liste der Kanäle entfernen, die zur Whitelist hinzugefügt wurden. Der Kanal \'%1$s\' wurde auf die Whitelist für %2$s gesetzt. @@ -884,15 +1032,36 @@ Nebeneffekt: Offizielle Kopfzeilen in Suchergebnissen werden ausgeblendet."Teilnehmen-Schaltfläche verstecken Abonnement-Button ausblenden Pausierte Overlay-Tasten ausblenden + Verstecke \"Trends\" Schaltfläche + \"Trends\" Schaltfläche wird versteckt. + \"Trends\" Schaltfläche wird angezeigt. + Shop-Schaltfläche verstecken + Shop-Schaltfläche wird versteckt. + Shop-Schaltfläche wird angezeigt. + Sticker ausblenden + Sticker sind versteckt. + Sticker werden angezeigt. Verstecke Label für bezahlte Promotion + Label für bezahlte Promotion wird versteckt. + Label für bezahlte Promotion wird angezeigt. Info-Panels ausblenden + Infokarten werden ausgeblendet. + Infokarten werden angezeigt. Live-Chat-Kopfzeile ausblenden Live-Chat-Kopfzeile wird ausgeblendet.\n\nZurück Button wird nicht ausgeblendet. Live-Chat-Kopfzeile wird angezeigt.\n\nZurück Button wird nicht ausgeblendet. Kanalleiste ausblenden + Kanalleiste ist ausgeblendet. + Kanalleiste wird angezeigt. Videotitel ausblenden + Titel ist ausgeblendet. + Titel wird angezeigt. Sound-Metadaten-Label ausblenden + Metadatenlabel ist ausgeblendet. + Metadaten-Label wird angezeigt. Verstecke vollständige Video-Linkbezeichnung + Video-Link-Label ist ausgeblendet. + Video-Link-Label wird angezeigt. Shop-Schaltfläche verstecken Super Dankeschön ausblenden @@ -924,6 +1093,11 @@ Nebeneffekt: Offizielle Kopfzeilen in Suchergebnissen werden ausgeblendet."Herz (Farbton) Ausgeblendet + Benutzerdefinierte Aktionen + Benutzerdefinierte Aktionen im Flyout-Menü aktivieren + Benutzerdefinierte Aktionen + Video-URL kopieren + Video öffnen Zeitstempel aktivieren "Zeitstempel ist aktiviert. @@ -961,6 +1135,7 @@ Bekannte Probleme: Da dies eine Funktion in der Entwicklungsphase von Google ist Haptisches Feedback aktivieren Haptisches Feedback ist aktiviert. Haptisches Feedback ist deaktiviert. + Wischgesten sind im Sperrbildschirmmodus deaktiviert. Wischen Hintergrund Sichtbarkeit Die Sichtbarkeit des Wischen Overlay-Hintergrunds Wischgrößen-Schwellenwert @@ -975,6 +1150,12 @@ Bekannte Probleme: Da dies eine Funktion in der Entwicklungsphase von Google ist Deaktiviere automatische HDR-Helligkeit Automatische HDR-Helligkeit ist deaktiviert Automatische HDR-Helligkeit ist aktiviert + Watch-Panel-Gesten deaktivieren + Wechsel in den Vollbildmodus beim Herunterwischen unter dem Videoplayer ist deaktiviert. + Wechsel in den Vollbildmodus beim Herunterwischen unter dem Videoplayer ist aktiviert. + Geste zum Wechseln des Videos deaktiviern + Wischen nach oben / nach unten wird nicht das nächste / vorherige Video abspielen. + Wischen nach oben / unten wird das nächste / vorherige Video abspielen. Auto Video @@ -1019,6 +1200,13 @@ Info: Benachrichtigung wird nicht angezeigt. Spoof device dimensions "Spoofs the device dimensions in order to unlock higher video qualities that may not be available on your device." + VP9 Codec deaktivieren + "VP9-Codec ist deaktiviert. + +• Maximale Auflösung beträgt 1080p. +• Videowiedergabe wird mehr Internet-Daten als VP9 verwenden. +• VP9-Codec wird immer noch für HDR-Videos verwendet." + VP9-Codec ist aktiviert. Replace software AV1 codec Replaces the software AV1 codec with the VP9 codec. Reject software AV1 codec response @@ -1048,6 +1236,9 @@ Einschränkung: Dislikes werden im Inkognito Modus nicht angezeigt." Kompakter Like-Button Like-Button für minimale Breite Like-Button für bestes Aussehen + Geschätzte Likes anzeigen + Geschätzte Likes werden angezeigt. + Geschätzte Likes sind versteckt. Zeige eine Benachrichtigung an, wenn die API nicht verfügbar ist Benachrichtigung wird angezeigt, wenn „Return YouTube Dislike“ nicht verfügbar ist. Benachrichtigung wird nicht angezeigt, wenn „Return YouTube Dislike“ nicht verfügbar ist. @@ -1055,7 +1246,12 @@ Einschränkung: Dislikes werden im Inkognito Modus nicht angezeigt." Über ReturnYouTubeDislike.com Dislikes Daten werden von der True RYD Worker API zur Verfügung gestellt. Tippe hier, um mehr zu erfahren. + Dislikes vorübergehend nicht verfügbar (API Timeout). + Dislikes nicht verfügbar (status %d). Dislikes nicht verfügbar (Client-API Limit erreicht) + Dislikes nicht verfügbar (%s). + Video neu laden, um mit Return YouTube Dislike abzustimmen + Versteckt SponsorBlock @@ -1289,6 +1485,7 @@ Drücke Weiter und deaktiviere Akku-Optimierungen." Einstellungen wurden erfolgreich importiert. Zurücksetzen + Patch-Informationen diff --git a/patches/src/main/resources/youtube/translations/el-rGR/strings.xml b/patches/src/main/resources/youtube/translations/el-rGR/strings.xml index 4a6fe30b3..dcc71c4dc 100644 --- a/patches/src/main/resources/youtube/translations/el-rGR/strings.xml +++ b/patches/src/main/resources/youtube/translations/el-rGR/strings.xml @@ -318,9 +318,6 @@ Playlists Απενεργοποίηση εφέ εκκίνησης εφαρμογής Το εφέ εκκίνησης της εφαρμογής είναι απενεργοποιημένο. Το εφέ εκκίνησης της εφαρμογής είναι ενεργοποιημένο. - Απενεργοποίηση διαφανούς γραμμής κατάστασης - Η γραμμή κατάστασης δεν είναι διαφανής. - Η διαφάνεια της γραμμής κατάστασης ορίζεται αυτόματα. Διαβαθμισμένη οθόνη φόρτωσης Η οθόνη φόρτωσης θα έχει σταδιακές αποχρώσεις φόντο. Η οθόνη φόρτωσης θα έχει στατική απόχρωση φόντο. @@ -493,12 +490,6 @@ Playlists Επίσης, ενδέχεται να εμφανίζονται διαφημίσεις στα Shorts. Αν η απενεργοποίηση δεν τεθεί σε ισχύ, δοκιμάστε να μεταβείτε σε λειτουργία ανώνυμης περιήγησης." - Απενεργοποίηση διαφανούς γραμμής στο φωτεινό θέμα - Η γραμμή πλοήγησης στο φωτεινό θέμα δεν είναι διαφανής. - Η διαφάνεια της γραμμής πλοήγησης στο φωτεινό θέμα ορίζεται αυτόματα. - Απενεργοποίηση διαφανούς γραμμής στο σκούρο θέμα - Η γραμμή πλοήγησης στο σκούρο θέμα δεν είναι διαφανής. - Η διαφάνεια της γραμμής πλοήγησης στο σκούρο θέμα ορίζεται αυτόματα. Γραμμή πλοήγησης Κρυμμένη. Εμφανίζεται. @@ -1799,24 +1790,20 @@ Playlists "Τα δεδομένα ροής δεν παραποιούνται. Η αναπαραγωγή βίντεο ενδέχεται να μη λειτουργεί σωστά." Η απενεργοποίηση αυτής της ρύθμισης ενδέχεται να προκαλέσει προβλήματα αναπαραγωγής βίντεο. Προεπιλογή - iOS - iOS Music - iOS TV - Android Creator Android TV Android VR + iOS + iOS TV Παρενέργειες παραποίησης - • Δεν ανακαλύφθηκαν ακόμη. - • Οι ταινίες ή τα βίντεο επί πληρωμή ενδέχεται να μην αναπαράγονται. "• Το μενού «Κομμάτι ήχου» λείπει. • Η λειτουργία «Σταθερή ένταση» δεν είναι διαθέσιμη. • Η λειτουργία «Απενεργοποίηση υποχρεωτικών κομματιών ήχου» δεν είναι διαθέσιμη." - Χρήση των προγραμμάτων πελάτη Android μόνο - Τα προγράμματα πελάτη Android χρησιμοποιούνται τη λήψη δεδομένων ροής. - Τα προγράμματα πελάτη Android και iOS χρησιμοποιούνται τη λήψη δεδομένων ροής. + • Δεν ανακαλύφθηκαν ακόμη. + • Οι ταινίες ή τα βίντεο επί πληρωμή ενδέχεται να μην αναπαράγονται. Εμφάνιση στο «Στατιστικά για σπασίκλες» Το πρόγραμμα πελάτη που χρησιμοποιείται για τη λήψη δεδομένων ροής εμφανίζεται στο μενού «Στατιστικά για σπασίκλες». Το πρόγραμμα πελάτη που χρησιμοποιείται για τη λήψη δεδομένων ροής δεν εμφανίζεται στο μενού «Στατιστικά για σπασίκλες». + Ιστορικό παρακολούθησης Διαχείριση των ρυθμίσεων που σχετίζονται με το ιστορικό παρακολούθησης. diff --git a/patches/src/main/resources/youtube/translations/es-rES/strings.xml b/patches/src/main/resources/youtube/translations/es-rES/strings.xml index 86aadb752..1da6cf42c 100644 --- a/patches/src/main/resources/youtube/translations/es-rES/strings.xml +++ b/patches/src/main/resources/youtube/translations/es-rES/strings.xml @@ -320,9 +320,6 @@ Limitación: Es posible que el botón Atrás de la barra de herramientas no func Desactivar animación de bienvenida La animación de bienvenida está desactivada. La animación de bienvenida está activada. - Desactivar barra de estado translúcida - La barra de estado es opaca. - La barra de estado es opaca o translúcida. Activar pantalla de carga de degradado La pantalla de carga de degradado está activada. La pantalla de carga de degradado está desactivada. @@ -495,12 +492,6 @@ Nota: Al activar esto también se ocultan forzosamente los anuncios de vídeos." Además, los anuncios ya no se bloquearán en Shorts. Si este ajuste no surte efecto, prueba a cambiar al modo incógnito." - Desactivar barra translúcida luminosa - La barra de navegación en modo claro es opaca. - . - Desactivar barra translúcida oscura - La barra de navegación en modo oscuro es opaca. - La barra de navegación en modo oscuro es opaca o translúcida. Ocultar barra de navegación La barra de navegación está oculta. La barra de navegación está visible. @@ -1768,24 +1759,20 @@ Pulsa el botón de continuar y desactiva las optimizaciones de la batería.""Los datos de transmisión no están falsificados. Es posible que la reproducción de vídeo no funcione." Desactivar este ajuste puede causar problemas de reproducción de vídeo. Cliente predeterminado - iOS - Música iOS - iOS TV - Creador de Android Android TV Android VR + iOS + iOS TV Efectos secundarios de falsificación - • Aún no encontrado. - • Las películas o vídeos de pago no pueden reproducirse. "• Falta el menú de pista de audio. • El volumen estable no está disponible. • Desactivar pistas de audio automáticas forzadas no está disponible." - Utilizar solo clientes Android - Los clientes Android se utilizan para obtener datos de streaming. - Los clientes Android e iOS se utilizan para obtener datos de streaming. + • Aún no encontrado. + • Las películas o vídeos de pago no pueden reproducirse. Mostrar en estadísticas para nerds El cliente utilizado para obtener datos de transmisión se muestra en estadísticas para nerds. El cliente utilizado para obtener datos de transmisión no se muestra en estadísticas para nerds. + Historial de reproducciones Cambiar ajustes relacionados con el historial de reproducciones. diff --git a/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml b/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml index c925ff19f..ac4b040df 100644 --- a/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml +++ b/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml @@ -322,9 +322,6 @@ Limitation : Le bouton Retour de la barre d'outils peut ne pas fonctionner."Désact. l\'animation de démarrage L\'animation de démarrage est désactivé. L\'animation de démarrage est activé. - Désactiver la barre de navigation translucide - La barre de navigation est opaque. - La barre de navigation est opaque ou translucide. Activer dégradé pendant le chargement Le dégradé pendant l\'écran de chargement est activé. Le dégradé pendant l\'écran de chargement est désactivé. @@ -497,12 +494,6 @@ Note : Activer ceci masquera également les publicités vidéos." Également, les publicités ne seront plus bloquées sur les Shorts. Si ce paramètre ne fait pas effet, essayer de passer en mode Incognito." - Désactiver la barre translucide clair - La barre de navigation en mode clair est opaque. - La barre de navigation en mode clair est opaque ou translucide. - Désactiver la barre translucide en mode sombre - La barre translucide en mode sombre est opaque. - La barre translucide en mode sombre est opaque ou translucide. Masquer la barre de navigation La barre de navigation est masqué. La barre de navigation est affichée. @@ -1777,18 +1768,20 @@ Cliquez sur le bouton Continuer et autorisez les modifications d'optimisations." "Les données de lecture en direct ne sont pas falsifiées. La lecture vidéo peut ne pas fonctionner." Désactiver ce paramètre peut entraîner des problèmes de lecture vidéo. Client par défaut - iOS - Musique iOS - TV iOS Android TV Android VR + iOS + TV iOS Effets inconnus de la falsification - • Les vidéos privées conçues pour enfants peuvent ne pas être lues. - • Les vidéos privées conçues pour enfants peuvent ne pas être lues. -• Les films ou vidéos payantes peuvent ne pas être lues. + "• Le menu 'Piste Audio' est manquant. +• Le volume stable n'es pas disponible. +• La désactivation forcée des pistes audio automatiques ne sont pas disponibles." + • Pas encore trouvé. + • Les films ou vidéos payantes peuvent ne pas être lues. Afficher dans \'Statistiques pour les nerds\' Le client utilisé pour récupérer les données de lecture en direct est affiché dans \'Statistiques pour les nerds\'. Le client utilisé pour récupérer les données de lecture en direct est masqué dans \'Statistiques pour les nerds\'. + Historique de visionnage Modifie les paramètres liés à l\'historique de visionnage. diff --git a/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml b/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml index 85713bdf4..df912c280 100644 --- a/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml +++ b/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml @@ -115,17 +115,17 @@ Koppints ide, ha többet szeretnél megtudni a DeArrow-ról." Kinyitható polcok elrejtése A kinyitható polcok el vannak rejtve. A kinyitható polcok láthatóak. - Rejtsd el a hírfolyam feliratok gombját + Feliratok gomb elrejtése A Feliratok gomb el van rejtve. A Feliratok gomb megjelenik. - Hírfolyam keresősáv elrejtése - A hírfolyam keresősáv elrejtve. - A hírfolyam keresősáv látható. - Hírfolyam kérdőívek elrejtése - A hírfolyam kérdőívek el vannak rejtve. - A hírfolyam kérdőívek láthatóak. + Keresősáv elrejtése + A keresősáv elrejtve. + A keresősáv látható. + Kérdőívek elrejtése + A kérdőívek elrejtve. + A kérdőívek megjelennek. Lebegő gomb elrejtése - A lebegő gomb el van rejtve. + A lebegő gomb elrejtve. A lebegő gomb látható. Kép polc elrejtése A kép polcok el vannak rejtve. @@ -230,7 +230,11 @@ Lejátszási listák A kommentek szűrve vannak. A kommentek nincsenek szűrve. Elrejtendő kulcsszavak - "Elrejteni kívánt kulcsszavak és kifejezések, új sorokkal elválasztva.\n\nA kulcsszavak lehetnek csatornanevek vagy bármilyen szöveg, amely a videók címében látható.\n\nA középen nagybetűs szavakat a kis- és nagybetűkkel együtt kell megadni (pl. iPhone, TikTok, LeBlanc)." + "Elrejteni kívánt kulcsszavak és kifejezések, új sorokkal elválasztva. + +A kulcsszavak lehetnek csatornanevek vagy bármilyen szöveg, amely a videók címében látható. + +A középen nagybetűs szavakat a kis- és nagybetűkkel együtt kell megadni (pl. iPhone, TikTok, LeBlanc)." A kulcsszó alapú szűrésről "Kezdőlapi / Feliratkozási / Keresési eredmények szűrve vannak egyező kulcsszavak alapján. @@ -272,14 +276,14 @@ Korlátozások: Kulcsok megtekintése Adja meg nyelvi sablonját a videók alatt megjelenő nézetek számához a felhasználói felületen. Minden kulcs (a nyelvében levő betű/szó) -> érték (a kulcs jelentése) új sorban legyen. A kulcsok a \"->\" előtt helyezkednek el. Ha megváltoztatja az alkalmazás vagy a rendszer nyelvét, akkor vissza kell állítania ezt a beállítást.\n\nPéldák:\nAngol: 10K views = K -> 1000, views -> megtekintések\nSpanyol: 10 K vistas = K -> 1000, vistas -> megtekintések K -> 1 000\nM -> 1 000 000\nB -> 1 000 000 000\nviews -> megtekintések - Szűrés nézettség alapján névjegy + Szűrés nézettség alapjánról "Kezdőlap / Feliratkozás / Keresés eredményei szűrve vannak, hogy elrejtse a meghatározott számnál kisebb vagy nagyobb nézettségű videókat. Korlátozások: • A Shortokat nem lehet elrejteni. • A 0 megtekintésű videók nincsenek kiszűrve." Kapcsolódó videók elrejtése - A kapcsolódó videók el vannak rejtve. + A kapcsolódó videók elrejtve. A kapcsolódó videók láthatóak. "Ez a beállítás korlátozza a lejátszó képernyőjére betölthető elrendezések maximális számát. @@ -318,9 +322,6 @@ Korlátozás: Előfordulhat, hogy az eszköztár Vissza gombja nem működik."Indító animáció letiltása Az indító animáció letiltva. Az indító animáció engedélyezve. - Átlátszó állapotsor letiltása - Az állapotsor nem látszik át. - Az állapotsor átlátszatlan vagy áttetsző. Színátmenetes betöltési képernyő engedélyezése A színátmenetes betöltési képernyő engedélyezve van. A színátmenetes betöltési képernyő le van tiltva. @@ -365,7 +366,7 @@ Ha kikapcsolja, akkor ajánlott törölni az app adatait, hogy elkerülje a UI h Fiók menü Elemek elrejtése vagy megjelenítése a fiók menüben és a Te fülön. Fiókmenü elrejtése - "Fiókmenü és az Ön lap elemeinek elrejtése. + "Fiókmenü és az Te lap elemeinek elrejtése. Előfordulhat, hogy egyes komponensek nincsenek elrejtve." Fiók menü szűrő A fiók menüben szűrendő menüpontok listája, új sorokkal elválasztva. @@ -376,8 +377,8 @@ Előfordulhat, hogy egyes komponensek nincsenek elrejtve." Egyéni szűrő Komponensek elrejtése egyéni szűrőkkel. Egyéni szűrő engedélyezése - Az egyéni szűrő engedélyezett. - Az egyéni szűrő le van tiltva. + Az egyéni szűrő engedélyezve. + Az egyéni szűrő letiltva. Egyéni szűrő A szűrendő összetevők listája új sorokkal elválasztva. @@ -391,8 +392,8 @@ Előfordulhat, hogy egyes komponensek nincsenek elrejtve." Az eredeti letöltés gomb megnyitja a külső letöltőt. Az eredeti letöltés gomb megnyitja az eredeti, beépített letöltőt. Lejátszási lista letöltése gomb felülbírálása - Az eredeti lejátszási lista letöltése gomb megnyitja a külső letöltőt. - Az eredeti lejátszási lista letöltése gomb megnyitja az eredeti, beépített letöltőt. + A eredeti lejátszási lista letöltése gomb mindig megjelenik, és a nyilvános lejátszási listákban megnyitja a külső letöltőt. + Ha megjelenik, az eredeti lejátszási lista letöltése gomb megnyitja az alkalmazáson belüli letöltőt. Lejátszási lista letöltő csomag neve A telepített külső letöltő alkalmazás csomagneve, például YTDLnis. @@ -412,7 +413,7 @@ Előfordulhat, hogy egyes komponensek nincsenek elrejtve." Minilejátszó típusa Letiltva Eredeti - Telefon + Minimális Tablet Modern 1 Modern 2 @@ -427,7 +428,9 @@ Előfordulhat, hogy egyes komponensek nincsenek elrejtve." • Koppintson duplán az eredeti méret visszaállításához." A dupla koppintás és összehúzás átméretezéshez le van tiltva. Fogd és vidd engedélyezése - "A fogd és vidd engedélyezett\n\nA minilejátszó a képernyő bármely sarkába elhúzható." + "A fogd és vidd engedélyezett + +A minilejátszó a képernyő bármely sarkába elhúzható." A fogd és vidd le van tiltva. Vízszintes húzás engedélyezése. "A vízszintes húzás engedélyezett. @@ -482,19 +485,15 @@ Csúsztasson a kibontáshoz vagy bezáráshoz." A navigációs sáv el van rejtve. A navigációs sáv látható. Létrehozás és értesítések gombok felcserélése - "A Létrehozás gomb megcserélése az Értesítések gombbal.\n\nMegjegyzés: Engedélyezés esetén a videó hirdetéseket is elrejti." + "A Létrehozás gomb megcserélése az Értesítések gombbal. + +Megjegyzés: Engedélyezés esetén a videó hirdetéseket is elrejti." A Létrehozás gomb nincs felcserélve az Értesítések gombbal. "Ennek kikapcsolása esetleg több reklámot tölt be a szerverről. Tovább, a reklámok nem lesznek tiltva a Shortokban. Ha ez a beállítás nem működik, váltson inkognító módra." - Világos mód áttetsző sáv letiltása - A világos mód navigációs sávja nem látszik át. - A világos mód navigációs sávja átlátszatlan vagy áttetsző. - Sötét mód áttetsző sáv letiltása - A sötét mód navigációs sávja nem látszik át. - A sötét mód navigációs sávja átlátszatlan vagy áttetsző. Navigációs sáv elrejtése A navigációs sáv el van rejtve. A navigációs sáv látható. @@ -899,7 +898,7 @@ Korlátozás: A videó címe eltűnik, ha rákattint." A megosztás gomb látható. Gyorsműveletek felső margó Állítsa be a keresősáv és a gyorsművelet rész közötti távolságot 0-32 között. - A gyors műveletek felső margójának 0 és 32 között kell lennie. Visszaállítás alapértelmezettre. + A gyors műveletek felső margójának 0 és 32 között kell lennie. Fekvő mód letiltása A videó tájolása álló mód teljes képernyő esetén. @@ -1069,7 +1068,7 @@ Az internetes adathasználat magasabb lehet, és a keresősáv bélyegképei kis Ez a funkció nagyon gyors internetkapcsolat mellett működik a legjobban." - Video leírás + Videó leírás A videóleíró komponenseinek elrejtése vagy megjelenítése. Gördülő szám animációk letiltása A gördülő számok nem animáltak. @@ -1329,6 +1328,10 @@ Korlátozások: Cserélje ki a csatorna kezelőt A csatorna név használatban van. A csatorna kezelő használatban van. + Régi lejátszó felület visszaállítása + "A régi lejátszó felület van használva. +Nincs margó a lejátszó tetején és alján." + A régi lejátszó felülete nincs használatban. Húzásvezérlések Automatikus fényerő bekapcsolása gesztussal @@ -1361,7 +1364,7 @@ Korlátozások: Csúsztatható átfedés mérete Az lehúzható képernyőterület százalékos aránya.\n\n Megjegyzés: Ezzel a képernyőterület méretét is megváltoztatja, ahol érzékeli az ugráshoz szükséges dupla koppintást. - A lehúzható terület mérete nem lehet nagyobb 50-nél. Visszaállítás az alapértelmezettre. + A csúsztatható terület mérete nem lehet nagyobb 50-nél. Visszaállítás az alapértelmezettre. Csúsztatási átfedés időkorlátja Az átfedés láthatóságának időtartama ezredmásodpercben Fényerő csúsztatás érzékenység @@ -1373,6 +1376,12 @@ Megjegyzés: Ezzel a képernyőterület méretét is megváltoztatja, ahol érz Automatikus HDR fényerő letiltása Az automatikus HDR fényerő le van tiltva. Az automatikus HDR fényerő engedélyezett. + Nézőpanel gesztusok letiltása + A teljes képernyőre való belépés a videólejátszó alatti lapozáskor letiltva. + A teljes képernyőre való belépés a videólejátszó alatti lefelé csúsztatáskor engedélyezve van. + A videóváltás lapozással letiltása + A felfelé/lefelé lapozás nem játssza le a következő/előző videót. + A felfelé/lefelé lapozással a következő/előző videót játsza le. Automatikus Videó @@ -1485,12 +1494,12 @@ Korlátozás: A nem tetszések lehet nem jelennek meg kijelentkezett felhasznál YouTube-felhasználónév visszaadása A YouTube-felhasználónév visszaadás engedélyezése A felhasználónév van használatban. - A kezelő van használatban. + Az azonosító van használatban. Megjelenítési formátum Felhasználónév - Felhasználónév (@kezelő) - \@kezelő (felhasználónév) - YouTube adat API kulcs + Felhasználónév (@azonosító) + \@azonosító (felhasználónév) + YouTube Data API kulcs A fejlesztői kulcs a YouTube Data API v3 használatához. A YouTube Data API-kulcsról "A YouTube Data API v3 fejlesztői kulcsa szükséges ahhoz, hogy a Kezelő-t Felhasználónév-re cseréljék. @@ -1749,15 +1758,20 @@ Kattintson az API-kulcs kiadás folyamatának megtekintéséhez." "Az adatfolyam nincs meghamisítva. Lehet, hogy a videó lejátszás nem működik." A beállítás kikapcsolása videólejátszási problémákat okozhat. Alapértelmezett kliens - iOS - iOS zene Android TV Android VR + iOS + iOS TV Hamisítás mellékhatásai + "• A hangsáv menü hiányzik. +• Stabil hangerő nem áll rendelkezésre. +• Kényszerített automatikus hangsávok kikapcsolása nem elérhető." • Még nem található. + • Előfordulhat, hogy a filmek vagy fizetős videók nem játszódnak le. Megjelenítés a statisztikában kockáknak Az adatfolyam lekérésére használt kliens a statisztikában kockáknak látható. Az adatfolyam lekérésére használt kliens a statisztikában kockáknak nem látható. + Megtekintési előzmények A megtekintési előzményekhez kapcsolódó beállítások módosítása. diff --git a/patches/src/main/resources/youtube/translations/it-rIT/strings.xml b/patches/src/main/resources/youtube/translations/it-rIT/strings.xml index a1e78d884..742fd2863 100644 --- a/patches/src/main/resources/youtube/translations/it-rIT/strings.xml +++ b/patches/src/main/resources/youtube/translations/it-rIT/strings.xml @@ -321,9 +321,6 @@ Nota: il pulsante Indietro della barra degli strumenti potrebbe non funzionare." Disattiva l\'animazione di avvio L\'animazione di avvio è disattivata. L\'animazione di avvio è attivata. - Disattiva la barra di stato traslucida - La barra di stato è opaca. - La barra di stato è opaca o traslucida. Attiva la schermata di caricamento gradiente La schermata di caricamento gradiente è attivata. La schermata di caricamento gradiente è disattivata. @@ -497,12 +494,6 @@ Nota: anche gli annunci video saranno nascosti." Inoltre, gli annunci degli Shorts non saranno più bloccati. Se questa impostazione non ha effetto, prova a passare alla navigazione in incognito." - Disattiva la barra di navigazione traslucida con tema chiaro - La barra di navigazione con tema chiaro è opaca. - La barra di navigazione con tema chiaro è opaca o traslucida. - Disattiva la barra di navigazione traslucida con tema scuro - La barra di navigazione con tema scuro è opaca. - La barra di navigazione con tema scuro è opaca o traslucida. Nascondi la barra di navigazione La barra di navigazione è nascosta. La barra di navigazione è visibile. @@ -1773,25 +1764,20 @@ Tocca il pulsante Continua e consenti le modifiche di ottimizzazione." "I dati in streaming non sono camuffati. La riproduzione potrebbe non funzionare." La disattivazione di questa impostazione potrebbe causare problemi di riproduzione. Client predefinito - iOS - iOS Music - iOS TV - Android Creator Android TV Android VR + iOS + iOS TV Effetti collaterali del camuffamento - • Nessuno ancora trovato. - • I film o i video a pagamento potrebbero non essere riprodotti. "• Il menù Traccia Audio è mancante. • Il menù Volume Stabile è mancante. • La disattivazione della traccia audio automatica forzata non funziona." - Usa solo il client Android - Il client Android è usato per recuperare i dati in streaming. - I client Android e iOS sono usati per recuperare i dati in streaming. - La disattivazione di questa impostazione potrebbe causare problemi di riproduzione. + • Nessuno ancora trovato. + • I film o i video a pagamento potrebbero non essere riprodotti. Mostra nelle statistiche per nerd Il client usato per recuperare i dati in streaming è visibile nelle statistiche per nerd. Il client usato per recuperare i dati in streaming è nascosto nelle statistiche per nerd. + Cronologia Cambia le impostazioni della cronologia. diff --git a/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml b/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml index 0eab6fd63..fb58966b3 100644 --- a/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml +++ b/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml @@ -78,7 +78,7 @@ DeArrow の詳細については、ここをタップしてください。"静止画サムネイルについて 静止画サムネイルは、各動画の最初/中間/最後の部分から取得されます。これらの画像は YouTube に直接組み込まれており、外部 API は使用されません。 高速な静止画サムネイル - 現在の設定: 中画質の静止画サムネイルを使用します。\n\n注意: 読み込みは速くなりますが、ライブ、公開予定、非常に古い動画は、サムネイルが空白になることがあります。 + 現在の設定: 中画質の静止画サムネイルを使用します。\n\n注意: 読み込みは速くなりますが、ライブ配信、公開予定、非常に古い動画は、サムネイルが空白になることがあります。 現在の設定: 高画質の静止画サムネイルを使用します。 取得する静止画のサムネイルの位置 動画の最初 @@ -325,9 +325,6 @@ DeArrow の詳細については、ここをタップしてください。"スプラッシュアニメーションを無効化 YouTube 起動時のスプラッシュアニメーションを無効にします。 YouTube 起動時のスプラッシュアニメーションを無効にします。 - 半透明なステータスバーを無効化 - ステータスバーを不透明にします。 - ステータスバーを不透明にします。 グラデーションの読み込み画面を有効化 アプリ起動時や動画の読み込み画面などでグラデーションを有効化します。 アプリ起動時や動画の読み込み画面などでグラデーションを有効化します。 @@ -500,12 +497,6 @@ DeArrow の詳細については、ここをタップしてください。" - 明るい半透明なナビゲーションバーを無効化 - ライトモードで半透明なナビゲーションバーを無効化します。 - ライトモードで半透明なナビゲーションバーを無効化します。 - 暗い半透明なナビゲーションバーを無効化 - ダークモードで半透明なナビゲーションバーを無効化します。 - ダークモードで半透明なナビゲーションバーを無効化します。 ナビゲーションバーを非表示 ナビゲーションバー(ホーム、登録チャンネルなどのボタン)を非表示にします。 ナビゲーションバー(ホーム、登録チャンネルなどのボタン)を非表示にします。 @@ -867,8 +858,8 @@ DeArrow の詳細については、ここをタップしてください。"「次の動画」コンテナーを非表示にします。 「次の動画」コンテナーを非表示にします。 チャットのリプレイボタンを非表示 - ライブで全画面表示時に右下に表示される「チャットのリプレイ」ボタンを非表示にします。\n\nライブチャットを終了すると全画面表示になります。 - ライブで全画面表示時に右下に表示される「チャットのリプレイ」ボタンを非表示にします。\n\nライブチャットを終了すると全画面表示になります。 + ライブ配信で全画面表示時に右下に表示される「チャットのリプレイ」ボタンを非表示にします。\n\nライブチャットを終了すると全画面表示になります。 + ライブ配信で全画面表示時に右下に表示される「チャットのリプレイ」ボタンを非表示にします。\n\nライブチャットを終了すると全画面表示になります。 関連動画を非表示 関連動画のオーバーレイを無効化します。 関連動画のオーバーレイを無効化します。 @@ -987,10 +978,10 @@ DeArrow の詳細については、ここをタップしてください。"タップするとホワイトリストのダイアログが開きます。 長押しするとホワイトリストの設定のダイアログが開きます。 「すべて再生」ボタンを表示 - "1 回タップすると、チャンネルに投稿されているすべての動画の再生リストを生成します。 + "タップすると、チャンネルに投稿されているすべての動画の再生リストを生成します。 タップして長押しすると、元に戻ります。 -注意: ライブでは動作しない可能性があります。" +注意: ライブ配信では動作しない可能性があります。" 再生リストの生成モード すべてのコンテンツ (時間順、昇順) すべてのコンテンツ (時間順) @@ -1004,7 +995,7 @@ DeArrow の詳細については、ここをタップしてください。"全員が閲覧可能なコンテンツのみ 「メンバーのみ」の動画 「メンバーのみ」のショート - 「メンバーのみ」のライブ + 「メンバーのみ」のライブ配信 チャンネル ID が一致しないため、再生リストを生成できません。 チャンネルのホワイトリスト ホワイトリストに登録したチャンネルのリストを確認/削除します。 @@ -1068,7 +1059,7 @@ DeArrow の詳細については、ここをタップしてください。"高画質のサムネイルを有効化 シークバーサムネイルを高画質化します。 シークバーサムネイルを高画質化します。 - "この機能を有効化することにより、シークバーサムネイルがないライブのアーカイブにサムネイルが復元されます。 + "これを有効化すると、シークバーサムネイルがないライブ配信のアーカイブにサムネイルが復元されます。 注意: ・通信量が増える可能性があります。 @@ -1276,8 +1267,8 @@ DeArrow の詳細については、ここをタップしてください。" - フライアウトメニューでカスタムアクションを使用できるようにします。\n\n注意: \n・YouTube のバージョンが 18.49.37 以前に偽装されている場合は機能しません。\n・ライブでは機能しません。 +・ライブ配信では機能しません。" + フライアウトメニューでカスタムアクションを使用できるようにします。\n\n注意: \n・YouTube のバージョンが 18.49.37 以前に偽装されている場合は機能しません。\n・ライブ配信では機能しません。 ツールバーのカスタムアクションを有効化 "ツールバーでカスタムアクションを使用できるようにします。 @@ -1336,9 +1327,8 @@ DeArrow の詳細については、ここをタップしてください。"現在の設定: チャンネルのハンドル名が表示されます。 古いプレーヤーレイアウトを復元 "古いプレーヤーレイアウトを復元します。 -プレーヤーの上部と下部に余白はありません。" - 古いプレーヤーレイアウトを復元します。 -プレーヤーの上部と下部に余白はありません。 +これによりプレーヤーの上部と下部から余白が削除されます。" + 古いプレーヤーレイアウトを復元します。\nこれによりプレーヤーの上部と下部から余白が削除されます。 スワイプコントロール スワイプして明るさの自動調節を有効化 @@ -1383,8 +1373,8 @@ DeArrow の詳細については、ここをタップしてください。"HDR 動画の明るさの自動調節を無効にします。 HDR 動画の明るさの自動調節を無効にします。 全画面表示ジェスチャーを無効化 - 動画のタイトルより下の領域を下にスワイプすると全画面表示に切り替える機能を無効化します。 - 動画のタイトルより下の領域を下にスワイプすると全画面表示に切り替える機能を無効化します。 + 動画のタイトルより下の領域を下にスワイプして全画面表示に切り替える機能を無効化します。 + 動画のタイトルより下の領域を下にスワイプして全画面表示に切り替える機能を無効化します。 スワイプして動画を切り替えるのを無効化 全画面表示時に、上/下にスワイプして次の動画/前の動画に切り替えられるようにします。 全画面表示時に、上/下にスワイプして次の動画/前の動画に切り替えられるようにします。 @@ -1775,20 +1765,20 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に "ストリーミングデータを偽装していない場合、動画の再生ができない可能性があります。" この設定をオフにした場合、バッファリングの問題が発生する可能性があります。 偽装するクライアントの種類 - iOS - iOS Music - iOS TV - Android Creator Android TV Android VR + iOS + iOS TV ストリーミングデータを偽装することによる副作用 + "・「音声トラック」メニューは表示されません。 +・「一定音量」は利用できません。 +・「音声トラックの強制を無効化」は利用できません。" ・まだ見つかっていません。 - ・子供向け動画は再生できない可能性があります。 -・映画や有料動画は再生できない可能性があります。 - Android クライアントのみを使用 + ・映画や有料動画は再生できない可能性があります。 統計情報に偽装したクライアントを表示 統計情報に偽装したストリーミングデータを表示します。 統計情報に偽装したストリーミングデータを表示します。 + 再生履歴 再生履歴に関連する設定を変更します。 diff --git a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml index 8245552dc..e7836e3e7 100644 --- a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml @@ -312,7 +312,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 앱 시작 페이지 유형 변경하기 "앱 시작 페이지가 항상 변경됩니다. -알려진 문제점: 툴바에서 '뒤로 가기' 버튼이 작동되지 않을 수 있습니다." +알려진 문제점: +• 툴바에서 '뒤로 가기' 버튼이 작동되지 않을 수 있습니다." 앱 시작 페이지가 한 번만 변경됩니다. 자동 오디오 트랙 비활성화하기 자동 오디오 트랙을 비활성화합니다. @@ -323,9 +324,6 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 스플래시 애니메이션 비활성화하기 앱을 시작할 때, 스플래시 애니메이션을 비활성화합니다. 앱을 시작할 때, 스플래시 애니메이션을 활성화합니다. - 반투명 상태바 비활성화하기 - 상태바가 불투명합니다. - 상태바가 불투명하거나 반투명합니다. 그라데이션 색상 로딩 화면 활성화하기 그라데이션 색상 로딩 화면을 활성화합니다. 그라데이션 색상 로딩 화면을 비활성화합니다. @@ -410,7 +408,7 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 미니 플레이어 앱 내에서 최소화된 플레이어의 스타일을 변경할 수 있습니다. 미니 플레이어 유형 - 사용하지 않음 + 사용 안함 기기 기본값 사용 최소화 태블릿 @@ -428,9 +426,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." \'두 번 누르기 동작\' 및 \'핀치하여 크기 조정\'을 비활성화합니다 드래그 & 드롭 활성화하기 "드래그 & 드롭을 활성화합니다. - • 미니 플레이어를 화면 구석으로 드래그 할 수 있습니다." - 드래그 & 드롭을 비활성화합니다. + 드래그 & 드롭을 비활성화합니다.\n• YouTube v19.44.39 에서는 드래그 & 드롭을 비활성화한 상태에서 모던 스타일 1, 2, 3을 사용하면, 미니 플레이어 상태에서 \'위로 스와이프하여 화면 펼치기\'와 \'아래로 스와이프하여 화면 닫기\'를 사용할 수 없습니다.\n• YouTube v19.16.39 에서는 위에 설명된 기능은 전부 사용할 수는 있지만, 드래그 & 드롭 기능이 지원되지 않습니다. 수평 드래그 제스처 활성화하기 "수평 드래그 제스처를 활성화합니다. @@ -493,12 +490,6 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 또한, Shorts에서 광고가 더 이상 숨겨지지 않습니다. 이 설정이 적용되지 않는 경우에는 시크릿 모드로 전환해 보세요." - 밝은 반투명 하단바 비활성화하기 - 밝은 테마 하단바가 불투명합니다. - 밝은 테마 하단바가 불투명하거나 반투명합니다. - 어두운 반투명 하단바 비활성화하기 - 어두운 테마 하단바가 불투명합니다. - 어두운 테마 하단바가 불투명하거나 반투명합니다. 하단바 숨기기 하단바가 숨겨집니다. 하단바가 표시됩니다. @@ -693,8 +684,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 줌 오버레이가 숨겨집니다. 줌 오버레이가 표시됩니다. 동영상 제목 하단 정리하기 - "제목 하단에서 다음 문구들이 숨겨집니다:\n#(해시태그), 모금 행사, 쇼핑, n개 제품,\n인기 급상승 동영상 #순위, 회원 전용 ..." - "제목 하단에서 다음 문구들이 표시됩니다:\n#(해시태그), 모금 행사, 쇼핑, n개 제품,\n인기 급상승 동영상 #순위, 회원 전용 ..." + "제목 하단에서 다음 문구들이 숨겨집니다:\n#(해시태그), 모금 행사, 쇼핑, n개 제품, 더빙,\n인기 급상승 동영상 #순위, 회원 전용 ..." + "제목 하단에서 다음 문구들이 표시됩니다:\n#(해시태그), 모금 행사, 쇼핑, n개 제품, 더빙,\n인기 급상승 동영상 #순위, 회원 전용 ..." 액션 버튼 플레이어 하단에 있는 액션 버튼을 숨기거나 표시할 수 있습니다. @@ -862,7 +853,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 동영상 제목 섹션 표시하기 "전체 화면에서 동영상 제목 섹션을 표시합니다. -알려진 문제점: 동영상 제목을 누르면 사라집니다." +알려진 문제점: +• 동영상 제목을 누르면 사라집니다." 자동재생 미리보기 컨테이너 숨기기 자동재생 미리보기 컨테이너가 숨겨집니다. 자동재생 미리보기 컨테이너가 표시됩니다. @@ -1139,7 +1131,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." Shorts 선반 숨기기 "Shorts 선반이 숨겨집니다. -알려진 문제점: 검색 결과에서 다음 헤더가 숨겨집니다. +알려진 문제점: +검색 결과에서 다음 헤더가 숨겨집니다. • 아티스트 또는 크리에이터의 최신 동영상 • 이전에 시청한 동영상 • 관련 검색어의 검색결과 @@ -1159,9 +1152,9 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 검색 결과에서 Shorts 선반 숨기기 검색 결과에서 Shorts 선반이 숨겨집니다. 검색 결과에서 Shorts 선반이 표시됩니다. - 시청 기록에서 Shorts 선반이 숨기기 - 시청 기록에서 Shorts 선반이 숨겨집니다. - 시청 기록에서 Shorts 선반이 표시됩니다. + 시청 기록에서 Shorts 숨기기 + 시청 기록에서 Shorts가 숨겨집니다. + 시청 기록에서 Shorts가 표시됩니다. Shorts 반복 상태 변경하기 Shorts 백그라운드 재생 반복 상태 변경하기 @@ -1433,7 +1426,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 음악에서 기본 동영상 재생 속도 비활성화하기 "음악 동영상에서 기본 동영상 재생 속도를 비활성화합니다. -알려진 문제점: 이 설정은 'YouTube Music에서 감상하기' 배너가 포함되지 않은 동영상에는 적용되지 않을 수 있습니다." +알려진 문제점: +• 이 설정은 'YouTube Music에서 감상하기' 배너가 포함되지 않은 동영상에는 적용되지 않을 수 있습니다." 음악 동영상에서 기본 동영상 재생 속도를 활성화합니다. Shorts에서 기본 동영상 재생 속도 활성화하기 Shorts에서 기본 동영상 재생 속도를 활성화합니다. @@ -1453,8 +1447,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." • 일부 스마트폰에서 이 설정을 활성화하면, 동영상 재생이 끊기거나 배터리 수명이 단축될 수 있으며, 알려지지 않은 문제점도 발생할 수 있습니다." VP9 코덱 비활성화하기 "VP9 코덱을 비활성화합니다. -• 재생 문제가 없는 계정이거나 iOS 클라이언트만 AV1 코덱을 지원하고 나머지 클라이언트는 VP9 코덱까지만 지원하기 때문에 iOS만 4K 동영상까지 재생될 수 있고, 나머지는 1080p까지 재생될 수 있습니다. -• AVC 코덱 동영상을 재생했을 경우에는 VP9보다 더 많은 데이터가 사용됩니다. +• 재생 문제가 없는 계정이거나 iOS 클라이언트는 AV1 코덱까지 지원되기 때문에 2160p까지 재생될 수 있고, 나머지 클라이언트는 VP9 코덱까지만 지원되기 때문에 1080p까지 재생될 수 있습니다. +• AVC 코덱 동영상을 재생했을 경우에는 VP9보다 더 많은 데이터가 사용되오니 주의하세요. • HDR 동영상을 재생하기 위해 HDR 동영상에서는 VP9 또는 AV1 코덱이 사용됩니다." VP9 코덱을 활성화합니다.\n• 예전에 업로드된 동영상에서 일부 화질 값들이 제거되어 360p와 1080p(Premium 기능)만 선택할 수 있거나 화질 메뉴를 선택할 수 없을 수 있습니다. AV1 코덱 변경하기 @@ -1478,7 +1472,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." Shorts에서 싫어요 수를 표시합니다. "Shorts에서 싫어요 수를 표시합니다. -알려진 문제점: 사용자가 로그인을 하지 않았거나 시크릿 모드에서는 싫어요 수가 표시되지 않을 수 있습니다." +알려진 문제점: +• 사용자가 로그인을 하지 않았거나 시크릿 모드에서는 싫어요 수가 표시되지 않을 수 있습니다." Shorts에서 싫어요 수를 표시하지 않습니다. 싫어요 수를 퍼센트로 표시하기 싫어요 수를 퍼센트로 표시합니다. @@ -1733,11 +1728,11 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요." 앱을 실행하려면 이 과정이 필요합니다." 웹사이트 열기 - "GmsCore를 배터리 최적화 목록에서 제외하여 앱 문제를 방지할 수 있습니다. + "GmsCore 앱 배터리 최적화를 비활성화(제한 없음)하여 앱 문제를 방지할 수 있습니다. -GmsCore를 배터리 최적화 목록에서 제외하더라도, 배터리 사용량에 부정적인 영향을 미치지 않습니다. +GmsCore 앱 배터리 최적화를 비활성화(제한 없음)하더라도, 배터리 사용량에 부정적인 영향을 미치지 않습니다. -배터리 최적화 목록에서 제외하려면 '계속하기' 버튼을 누르세요." +앱 배터리 최적화를 비활성화(제한 없음)하려면 '계속하기' 버튼을 누르세요." 계속하기 추적 쿼리를 제거한 링크 공유하기 링크를 공유할 때, URL에서 추적 쿼리 매개변수를 제거합니다. (URL의 뒷부분 \'?si=...\' 이 제거됨.) @@ -1778,24 +1773,21 @@ GmsCore를 배터리 최적화 목록에서 제외하더라도, 배터리 사용 "스트리밍 데이터를 변경하지 않습니다.\n동영상 재생 문제가 발생할 수 있습니다." 이 설정을 비활성화하면 동영상 재생 문제가 발생할 수 있습니다. 기본 클라이언트 - iOS - iOS Music - iOS TV - Android Creator Android TV Android VR + iOS + iOS TV 알려진 문제점 - • 아직 발견되지 않았습니다. - • 영화 또는 회원 전용 동영상과 같은 유료 동영상이 재생되지 않을 수 있습니다. "• 오디오 트랙 메뉴가 표시되지 않습니다. • 안정적인 볼륨을 사용할 수 없습니다. -• 자동 오디오 트랙을 비활성화할 수 없습니다." - Android 클라이언트만 사용하기 - Android 클라이언트를 스트리밍 데이터를 가져오는 데 사용합니다. - Android 와 iOS 클라이언트를 스트리밍 데이터를 가져오는 데 사용합니다. +• 자동 오디오 트랙을 비활성화할 수 없습니다. +• VR은 Kids // TV는 재생목록과 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다." + • 주요 문제점은 아직 발견되지 않았습니다.\n• 영화, 유료, 비공개 그리고 연령 제한 동영상에서 다른 클라이언트가 사용될 수 있습니다. + • 영화 또는 유료 동영상이 재생되지 않을 수 있습니다.\n• 안정적인 볼륨을 사용할 수 없습니다.\n• 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다. 전문 통계에서 표시하기 - \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 전문 통계에서 표시됩니다. - \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 전문 통계에서 숨겨집니다. + \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 전문 통계에서 표시됩니다.\n\n• 만약 선택한 기본 클라이언트가 재생할 수 없는 동영상을 재생하려하거나 클라이언트 재생 문제가 발생하면, 그 문제를 해결하기 위해 다른 클라이언트가 사용되는 경우도 있기 때문에 전문 통계에서 다르게 표시될 수 있습니다. + \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 전문 통계에서 숨겨집니다.\n\n• 만약 선택한 기본 클라이언트가 재생할 수 없는 동영상을 재생하려하거나 클라이언트 재생 문제가 발생하면 그 문제를 해결하기 위해 다른 클라이언트가 사용되는 경우도 있기 때문에 전문 통계에서 다르게 표시될 수 있습니다. + 시청 기록 시청 기록과 관련된 설정을 변경할 수 있습니다. diff --git a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml index 18f67e6a6..da3713f99 100644 --- a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml +++ b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml @@ -320,9 +320,6 @@ Ograniczenie: Przycisk wstecz na pasku narzędzi może nie działać." Animacja uruchamiania aplikacji Wyłączona Włączona - Półprzezroczystość paska statusu - Wyłączona - Włączona Kolorowy ekran ładowania Włączony Wyłączony @@ -494,12 +491,6 @@ Notka: włączenie tej opcji wymusza ukrywanie reklam w filmach." Dodatkowo, reklamy nie będą już blokowane w Shortsach. Jeśli opcja nie przynosi skutku, spróbuj przełączyć się na tryb incognito." - Półprzezroczystość paska nawigacji na jasnym motywie - Wyłączona - Włączona - Półprzezroczystość paska nawigacji na ciemnym motywie - Wyłączona - Włączona Pasek nawigacji Ukryty Widoczny @@ -1770,25 +1761,20 @@ Stuknij przycisk kontynuacji i zezwól na zmiany w optymalizacji." "Wyłączone. Odtwarzanie filmów może nie działać" Wyłączenie tej opcji może spowodować problemy z odtwarzaniem filmów. Domyślny klient - iOS - iOS Music - iOS TV - Kreator Androida Android TV Android VR + iOS + iOS TV Efekty uboczne oszukiwania - • Jeszcze nie znaleziono - • Filmy kinowe lub płatne filmy mogą się nie odtwarzać "• Brakuje menu od ścieżki dźwiękowej • Stabilna głośność nie jest dostępna • Wyłączenie automatycznego wymuszania ścieżki dźwiękowej nie jest dostępne" - Używaj wyłącznie klientów Androida - Tak - Nie - Wyłączenie tego ustawienia może spowodować problemy z odtwarzaniem filmów. + • Jeszcze nie znaleziono + • Filmy kinowe lub płatne filmy mogą się nie odtwarzać Informacja w statystykach dla nerdów Widoczna Ukryta + Historia oglądania Zmień ustawienia związane z historią oglądania diff --git a/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml b/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml index b7c30d974..1194f88a4 100644 --- a/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml +++ b/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml @@ -320,9 +320,6 @@ Limitação: O botão voltar na barra de ferramentas pode não funcionar."Desativar animação inicial A animação inicial está desativada. A animação do inicial está ativada. - Desativar barra de status transparente - A barra de status está opaca. - A barra de status está opaca ou transparente. Ativar tela de carregamento gradiente A tela de carregamento gradiente está ativada. A tela de carregamento gradiente está desativada. @@ -495,12 +492,6 @@ Nota: Ativar isso também oculta anúncios de vídeo à força." Além disso, os anúncios não serão mais bloqueados no Shorts. Se essa configuração não surtir efeito, tente alternar para o modo anônimo." - Desativar barra transparente no modo claro - A barra de navegação no modo claro está opaca. - A barra de navegação no modo claro está opaca ou transparente. - Desativar barra transparente no modo escuro - A barra de navegação no modo escuro está opaca. - A barra de navegação no modo escuro está opaca ou transparente. Ocultar barra de navegação A barra de navegação está oculta. A barra de navegação será exibida. @@ -1769,15 +1760,20 @@ Toque no botão continuar e desative as otimizações da bateria." "Os dados de streaming não são falsificados. A reprodução de vídeo pode não funcionar." Desativar esta configuração pode causar problemas de reprodução de vídeo. Cliente padrão - iOS - iOS Music Android TV Android VR + iOS + iOS TV Efeitos colaterais da falsificação + "• O menu de faixa de áudio está faltando. +• Volume estável não está disponível. +• Desativar faixas de áudio automático forçadas não está disponível." • Ainda não encontrado. + • Filmes ou vídeos pagos podem não reproduzir. Exibir em Estatísticas para nerds O cliente usado para buscar dados de streaming é mostrado em Estatísticas para nerds. O cliente usado para buscar dados de streaming está oculto em Estatísticas para nerds. + Histórico de exibição Altere as configurações relacionadas ao histórico de exibição. diff --git a/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml b/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml index 5b11bf3ed..83c75d092 100644 --- a/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml +++ b/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml @@ -332,9 +332,6 @@ Shorts Анимированная заставка Анимированная заставка отключена. Анимированная заставка включена. - Полупрозрачная строка состояния - Отключена. - Включена. Переливающийся экран загрузки Переливающийся экран загрузки включен. Переливающийся экран загрузки отключен. @@ -507,12 +504,6 @@ Shorts Кроме того, реклама больше не будет блокироваться в Shorts. Если эта настройка не вступила в силу, попробуйте перейти в режим инкогнито." - Светлая полупрозрачная панель навигации - Отключена. - Включена. - Темная полупрозрачная панель навигации - Отключена. - Включена. Панель навигации Панель навигации скрыта. Панель навигации отображена. @@ -1793,24 +1784,20 @@ Shorts Воспроизведение видео может не работать." Отключение этой настройки вызовет проблемы с воспроизведением видео. Клиент по умолчанию - iOS - Музыка iOS - iOS TV - Редактор Android Android TV Android VR + iOS + iOS TV Эффекты от подмены - • Еще не найдено. - • Платные видео и фильмы могут не проигрываться. "• Меню аудио дорожки отсутствует. • Стабильная громкость недоступна. • Отключить принудительные автозвуковые дорожки недоступна." - Использовать только клиенты Android - Android клиенты используются для получения потоковых данных. - Android и iOS клиенты используются для получения потоковых данных. + • Еще не найдено. + • Платные видео и фильмы могут не проигрываться. Статистике для сисадминов Клиент потоковых данных отображается в Статистике для сисадминов. Клиент потоковых данных скрыт в Статистике для сисадминов. + История просмотра Изменить настройки истории просмотра. diff --git a/patches/src/main/resources/youtube/translations/tr-rTR/strings.xml b/patches/src/main/resources/youtube/translations/tr-rTR/strings.xml index 70b5e91e9..04f405347 100644 --- a/patches/src/main/resources/youtube/translations/tr-rTR/strings.xml +++ b/patches/src/main/resources/youtube/translations/tr-rTR/strings.xml @@ -1507,6 +1507,7 @@ Devam düğmesine dokunun ve pil optimizasyonlarını devre dışı bırakın."< Sıfırla Ayarlar panoya kopyalandı + İzleme geçmişi İzlemek geçmişi ile alakalı ayarları değiştirir. diff --git a/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml b/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml index ce1410442..271f1b39e 100644 --- a/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml +++ b/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml @@ -320,9 +320,6 @@ Вимкнути сплеш анімацію Сплеш анімацію вимкнено. Сплеш анімацію увімкнено. - Вимкнути напівпрозорість рядка стану - Рядок стану непрозорий. - Рядок стану непрозорий чи напівпрозорий. Увімкнути градієнт екрану завантаження Градієнт екрану завантаження увімкнено. Градієнт екрану завантаження вимкнено. @@ -495,12 +492,6 @@ А також, рекламу більше не блокуватиметься в Shorts. Якщо це налаштування не діє, спробуйте перемкнути Анонімний режим." - Вимкнути напівпрозорість світлої панелі - Панель навігації у світлому режимі непрозора. - Панель навігації у світлому режимі непрозора чи напівпрозора. - Вимкнути напівпрозорість темної панелі - Панель навігації у темному режимі непрозора. - Панель навігації у темному режимі непрозора чи напівпрозора. Приховати панель навігації Панель навігації приховано. Панель навігації показується. @@ -1771,24 +1762,20 @@ "Дані трансляції не підроблено. Відтворення відео може не працювати." Вимикання цього налаштування може призвести до проблем відтворення відео. Основний клієнт - iOS - Музика iOS - iOS TV - Розробник Android Android TV Android VR + iOS + iOS TV Побічні ефекти імітування - • Ще не знайдено. - • Фільми чи платні відео можуть не відтворюватися. "• Меню звукової доріжки відсутнє. • Стабілізація гучності недоступна. • Вимикання примусових звукових доріжок недоступне." - Використовувати лише клієнти Android - Використовується клієнти Android для отримання потокових даних. - Використовується клієнти Android та iOS для отримання потокових даних. + • Відео для дітей можуть не відтворюватися. + • Фільми чи платні відео можуть не відтворюватися. Показувати в Статистика для сисадмінів Клієнт, що використовується для отримання даних трансляції показується у Статистика для сисадмінів. Клієнт, що використовується для отримання даних трансляції приховано у Статистика для сисадмінів. + Історія перегляду Змінити налаштування пов\'язані з історією перегляду. diff --git a/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml b/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml index fd0eb4912..de090ee13 100644 --- a/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml +++ b/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml @@ -13,7 +13,7 @@ Làm mới và khởi động lại Bình thường Tên gói trình tải xuống video - Nhập tên gói ứng dụng trình tải xuống đã cài đặt trên thiết bị của bạn, chẳng hạn như NewPipe hoặc YTDLnis. + Chọn trình tải xuống hoặc nhập tên gói ứng dụng trình tải xuống đã được cài đặt trên thiết bị của bạn, chẳng hạn như NewPipe hoặc YTDLnis. Trình tải xuống bên ngoài Chú ý "Có vẻ như %1$s chưa được cài đặt. @@ -30,9 +30,9 @@ Ẩn kệ Sản phẩm Kệ Sản phẩm đã ẩn. Kệ Sản phẩm được hiển thị. - Ẩn kệ cửa hàng - Kệ cửa hàng được hiển thị bên dưới trình phát. - Kệ cửa hàng đã ẩn bên dưới trình phát. + Ẩn kệ Cửa hàng bên dưới trình phát + Kệ Cửa hàng được hiển thị. + Kệ Cửa hàng đã ẩn. Ẩn nhãn nội dung được trả tiền để quảng cáo Nhãn nội dung được trả tiền để quảng cáo đã ẩn. Nhãn nội dung được trả tiền để quảng cáo được hiển thị. @@ -143,7 +143,7 @@ Nhấn vào đây để tìm hiểu thêm về DeArrow." Ẩn kệ Phim và chương trình Kệ phim và chương trình đã ẩn. Kệ phim và chương trình được hiển thị. - Ẩn nút Thông báo cho tôi + Ẩn nút \"Thông báo cho tôi\" Nút \"Thông báo cho tôi\" đã ẩn bên dưới video sắp diễn ra. Nút \"Thông báo cho tôi\" được hiển thị bên dưới video sắp diễn ra. Ẩn kệ Chơi game trên YouTube @@ -244,7 +244,7 @@ Bộ lọc có phân biệt chữ hoa chữ thường, vì vậy bạn cần nh • Một số thành phần giao diện người dùng có thể không bị ẩn. • Tìm kiếm từ khoá có thể không cho kết quả nào." Khớp toàn bộ từ - Đặt từ/cụm từ cần lọc trong dấu ngoặc kép sẽ ngăn chặn các kết quả chỉ trùng một phần với tiêu đề video và tên kênh.<br><br>Ví dụ,<br><b>\"ai\"</b> sẽ ẩn video: <b>How does AI work?</b><br>nhưng sẽ không ẩn: <b>What does fair use mean?</b> + Đặt từ hoặc cụm từ cần lọc trong dấu ngoặc kép sẽ ngăn chặn các kết quả chỉ trùng một phần với tiêu đề video và tên kênh.<br><br>Ví dụ,<br><b>\"ai\"</b> sẽ ẩn video: <b>How does AI work?</b><br>nhưng sẽ không ẩn: <b>What does fair use mean?</b> Từ khoá không hợp lệ: %s. Hãy thêm dấu ngoặc kép để sử dụng từ khoá: %s. Từ khóa có các định nghĩa mâu thuẫn với nhau. %s. @@ -323,9 +323,6 @@ Hạn chế: Nút Quay lại trên thanh công cụ có thể không hoạt đ Tắt hoạt ảnh khi ứng dụng khởi chạy Hoạt ảnh khi ứng dụng khởi chạy đã tắt. Hoạt ảnh khi ứng dụng khởi chạy được bật. - Vô hiệu hoá thanh trạng thái trong suốt - Thanh trạng thái không còn trong suốt. - Thanh trạng thái có thể trong suốt hoặc không. Màn hình tải hiệu ứng gradient Màn hình tải hiệu ứng gradient đã bật. Màn hình tải hiệu ứng gradient đã tắt. @@ -393,13 +390,13 @@ Một số mục có thể không bị ẩn." Nút tải xuống Ghi đè nút tải xuống video - Nút tải xuống video sẽ mở trình tải xuống bên ngoài của bạn. - Nút tải xuống video sẽ mở trình tải xuống tích hợp sẵn trong ứng dụng. + Khi thao tác với nút tải xuống video sẽ mở trình tải xuống bên ngoài của bạn. + Khi thao tác với nút tải xuống video sẽ mở trình tải xuống được tích hợp sẵn của Youtube. Ghi đè nút tải xuống danh sách phát - Nút tải xuống danh sách phát sẽ luôn được hiển thị, và khi thao tác sẽ mở trình tải xuống bên ngoài đối với các danh sách phát công khai. - Nếu được hiển thị, nút tải xuống danh sách phát sẽ mở trình tải xuống tích hợp sẵn trong ứng dụng. + Nút tải xuống danh sách phát sẽ luôn được hiển thị, và đối với danh sách phát công khai, khi thao tác với nút sẽ mở trình tải xuống bên ngoài của bạn. + Nếu được hiển thị, nút tải xuống danh sách phát sẽ mở trình tải xuống được tích hợp sẵn của Youtube. Tên gói trình tải xuống danh sách phát - Nhập tên gói ứng dụng trình tải xuống đã cài đặt trên thiết bị của bạn, chẳng hạn như YTDLnis. + Chọn trình tải xuống hoặc nhập tên gói ứng dụng trình tải xuống đã được cài đặt trên thiết bị của bạn, chẳng hạn như YTDLnis. Ghi đè nút Youtube Music Nút Youtube Music sẽ mở ứng dụng RVX Music. @@ -456,7 +453,7 @@ Vuốt trình phát thu nhỏ để mở rộng hoặc đóng." Các nút tua nhanh và tua lại đã ẩn. Các nút tua nhanh và tua lại được hiển thị. Kích thước ban đầu - Nhập kích thước ban đầu trên màn hình tính bằng pixel. + Nhập kích thước ban đầu của trình phát thu nhỏ, tính bằng pixel. Kích thước pixel phải nằm trong khoảng từ %1$s tới %2$s. Độ mờ lớp phủ Giá trị độ mờ của lớp phủ trình phát thu nhỏ trong khoảng từ 0 đến 100, trong đó 0 là trong suốt. @@ -488,7 +485,7 @@ Vuốt trình phát thu nhỏ để mở rộng hoặc đóng." Ẩn tên các thẻ Tên các thẻ đã ẩn. Tên các thẻ được hiển thị. - Đổi vị trí nút Tạo và nút Thông báo + Hoán đổi nút Tạo và nút Thông báo "Nút Tạo đã được đổi vị trí với nút Thông báo. Lưu ý: Bật tuỳ chọn này cũng sẽ ẩn các quảng cáo dạng video." @@ -498,13 +495,7 @@ Lưu ý: Bật tuỳ chọn này cũng sẽ ẩn các quảng cáo dạng video. Ngoài ra, quảng cáo sẽ không còn bị chặn trong trình phát Shorts. Nếu cài đặt này không có hiệu lực, hãy thử chuyển sang chế độ Ẩn danh." - Vô hiệu hoá thanh trong suốt ở giao diện sáng - Thanh điều hướng ở giao diện sáng không còn trong suốt. - Thanh điều hướng ở giao diện sáng có thể trong suốt hoặc không. - Vô hiệu hoá thanh trong suốt ở giao diện tối - Thanh điều hướng ở giao diện tối không còn trong suốt. - Thanh điều hướng ở giao diện tối có thể trong suốt hoặc không. - Ẩn Thanh điều hướng + Ẩn thanh điều hướng Thanh điều hướng đã ẩn. Thanh điều hướng được hiển thị. @@ -1013,14 +1004,14 @@ Hạn chế: Không thể tạo danh sách phát do ID kênh không trùng khớp. Danh sách trắng Kiểm tra hoặc xóa các kênh đã thêm vào Danh sách trắng. - Kênh \'%1$s\' đã được thêm vào Danh sách trắng %2$s. - Không thể thêm kênh \'%1$s\' vào Danh sách trắng %2$s. - Kênh \'%1$s\' đã bị xóa khỏi Danh sách trắng %2$s. - Không thể xóa kênh \'%1$s\' khỏi Danh sách trắng %2$s. - Xóa kênh \'%1$s\' khỏi Danh sách trắng %2$s? - Không có kênh nào nằm trong Danh sách trắng. - Chưa được thêm vào Danh sách trắng. - Đã thêm vào Danh sách trắng. + Kênh \'%1$s\' đã được thêm vào Danh sách trắng của %2$s. + Không thêm được kênh \'%1$s\' vào Danh sách trắng của %2$s. + Kênh \'%1$s\' đã bị xóa khỏi Danh sách trắng của %2$s. + Không xóa được kênh \'%1$s\' khỏi Danh sách trắng của %2$s. + Chắc chắn xóa kênh \'%1$s\' khỏi Danh sách trắng của %2$s? + Không có kênh nào. + Chưa thêm. + Đã thêm. Tốc độ phát SponsorBlock Không tải được thông tin kênh. @@ -1134,8 +1125,8 @@ Mở rộng mô tả video có thể không hoạt động nếu bạn nhập n Trinh phát Shorts sẽ không tiếp tục khi ứng dụng khởi chạy. Trinh phát Shorts sẽ tiếp tục khi ứng dụng khởi chạy. Ẩn nút nổi - "Các nút nổi như 'Dùng âm thanh này' đã ẩn trong thẻ kênh Shorts." - "Các nút nổi như 'Dùng âm thanh này' được hiển thị trong thẻ kênh Shorts." + "Các nút nổi như \"Dùng âm thanh này\" đã ẩn trong thẻ kênh Shorts." + "Các nút nổi như \"Dùng âm thanh này\" được hiển thị trong thẻ kênh Shorts." Kệ Shorts Ẩn kệ Shorts @@ -1159,8 +1150,8 @@ Cụ thể: Ẩn trong phần Nhật ký xem. Hiển thị trong phần Nhật ký xem. - Thay đổi trạng thái lặp lại video ngắn - Thay đổi trạng thái lặp lại dưới nền của video ngắn + Thay đổi trạng thái lặp lại của video ngắn + Thay đổi trạng thái lặp lại khi phát trong nền của video ngắn Tự động phát Mặc định Dừng @@ -1198,7 +1189,7 @@ Cụ thể: Ẩn tiêu đề Trò chuyện trực tiếp Tiêu đề Trò chuyện trực tiếp đã ẩn.\n\nNút Quay lại trong tiêu đề sẽ không bị ẩn. Tiêu đề Trò chuyện trực tiếp được hiển thị.\n\nNút Quay lại trong tiêu đề sẽ không bị ẩn. - Ẩn Thanh kênh + Ẩn thanh kênh Thanh kênh đã ẩn. Thanh kênh được hiển thị. Ẩn tiêu đề video @@ -1256,9 +1247,9 @@ Cụ thể: Ẩn nút Chia sẻ Nút Chia sẻ đã ẩn. Nút Chia sẻ được hiển thị. - Nút Âm thanh - Nút âm thanh đã ẩn. - Nút âm thanh được hiển thị. + Ẩn nút Âm thanh + Nút Âm thanh đã ẩn. + Nút Âm thanh được hiển thị. Hoạt ảnh/Phản hồi Tắt hiệu ứng nút Thích @@ -1286,7 +1277,7 @@ Hạn chế: Tác vụ tuỳ chỉnh trong thanh công cụ "Tác vụ tuỳ chỉnh được bật trong thanh công cụ. -Nhấn và giữ nút Thêm để hiển thị hộp thoại Tác vụ tuỳ chỉnh." +Nhấn và giữ nút Thêm (⋮) để hiển thị hộp thoại Tác vụ tuỳ chỉnh." Tác vụ tuỳ chỉnh đã tắt trong thanh công cụ. Tác vụ tuỳ chỉnh Sao chép URL của video @@ -1312,7 +1303,7 @@ Nhấn và giữ nút Thêm để hiển thị hộp thoại Tác vụ tuỳ ch Giới thiệu về Tác vụ tuỳ chọn "Hiện tính năng này vẫn đang trong giai đoạn thử nghiệm, vì vậy không có gì đảm bảo rằng tính năng này sẽ hoạt động một cách hoàn hảo. -Hầu hết các lỗi không thể sửa được do hạn chế tới từ phía ứng dụng, vì vậy vui lòng chỉ sử dụng cho mục đích thử nghiệm." +Hầu hết các lỗi không thể sửa được do hạn chế tới từ phía ứng dụng, cuối cùng vui lòng chỉ sử dụng chúng cho mục đích thử nghiệm." Dấu thời gian "Dấu thời gian được bật. @@ -1329,7 +1320,7 @@ Hạn chế: Ẩn thanh công cụ Thanh công cụ đã ẩn. Thanh công cụ được hiển thị. - Ẩn Thanh điều hướng + Ẩn thanh điều hướng Thanh điều hướng đã ẩn. Thanh điều hướng được hiển thị. Chiều cao của khoảng trống @@ -1722,7 +1713,7 @@ Nhấp vào đây để xem các bước phát hành khóa API." Mở theo mặc định Để mở liên kết YouTube trong RVX, hãy bật \'Mở các đường liên kết được hỗ trợ\' và thêm các đường liên kết được hỗ trợ. GmsCore - Chuyển hướng tới cài đặt GmsCore và bật Cloud Messaging để nhận thông báo đẩy. + Chuyển hướng tới cài đặt MicroG và bật Cloud Messaging để nhận thông báo đẩy. GmsCore chưa được cài đặt. Hãy cài đặt nó đi nào. Hành động cần thiết "Hiện GmsCore không có quyền chạy nền. @@ -1741,9 +1732,9 @@ Nhấn vào Tiếp tục và cho phép thay đổi lựa chọn tối ưu hoá p Loại bỏ các tham số truy vấn theo dõi khỏi URL khi chia sẻ liên kết. Vô hiệu hoá giao thức QUIC "Vô hiệu hoá giao thức QUIC của CronetEngine để giảm độ trễ khi phát video." - Thay đổi giao diện chia sẻ - Sử dụng giao diện chia sẻ của hệ thống. - Sử dụng giao diện chia sẻ của ứng dụng. + Thay đổi bảng chia sẻ + Đang sử dụng bảng chia sẻ của hệ thống Android. + Đang sử dụng bảng chia sẻ trong ứng dụng Youtube. Codec OPUS Kích hoạt codec OPUS nếu phản hồi của trình phát bao gồm codec OPUS. @@ -1776,24 +1767,20 @@ Nhấn vào Tiếp tục và cho phép thay đổi lựa chọn tối ưu hoá p "Luồng dữ liệu trực tuyến chưa được giả mạo. Khi phát video có thể gặp sự cố đứng hình." Tắt cài đặt này có thể gây ra sự cố phát video. Ứng dụng khách mặc định - iOS - Music iOS - TV iOS - Android Creator Android TV Android VR + iOS + iOS TV Hạn chế - • Chưa tìm thấy. - • Phim hoặc video trả phí có thể không phát được. "• Mục Bản âm thanh bị thiếu. • Âm lượng ổn định không khả dụng. -• Tắt buộc bản âm thanh tự động không khả dụng." - Chỉ sử dụng ứng dụng khách Android - Ứng dụng khách Android được sử dụng để nạp luồng dữ liệu trực tuyến. - Ứng dụng khách Android và iOS được sử dụng để nạp luồng dữ liệu trực tuyến. +• Tắt bắt buộc bản âm thanh tự động không khả dụng." + • Chưa tìm thấy. + • Phim hoặc video trả phí có thể không phát được. Hiển thị trong Thống kê chi tiết Ứng dụng khách sử dụng để nạp luồng dữ liệu trực tuyến được hiển thị trong Thống kê chi tiết. Ứng dụng khách sử dụng để nạp luồng dữ liệu trực tuyến đã ẩn trong Thống kê chi tiết. + Nhật ký xem Thay đổi cài đặt liên quan đến nhật ký xem. diff --git a/patches/src/main/resources/youtube/translations/zh-rCN/strings.xml b/patches/src/main/resources/youtube/translations/zh-rCN/strings.xml index 81d1e8256..2a13f2e2d 100644 --- a/patches/src/main/resources/youtube/translations/zh-rCN/strings.xml +++ b/patches/src/main/resources/youtube/translations/zh-rCN/strings.xml @@ -1647,13 +1647,14 @@ "流媒体数据未伪装,视频可能无法正常播放" 关闭此选项可能会导致视频不能正常播放 默认客户端 - iOS Android TV Android VR + iOS 伪装副作用 显示统计信息 用于获取流媒体数据的客户端已在统计信息中显示 用于获取流媒体数据的客户端已在统计信息中隐藏 + 观看历史 更改与观看历史记录相关的设置 diff --git a/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml b/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml index f733605a0..e23fbf872 100644 --- a/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml +++ b/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml @@ -319,9 +319,6 @@ 停用啟動動畫 啟動動畫已停用 啟動動畫已啟用 - 禁用半透明狀態列 - 狀態列不透明。 - 狀態列是不透明或半透明的。 啟用漸變載入畫面 漸變載入畫面已啟用 漸變載入畫面已停用 @@ -494,12 +491,6 @@ 此外,廣告將不再在 Shorts 中被封鎖。 若此設定未生效,請嘗試切換至無痕模式。" - 停用淺色半透明條 - 淺色模式導覽列不透明。 - 淺色模式導覽列不透明或半透明。 - 停用深色半透明欄 - 深色模式導覽列不透明。 - 深色模式導覽列不透明或半透明。 隱藏導覽列 導覽列已隱藏。 導覽列已顯示。 @@ -1771,21 +1762,20 @@ "串流資料未偽裝。 影片可能無法播放。" 關閉此設定可能會導致影片播放問題。 預設客戶端 - iOS - iOS 音樂 - iOS TV - Android 創作者 Android 電視 Android VR + iOS + iOS TV 偽裝副作用 - • 尚未找到。 - • 電影或付費影片可能無法播放。 "• 音軌選單缺失。 • 穩定音量不可用。 • 停用強制自動音軌不可用。" + • 尚未找到。 + • 電影或付費影片可能無法播放。 顯示統計資料 用於取得串流資料的用戶端顯示在統計資料中。 用於獲取串流資料的用戶端隱藏在統計資料中。 + 觀看歷史記錄 變更與觀看歷史記錄相關的設定。 From 39a86901a2f232c56ac4bbf84a88fe58ea48a512 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 22:05:14 +0900 Subject: [PATCH 25/65] build: Bump gradle --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradlew | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fb602ee2a..e1b837a19 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=31c55713e40233a8303827ceb42ca48a47267a0ad4bab9177123121e71524c26 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionSha256Sum=7a00d51fb93147819aab76024feece20b6b84e420694101f276be952e08bef03 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f5feea6d6..f3b75f3b0 100755 --- a/gradlew +++ b/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum From 234695dd7012ad2cd0e976563fa47992ba804876 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 31 Dec 2024 22:07:24 +0900 Subject: [PATCH 26/65] bump 5.2.1-dev.1 --- README.md | 8 ++++---- gradle.properties | 2 +- patches.json | 17 +++++++++-------- patches/api/patches.api | 6 ++++++ 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1365d9be0..dcc4825c8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm | `Ambient mode control` | Adds options to disable Ambient mode and to bypass Ambient mode restrictions. | 18.29.38 ~ 19.44.39 | | `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 18.29.38 ~ 19.44.39 | | `Change player flyout menu toggles` | Adds an option to use text toggles instead of switch toggles within the additional settings menu. | 18.29.38 ~ 19.44.39 | -| `Change share sheet` | Add option to change from in-app share sheet to system share sheet. | 18.29.38 ~ 19.44.39 | +| `Change share sheet` | Adds an option to change the in-app share sheet to the system share sheet. | 18.29.38 ~ 19.44.39 | | `Change start page` | Adds an option to set which page the app opens in instead of the homepage. | 18.29.38 ~ 19.44.39 | | `Custom Shorts action buttons` | Changes, at compile time, the icon of the action buttons of the Shorts player. | 18.29.38 ~ 19.44.39 | | `Custom branding icon for YouTube` | Changes the YouTube app icon to the icon specified in patch options. | 18.29.38 ~ 19.44.39 | @@ -46,7 +46,7 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm | `Hide layout components` | Adds options to hide general layout components. | 18.29.38 ~ 19.44.39 | | `Hide player buttons` | Adds options to hide buttons in the video player. | 18.29.38 ~ 19.44.39 | | `Hide player flyout menu` | Adds options to hide player flyout menu components. | 18.29.38 ~ 19.44.39 | -| `Hide shortcuts` | Remove, at compile time, the app shortcuts that appears when app icon is long pressed. | 18.29.38 ~ 19.44.39 | +| `Hide shortcuts` | Remove, at compile time, the app shortcuts that appears when the app icon is long pressed. | 18.29.38 ~ 19.44.39 | | `Hook YouTube Music actions` | Adds support for opening music in RVX Music using the in-app YouTube Music button. | 18.29.38 ~ 19.44.39 | | `Hook download actions` | Adds support to download videos with an external downloader app using the in-app download button. | 18.29.38 ~ 19.44.39 | | `Layout switch` | Adds an option to spoof the dpi in order to use a tablet or phone layout. | 18.29.38 ~ 19.44.39 | @@ -68,7 +68,7 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm | `Spoof streaming data` | Adds options to spoof the streaming data to allow playback. | 18.29.38 ~ 19.44.39 | | `Swipe controls` | Adds options for controlling volume and brightness with swiping, and whether to enter fullscreen when swiping down below the player. | 18.29.38 ~ 19.44.39 | | `Theme` | Changes the app's theme to the values specified in patch options. | 18.29.38 ~ 19.44.39 | -| `Toolbar components` | Adds options to hide or change components located on the toolbar, such as toolbar buttons, search bar, and header. | 18.29.38 ~ 19.44.39 | +| `Toolbar components` | Adds options to hide or change components located on the toolbar, such as the search bar, header, and toolbar buttons. | 18.29.38 ~ 19.44.39 | | `Translations for YouTube` | Add translations or remove string resources. | 18.29.38 ~ 19.44.39 | | `Video playback` | Adds options to customize settings related to video playback, such as default video quality and playback speed. | 18.29.38 ~ 19.44.39 | | `Visual preferences icons for YouTube` | Adds icons to specific preferences in the settings. | 18.29.38 ~ 19.44.39 | @@ -84,7 +84,7 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm | `Bitrate default value` | Sets the audio quality to 'Always High' when you first install the app. | 6.20.51 ~ 7.25.53 | | `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 6.20.51 ~ 7.25.53 | | `Certificate spoof` | Enables YouTube Music to work with Android Auto by spoofing the YouTube Music certificate. | 6.20.51 ~ 7.25.53 | -| `Change share sheet` | Add option to change from in-app share sheet to system share sheet. | 6.20.51 ~ 7.25.53 | +| `Change share sheet` | Adds an option to change the in-app share sheet to the system share sheet. | 6.20.51 ~ 7.25.53 | | `Change start page` | Adds an option to set which page the app opens in instead of the homepage. | 6.20.51 ~ 7.25.53 | | `Custom branding icon for YouTube Music` | Changes the YouTube Music app icon to the icon specified in patch options. | 6.20.51 ~ 7.25.53 | | `Custom branding name for YouTube Music` | Renames the YouTube Music app to the name specified in patch options. | 6.20.51 ~ 7.25.53 | diff --git a/gradle.properties b/gradle.properties index 9013491db..2c56af065 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,5 +4,5 @@ org.gradle.parallel = true android.useAndroidX = true kotlin.code.style = official kotlin.jvm.target.validation.mode = IGNORE -version = 5.1.3 +version = 5.2.1-dev.1 diff --git a/patches.json b/patches.json index eac961c94..297f13633 100644 --- a/patches.json +++ b/patches.json @@ -186,7 +186,7 @@ }, { "name": "Change share sheet", - "description": "Add option to change from in-app share sheet to system share sheet.", + "description": "Adds an option to change the in-app share sheet to the system share sheet.", "use": true, "dependencies": [ "Settings for YouTube Music", @@ -207,7 +207,7 @@ }, { "name": "Change share sheet", - "description": "Add option to change from in-app share sheet to system share sheet.", + "description": "Adds an option to change the in-app share sheet to the system share sheet.", "use": true, "dependencies": [ "Settings for YouTube", @@ -364,7 +364,7 @@ { "key": "changeSplashIcon", "title": "Change splash icons", - "description": "Apply the custom branding icon to the splash screen.", + "description": "Apply the custom branding icon to the splash screen. Supports from YouTube 18.29.38 to YouTube 19.16.39.", "required": true, "type": "kotlin.Boolean", "default": true, @@ -1619,7 +1619,7 @@ }, { "name": "Hide shortcuts", - "description": "Remove, at compile time, the app shortcuts that appears when app icon is long pressed.", + "description": "Remove, at compile time, the app shortcuts that appears when the app icon is long pressed.", "use": false, "dependencies": [ "Settings for YouTube", @@ -1861,7 +1861,8 @@ "BytecodePatch", "ResourcePatch", "ResourcePatch", - "Settings for YouTube" + "Settings for YouTube", + "ResourcePatch" ], "compatiblePackages": { "com.google.android.youtube": [ @@ -1891,7 +1892,7 @@ { "key": "bottomMargin", "title": "Bottom margin", - "description": "The bottom margin for the overlay buttons and timestamp.", + "description": "The bottom margin for the overlay buttons and timestamp. Supports from YouTube 18.29.38 to YouTube 19.16.39.", "required": true, "type": "kotlin.String", "default": "2.5dip", @@ -1904,7 +1905,7 @@ { "key": "widerButtonsSpace", "title": "Wider between-buttons space", - "description": "Prevent adjacent button presses by increasing the horizontal spacing between buttons.", + "description": "Prevent adjacent button presses by increasing the horizontal spacing between buttons. Supports from YouTube 18.29.38 to YouTube 19.16.39.", "required": true, "type": "kotlin.Boolean", "default": false, @@ -2651,7 +2652,7 @@ }, { "name": "Toolbar components", - "description": "Adds options to hide or change components located on the toolbar, such as toolbar buttons, search bar, and header.", + "description": "Adds options to hide or change components located on the toolbar, such as the search bar, header, and toolbar buttons.", "use": true, "dependencies": [ "BytecodePatch", diff --git a/patches/api/patches.api b/patches/api/patches.api index d19702041..ee38b4f51 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -194,6 +194,8 @@ public final class app/revanced/patches/music/utils/playservice/VersionCheckPatc public final class app/revanced/patches/music/utils/resourceid/SharedResourceIdPatchKt { public static final fun getAccountSwitcherAccessibility ()J + public static final fun getActionBarLogo ()J + public static final fun getActionBarLogoRingo2 ()J public static final fun getBottomSheetRecyclerView ()J public static final fun getButtonContainer ()J public static final fun getButtonIconPaddingMedium ()J @@ -233,6 +235,8 @@ public final class app/revanced/patches/music/utils/resourceid/SharedResourceIdP public static final fun getTouchOutside ()J public static final fun getTrimSilenceSwitch ()J public static final fun getVarispeedUnavailableTitle ()J + public static final fun getYtmLogo ()J + public static final fun getYtmLogoRingo2 ()J public static final fun isTablet ()J } @@ -1150,6 +1154,7 @@ public final class app/revanced/util/BytecodeUtilsKt { public static final fun or (Lcom/android/tools/smali/dexlib2/AccessFlags;I)I public static final fun or (Lcom/android/tools/smali/dexlib2/AccessFlags;Lcom/android/tools/smali/dexlib2/AccessFlags;)I public static final fun parametersEqual (Ljava/lang/Iterable;Ljava/lang/Iterable;)Z + public static final fun replaceLiteralInstructionCall (Lapp/revanced/patcher/patch/BytecodePatchContext;JJ)V public static final fun replaceLiteralInstructionCall (Lapp/revanced/patcher/patch/BytecodePatchContext;JLjava/lang/String;)V public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Z)V public static synthetic fun returnEarly$default (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ZILjava/lang/Object;)V @@ -1178,6 +1183,7 @@ public final class app/revanced/util/ResourceUtilsKt { public static final fun copyXmlNode (Lapp/revanced/patcher/patch/ResourcePatchContext;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lkotlin/Unit; public static final fun copyXmlNode (Ljava/lang/String;Lapp/revanced/patcher/util/Document;Lapp/revanced/patcher/util/Document;)Ljava/lang/AutoCloseable; public static final fun doRecursively (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V + public static final fun getBooleanOptionValue (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;)Lapp/revanced/patcher/patch/Option; public static final fun getResourceGroup (Ljava/util/List;[Ljava/lang/String;)Ljava/util/List; public static final fun getStringOptionValue (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;)Lapp/revanced/patcher/patch/Option; public static final fun insertNode (Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V From 1da26645136658fae2e854907a9b371446cbb45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20Gia=20B=E1=BA=A3o?= <70064328+YT-Advanced@users.noreply.github.com> Date: Fri, 3 Jan 2025 17:26:34 +0700 Subject: [PATCH 27/65] feat(YouTube - Video playback): Improve `Disable music playback speed` setting (#117) * fix(Default Music playback speed): Fix side effect left * fix(Spoof Streaming Data): `approxDurationMs` can be fetched multiple time * fix(Spoof Streaming Data): Prevent playback issues on Kids videos with music * Up to now, there have been no recorded cases of playback issues in ANDROID_MUSIC. So it will be better to use this client instead of IOS to handle Kids video with music * Example video: https://youtu.be/bHtvEpeXrfc * fix: Apply code review suggestions * chore: Lint code --------- Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com> --- .../shared/patches/client/AppClient.kt | 27 +- .../shared/patches/client/WebClient.kt | 43 +++ .../spoof/SpoofStreamingDataPatch.java | 1 - .../patches/spoof/requests/PlayerRoutes.java | 90 ------ .../patches/spoof/requests/PlayerRoutes.kt | 147 +++++++++ .../spoof/requests/StreamingDataRequest.java | 267 ---------------- .../spoof/requests/StreamingDataRequest.kt | 299 ++++++++++++++++++ .../patches/video/PlaybackSpeedPatch.java | 48 +-- .../patches/video/requests/MusicRequest.kt | 240 ++++++++++++++ .../video/requests/PlaylistRequest.java | 205 ------------ .../extension/youtube/settings/Settings.java | 2 +- .../video/playback/VideoPlaybackPatch.kt | 2 +- .../youtube/settings/host/values/strings.xml | 10 +- .../youtube/settings/xml/revanced_prefs.xml | 2 +- 14 files changed, 772 insertions(+), 611 deletions(-) create mode 100644 extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/WebClient.kt delete mode 100644 extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java create mode 100644 extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt delete mode 100644 extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java create mode 100644 extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt create mode 100644 extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt delete mode 100644 extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt index f4728d69b..d741b51c5 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt @@ -4,6 +4,9 @@ import android.os.Build import app.revanced.extension.shared.patches.PatchStatus import app.revanced.extension.shared.settings.BaseSettings +/** + * Used to fetch streaming data. + */ object AppClient { // IOS /** @@ -46,7 +49,7 @@ object AppClient { // IOS UNPLUGGED /** - * Video not playable: Paid / Movie + * Video not playable: Paid / Movie / Playlists / Music * Note: Audio track available */ private const val PACKAGE_NAME_IOS_UNPLUGGED = "com.google.ios.youtubeunplugged" @@ -170,7 +173,6 @@ object AppClient { return BaseSettings.SPOOF_STREAMING_DATA_IOS_FORCE_AVC.get() } - @JvmStatic val availableClientTypes: Array get() = if (PatchStatus.SpoofStreamingDataMusic()) ClientType.CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC @@ -185,43 +187,35 @@ object AppClient { /** * Device model, equivalent to [Build.MODEL] (System property: ro.product.model) */ - @JvmField - val deviceModel: String? = Build.MODEL, + val deviceModel: String = Build.MODEL, /** * Device OS version, equivalent to [Build.VERSION.RELEASE] (System property: ro.system.build.version.release) */ - @JvmField - val osVersion: String? = Build.VERSION.RELEASE, + val osVersion: String = Build.VERSION.RELEASE, /** * Client user-agent. */ - @JvmField val userAgent: String, /** * Android SDK version, equivalent to [Build.VERSION.SDK] (System property: ro.build.version.sdk) * Field is null if not applicable. */ - @JvmField val androidSdkVersion: String? = null, /** * App version. */ - @JvmField val clientVersion: String, /** * If the client can access the API logged in. */ - @JvmField - val canLogin: Boolean? = true, + val canLogin: Boolean = true, /** - * If a poToken should be used. + * Whether a poToken is required to get playback for more than 1 minute. */ - @JvmField - val usePoToken: Boolean? = false, + val requirePoToken: Boolean = false, /** * Friendly name displayed in stats for nerds. */ - @JvmField val friendlyName: String ) { ANDROID_VR( @@ -260,7 +254,7 @@ object AppClient { userAgent = USER_AGENT_IOS, clientVersion = CLIENT_VERSION_IOS, canLogin = false, - usePoToken = true, + requirePoToken = true, friendlyName = if (forceAVC()) "iOS Force AVC" else @@ -274,7 +268,6 @@ object AppClient { friendlyName = "Android Music" ); - @JvmField val clientName: String = name companion object { diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/WebClient.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/WebClient.kt new file mode 100644 index 000000000..b77806c81 --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/WebClient.kt @@ -0,0 +1,43 @@ +package app.revanced.extension.shared.patches.client + +/** + * Used to fetch video information. + */ +@Suppress("unused") +object WebClient { + /** + * This user agent does not require a PoToken in [ClientType.MWEB] + * https://github.com/yt-dlp/yt-dlp/blob/0b6b7742c2e7f2a1fcb0b54ef3dd484bab404b3f/yt_dlp/extractor/youtube.py#L259 + */ + private const val USER_AGENT_SAFARI = + "Mozilla/5.0 (iPad; CPU OS 16_7_10 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1,gzip(gfe)" + + enum class ClientType( + /** + * [YouTube client type](https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients) + */ + val id: Int, + /** + * Client user-agent. + */ + @JvmField + val userAgent: String = USER_AGENT_SAFARI, + /** + * Client version. + */ + @JvmField + val clientVersion: String + ) { + MWEB( + id = 2, + clientVersion = "2.20241202.07.00" + ), + WEB_REMIX( + id = 29, + clientVersion = "1.20241127.01.00", + ); + + @JvmField + val clientName: String = name + } +} diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java index a067331a6..860728123 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java @@ -222,7 +222,6 @@ public class SpoofStreamingDataPatch { final Long approxDurationMs = approxDurationMsMap.get(videoId); if (approxDurationMs != null) { Logger.printDebug(() -> "Replacing video length: " + approxDurationMs + " for videoId: " + videoId); - approxDurationMsMap.remove(videoId); return approxDurationMs; } } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java deleted file mode 100644 index 18e01840a..000000000 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java +++ /dev/null @@ -1,90 +0,0 @@ -package app.revanced.extension.shared.patches.spoof.requests; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.IOException; -import java.net.HttpURLConnection; - -import app.revanced.extension.shared.patches.client.AppClient.ClientType; -import app.revanced.extension.shared.requests.Requester; -import app.revanced.extension.shared.requests.Route; -import app.revanced.extension.shared.utils.Logger; -import app.revanced.extension.shared.utils.Utils; - -@SuppressWarnings({"ExtractMethodRecommender", "deprecation"}) -public final class PlayerRoutes { - public static final Route.CompiledRoute GET_PLAYLIST_PAGE = new Route( - Route.Method.POST, - "next" + - "?fields=contents.singleColumnWatchNextResults.playlist.playlist" - ).compile(); - static final Route.CompiledRoute GET_STREAMING_DATA = new Route( - Route.Method.POST, - "player" + - "?fields=streamingData" + - "&alt=proto" - ).compile(); - private static final String YT_API_URL = "https://youtubei.googleapis.com/youtubei/v1/"; - /** - * TCP connection and HTTP read timeout - */ - private static final int CONNECTION_TIMEOUT_MILLISECONDS = 10 * 1000; // 10 Seconds. - - private static final String LOCALE_LANGUAGE = Utils.getContext().getResources() - .getConfiguration().locale.getLanguage(); - - private PlayerRoutes() { - } - - public static JSONObject createInnertubeBody(ClientType clientType) { - JSONObject innerTubeBody = new JSONObject(); - - try { - JSONObject client = new JSONObject(); - client.put("clientName", clientType.clientName); - client.put("clientVersion", clientType.clientVersion); - client.put("deviceModel", clientType.deviceModel); - client.put("osVersion", clientType.osVersion); - if (clientType.androidSdkVersion != null) { - client.put("androidSdkVersion", clientType.androidSdkVersion); - client.put("osName", "Android"); - } else { - client.put("deviceMake", "Apple"); - client.put("osName", "iOS"); - } - if (!clientType.canLogin) { - client.put("hl", LOCALE_LANGUAGE); - } - - JSONObject context = new JSONObject(); - context.put("client", client); - - innerTubeBody.put("context", context); - innerTubeBody.put("contentCheckOk", true); - innerTubeBody.put("racyCheckOk", true); - innerTubeBody.put("videoId", "%s"); - } catch (JSONException e) { - Logger.printException(() -> "Failed to create innerTubeBody", e); - } - - return innerTubeBody; - } - - /** - * @noinspection SameParameterValue - */ - public static HttpURLConnection getPlayerResponseConnectionFromRoute(Route.CompiledRoute route, ClientType clientType) throws IOException { - var connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route); - - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("User-Agent", clientType.userAgent); - - connection.setUseCaches(false); - connection.setDoOutput(true); - - connection.setConnectTimeout(CONNECTION_TIMEOUT_MILLISECONDS); - connection.setReadTimeout(CONNECTION_TIMEOUT_MILLISECONDS); - return connection; - } -} \ No newline at end of file diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt new file mode 100644 index 000000000..36bf03e01 --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt @@ -0,0 +1,147 @@ +package app.revanced.extension.shared.patches.spoof.requests + +import app.revanced.extension.shared.patches.client.AppClient +import app.revanced.extension.shared.patches.client.WebClient +import app.revanced.extension.shared.requests.Requester +import app.revanced.extension.shared.requests.Route +import app.revanced.extension.shared.requests.Route.CompiledRoute +import app.revanced.extension.shared.utils.Logger +import app.revanced.extension.shared.utils.Utils +import org.apache.commons.lang3.StringUtils +import org.json.JSONException +import org.json.JSONObject +import java.io.IOException +import java.net.HttpURLConnection +import java.nio.charset.StandardCharsets + +@Suppress("deprecation") +object PlayerRoutes { + @JvmField + val GET_CATEGORY: CompiledRoute = Route( + Route.Method.POST, + "player" + + "?fields=microformat.playerMicroformatRenderer.category" + ).compile() + + @JvmField + val GET_PLAYLIST_PAGE: CompiledRoute = Route( + Route.Method.POST, + "next" + + "?fields=contents.singleColumnWatchNextResults.playlist.playlist" + ).compile() + + @JvmField + val GET_STREAMING_DATA: CompiledRoute = Route( + Route.Method.POST, + "player" + + "?fields=streamingData" + + "&alt=proto" + ).compile() + + private const val YT_API_URL = "https://youtubei.googleapis.com/youtubei/v1/" + + /** + * TCP connection and HTTP read timeout + */ + private const val CONNECTION_TIMEOUT_MILLISECONDS = 10 * 1000 // 10 Seconds. + + private val LOCALE_LANGUAGE: String = Utils.getContext().resources + .configuration.locale.language + + @JvmStatic + fun createApplicationRequestBody( + clientType: AppClient.ClientType, + videoId: String, + playlistId: String? = null, + botGuardPoToken: String? = null, + visitorId: String? = null, + ): ByteArray { + val innerTubeBody = JSONObject() + + try { + val client = JSONObject() + client.put("clientName", clientType.clientName) + client.put("clientVersion", clientType.clientVersion) + client.put("deviceModel", clientType.deviceModel) + client.put("osVersion", clientType.osVersion) + if (clientType.androidSdkVersion != null) { + client.put("androidSdkVersion", clientType.androidSdkVersion) + client.put("osName", "Android") + } else { + client.put("deviceMake", "Apple") + client.put("osName", "iOS") + } + if (!clientType.canLogin) { + client.put("hl", LOCALE_LANGUAGE) + } + + val context = JSONObject() + context.put("client", client) + + innerTubeBody.put("context", context) + innerTubeBody.put("contentCheckOk", true) + innerTubeBody.put("racyCheckOk", true) + innerTubeBody.put("videoId", videoId) + + if (playlistId != null) { + innerTubeBody.put("playlistId", playlistId) + } + + if (!StringUtils.isAnyEmpty(botGuardPoToken, visitorId)) { + val serviceIntegrityDimensions = JSONObject() + serviceIntegrityDimensions.put("poToken", botGuardPoToken) + innerTubeBody.put("serviceIntegrityDimensions", serviceIntegrityDimensions) + } + } catch (e: JSONException) { + Logger.printException({ "Failed to create application innerTubeBody" }, e) + } + + return innerTubeBody.toString().toByteArray(StandardCharsets.UTF_8) + } + + @JvmStatic + fun createWebInnertubeBody( + clientType: WebClient.ClientType, + videoId: String + ): ByteArray { + val innerTubeBody = JSONObject() + + try { + val client = JSONObject() + client.put("clientName", clientType.clientName) + client.put("clientVersion", clientType.clientVersion) + val context = JSONObject() + context.put("client", client) + + val lockedSafetyMode = JSONObject() + lockedSafetyMode.put("lockedSafetyMode", false) + val user = JSONObject() + user.put("user", lockedSafetyMode) + + innerTubeBody.put("context", context) + innerTubeBody.put("contentCheckOk", true) + innerTubeBody.put("racyCheckOk", true) + innerTubeBody.put("videoId", videoId) + } catch (e: JSONException) { + Logger.printException({ "Failed to create web innerTubeBody" }, e) + } + + return innerTubeBody.toString().toByteArray(StandardCharsets.UTF_8) + } + + @JvmStatic + @Throws(IOException::class) + fun getPlayerResponseConnectionFromRoute(route: CompiledRoute, userAgent: String): HttpURLConnection { + val connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route) + + connection.setRequestProperty("Content-Type", "application/json") + connection.setRequestProperty("User-Agent", userAgent) + + connection.useCaches = false + connection.doOutput = true + + connection.connectTimeout = CONNECTION_TIMEOUT_MILLISECONDS + connection.readTimeout = CONNECTION_TIMEOUT_MILLISECONDS + return connection + } +} \ No newline at end of file diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java deleted file mode 100644 index b4da8c61c..000000000 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.java +++ /dev/null @@ -1,267 +0,0 @@ -package app.revanced.extension.shared.patches.spoof.requests; - -import static app.revanced.extension.shared.patches.client.AppClient.getAvailableClientTypes; -import static app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.GET_STREAMING_DATA; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.apache.commons.lang3.ArrayUtils; -import org.json.JSONObject; - -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.SocketTimeoutException; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import app.revanced.extension.shared.patches.client.AppClient.ClientType; -import app.revanced.extension.shared.settings.BaseSettings; -import app.revanced.extension.shared.utils.Logger; -import app.revanced.extension.shared.utils.Utils; - -/** - * Video streaming data. Fetching is tied to the behavior YT uses, - * where this class fetches the streams only when YT fetches. - *

- * Effectively the cache expiration of these fetches is the same as the stock app, - * since the stock app would not use expired streams and therefor - * the extension replace stream hook is called only if YT - * did use its own client streams. - */ -public class StreamingDataRequest { - - private static final ClientType[] CLIENT_ORDER_TO_USE; - private static final String AUTHORIZATION_HEADER = "Authorization"; - private static final String VISITOR_ID_HEADER = "X-Goog-Visitor-Id"; - private static final String[] REQUEST_HEADER_KEYS = { - AUTHORIZATION_HEADER, // Available only to logged-in users. - "X-GOOG-API-FORMAT-VERSION", - VISITOR_ID_HEADER - }; - private static ClientType lastSpoofedClientType; - - - /** - * TCP connection and HTTP read timeout. - */ - private static final int HTTP_TIMEOUT_MILLISECONDS = 10 * 1000; - /** - * Any arbitrarily large value, but must be at least twice {@link #HTTP_TIMEOUT_MILLISECONDS} - */ - private static final int MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000; - private static final Map cache = Collections.synchronizedMap( - new LinkedHashMap<>(100) { - /** - * Cache limit must be greater than the maximum number of videos open at once, - * which theoretically is more than 4 (3 Shorts + one regular minimized video). - * But instead use a much larger value, to handle if a video viewed a while ago - * is somehow still referenced. Each stream is a small array of Strings - * so memory usage is not a concern. - */ - private static final int CACHE_LIMIT = 50; - - @Override - protected boolean removeEldestEntry(Entry eldest) { - return size() > CACHE_LIMIT; // Evict the oldest entry if over the cache limit. - } - }); - - public static String getLastSpoofedClientName() { - return lastSpoofedClientType == null - ? "Unknown" - : lastSpoofedClientType.friendlyName; - } - - static { - ClientType[] allClientTypes = getAvailableClientTypes(); - ClientType preferredClient = BaseSettings.SPOOF_STREAMING_DATA_TYPE.get(); - - if (ArrayUtils.indexOf(allClientTypes, preferredClient) < 0) { - CLIENT_ORDER_TO_USE = allClientTypes; - } else { - CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length]; - CLIENT_ORDER_TO_USE[0] = preferredClient; - - int i = 1; - for (ClientType c : allClientTypes) { - if (c != preferredClient) { - CLIENT_ORDER_TO_USE[i++] = c; - } - } - } - } - - private final String videoId; - private final Future future; - - private StreamingDataRequest(String videoId, Map playerHeaders, String visitorId, - String botGuardPoToken, String droidGuardPoToken) { - Objects.requireNonNull(playerHeaders); - this.videoId = videoId; - this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId, playerHeaders, visitorId, botGuardPoToken, droidGuardPoToken)); - } - - public static void fetchRequest(String videoId, Map fetchHeaders, String visitorId, - String botGuardPoToken, String droidGuardPoToken) { - // Always fetch, even if there is an existing request for the same video. - cache.put(videoId, new StreamingDataRequest(videoId, fetchHeaders, visitorId, botGuardPoToken, droidGuardPoToken)); - } - - @Nullable - public static StreamingDataRequest getRequestForVideoId(String videoId) { - return cache.get(videoId); - } - - private static void handleConnectionError(String toastMessage, @Nullable Exception ex) { - Logger.printInfo(() -> toastMessage, ex); - } - - @Nullable - private static HttpURLConnection send(ClientType clientType, String videoId, Map playerHeaders, - String visitorId, String botGuardPoToken, String droidGuardPoToken) { - Objects.requireNonNull(clientType); - Objects.requireNonNull(videoId); - Objects.requireNonNull(playerHeaders); - - final long startTime = System.currentTimeMillis(); - Logger.printDebug(() -> "Fetching video streams for: " + videoId + " using client: " + clientType); - - try { - HttpURLConnection connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(GET_STREAMING_DATA, clientType); - connection.setConnectTimeout(HTTP_TIMEOUT_MILLISECONDS); - connection.setReadTimeout(HTTP_TIMEOUT_MILLISECONDS); - - for (String key : REQUEST_HEADER_KEYS) { - String value = playerHeaders.get(key); - if (value != null) { - if (key.equals(AUTHORIZATION_HEADER)) { - if (!clientType.canLogin) { - Logger.printDebug(() -> "Not including request header: " + key); - continue; - } - } - if (key.equals(VISITOR_ID_HEADER) && - clientType.usePoToken && - !botGuardPoToken.isEmpty() && - !visitorId.isEmpty()) { - String originalVisitorId = value; - Logger.printDebug(() -> "Original visitor id:\n" + originalVisitorId); - Logger.printDebug(() -> "Replaced visitor id:\n" + visitorId); - value = visitorId; - } - - connection.setRequestProperty(key, value); - } - } - - JSONObject innerTubeBodyJson = PlayerRoutes.createInnertubeBody(clientType); - if (clientType.usePoToken && !botGuardPoToken.isEmpty() && !visitorId.isEmpty()) { - JSONObject serviceIntegrityDimensions = new JSONObject(); - serviceIntegrityDimensions.put("poToken", botGuardPoToken); - innerTubeBodyJson.put("serviceIntegrityDimensions", serviceIntegrityDimensions); - if (!droidGuardPoToken.isEmpty()) { - Logger.printDebug(() -> "Original poToken (droidGuardPoToken):\n" + droidGuardPoToken); - } - Logger.printDebug(() -> "Replaced poToken (botGuardPoToken):\n" + botGuardPoToken); - } - - String innerTubeBody = String.format(innerTubeBodyJson.toString(), videoId); - byte[] requestBody = innerTubeBody.getBytes(StandardCharsets.UTF_8); - connection.setFixedLengthStreamingMode(requestBody.length); - connection.getOutputStream().write(requestBody); - - final int responseCode = connection.getResponseCode(); - if (responseCode == 200) return connection; - - // This situation likely means the patches are outdated. - // Use a toast message that suggests updating. - handleConnectionError("Playback error (App is outdated?) " + clientType + ": " - + responseCode + " response: " + connection.getResponseMessage(), - null); - } catch (SocketTimeoutException ex) { - handleConnectionError("Connection timeout", ex); - } catch (IOException ex) { - handleConnectionError("Network error", ex); - } catch (Exception ex) { - Logger.printException(() -> "send failed", ex); - } finally { - Logger.printDebug(() -> "video: " + videoId + " took: " + (System.currentTimeMillis() - startTime) + "ms"); - } - - return null; - } - - private static ByteBuffer fetch(String videoId, Map playerHeaders, String visitorId, - String botGuardPoToken, String droidGuardPoToken) { - lastSpoofedClientType = null; - - // Retry with different client if empty response body is received. - for (ClientType clientType : CLIENT_ORDER_TO_USE) { - HttpURLConnection connection = send(clientType, videoId, playerHeaders, visitorId, botGuardPoToken, droidGuardPoToken); - if (connection != null) { - try { - // gzip encoding doesn't response with content length (-1), - // but empty response body does. - if (connection.getContentLength() == 0) { - Logger.printDebug(() -> "Received empty response" + "\nClient: " + clientType + "\nVideo: " + videoId); - } else { - try (InputStream inputStream = new BufferedInputStream(connection.getInputStream()); - ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - byte[] buffer = new byte[2048]; - int bytesRead; - while ((bytesRead = inputStream.read(buffer)) >= 0) { - baos.write(buffer, 0, bytesRead); - } - lastSpoofedClientType = clientType; - - return ByteBuffer.wrap(baos.toByteArray()); - } - } - } catch (IOException ex) { - Logger.printException(() -> "Fetch failed while processing response data", ex); - } - } - } - - handleConnectionError("Could not fetch any client streams", null); - return null; - } - - public boolean fetchCompleted() { - return future.isDone(); - } - - @Nullable - public ByteBuffer getStream() { - try { - return future.get(MAX_MILLISECONDS_TO_WAIT_FOR_FETCH, TimeUnit.MILLISECONDS); - } catch (TimeoutException ex) { - Logger.printInfo(() -> "getStream timed out", ex); - } catch (InterruptedException ex) { - Logger.printException(() -> "getStream interrupted", ex); - Thread.currentThread().interrupt(); // Restore interrupt status flag. - } catch (ExecutionException ex) { - Logger.printException(() -> "getStream failure", ex); - } - - return null; - } - - @NonNull - @Override - public String toString() { - return "StreamingDataRequest{" + "videoId='" + videoId + '\'' + '}'; - } -} diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt new file mode 100644 index 000000000..1d6837b9f --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt @@ -0,0 +1,299 @@ +package app.revanced.extension.shared.patches.spoof.requests + +import androidx.annotation.GuardedBy +import app.revanced.extension.shared.patches.client.AppClient +import app.revanced.extension.shared.patches.client.AppClient.availableClientTypes +import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.GET_STREAMING_DATA +import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.createApplicationRequestBody +import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.getPlayerResponseConnectionFromRoute +import app.revanced.extension.shared.settings.BaseSettings +import app.revanced.extension.shared.utils.Logger +import app.revanced.extension.shared.utils.Utils +import org.apache.commons.lang3.ArrayUtils +import org.apache.commons.lang3.StringUtils +import java.io.BufferedInputStream +import java.io.ByteArrayOutputStream +import java.io.IOException +import java.net.HttpURLConnection +import java.net.SocketTimeoutException +import java.nio.ByteBuffer +import java.util.Collections +import java.util.Objects +import java.util.concurrent.ExecutionException +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException + +/** + * Video streaming data. Fetching is tied to the behavior YT uses, + * where this class fetches the streams only when YT fetches. + * + * Effectively the cache expiration of these fetches is the same as the stock app, + * since the stock app would not use expired streams and therefor + * the extension replace stream hook is called only if YT + * did use its own client streams. + */ +class StreamingDataRequest private constructor( + videoId: String, playerHeaders: Map, visitorId: String, + botGuardPoToken: String, droidGuardPoToken: String +) { + private val videoId: String + private val future: Future + + init { + Objects.requireNonNull(playerHeaders) + this.videoId = videoId + this.future = Utils.submitOnBackgroundThread { + fetch( + videoId, + playerHeaders, + visitorId, + botGuardPoToken, + droidGuardPoToken + ) + } + } + + fun fetchCompleted(): Boolean { + return future.isDone + } + + val stream: ByteBuffer? + get() { + try { + return future[MAX_MILLISECONDS_TO_WAIT_FOR_FETCH.toLong(), TimeUnit.MILLISECONDS] + } catch (ex: TimeoutException) { + Logger.printInfo( + { "getStream timed out" }, + ex + ) + } catch (ex: InterruptedException) { + Logger.printException( + { "getStream interrupted" }, + ex + ) + Thread.currentThread().interrupt() // Restore interrupt status flag. + } catch (ex: ExecutionException) { + Logger.printException( + { "getStream failure" }, + ex + ) + } + + return null + } + + override fun toString(): String { + return "StreamingDataRequest{videoId='$videoId'}" + } + + companion object { + private var CLIENT_ORDER_TO_USE: Array + private const val AUTHORIZATION_HEADER = "Authorization" + private const val VISITOR_ID_HEADER = "X-Goog-Visitor-Id" + private val REQUEST_HEADER_KEYS = arrayOf( + AUTHORIZATION_HEADER, // Available only to logged-in users. + "X-GOOG-API-FORMAT-VERSION", + VISITOR_ID_HEADER + ) + private var lastSpoofedClientType: AppClient.ClientType? = null + + + /** + * TCP connection and HTTP read timeout. + */ + private const val HTTP_TIMEOUT_MILLISECONDS = 10 * 1000 + + /** + * Any arbitrarily large value, but must be at least twice [.HTTP_TIMEOUT_MILLISECONDS] + */ + private const val MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000 + @GuardedBy("itself") + val cache: MutableMap = Collections.synchronizedMap( + object : LinkedHashMap(100) { + /** + * Cache limit must be greater than the maximum number of videos open at once, + * which theoretically is more than 4 (3 Shorts + one regular minimized video). + * But instead use a much larger value, to handle if a video viewed a while ago + * is somehow still referenced. Each stream is a small array of Strings + * so memory usage is not a concern. + */ + private val CACHE_LIMIT = 50 + + override fun removeEldestEntry(eldest: Map.Entry): Boolean { + return size > CACHE_LIMIT // Evict the oldest entry if over the cache limit. + } + }) + + @JvmStatic + val lastSpoofedClientName: String + get() = lastSpoofedClientType + ?.friendlyName + ?: "Unknown" + + init { + val allClientTypes: Array = availableClientTypes + val preferredClient = BaseSettings.SPOOF_STREAMING_DATA_TYPE.get() + + CLIENT_ORDER_TO_USE = allClientTypes + if (ArrayUtils.indexOf(allClientTypes, preferredClient) >= 0) { + CLIENT_ORDER_TO_USE[0] = preferredClient + var i = 1 + for (c in allClientTypes) { + if (c != preferredClient) { + CLIENT_ORDER_TO_USE[i++] = c + } + } + } + } + + @JvmStatic + fun fetchRequest( + videoId: String, fetchHeaders: Map, visitorId: String, + botGuardPoToken: String, droidGuardPoToken: String + ) { + // Always fetch, even if there is an existing request for the same video. + cache[videoId] = + StreamingDataRequest( + videoId, + fetchHeaders, + visitorId, + botGuardPoToken, + droidGuardPoToken + ) + } + + @JvmStatic + fun getRequestForVideoId(videoId: String): StreamingDataRequest? { + return cache[videoId] + } + + private fun handleConnectionError(toastMessage: String, ex: Exception?) { + Logger.printInfo({ toastMessage }, ex) + } + + private fun send( + clientType: AppClient.ClientType, videoId: String, playerHeaders: Map, + visitorId: String, botGuardPoToken: String, droidGuardPoToken: String + ): HttpURLConnection? { + Objects.requireNonNull(clientType) + Objects.requireNonNull(videoId) + Objects.requireNonNull(playerHeaders) + + val startTime = System.currentTimeMillis() + Logger.printDebug { "Fetching video streams for: $videoId using client: $clientType" } + + try { + val connection = getPlayerResponseConnectionFromRoute(GET_STREAMING_DATA, clientType.userAgent) + connection.connectTimeout = HTTP_TIMEOUT_MILLISECONDS + connection.readTimeout = HTTP_TIMEOUT_MILLISECONDS + + val usePoToken = clientType.requirePoToken && !StringUtils.isAnyEmpty(botGuardPoToken, visitorId) + + for (key in REQUEST_HEADER_KEYS) { + var value = playerHeaders[key] + if (value != null) { + if (key == AUTHORIZATION_HEADER) { + if (!clientType.canLogin) { + Logger.printDebug { "Not including request header: $key" } + continue + } + } + if (key == VISITOR_ID_HEADER && usePoToken) { + val originalVisitorId: String = value + Logger.printDebug { "Original visitor id:\n$originalVisitorId" } + Logger.printDebug { "Replaced visitor id:\n$visitorId" } + value = visitorId + } + + connection.setRequestProperty(key, value) + } + } + + val requestBody: ByteArray + if (usePoToken) { + requestBody = createApplicationRequestBody( + clientType = clientType, + videoId = videoId, + botGuardPoToken = botGuardPoToken, + visitorId = visitorId + ) + if (droidGuardPoToken.isNotEmpty()) { + Logger.printDebug { "Original poToken (droidGuardPoToken):\n$droidGuardPoToken" } + } + Logger.printDebug { "Replaced poToken (botGuardPoToken):\n$botGuardPoToken" } + } else { + requestBody = + createApplicationRequestBody(clientType = clientType, videoId = videoId) + } + connection.setFixedLengthStreamingMode(requestBody.size) + connection.outputStream.write(requestBody) + + val responseCode = connection.responseCode + if (responseCode == 200) return connection + + // This situation likely means the patches are outdated. + // Use a toast message that suggests updating. + handleConnectionError( + ("Playback error (App is outdated?) " + clientType + ": " + + responseCode + " response: " + connection.responseMessage), + null + ) + } catch (ex: SocketTimeoutException) { + handleConnectionError("Connection timeout", ex) + } catch (ex: IOException) { + handleConnectionError("Network error", ex) + } catch (ex: Exception) { + Logger.printException({ "send failed" }, ex) + } finally { + Logger.printDebug { "video: " + videoId + " took: " + (System.currentTimeMillis() - startTime) + "ms" } + } + + return null + } + + private fun fetch( + videoId: String, playerHeaders: Map, visitorId: String, + botGuardPoToken: String, droidGuardPoToken: String + ): ByteBuffer? { + lastSpoofedClientType = null + + // Retry with different client if empty response body is received. + for (clientType in CLIENT_ORDER_TO_USE) { + send( + clientType, + videoId, + playerHeaders, + visitorId, + botGuardPoToken, + droidGuardPoToken + )?.let { connection -> + try { + // gzip encoding doesn't response with content length (-1), + // but empty response body does. + if (connection.contentLength == 0) { + Logger.printDebug { "Received empty response\nClient: $clientType\nVideo: $videoId" } + } else { + BufferedInputStream(connection.inputStream).use { inputStream -> + ByteArrayOutputStream().use { stream -> + val buffer = ByteArray(2048) + var bytesRead: Int + while ((inputStream.read(buffer).also { bytesRead = it }) >= 0) { + stream.write(buffer, 0, bytesRead) + } + lastSpoofedClientType = clientType + return ByteBuffer.wrap(stream.toByteArray()) + } + } + } + } catch (ex: IOException) { + Logger.printException({ "Fetch failed while processing response data" }, ex) + } + } + } + + handleConnectionError("Could not fetch any client streams", null) + return null + } + } +} diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/PlaybackSpeedPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/PlaybackSpeedPatch.java index ca2ad8fc1..5211c6a47 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/PlaybackSpeedPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/PlaybackSpeedPatch.java @@ -10,13 +10,15 @@ import org.apache.commons.lang3.BooleanUtils; import app.revanced.extension.shared.utils.Logger; import app.revanced.extension.shared.utils.Utils; import app.revanced.extension.youtube.patches.utils.PatchStatus; -import app.revanced.extension.youtube.patches.video.requests.PlaylistRequest; +import app.revanced.extension.youtube.patches.video.requests.MusicRequest; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.VideoInformation; import app.revanced.extension.youtube.whitelist.Whitelist; @SuppressWarnings("unused") public class PlaybackSpeedPatch { + private static final boolean DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC = + Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC.get(); private static final long TOAST_DELAY_MILLISECONDS = 750; private static long lastTimeSpeedChanged; private static boolean isLiveStream; @@ -39,8 +41,8 @@ public class PlaybackSpeedPatch { /** * Injection point. */ - public static void fetchPlaylistData(@NonNull String videoId, boolean isShortAndOpeningOrPlaying) { - if (Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC.get()) { + public static void fetchMusicRequest(@NonNull String videoId, boolean isShortAndOpeningOrPlaying) { + if (DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC) { try { final boolean videoIdIsShort = VideoInformation.lastPlayerResponseIsShort(); // Shorts shelf in home and subscription feed causes player response hook to be called, @@ -50,9 +52,12 @@ public class PlaybackSpeedPatch { return; } - PlaylistRequest.fetchRequestIfNeeded(videoId); + MusicRequest.fetchRequestIfNeeded( + videoId, + Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC_TYPE.get() + ); } catch (Exception ex) { - Logger.printException(() -> "fetchPlaylistData failure", ex); + Logger.printException(() -> "fetchMusicRequest failure", ex); } } } @@ -61,15 +66,16 @@ public class PlaybackSpeedPatch { * Injection point. */ public static float getPlaybackSpeedInShorts(final float playbackSpeed) { - if (!VideoInformation.lastPlayerResponseIsShort()) - return playbackSpeed; - if (!Settings.ENABLE_DEFAULT_PLAYBACK_SPEED_SHORTS.get()) - return playbackSpeed; + if (VideoInformation.lastPlayerResponseIsShort() && + Settings.ENABLE_DEFAULT_PLAYBACK_SPEED_SHORTS.get() + ) { + float defaultPlaybackSpeed = getDefaultPlaybackSpeed(VideoInformation.getChannelId(), null); + Logger.printDebug(() -> "overridePlaybackSpeed in Shorts: " + defaultPlaybackSpeed); - float defaultPlaybackSpeed = getDefaultPlaybackSpeed(VideoInformation.getChannelId(), null); - Logger.printDebug(() -> "overridePlaybackSpeed in Shorts: " + defaultPlaybackSpeed); + return defaultPlaybackSpeed; + } - return defaultPlaybackSpeed; + return playbackSpeed; } /** @@ -118,23 +124,21 @@ public class PlaybackSpeedPatch { } private static float getDefaultPlaybackSpeed(@NonNull String channelId, @Nullable String videoId) { - return (Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_LIVE.get() && isLiveStream) || - Whitelist.isChannelWhitelistedPlaybackSpeed(channelId) || - getPlaylistData(videoId) + return (isLiveStream || Whitelist.isChannelWhitelistedPlaybackSpeed(channelId) || isMusic(videoId)) ? 1.0f : Settings.DEFAULT_PLAYBACK_SPEED.get(); } - private static boolean getPlaylistData(@Nullable String videoId) { - if (Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC.get() && videoId != null) { + private static boolean isMusic(@Nullable String videoId) { + if (DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC && videoId != null) { try { - PlaylistRequest request = PlaylistRequest.getRequestForVideoId(videoId); - final boolean isPlaylist = request != null && BooleanUtils.toBoolean(request.getStream()); - Logger.printDebug(() -> "isPlaylist: " + isPlaylist); + MusicRequest request = MusicRequest.getRequestForVideoId(videoId); + final boolean isMusic = request != null && BooleanUtils.toBoolean(request.getStream()); + Logger.printDebug(() -> "videoId: " + videoId + ", isMusic: " + isMusic); - return isPlaylist; + return isMusic; } catch (Exception ex) { - Logger.printException(() -> "getPlaylistData failure", ex); + Logger.printException(() -> "getMusicRequest failure", ex); } } diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt new file mode 100644 index 000000000..72d765c16 --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt @@ -0,0 +1,240 @@ +package app.revanced.extension.youtube.patches.video.requests + +import android.annotation.SuppressLint +import androidx.annotation.GuardedBy +import app.revanced.extension.shared.patches.client.AppClient +import app.revanced.extension.shared.patches.client.WebClient +import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes +import app.revanced.extension.shared.requests.Requester +import app.revanced.extension.shared.utils.Logger +import app.revanced.extension.shared.utils.Utils +import app.revanced.extension.youtube.shared.VideoInformation +import org.json.JSONException +import org.json.JSONObject +import java.io.IOException +import java.net.SocketTimeoutException +import java.util.Objects +import java.util.concurrent.ExecutionException +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException + +class MusicRequest private constructor(private val videoId: String, private val checkCategory: Boolean) { + /** + * Time this instance and the fetch future was created. + */ + private val timeFetched = System.currentTimeMillis() + private val future: Future = Utils.submitOnBackgroundThread { + fetch( + videoId, + checkCategory, + ) + } + + fun isExpired(now: Long): Boolean { + val timeSinceCreation = now - timeFetched + if (timeSinceCreation > CACHE_RETENTION_TIME_MILLISECONDS) { + return true + } + + // Only expired if the fetch failed (API null response). + return (fetchCompleted() && stream == null) + } + + /** + * @return if the fetch call has completed. + */ + private fun fetchCompleted(): Boolean { + return future.isDone + } + + val stream: Boolean? + get() { + try { + return future[MAX_MILLISECONDS_TO_WAIT_FOR_FETCH, TimeUnit.MILLISECONDS] + } catch (ex: TimeoutException) { + Logger.printInfo( + { "getStream timed out" }, + ex + ) + } catch (ex: InterruptedException) { + Logger.printException( + { "getStream interrupted" }, + ex + ) + Thread.currentThread().interrupt() // Restore interrupt status flag. + } catch (ex: ExecutionException) { + Logger.printException( + { "getStream failure" }, + ex + ) + } + + return null + } + + companion object { + /** + * How long to keep fetches until they are expired. + */ + private const val CACHE_RETENTION_TIME_MILLISECONDS = 60 * 1000L // 1 Minute + + private const val MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000L // 20 seconds + + @GuardedBy("itself") + private val cache: MutableMap = HashMap() + + @JvmStatic + @SuppressLint("ObsoleteSdkInt") + fun fetchRequestIfNeeded(videoId: String, checkCategory: Boolean) { + Objects.requireNonNull(videoId) + synchronized(cache) { + val now = System.currentTimeMillis() + cache.values.removeIf { request: MusicRequest -> + val expired = request.isExpired(now) + if (expired) Logger.printDebug { "Removing expired stream: " + request.videoId } + expired + } + if (!cache.containsKey(videoId)) { + cache[videoId] = MusicRequest(videoId, checkCategory) + } + } + } + + @JvmStatic + fun getRequestForVideoId(videoId: String): MusicRequest? { + synchronized(cache) { + return cache[videoId] + } + } + + private fun handleConnectionError(toastMessage: String, ex: Exception?) { + Logger.printInfo({ toastMessage }, ex) + } + + private fun sendApplicationRequest(videoId: String): JSONObject? { + Objects.requireNonNull(videoId) + + val startTime = System.currentTimeMillis() + val clientType = AppClient.ClientType.ANDROID_VR + val clientTypeName = clientType.name + Logger.printDebug { "Fetching playlist request for: $videoId using client: $clientTypeName" } + + try { + val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(PlayerRoutes.GET_PLAYLIST_PAGE, clientType.userAgent) + val requestBody = + PlayerRoutes.createApplicationRequestBody(clientType, videoId, "RD$videoId") + + connection.setFixedLengthStreamingMode(requestBody.size) + connection.outputStream.write(requestBody) + + val responseCode = connection.responseCode + if (responseCode == 200) return Requester.parseJSONObject(connection) + + handleConnectionError( + (clientTypeName + " not available with response code: " + + responseCode + " message: " + connection.responseMessage), + null + ) + } catch (ex: SocketTimeoutException) { + handleConnectionError("Connection timeout", ex) + } catch (ex: IOException) { + handleConnectionError("Network error", ex) + } catch (ex: Exception) { + Logger.printException({ "sendApplicationRequest failed" }, ex) + } finally { + Logger.printDebug { "video: " + videoId + " took: " + (System.currentTimeMillis() - startTime) + "ms" } + } + + return null + } + + private fun sendWebRequest(videoId: String): JSONObject? { + Objects.requireNonNull(videoId) + + val startTime = System.currentTimeMillis() + val clientType = WebClient.ClientType.MWEB + val clientTypeName = clientType.name + Logger.printDebug { "Fetching playability request for: $videoId using client: $clientTypeName" } + + try { + val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(PlayerRoutes.GET_CATEGORY, clientType.userAgent) + val requestBody = + PlayerRoutes.createWebInnertubeBody(clientType, videoId) + + connection.setFixedLengthStreamingMode(requestBody.size) + connection.outputStream.write(requestBody) + + val responseCode = connection.responseCode + if (responseCode == 200) return Requester.parseJSONObject(connection) + + handleConnectionError( + (clientTypeName + " not available with response code: " + + responseCode + " message: " + connection.responseMessage), + null + ) + } catch (ex: SocketTimeoutException) { + handleConnectionError("Connection timeout", ex) + } catch (ex: IOException) { + handleConnectionError("Network error", ex) + } catch (ex: Exception) { + Logger.printException({ "sendWebRequest failed" }, ex) + } finally { + Logger.printDebug { "video: " + videoId + " took: " + (System.currentTimeMillis() - startTime) + "ms" } + } + + return null + } + + private fun parseApplicationResponse(playlistJson: JSONObject): Boolean { + try { + val playerParams: String? = (playlistJson + .getJSONObject("contents") + .getJSONObject("singleColumnWatchNextResults") + .getJSONObject("playlist") + .getJSONObject("playlist") + .getJSONArray("contents")[0] as JSONObject) + .getJSONObject("playlistPanelVideoRenderer") + .getJSONObject("navigationEndpoint") + .getJSONObject("watchEndpoint") + .getString("playerParams") + + return VideoInformation.isMixPlaylistsOpenedByUser(playerParams!!) + } catch (e: JSONException) { + Logger.printDebug { "Fetch failed while processing Application response data for response: $playlistJson" } + } + + return false + } + + private fun parseWebResponse(microFormatJson: JSONObject): Boolean { + try { + return microFormatJson + .getJSONObject("playerMicroformatRenderer") + .getJSONObject("category") + .getString("status") + .equals("Music") + } catch (e: JSONException) { + Logger.printDebug { "Fetch failed while processing Web response data for response: $microFormatJson" } + } + + return false + } + + private fun fetch(videoId: String, checkCategory: Boolean): Boolean { + if (checkCategory) { + val microFormatJson = sendWebRequest(videoId) + if (microFormatJson != null) { + return parseWebResponse(microFormatJson) + } + } else { + val playlistJson = sendApplicationRequest(videoId) + if (playlistJson != null) { + return parseApplicationResponse(playlistJson) + } + } + + return false + } + } +} diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java deleted file mode 100644 index db12d6d23..000000000 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java +++ /dev/null @@ -1,205 +0,0 @@ -package app.revanced.extension.youtube.patches.video.requests; - -import static app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.GET_PLAYLIST_PAGE; - -import android.annotation.SuppressLint; - -import androidx.annotation.GuardedBy; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.SocketTimeoutException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import app.revanced.extension.shared.patches.client.AppClient.ClientType; -import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes; -import app.revanced.extension.shared.requests.Requester; -import app.revanced.extension.shared.utils.Logger; -import app.revanced.extension.shared.utils.Utils; -import app.revanced.extension.youtube.shared.VideoInformation; - -public class PlaylistRequest { - - /** - * How long to keep fetches until they are expired. - */ - private static final long CACHE_RETENTION_TIME_MILLISECONDS = 60 * 1000; // 1 Minute - - private static final long MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000; // 20 seconds - - @GuardedBy("itself") - private static final Map cache = new HashMap<>(); - - @SuppressLint("ObsoleteSdkInt") - public static void fetchRequestIfNeeded(@Nullable String videoId) { - Objects.requireNonNull(videoId); - synchronized (cache) { - final long now = System.currentTimeMillis(); - - cache.values().removeIf(request -> { - final boolean expired = request.isExpired(now); - if (expired) Logger.printDebug(() -> "Removing expired stream: " + request.videoId); - return expired; - }); - - if (!cache.containsKey(videoId)) { - cache.put(videoId, new PlaylistRequest(videoId)); - } - } - } - - @Nullable - public static PlaylistRequest getRequestForVideoId(@Nullable String videoId) { - synchronized (cache) { - return cache.get(videoId); - } - } - - private static void handleConnectionError(String toastMessage, @Nullable Exception ex) { - Logger.printInfo(() -> toastMessage, ex); - } - - @Nullable - private static JSONObject send(ClientType clientType, String videoId) { - Objects.requireNonNull(clientType); - Objects.requireNonNull(videoId); - - final long startTime = System.currentTimeMillis(); - String clientTypeName = clientType.name(); - Logger.printDebug(() -> "Fetching playlist request for: " + videoId + " using client: " + clientTypeName); - - try { - HttpURLConnection connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(GET_PLAYLIST_PAGE, clientType); - - JSONObject innerTubeBodyJson = PlayerRoutes.createInnertubeBody(clientType); - innerTubeBodyJson.put("playlistId", "%s"); - - String innerTubeBody = String.format( - Locale.ENGLISH, - innerTubeBodyJson.toString(), - videoId, - "RD" + videoId - ); - byte[] requestBody = innerTubeBody.getBytes(StandardCharsets.UTF_8); - connection.setFixedLengthStreamingMode(requestBody.length); - connection.getOutputStream().write(requestBody); - - final int responseCode = connection.getResponseCode(); - if (responseCode == 200) return Requester.parseJSONObject(connection); - - handleConnectionError(clientTypeName + " not available with response code: " - + responseCode + " message: " + connection.getResponseMessage(), - null); - } catch (SocketTimeoutException ex) { - handleConnectionError("Connection timeout", ex); - } catch (IOException ex) { - handleConnectionError("Network error", ex); - } catch (Exception ex) { - Logger.printException(() -> "send failed", ex); - } finally { - Logger.printDebug(() -> "video: " + videoId + " took: " + (System.currentTimeMillis() - startTime) + "ms"); - } - - return null; - } - - private static Boolean fetch(@NonNull String videoId) { - final ClientType clientType = ClientType.ANDROID_VR; - final JSONObject playlistJson = send(clientType, videoId); - if (playlistJson != null) { - try { - final JSONObject singleColumnWatchNextResultsJsonObject = playlistJson - .getJSONObject("contents") - .getJSONObject("singleColumnWatchNextResults"); - - if (!singleColumnWatchNextResultsJsonObject.has("playlist")) { - return false; - } - - final JSONObject playlistJsonObject = singleColumnWatchNextResultsJsonObject - .getJSONObject("playlist") - .getJSONObject("playlist"); - - final Object currentStreamObject = playlistJsonObject - .getJSONArray("contents") - .get(0); - - if (!(currentStreamObject instanceof JSONObject currentStreamJsonObject)) { - return false; - } - - final JSONObject watchEndpointJsonObject = currentStreamJsonObject - .getJSONObject("playlistPanelVideoRenderer") - .getJSONObject("navigationEndpoint") - .getJSONObject("watchEndpoint"); - - Logger.printDebug(() -> "watchEndpoint: " + watchEndpointJsonObject); - - return watchEndpointJsonObject.has("playerParams") && - VideoInformation.isMixPlaylistsOpenedByUser(watchEndpointJsonObject.getString("playerParams")); - } catch (JSONException e) { - Logger.printDebug(() -> "Fetch failed while processing response data for response: " + playlistJson); - } - } - - return false; - } - - /** - * Time this instance and the fetch future was created. - */ - private final long timeFetched; - private final String videoId; - private final Future future; - - private PlaylistRequest(String videoId) { - this.timeFetched = System.currentTimeMillis(); - this.videoId = videoId; - this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId)); - } - - public boolean isExpired(long now) { - final long timeSinceCreation = now - timeFetched; - if (timeSinceCreation > CACHE_RETENTION_TIME_MILLISECONDS) { - return true; - } - - // Only expired if the fetch failed (API null response). - return (fetchCompleted() && getStream() == null); - } - - /** - * @return if the fetch call has completed. - */ - public boolean fetchCompleted() { - return future.isDone(); - } - - public Boolean getStream() { - try { - return future.get(MAX_MILLISECONDS_TO_WAIT_FOR_FETCH, TimeUnit.MILLISECONDS); - } catch (TimeoutException ex) { - Logger.printInfo(() -> "getStream timed out", ex); - } catch (InterruptedException ex) { - Logger.printException(() -> "getStream interrupted", ex); - Thread.currentThread().interrupt(); // Restore interrupt status flag. - } catch (ExecutionException ex) { - Logger.printException(() -> "getStream failure", ex); - } - - return null; - } -} diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java index a7b48bbf5..5093be2df 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -524,7 +524,6 @@ public class Settings extends BaseSettings { public static final IntegerSetting DEFAULT_VIDEO_QUALITY_MOBILE = new IntegerSetting("revanced_default_video_quality_mobile", -2); public static final IntegerSetting DEFAULT_VIDEO_QUALITY_WIFI = new IntegerSetting("revanced_default_video_quality_wifi", -2); public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE, true); - public static final BooleanSetting DISABLE_DEFAULT_PLAYBACK_SPEED_LIVE = new BooleanSetting("revanced_disable_default_playback_speed_live", TRUE); public static final BooleanSetting ENABLE_CUSTOM_PLAYBACK_SPEED = new BooleanSetting("revanced_enable_custom_playback_speed", FALSE, true); public static final BooleanSetting CUSTOM_PLAYBACK_SPEED_MENU_TYPE = new BooleanSetting("revanced_custom_playback_speed_menu_type", FALSE, parent(ENABLE_CUSTOM_PLAYBACK_SPEED)); public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds", "0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.25\n2.5", true, parent(ENABLE_CUSTOM_PLAYBACK_SPEED)); @@ -535,6 +534,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE, true); // Experimental Flags public static final BooleanSetting DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC = new BooleanSetting("revanced_disable_default_playback_speed_music", FALSE, true); + public static final BooleanSetting DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC_TYPE = new BooleanSetting("revanced_disable_default_playback_speed_music_type", FALSE, true, parent(DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC)); public static final BooleanSetting ENABLE_DEFAULT_PLAYBACK_SPEED_SHORTS = new BooleanSetting("revanced_enable_default_playback_speed_shorts", FALSE); public static final BooleanSetting SKIP_PRELOADED_BUFFER = new BooleanSetting("revanced_skip_preloaded_buffer", FALSE, true, "revanced_skip_preloaded_buffer_user_dialog_message"); public static final BooleanSetting SKIP_PRELOADED_BUFFER_TOAST = new BooleanSetting("revanced_skip_preloaded_buffer_toast", TRUE); diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt index ccebc248a..895d7b505 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt @@ -173,7 +173,7 @@ val videoPlaybackPatch = bytecodePatch( } hookBackgroundPlayVideoInformation("$EXTENSION_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V") - hookPlayerResponseVideoId("$EXTENSION_PLAYBACK_SPEED_CLASS_DESCRIPTOR->fetchPlaylistData(Ljava/lang/String;Z)V") + hookPlayerResponseVideoId("$EXTENSION_PLAYBACK_SPEED_CLASS_DESCRIPTOR->fetchMusicRequest(Ljava/lang/String;Z)V") updatePatchStatus(PATCH_STATUS_CLASS_DESCRIPTOR, "RememberPlaybackSpeed") diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index 03c8fbcfc..8ce18e22a 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -1497,9 +1497,6 @@ No margins on top and bottom of player." Disable HDR video HDR video is disabled. HDR video is enabled. - Disable playback speed for live streams - Default playback speed is disabled for live streams. - Default playback speed is enabled for live streams. Enable custom playback speed Custom playback speed is enabled. Custom playback speed is disabled. @@ -1524,10 +1521,11 @@ No margins on top and bottom of player." Old video quality menu is shown. Old video quality menu is not shown. Disable playback speed for music - "Default playback speed is disabled for music. - -Limitation: This setting may not apply to videos that do not include the 'Listen on YouTube Music' banner." + Default playback speed is disabled for music. Default playback speed is enabled for music. + Validate using categories + Default playback speed is disabled if the video category is Music. + Default playback speed is disabled for videos playable on YouTube Music. Enable Shorts default playback speed Default playback speed applies to Shorts. Default playback speed does not apply to Shorts. diff --git a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml index e579f0dac..8c4f1daf1 100644 --- a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -684,7 +684,6 @@ - @@ -695,6 +694,7 @@ + From 8ab67bc6efdbd7a4cc1eed6c43006ae3501001f2 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 20:04:50 +0900 Subject: [PATCH 28/65] feat(YouTube Music): Add `Disable music video in album` patch https://github.com/inotia00/ReVanced_Extended/issues/2568 --- .../patches/misc/AlbumMusicVideoPatch.java | 109 +++++++++++ .../patches/misc/requests/PipedRequester.java | 177 ++++++++++++++++++ .../patches/misc/requests/PipedRoutes.java | 22 +++ .../extension/music/settings/Settings.java | 1 + .../extension/music/utils/VideoUtils.java | 7 + .../music/misc/album/AlbumMusicVideoPatch.kt | 85 +++++++++ .../patches/music/misc/album/Fingerprints.kt | 69 +++++++ .../utils/dismiss/DismissQueueHookPatch.kt | 42 +++++ .../music/utils/dismiss/Fingerprints.kt | 24 +++ .../patches/music/utils/patch/PatchList.kt | 4 + .../utils/playservice/VersionCheckPatch.kt | 3 + .../music/settings/host/values/strings.xml | 6 + 12 files changed, 549 insertions(+) create mode 100644 extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java create mode 100644 extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/requests/PipedRequester.java create mode 100644 extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/requests/PipedRoutes.java create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/utils/dismiss/DismissQueueHookPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/utils/dismiss/Fingerprints.kt diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java new file mode 100644 index 000000000..d7ccccbad --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java @@ -0,0 +1,109 @@ +package app.revanced.extension.music.patches.misc; + +import androidx.annotation.NonNull; + +import java.util.concurrent.atomic.AtomicBoolean; + +import app.revanced.extension.music.patches.misc.requests.PipedRequester; +import app.revanced.extension.music.settings.Settings; +import app.revanced.extension.music.utils.VideoUtils; +import app.revanced.extension.shared.utils.Logger; + +@SuppressWarnings("unused") +public class AlbumMusicVideoPatch { + private static final String YOUTUBE_MUSIC_ALBUM_PREFIX = "OLAK"; + private static final boolean DISABLE_MUSIC_VIDEO_IN_ALBUM = + Settings.DISABLE_MUSIC_VIDEO_IN_ALBUM.get(); + + private static final AtomicBoolean isVideoLaunched = new AtomicBoolean(false); + + @NonNull + private static volatile String playerResponseVideoId = ""; + + @NonNull + private static volatile String currentVideoId = ""; + + /** + * Injection point. + */ + public static void newPlayerResponse(@NonNull String videoId, @NonNull String playlistId, final int playlistIndex) { + if (!DISABLE_MUSIC_VIDEO_IN_ALBUM) { + return; + } + if (!playlistId.startsWith(YOUTUBE_MUSIC_ALBUM_PREFIX)) { + return; + } + if (playlistIndex < 0) { + return; + } + if (playerResponseVideoId.equals(videoId)) { + return; + } + playerResponseVideoId = videoId; + + // Fetch from piped instances. + PipedRequester.fetchRequestIfNeeded(videoId, playlistId, playlistIndex); + } + + /** + * Injection point. + */ + public static void newVideoLoaded(@NonNull String videoId) { + if (!DISABLE_MUSIC_VIDEO_IN_ALBUM) { + return; + } + if (currentVideoId.equals(videoId)) { + return; + } + currentVideoId = videoId; + + // If the user is using a not fast enough internet connection, there will be a slight delay. + // Otherwise, the video may open repeatedly. + VideoUtils.runOnMainThreadDelayed(() -> openOfficialMusicIfNeeded(videoId), 750); + } + + private static void openOfficialMusicIfNeeded(@NonNull String videoId) { + try { + PipedRequester request = PipedRequester.getRequestForVideoId(videoId); + if (request == null) { + return; + } + String songId = request.getStream(); + if (songId == null) { + return; + } + + // It is handled by YouTube Music's internal code. + // There is a slight delay before the dismiss request is reflected. + VideoUtils.dismissQueue(); + + // Every time a new video is opened, a snack bar appears indicating that the account has been switched. + // To prevent this, hide the snack bar while a new video is opening. + isVideoLaunched.compareAndSet(false, true); + + // The newly opened video is not a music video. + // To prevent fetch requests from being sent, set the video id to the newly opened video + VideoUtils.runOnMainThreadDelayed(() -> { + playerResponseVideoId = songId; + currentVideoId = songId; + VideoUtils.openInYouTubeMusic(songId); + }, 750); + + // If a new video is opened, the snack bar will be shown. + VideoUtils.runOnMainThreadDelayed(() -> isVideoLaunched.compareAndSet(true, false), 1500); + } catch (Exception ex) { + Logger.printException(() -> "openOfficialMusicIfNeeded failure", ex); + } + } + + /** + * Injection point. + */ + public static boolean hideSnackBar() { + if (!DISABLE_MUSIC_VIDEO_IN_ALBUM) { + return false; + } + return isVideoLaunched.get(); + } + +} diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/requests/PipedRequester.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/requests/PipedRequester.java new file mode 100644 index 000000000..d88623742 --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/requests/PipedRequester.java @@ -0,0 +1,177 @@ +package app.revanced.extension.music.patches.misc.requests; + +import android.annotation.SuppressLint; + +import androidx.annotation.GuardedBy; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.SocketTimeoutException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import app.revanced.extension.shared.requests.Requester; +import app.revanced.extension.shared.utils.Logger; +import app.revanced.extension.shared.utils.Utils; + +public class PipedRequester { + /** + * How long to keep fetches until they are expired. + */ + private static final long CACHE_RETENTION_TIME_MILLISECONDS = 60 * 1000; // 1 Minute + + private static final long MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000; // 20 seconds + + @GuardedBy("itself") + private static final Map cache = new HashMap<>(); + + @SuppressLint("ObsoleteSdkInt") + public static void fetchRequestIfNeeded(@NonNull String videoId, @NonNull String playlistId, final int playlistIndex) { + synchronized (cache) { + final long now = System.currentTimeMillis(); + + cache.values().removeIf(request -> { + final boolean expired = request.isExpired(now); + if (expired) Logger.printDebug(() -> "Removing expired stream: " + request.videoId); + return expired; + }); + + if (!cache.containsKey(videoId)) { + PipedRequester pipedRequester = new PipedRequester(videoId, playlistId, playlistIndex); + cache.put(videoId, pipedRequester); + } + } + } + + @Nullable + public static PipedRequester getRequestForVideoId(@Nullable String videoId) { + synchronized (cache) { + return cache.get(videoId); + } + } + + /** + * TCP timeout + */ + private static final int TIMEOUT_TCP_DEFAULT_MILLISECONDS = 2 * 1000; // 2 seconds + + /** + * HTTP response timeout + */ + private static final int TIMEOUT_HTTP_DEFAULT_MILLISECONDS = 4 * 1000; // 4 seconds + + @Nullable + private static JSONObject send(@NonNull String videoId, @NonNull String playlistId, final int playlistIndex) { + final long startTime = System.currentTimeMillis(); + Logger.printDebug(() -> "Fetching piped instances (videoId: '" + videoId + + "', playlistId: '" + playlistId + "', playlistIndex: '" + playlistIndex + "'"); + + try { + HttpURLConnection connection = PipedRoutes.getPlaylistConnectionFromRoute(playlistId); + connection.setConnectTimeout(TIMEOUT_TCP_DEFAULT_MILLISECONDS); + connection.setReadTimeout(TIMEOUT_HTTP_DEFAULT_MILLISECONDS); + + final int responseCode = connection.getResponseCode(); + if (responseCode == 200) return Requester.parseJSONObject(connection); + + handleConnectionError("API not available: " + responseCode); + } catch (SocketTimeoutException ex) { + handleConnectionError("Connection timeout", ex); + } catch (IOException ex) { + handleConnectionError("Network error", ex); + } catch (Exception ex) { + Logger.printException(() -> "send failed", ex); + } finally { + Logger.printDebug(() -> "playlist: " + playlistId + " took: " + (System.currentTimeMillis() - startTime) + "ms"); + } + + return null; + } + + @Nullable + private static String fetch(@NonNull String videoId, @NonNull String playlistId, final int playlistIndex) { + final JSONObject playlistJson = send(videoId, playlistId, playlistIndex); + if (playlistJson != null) { + try { + final String songId = playlistJson.getJSONArray("relatedStreams") + .getJSONObject(playlistIndex) + .getString("url") + .replaceAll("/.+=", ""); + if (songId.isEmpty()) { + handleConnectionError("Url is empty!"); + } else if (!songId.equals(videoId)) { + return songId; + } + } catch (JSONException e) { + Logger.printDebug(() -> "Fetch failed while processing response data for response: " + playlistJson); + } + } + + return null; + } + + private static void handleConnectionError(@NonNull String errorMessage) { + handleConnectionError(errorMessage, null); + } + + private static void handleConnectionError(@NonNull String errorMessage, @Nullable Exception ex) { + if (ex != null) { + Logger.printInfo(() -> errorMessage, ex); + } + } + + + /** + * Time this instance and the fetch future was created. + */ + private final long timeFetched; + private final String videoId; + private final Future future; + + private PipedRequester(@NonNull String videoId, @NonNull String playlistId, final int playlistIndex) { + this.timeFetched = System.currentTimeMillis(); + this.videoId = videoId; + this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId, playlistId, playlistIndex)); + } + + public boolean isExpired(long now) { + final long timeSinceCreation = now - timeFetched; + if (timeSinceCreation > CACHE_RETENTION_TIME_MILLISECONDS) { + return true; + } + + // Only expired if the fetch failed (API null response). + return (fetchCompleted() && getStream() == null); + } + + /** + * @return if the fetch call has completed. + */ + public boolean fetchCompleted() { + return future.isDone(); + } + + public String getStream() { + try { + return future.get(MAX_MILLISECONDS_TO_WAIT_FOR_FETCH, TimeUnit.MILLISECONDS); + } catch (TimeoutException ex) { + Logger.printInfo(() -> "getStream timed out", ex); + } catch (InterruptedException ex) { + Logger.printException(() -> "getStream interrupted", ex); + Thread.currentThread().interrupt(); // Restore interrupt status flag. + } catch (ExecutionException ex) { + Logger.printException(() -> "getStream failure", ex); + } + + return null; + } +} diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/requests/PipedRoutes.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/requests/PipedRoutes.java new file mode 100644 index 000000000..fff5070df --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/requests/PipedRoutes.java @@ -0,0 +1,22 @@ +package app.revanced.extension.music.patches.misc.requests; + +import static app.revanced.extension.shared.requests.Route.Method.GET; + +import java.io.IOException; +import java.net.HttpURLConnection; + +import app.revanced.extension.shared.requests.Requester; +import app.revanced.extension.shared.requests.Route; + +class PipedRoutes { + private static final String PIPED_URL = "https://pipedapi.kavin.rocks/"; + private static final Route GET_PLAYLIST = new Route(GET, "playlists/{playlist_id}"); + + private PipedRoutes() { + } + + static HttpURLConnection getPlaylistConnectionFromRoute(String... params) throws IOException { + return Requester.getConnectionFromRoute(PIPED_URL, GET_PLAYLIST, params); + } + +} \ No newline at end of file diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java index 77bac406c..4ff5dc57e 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java @@ -178,6 +178,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting CHANGE_SHARE_SHEET = new BooleanSetting("revanced_change_share_sheet", FALSE, true); public static final BooleanSetting DISABLE_CAIRO_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_cairo_splash_animation", FALSE, true); public static final BooleanSetting DISABLE_DRC_AUDIO = new BooleanSetting("revanced_disable_drc_audio", FALSE, true); + public static final BooleanSetting DISABLE_MUSIC_VIDEO_IN_ALBUM = new BooleanSetting("revanced_disable_music_video_in_album", FALSE, true); public static final BooleanSetting ENABLE_OPUS_CODEC = new BooleanSetting("revanced_enable_opus_codec", FALSE, true); public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false); public static final BooleanSetting SPOOF_CLIENT = new BooleanSetting("revanced_spoof_client", FALSE, true); diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/utils/VideoUtils.java b/extensions/shared/src/main/java/app/revanced/extension/music/utils/VideoUtils.java index 059c311bd..9f2b6b22f 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/utils/VideoUtils.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/utils/VideoUtils.java @@ -71,6 +71,13 @@ public class VideoUtils extends IntentUtils { launchView(url, context.getPackageName()); } + /** + * Rest of the implementation added by patch. + */ + public static void dismissQueue() { + Log.d("Extended: VideoUtils", "Queue dismissed"); + } + /** * Rest of the implementation added by patch. */ diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt new file mode 100644 index 000000000..900ec0f75 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt @@ -0,0 +1,85 @@ +package app.revanced.patches.music.misc.album + +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE +import app.revanced.patches.music.utils.dismiss.dismissQueueHookPatch +import app.revanced.patches.music.utils.extension.Constants.MISC_PATH +import app.revanced.patches.music.utils.patch.PatchList.DISABLE_MUSIC_VIDEO_IN_ALBUM +import app.revanced.patches.music.utils.playservice.is_7_03_or_greater +import app.revanced.patches.music.utils.playservice.versionCheckPatch +import app.revanced.patches.music.utils.settings.CategoryType +import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus +import app.revanced.patches.music.utils.settings.addSwitchPreference +import app.revanced.patches.music.utils.settings.settingsPatch +import app.revanced.patches.music.video.information.videoIdHook +import app.revanced.patches.music.video.information.videoInformationPatch +import app.revanced.util.fingerprint.methodOrThrow + +private const val EXTENSION_CLASS_DESCRIPTOR = + "$MISC_PATH/AlbumMusicVideoPatch;" + +@Suppress("unused") +val albumMusicVideoPatch = bytecodePatch( + DISABLE_MUSIC_VIDEO_IN_ALBUM.title, + DISABLE_MUSIC_VIDEO_IN_ALBUM.summary, + false, +) { + compatibleWith(COMPATIBLE_PACKAGE) + + dependsOn( + settingsPatch, + dismissQueueHookPatch, + videoInformationPatch, + versionCheckPatch, + ) + + execute { + + // region hook player response + + val fingerprint = if (is_7_03_or_greater) { + playerParameterBuilderFingerprint + } else { + playerParameterBuilderLegacyFingerprint + } + + fingerprint.methodOrThrow().addInstruction( + 0, + "invoke-static {p1, p4, p5}, $EXTENSION_CLASS_DESCRIPTOR->newPlayerResponse(Ljava/lang/String;Ljava/lang/String;I)V" + ) + + // endregion + + // region hook video id + + videoIdHook("$EXTENSION_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") + + // endregion + + // region patch for hide snack bar + + snackBarParentFingerprint.methodOrThrow().addInstructionsWithLabels( + 0, """ + invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->hideSnackBar()Z + move-result v0 + if-eqz v0, :hide + return-void + :hide + nop + """ + ) + + // endregion + + addSwitchPreference( + CategoryType.MISC, + "revanced_disable_music_video_in_album", + "false" + ) + + updatePatchStatus(DISABLE_MUSIC_VIDEO_IN_ALBUM) + + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt new file mode 100644 index 000000000..e77dc2012 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt @@ -0,0 +1,69 @@ +package app.revanced.patches.music.misc.album + +import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.or +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +/** + * For targets 7.03 and later. + */ +internal val playerParameterBuilderFingerprint = legacyFingerprint( + name = "playerParameterBuilderFingerprint", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "L", + parameters = listOf( + "Ljava/lang/String;", // VideoId. + "[B", + "Ljava/lang/String;", // Player parameters proto buffer. + "Ljava/lang/String;", // PlaylistId. + "I", // PlaylistIndex. + "I", + "L", + "Ljava/util/Set;", + "Ljava/lang/String;", + "Ljava/lang/String;", + "L", + "Z", + "Z", + "Z", // Appears to indicate if the video id is being opened or is currently playing. + ), + strings = listOf("psps") +) + +/** + * For targets 7.02 and earlier. + */ +internal val playerParameterBuilderLegacyFingerprint = legacyFingerprint( + name = "playerParameterBuilderLegacyFingerprint", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "L", + parameters = listOf( + "Ljava/lang/String;", // VideoId. + "[B", + "Ljava/lang/String;", // Player parameters proto buffer. + "Ljava/lang/String;", // PlaylistId. + "I", // PlaylistIndex. + "I", + "Ljava/util/Set;", + "Ljava/lang/String;", + "Ljava/lang/String;", + "L", + "Z", + "Z", // Appears to indicate if the video id is being opened or is currently playing. + ), + opcodes = listOf( + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_INTERFACE + ) +) + +internal val snackBarParentFingerprint = legacyFingerprint( + name = "snackBarParentFingerprint", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "V", + parameters = listOf("L"), + strings = listOf("No suitable parent found from the given view. Please provide a valid view.") +) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/dismiss/DismissQueueHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/dismiss/DismissQueueHookPatch.kt new file mode 100644 index 000000000..7cb76868f --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/dismiss/DismissQueueHookPatch.kt @@ -0,0 +1,42 @@ +package app.revanced.patches.music.utils.dismiss + +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.music.utils.extension.Constants.EXTENSION_PATH +import app.revanced.util.addStaticFieldToExtension +import app.revanced.util.fingerprint.methodOrThrow +import app.revanced.util.getWalkerMethod + +private const val EXTENSION_VIDEO_UTILS_CLASS_DESCRIPTOR = + "$EXTENSION_PATH/utils/VideoUtils;" + +@Suppress("unused") +val dismissQueueHookPatch = bytecodePatch( + description = "dismissQueueHookPatch" +) { + + execute { + + dismissQueueFingerprint.methodOrThrow().apply { + val dismissQueueIndex = indexOfDismissQueueInstruction(this) + + getWalkerMethod(dismissQueueIndex).apply { + val smaliInstructions = + """ + if-eqz v0, :ignore + invoke-virtual {v0}, $definingClass->$name()V + :ignore + return-void + """ + + addStaticFieldToExtension( + EXTENSION_VIDEO_UTILS_CLASS_DESCRIPTOR, + "dismissQueue", + "dismissQueueClass", + definingClass, + smaliInstructions + ) + } + } + + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/dismiss/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/dismiss/Fingerprints.kt new file mode 100644 index 000000000..49c00a3b7 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/dismiss/Fingerprints.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.music.utils.dismiss + +import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +internal val dismissQueueFingerprint = legacyFingerprint( + name = "dismissQueueFingerprint", + returnType = "V", + parameters = listOf("L"), + customFingerprint = { method, _ -> + method.name == "handleDismissWatchEvent" && + indexOfDismissQueueInstruction(method) >= 0 + } +) + +internal fun indexOfDismissQueueInstruction(method: Method) = + method.indexOfFirstInstruction { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.definingClass?.endsWith("/MppWatchWhileLayout;") == true + } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt index 5a9c71bbc..2ec3454ce 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt @@ -57,6 +57,10 @@ internal enum class PatchList( "Disable dislike redirection", "Adds an option to disable redirection to the next track when clicking the Dislike button." ), + DISABLE_MUSIC_VIDEO_IN_ALBUM( + "Disable music video in album", + "Adds option to redirect music videos from albums." + ), ENABLE_OPUS_CODEC( "Enable OPUS codec", "Adds an options to enable the OPUS audio codec if the player response includes." diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/playservice/VersionCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/playservice/VersionCheckPatch.kt index 372251b2b..6344ff17a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/playservice/VersionCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/playservice/VersionCheckPatch.kt @@ -11,6 +11,8 @@ var is_6_36_or_greater = false private set var is_6_42_or_greater = false private set +var is_7_03_or_greater = false + private set var is_7_06_or_greater = false private set var is_7_13_or_greater = false @@ -43,6 +45,7 @@ val versionCheckPatch = resourcePatch( is_6_27_or_greater = 234412000 <= playStoreServicesVersion is_6_36_or_greater = 240399000 <= playStoreServicesVersion is_6_42_or_greater = 240999000 <= playStoreServicesVersion + is_7_03_or_greater = 242199000 <= playStoreServicesVersion is_7_06_or_greater = 242499000 <= playStoreServicesVersion is_7_13_or_greater = 243199000 <= playStoreServicesVersion is_7_17_or_greater = 243530000 <= playStoreServicesVersion diff --git a/patches/src/main/resources/music/settings/host/values/strings.xml b/patches/src/main/resources/music/settings/host/values/strings.xml index 7d62c7fd5..ef3c97f92 100644 --- a/patches/src/main/resources/music/settings/host/values/strings.xml +++ b/patches/src/main/resources/music/settings/host/values/strings.xml @@ -420,6 +420,12 @@ Click to see how to issue a API key." Disables Cairo splash animation when the app starts up. Disable DRC audio Disables DRC (Dynamic Range Compression) applied to audio. + Disable music video in album + "When a non-premium user plays a song included in an album, the music video is sometimes played instead of the official song. + +If such a music video is detected playing, it is redirected to the official song. + +A piped instance is used, but the API may not be available in some regions." Enable debug logging Prints the debug log. Enable debug buffer logging From c6ad8331bcc1c190c13cc67bb7abfb2422620616 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 21:44:30 +0900 Subject: [PATCH 29/65] fix(YouTube - Spoof streaming data): Mark login-required client --- .../shared/patches/client/AppClient.kt | 13 +++++++++++-- .../patches/spoof/requests/PlayerRoutes.kt | 2 +- .../spoof/requests/StreamingDataRequest.kt | 7 ++++++- .../youtube/settings/host/values/strings.xml | 17 +++++++++++------ 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt index d741b51c5..731203771 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt @@ -207,8 +207,14 @@ object AppClient { val clientVersion: String, /** * If the client can access the API logged in. + * If false, 'Authorization' must not be included. */ - val canLogin: Boolean = true, + val supportsCookies: Boolean = true, + /** + * If the client can only access the API logged in. + * If true, 'Authorization' must be included. + */ + val requireAuth: Boolean = false, /** * Whether a poToken is required to get playback for more than 1 minute. */ @@ -234,6 +240,7 @@ object AppClient { userAgent = USER_AGENT_ANDROID_UNPLUGGED, androidSdkVersion = ANDROID_SDK_VERSION_ANDROID_UNPLUGGED, clientVersion = CLIENT_VERSION_ANDROID_UNPLUGGED, + requireAuth = true, friendlyName = "Android TV" ), IOS_UNPLUGGED( @@ -242,6 +249,7 @@ object AppClient { osVersion = OS_VERSION_IOS, userAgent = USER_AGENT_IOS_UNPLUGGED, clientVersion = CLIENT_VERSION_IOS_UNPLUGGED, + requireAuth = true, friendlyName = if (forceAVC()) "iOS TV Force AVC" else @@ -253,7 +261,7 @@ object AppClient { osVersion = OS_VERSION_IOS, userAgent = USER_AGENT_IOS, clientVersion = CLIENT_VERSION_IOS, - canLogin = false, + supportsCookies = false, requirePoToken = true, friendlyName = if (forceAVC()) "iOS Force AVC" @@ -265,6 +273,7 @@ object AppClient { userAgent = USER_AGENT_ANDROID_MUSIC, androidSdkVersion = ANDROID_SDK_VERSION_ANDROID_MUSIC, clientVersion = CLIENT_VERSION_ANDROID_MUSIC, + requireAuth = true, friendlyName = "Android Music" ); diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt index 36bf03e01..666e04858 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt @@ -71,7 +71,7 @@ object PlayerRoutes { client.put("deviceMake", "Apple") client.put("osName", "iOS") } - if (!clientType.canLogin) { + if (!clientType.supportsCookies) { client.put("hl", LOCALE_LANGUAGE) } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt index 1d6837b9f..3732774a4 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt @@ -194,7 +194,7 @@ class StreamingDataRequest private constructor( var value = playerHeaders[key] if (value != null) { if (key == AUTHORIZATION_HEADER) { - if (!clientType.canLogin) { + if (!clientType.supportsCookies) { Logger.printDebug { "Not including request header: $key" } continue } @@ -260,6 +260,11 @@ class StreamingDataRequest private constructor( // Retry with different client if empty response body is received. for (clientType in CLIENT_ORDER_TO_USE) { + if (clientType.requireAuth && + playerHeaders[AUTHORIZATION_HEADER] == null) { + Logger.printDebug { "Skipped login-required client (incognito mode or not logged in)\nClient: $clientType\nVideo: $videoId" } + continue + } send( clientType, videoId, diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index 8ce18e22a..746137b9d 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -1907,16 +1907,21 @@ Tap the continue button and allow optimization changes." "Streaming data is not spoofed. Video playback may not work." Turning off this setting may cause video playback issues. Default client - Android TV + "Android TV +(Login required)" Android VR - iOS - iOS TV + "iOS +(PoToken required)" + "iOS TV +(Login required)" Spoofing side effects "• Audio track menu is missing. • Stable volume is not available. -• Disable forced auto audio tracks is not available." - • There may be playback issues (Deprecated). - • Movies or paid videos may not play. +• Disable forced auto audio tracks is not available. +• Kids videos may not play when logged out or in incognito mode." + • There may be playback issues (PoToken required). + "• Movies or paid videos may not play. +• Kids videos may not play when logged out or in incognito mode." Force iOS AVC (H.264) Video codec is forced to AVC (H.264). Video codec is determined automatically. From a596959d710dfea5bfb49df346b8070cec10e02c Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 21:48:58 +0900 Subject: [PATCH 30/65] feat(YouTube - Fullscreen components): Remove `Force fullscreen` setting --- .../youtube/patches/player/PlayerPatch.java | 34 ------------ .../extension/youtube/settings/Settings.java | 1 - .../ReVancedSettingsPreference.java | 22 -------- .../youtube/player/fullscreen/Fingerprints.kt | 20 ------- .../fullscreen/FullscreenComponentsPatch.kt | 55 ------------------- .../youtube/settings/host/values/strings.xml | 5 -- .../youtube/settings/xml/revanced_prefs.xml | 3 +- 7 files changed, 1 insertion(+), 139 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java index e7fd135d1..669d57fae 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java @@ -5,8 +5,6 @@ import static app.revanced.extension.shared.utils.Utils.hideViewByRemovingFromPa import static app.revanced.extension.shared.utils.Utils.hideViewUnderCondition; import static app.revanced.extension.youtube.utils.ExtendedUtils.validateValue; -import android.app.Activity; -import android.content.pm.ActivityInfo; import android.support.v7.widget.RecyclerView; import android.util.TypedValue; import android.view.View; @@ -20,7 +18,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import java.lang.ref.WeakReference; import java.util.Objects; import app.revanced.extension.shared.settings.BaseSettings; @@ -328,37 +325,6 @@ public class PlayerPatch { Utils.runOnMainThreadDelayed(() -> isScreenOn = false, Settings.KEEP_LANDSCAPE_MODE_TIMEOUT.get()); } - private static WeakReference watchDescriptorActivityRef = new WeakReference<>(null); - private static volatile boolean isLandScapeVideo = true; - - public static void setWatchDescriptorActivity(Activity activity) { - watchDescriptorActivityRef = new WeakReference<>(activity); - } - - public static boolean forceFullscreen(boolean original) { - if (!Settings.FORCE_FULLSCREEN.get()) - return original; - - Utils.runOnMainThreadDelayed(PlayerPatch::setOrientation, 1000); - return true; - } - - private static void setOrientation() { - final Activity watchDescriptorActivity = watchDescriptorActivityRef.get(); - final int requestedOrientation = isLandScapeVideo - ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE - : watchDescriptorActivity.getRequestedOrientation(); - - watchDescriptorActivity.setRequestedOrientation(requestedOrientation); - } - - public static void setVideoPortrait(int width, int height) { - if (!Settings.FORCE_FULLSCREEN.get()) - return; - - isLandScapeVideo = width > height; - } - // endregion // region [Hide comments component] patch diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 5093be2df..593395496 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -353,7 +353,6 @@ public class Settings extends BaseSettings { public static final BooleanSetting DISABLE_LANDSCAPE_MODE = new BooleanSetting("revanced_disable_landscape_mode", FALSE, true); public static final BooleanSetting ENABLE_COMPACT_CONTROLS_OVERLAY = new BooleanSetting("revanced_enable_compact_controls_overlay", FALSE, true); - public static final BooleanSetting FORCE_FULLSCREEN = new BooleanSetting("revanced_force_fullscreen", FALSE, true); public static final BooleanSetting KEEP_LANDSCAPE_MODE = new BooleanSetting("revanced_keep_landscape_mode", FALSE, true); public static final LongSetting KEEP_LANDSCAPE_MODE_TIMEOUT = new LongSetting("revanced_keep_landscape_mode_timeout", 3000L, true); diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java index e902d2ab8..dc13a6bb6 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java @@ -49,7 +49,6 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment { ChangeHeaderPreferenceLinks(); ExternalDownloaderPreferenceLinks(); FullScreenPanelPreferenceLinks(); - LayoutOverrideLinks(); MiniPlayerPreferenceLinks(); NavigationPreferenceLinks(); RYDPreferenceLinks(); @@ -93,16 +92,6 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment { ); } - /** - * Enable/Disable Layout Override Preference - */ - private static void LayoutOverrideLinks() { - enableDisablePreferences( - ExtendedUtils.isTablet(), - Settings.FORCE_FULLSCREEN - ); - } - /** * Enable/Disable Preferences not working in tablet layout */ @@ -139,17 +128,6 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment { Settings.HIDE_QUICK_ACTIONS_SAVE_TO_PLAYLIST_BUTTON, Settings.HIDE_QUICK_ACTIONS_SHARE_BUTTON ); - - enableDisablePreferences( - Settings.DISABLE_LANDSCAPE_MODE.get(), - Settings.FORCE_FULLSCREEN - ); - - enableDisablePreferences( - Settings.FORCE_FULLSCREEN.get(), - Settings.DISABLE_LANDSCAPE_MODE - ); - } /** diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/Fingerprints.kt index d89496da6..f65a4b917 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/Fingerprints.kt @@ -23,19 +23,6 @@ internal val broadcastReceiverFingerprint = legacyFingerprint( } ) -internal val clientSettingEndpointFingerprint = legacyFingerprint( - name = "clientSettingEndpointFingerprint", - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("L", "Ljava/util/Map;"), - strings = listOf( - "OVERRIDE_EXIT_FULLSCREEN_TO_MAXIMIZED", - "force_fullscreen", - "start_watch_minimized", - "watch" - ) -) - internal val engagementPanelFingerprint = legacyFingerprint( name = "engagementPanelFingerprint", returnType = "L", @@ -72,10 +59,3 @@ internal val relatedEndScreenResultsFingerprint = legacyFingerprint( literals = listOf(appRelatedEndScreenResults), ) -internal val videoPortraitParentFingerprint = legacyFingerprint( - name = "videoPortraitParentFingerprint", - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("L", "Ljava/util/Map;"), - strings = listOf("Acquiring NetLatencyActionLogger failed. taskId=") -) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/FullscreenComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/FullscreenComponentsPatch.kt index f00ad80bd..e57b0d6c7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/FullscreenComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/FullscreenComponentsPatch.kt @@ -42,7 +42,6 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference @@ -198,60 +197,6 @@ val fullscreenComponentsPatch = bytecodePatch( // endregion - // region patch for force fullscreen - - clientSettingEndpointFingerprint.methodOrThrow().apply { - val getActivityIndex = indexOfFirstStringInstructionOrThrow("watch") + 2 - val getActivityReference = - getInstruction(getActivityIndex).reference - val classRegister = - getInstruction(getActivityIndex).registerB - - val watchDescriptorMethodIndex = - indexOfFirstStringInstructionOrThrow("start_watch_minimized") - 1 - val watchDescriptorRegister = - getInstruction(watchDescriptorMethodIndex).registerD - - addInstructions( - watchDescriptorMethodIndex, """ - invoke-static {v$watchDescriptorRegister}, $PLAYER_CLASS_DESCRIPTOR->forceFullscreen(Z)Z - move-result v$watchDescriptorRegister - """ - ) - - // hooks Activity. - val insertIndex = indexOfFirstStringInstructionOrThrow("force_fullscreen") - val freeRegister = getInstruction(insertIndex).registerA - - addInstructions( - insertIndex, """ - iget-object v$freeRegister, v$classRegister, $getActivityReference - check-cast v$freeRegister, Landroid/app/Activity; - invoke-static {v$freeRegister}, $PLAYER_CLASS_DESCRIPTOR->setWatchDescriptorActivity(Landroid/app/Activity;)V - """ - ) - } - - videoPortraitParentFingerprint.methodOrThrow().apply { - val stringIndex = - indexOfFirstStringInstructionOrThrow("Acquiring NetLatencyActionLogger failed. taskId=") - val invokeIndex = - indexOfFirstInstructionOrThrow(stringIndex, Opcode.INVOKE_INTERFACE) - val targetIndex = indexOfFirstInstructionOrThrow(invokeIndex, Opcode.CHECK_CAST) - val targetClass = - getInstruction(targetIndex).reference.toString() - - // add an instruction to check the vertical video - findMethodOrThrow(targetClass) { - parameters == listOf("I", "I", "Z") - }.addInstruction( - 1, - "invoke-static {p1, p2}, $PLAYER_CLASS_DESCRIPTOR->setVideoPortrait(II)V" - ) - } - - // endregion - // region patch for disable landscape mode onConfigurationChangedMethod.apply { diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index 746137b9d..6a4648ebe 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -980,11 +980,6 @@ Limitation: Video title disappears when clicked." Enable compact controls overlay Controls overlay does not fill the fullscreen. Controls overlay fills the fullscreen. - Force fullscreen - "Videos will be switched to fullscreen in the following situations: - -• When a video is started. -• When a timestamp in the comments is clicked on." Keep landscape mode Keeps landscape mode when turning the screen off and on in fullscreen. Keep landscape mode timeout diff --git a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml index 8c4f1daf1..43903afc8 100644 --- a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -416,8 +416,7 @@ - - SETTINGS: FULLSCREEN_COMPONENTS --> + SETTINGS: FULLSCREEN_COMPONENTS --> - + - From 945b91eebb251e24d40d85621cc044b9bf7cad7b Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:04:27 +0900 Subject: [PATCH 34/65] feat(YouTube - Hide layout components): Add `Disable translucent status bar` setting --- .../youtube/patches/general/GeneralPatch.java | 9 +++++++ .../extension/youtube/settings/Settings.java | 1 + .../general/components/Fingerprints.kt | 9 +++++++ .../components/LayoutComponentsPatch.kt | 27 ++++++++++++++++--- .../youtube/settings/host/values/strings.xml | 3 +++ .../youtube/settings/xml/revanced_prefs.xml | 3 +++ 6 files changed, 48 insertions(+), 4 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java index f1dd20b99..9ce634720 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java @@ -128,6 +128,15 @@ public class GeneralPatch { // region [Hide layout components] patch + public static boolean disableTranslucentStatusBar(boolean original) { + try { + return !Settings.DISABLE_TRANSLUCENT_STATUS_BAR.get() && original; + } catch (Exception ex) { + Logger.printException(() -> "Failed to load disableTranslucentStatusBar", ex); + } + return original; + } + private static String[] accountMenuBlockList; static { diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 6a4c79418..043af0fee 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -148,6 +148,7 @@ public class Settings extends BaseSettings { new ChangeStartPagePatch.ChangeStartPageTypeAvailability()); public static final BooleanSetting DISABLE_AUTO_AUDIO_TRACKS = new BooleanSetting("revanced_disable_auto_audio_tracks", FALSE); public static final BooleanSetting DISABLE_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_splash_animation", FALSE, true); + public static final BooleanSetting DISABLE_TRANSLUCENT_STATUS_BAR = new BooleanSetting("revanced_disable_translucent_status_bar", TRUE, true); public static final BooleanSetting ENABLE_GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_enable_gradient_loading_screen", FALSE, true); public static final BooleanSetting HIDE_FLOATING_MICROPHONE = new BooleanSetting("revanced_hide_floating_microphone", TRUE, true); public static final BooleanSetting HIDE_GRAY_SEPARATOR = new BooleanSetting("revanced_hide_gray_separator", TRUE); diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/Fingerprints.kt index e37d96d1d..0acbf1fa6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/Fingerprints.kt @@ -134,3 +134,12 @@ internal val tooltipContentViewFingerprint = legacyFingerprint( literals = listOf(toolTipContentView), ) +internal const val TRANSLUCENT_STATUS_BAR_FEATURE_FLAG = 45400535L + +internal val translucentStatusBarFeatureFlagFingerprint = legacyFingerprint( + name = "translucentStatusBarFeatureFlagFingerprint", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "Z", + literals = listOf(TRANSLUCENT_STATUS_BAR_FEATURE_FLAG) +) + diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt index a80c7b44b..05b29167a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt @@ -17,10 +17,13 @@ import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH import app.revanced.patches.youtube.utils.patch.PatchList.HIDE_LAYOUT_COMPONENTS +import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater +import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.resourceid.accountSwitcherAccessibility import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch +import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.matchOrThrow import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.mutableClassOrThrow @@ -55,10 +58,16 @@ val layoutComponentsPatch = bytecodePatch( sharedResourceIdPatch, settingsMenuPatch, viewGroupMarginLayoutParamsHookPatch, + versionCheckPatch, ) execute { + var settingArray = arrayOf( + "PREFERENCE_SCREEN: GENERAL", + "SETTINGS: HIDE_LAYOUT_COMPONENTS" + ) + // region patch for disable pip notification pipNotificationFingerprint.matchOrThrow().let { @@ -86,6 +95,19 @@ val layoutComponentsPatch = bytecodePatch( // endregion + // region patch for disable translucent status bar + + if (is_19_25_or_greater) { + translucentStatusBarFeatureFlagFingerprint.injectLiteralInstructionBooleanCall( + TRANSLUCENT_STATUS_BAR_FEATURE_FLAG, + "$GENERAL_CLASS_DESCRIPTOR->disableTranslucentStatusBar(Z)Z" + ) + + settingArray += "SETTINGS: DISABLE_TRANSLUCENT_STATUS_BAR" + } + + // endregion + // region patch for disable update screen appBlockingCheckResultToStringFingerprint.mutableClassOrThrow().methods.first { method -> @@ -234,10 +256,7 @@ val layoutComponentsPatch = bytecodePatch( // region add settings addPreference( - arrayOf( - "PREFERENCE_SCREEN: GENERAL", - "SETTINGS: HIDE_LAYOUT_COMPONENTS" - ), + settingArray, HIDE_LAYOUT_COMPONENTS ) diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index b26b9bafb..d60cd55a4 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -352,6 +352,9 @@ Limitation: Back button on the toolbar may not work." Disable splash animation Splash animation is disabled. Splash animation is enabled. + Disable translucent status bar + Status bar is opaque. + Status bar is opaque or translucent. Enable gradient loading screen Gradient loading screen is enabled. Gradient loading screen is disabled. diff --git a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml index 22284a761..f3124f384 100644 --- a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -281,6 +281,9 @@ + + From a10e400cfa0c7b16766e9cf0a71acc1ca4a92adf Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:05:03 +0900 Subject: [PATCH 35/65] fix build error --- .../main/java/app/revanced/extension/shared/utils/Utils.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java index 68077e339..3d500e657 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java @@ -522,6 +522,11 @@ public class Utils { ); } + public static boolean isLandscapeOrientation() { + final int orientation = context.getResources().getConfiguration().orientation; + return orientation == Configuration.ORIENTATION_LANDSCAPE; + } + /** * Automatically logs any exceptions the runnable throws. * From 1424d0b7a752800669bd09abffa8ed47068613ac Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:06:48 +0900 Subject: [PATCH 36/65] fix(YouTube): Patched app crashes after first launch or clearing data --- .../youtube/patches/general/GeneralPatch.java | 28 ++++++++++--------- .../gesture/core/BaseGestureController.kt | 4 ++- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java index 9ce634720..f2acff742 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java @@ -206,8 +206,6 @@ public class GeneralPatch { // region [Hide navigation bar components] patch - private static final int fillBellCairoBlack = ResourceUtils.getDrawableIdentifier("yt_fill_bell_cairo_black_24"); - private static final Map shouldHideMap = new EnumMap<>(NavigationButton.class) { { put(NavigationButton.HOME, Settings.HIDE_NAVIGATION_HOME_BUTTON.get()); @@ -231,6 +229,7 @@ public class GeneralPatch { * @noinspection ALL */ public static void setCairoNotificationFilledIcon(EnumMap enumMap, Enum tabActivityCairo) { + final int fillBellCairoBlack = ResourceUtils.getDrawableIdentifier("yt_fill_bell_cairo_black_24"); if (fillBellCairoBlack != 0) { // It's very unlikely, but Google might fix this issue someday. // If so, [fillBellCairoBlack] might already be in enumMap. @@ -240,7 +239,12 @@ public class GeneralPatch { } public static boolean switchCreateWithNotificationButton(boolean original) { - return Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get() || original; + try { + return Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get() || original; + } catch (Exception ex) { + Logger.printException(() -> "switchCreateWithNotificationButton Failed", ex); + } + return original; } public static void navigationTabCreated(NavigationButton button, View tabView) { @@ -322,9 +326,6 @@ public class GeneralPatch { // region [Toolbar components] patch - private static final int generalHeaderAttributeId = ResourceUtils.getAttrIdentifier("ytWordmarkHeader"); - private static final int premiumHeaderAttributeId = ResourceUtils.getAttrIdentifier("ytPremiumWordmarkHeader"); - public static void setDrawerNavigationHeader(View lithoView) { final int headerAttributeId = getHeaderAttributeId(); @@ -342,8 +343,8 @@ public class GeneralPatch { public static int getHeaderAttributeId() { return Settings.CHANGE_YOUTUBE_HEADER.get() - ? premiumHeaderAttributeId - : generalHeaderAttributeId; + ? ResourceUtils.getAttrIdentifier("ytPremiumWordmarkHeader") + : ResourceUtils.getAttrIdentifier("ytWordmarkHeader"); } public static boolean overridePremiumHeader() { @@ -355,11 +356,6 @@ public class GeneralPatch { return ResourceUtils.getDrawable(""); } - private static final int searchBarId = ResourceUtils.getIdIdentifier("search_bar"); - private static final int youtubeTextId = ResourceUtils.getIdIdentifier("youtube_text"); - private static final int searchBoxId = ResourceUtils.getIdIdentifier("search_box"); - private static final int searchIconId = ResourceUtils.getIdIdentifier("search_icon"); - private static final boolean wideSearchbarEnabled = Settings.ENABLE_WIDE_SEARCH_BAR.get(); // Loads the search bar deprecated by Google. private static final boolean wideSearchbarWithHeaderEnabled = Settings.ENABLE_WIDE_SEARCH_BAR_WITH_HEADER.get(); @@ -398,12 +394,18 @@ public class GeneralPatch { public static void setWideSearchBarLayout(View view) { if (!wideSearchbarEnabled) return; + + final int searchBarId = ResourceUtils.getIdIdentifier("search_bar"); if (!(view.findViewById(searchBarId) instanceof RelativeLayout searchBarView)) return; // When the deprecated search bar is loaded, two search bars overlap. // Manually hides another search bar. if (wideSearchbarWithHeaderEnabled) { + final int youtubeTextId = ResourceUtils.getIdIdentifier("youtube_text"); + final int searchBoxId = ResourceUtils.getIdIdentifier("search_box"); + final int searchIconId = ResourceUtils.getIdIdentifier("search_icon"); + final View searchIconView = searchBarView.findViewById(searchIconId); final View searchBoxView = searchBarView.findViewById(searchBoxId); final View textView = searchBarView.findViewById(youtubeTextId); diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/BaseGestureController.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/BaseGestureController.kt index ac995bfd7..314fb3d76 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/BaseGestureController.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/gesture/core/BaseGestureController.kt @@ -87,8 +87,10 @@ abstract class BaseGestureController( distanceX: Float, distanceY: Float, ): Boolean { + if (from == null) return false + // submit to swipe detector - submitForSwipe(from!!, to, distanceX, distanceY) + submitForSwipe(from, to, distanceX, distanceY) // call swipe callback if in a swipe return if (currentSwipe != SwipeDetector.SwipeDirection.NONE) { From 07cb38d7a23d865ec070f09ca105ee100b7afdc0 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:07:03 +0900 Subject: [PATCH 37/65] fix build error --- .../patches/swipe/SwipeControlsPatch.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/swipe/SwipeControlsPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/swipe/SwipeControlsPatch.java index 01b302675..f4b0d16ad 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/swipe/SwipeControlsPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/swipe/SwipeControlsPatch.java @@ -27,8 +27,22 @@ public class SwipeControlsPatch { /** * Injection point. */ - public static boolean disableWatchPanelGestures() { - return !Settings.DISABLE_WATCH_PANEL_GESTURES.get(); + public static boolean disableSwipeToEnterFullscreenModeBelowThePlayer() { + return !Settings.DISABLE_SWIPE_TO_ENTER_FULLSCREEN_MODE_BELOW_THE_PLAYER.get(); + } + + /** + * Injection point. + */ + public static boolean disableSwipeToEnterFullscreenModeInThePlayer(boolean original) { + return !Settings.DISABLE_SWIPE_TO_ENTER_FULLSCREEN_MODE_IN_THE_PLAYER.get() && original; + } + + /** + * Injection point. + */ + public static boolean disableSwipeToExitFullscreenMode(boolean original) { + return !Settings.DISABLE_SWIPE_TO_EXIT_FULLSCREEN_MODE.get() && original; } /** From 2760fce64696ad84fe1387240751dcc1d5b16927 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:09:39 +0900 Subject: [PATCH 38/65] fix(YouTube - Toolbar components): Use Cairo icon for settings icon when `Replace Create button` is turned on --- .../youtube/patches/general/GeneralPatch.java | 29 +++++++++++++++---- .../youtube/utils/ExtendedUtils.java | 1 + 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java index f2acff742..af5337825 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java @@ -44,6 +44,7 @@ import app.revanced.extension.shared.utils.Logger; import app.revanced.extension.shared.utils.ResourceUtils; import app.revanced.extension.shared.utils.Utils; import app.revanced.extension.youtube.settings.Settings; +import app.revanced.extension.youtube.utils.ExtendedUtils; import app.revanced.extension.youtube.utils.ThemeUtils; @SuppressWarnings("unused") @@ -520,14 +521,30 @@ public class GeneralPatch { imageView.setImageDrawable(drawable); } - private static final int settingsDrawableId = - ResourceUtils.getDrawableIdentifier("yt_outline_gear_black_24"); - public static int getCreateButtonDrawableId(int original) { - return Settings.REPLACE_TOOLBAR_CREATE_BUTTON.get() && - settingsDrawableId != 0 + if (!Settings.REPLACE_TOOLBAR_CREATE_BUTTON.get()) { + return original; + } + + final int settingsDrawableId = + ResourceUtils.getDrawableIdentifier("yt_outline_gear_black_24"); + + if (settingsDrawableId == 0) { + return original; + } + + // If the user has patched YouTube 19.26.42, + // Or spoofed the app version to 19.26.42 or earlier. + if (!ExtendedUtils.IS_19_28_OR_GREATER || ExtendedUtils.isSpoofingToLessThan("19.27.00")) { + return settingsDrawableId; + } + + final int settingsCairoDrawableId = + ResourceUtils.getDrawableIdentifier("yt_outline_gear_cairo_black_24"); + + return settingsCairoDrawableId == 0 ? settingsDrawableId - : original; + : settingsCairoDrawableId; } public static void replaceCreateButton(String enumString, View toolbarView) { diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/utils/ExtendedUtils.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/utils/ExtendedUtils.java index 77f328b52..3af96e1c8 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/utils/ExtendedUtils.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/utils/ExtendedUtils.java @@ -16,6 +16,7 @@ public class ExtendedUtils extends PackageUtils { public static final boolean IS_19_20_OR_GREATER = getAppVersionName().compareTo("19.20.00") >= 0; public static final boolean IS_19_21_OR_GREATER = getAppVersionName().compareTo("19.21.00") >= 0; public static final boolean IS_19_26_OR_GREATER = getAppVersionName().compareTo("19.26.00") >= 0; + public static final boolean IS_19_28_OR_GREATER = getAppVersionName().compareTo("19.28.00") >= 0; public static final boolean IS_19_29_OR_GREATER = getAppVersionName().compareTo("19.29.00") >= 0; public static final boolean IS_19_34_OR_GREATER = getAppVersionName().compareTo("19.34.00") >= 0; From f5834ab7421bab821ff51a93f67d4d33f8a2367e Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:12:35 +0900 Subject: [PATCH 39/65] fix(YouTube - Overlay buttons): Overlay buttons do not disappear immediately when fullscreen button is clicked --- .../patches/utils/PlayerControlsPatch.java | 2 +- .../extension/youtube/shared/BottomSheetState.kt | 2 +- .../extension/youtube/shared/LockModeState.kt | 2 +- .../youtube/shared/PlayerControlsVisibility.kt | 1 + .../extension/youtube/shared/PlayerType.kt | 2 +- .../youtube/shared/ShortsPlayerState.kt | 2 +- .../extension/youtube/shared/VideoState.kt | 1 + .../utils/playercontrols/PlayerControlsPatch.kt | 16 ++++++++++++++++ 8 files changed, 23 insertions(+), 5 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlayerControlsPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlayerControlsPatch.java index 5a6e56f6a..7a3442505 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlayerControlsPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlayerControlsPatch.java @@ -106,7 +106,7 @@ public class PlayerControlsPatch { } } - private static void changeVisibilityNegatedImmediately() { + public static void changeVisibilityNegatedImmediately() { // AlwaysRepeat.changeVisibilityNegatedImmediate(); // CopyVideoUrl.changeVisibilityNegatedImmediate(); // CopyVideoUrlTimestamp.changeVisibilityNegatedImmediate(); diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/BottomSheetState.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/BottomSheetState.kt index 2d8b513a3..83e4dd514 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/BottomSheetState.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/BottomSheetState.kt @@ -31,7 +31,7 @@ enum class BottomSheetState { onChange(currentBottomSheetState) } - @Volatile // value is read/write from different threads + @Volatile // Read/write from different threads. private var currentBottomSheetState = CLOSED /** diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/LockModeState.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/LockModeState.kt index 9a330e687..2b7063664 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/LockModeState.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/LockModeState.kt @@ -40,7 +40,7 @@ enum class LockModeState { onChange(value) } - @Volatile // value is read/write from different threads + @Volatile // Read/write from different threads. private var currentLockModeState = LOCK_MODE_STATE_ENUM_UNKNOWN /** diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibility.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibility.kt index e5c8e6639..c7cf1bbd7 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibility.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibility.kt @@ -38,6 +38,7 @@ enum class PlayerControlsVisibility { currentPlayerControlsVisibility = value } + @Volatile // Read/write from different threads. private var currentPlayerControlsVisibility: PlayerControlsVisibility? = null } } \ No newline at end of file diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerType.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerType.kt index 9bfaffe58..201d32085 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerType.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/PlayerType.kt @@ -71,7 +71,7 @@ enum class PlayerType { onChange(value) } - @Volatile // value is read/write from different threads + @Volatile // Read/write from different threads. private var currentPlayerType = NONE /** diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/ShortsPlayerState.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/ShortsPlayerState.kt index b0aed2e79..e3e56c58e 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/ShortsPlayerState.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/ShortsPlayerState.kt @@ -31,7 +31,7 @@ enum class ShortsPlayerState { onChange(value) } - @Volatile // value is read/write from different threads + @Volatile // Read/write from different threads. private var currentShortsPlayerState = CLOSED /** diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/VideoState.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/VideoState.kt index 4e1888a7c..b26759ce9 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/VideoState.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/VideoState.kt @@ -39,6 +39,7 @@ enum class VideoState { currentVideoState = value } + @Volatile // Read/write from different threads. private var currentVideoState: VideoState? = null } } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playercontrols/PlayerControlsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playercontrols/PlayerControlsPatch.kt index 8a648f0f4..e0e54f204 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playercontrols/PlayerControlsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playercontrols/PlayerControlsPatch.kt @@ -9,8 +9,11 @@ import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch +import app.revanced.patches.youtube.utils.fullscreen.enterFullscreenMethod +import app.revanced.patches.youtube.utils.fullscreen.fullscreenButtonHookPatch import app.revanced.patches.youtube.utils.playerButtonsResourcesFingerprint import app.revanced.patches.youtube.utils.playerButtonsVisibilityFingerprint +import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch @@ -46,6 +49,7 @@ private val playerControlsBytecodePatch = bytecodePatch( sharedExtensionPatch, sharedResourceIdPatch, versionCheckPatch, + fullscreenButtonHookPatch, ) execute { @@ -114,6 +118,18 @@ private val playerControlsBytecodePatch = bytecodePatch( // endregion + // region patch for fix buttons do not hide immediately when fullscreen button is clicked + + // Reproduced only in RVX + if (is_19_23_or_greater) { + enterFullscreenMethod.addInstruction( + 0, + "invoke-static {}, $EXTENSION_PLAYER_CONTROLS_CLASS_DESCRIPTOR->changeVisibilityNegatedImmediately()V" + ) + } + + // endregion + // region patch initialize of overlay button or SponsorBlock button mapOf( From 574cd8410eb5177d2be6036f4a4dea60dd0dc601 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:14:47 +0900 Subject: [PATCH 40/65] fix(YouTube - Settings): Misaligned icons and titles in RVX settings toolbar on Android 15 https://github.com/inotia00/ReVanced_Extended/issues/2602 --- .../ReVancedPreferenceFragment.java | 14 +++++++++++++ .../VideoQualitySettingsActivity.java | 21 ++++++++++++------- .../layout/revanced_settings_with_toolbar.xml | 6 +++--- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java index cf46d1a79..d5abb90e7 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java @@ -1,5 +1,6 @@ package app.revanced.extension.youtube.settings.preference; +import static com.google.android.apps.youtube.app.settings.videoquality.VideoQualitySettingsActivity.setToolbarLayoutParams; import static app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment.showRestartDialog; import static app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment.updateListPreferenceSummary; import static app.revanced.extension.shared.utils.ResourceUtils.getXmlIdentifier; @@ -18,6 +19,7 @@ import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.graphics.Insets; import android.net.Uri; import android.os.Bundle; import android.preference.EditTextPreference; @@ -31,6 +33,7 @@ import android.preference.PreferenceScreen; import android.preference.SwitchPreference; import android.util.TypedValue; import android.view.ViewGroup; +import android.view.WindowInsets; import android.widget.TextView; import android.widget.Toolbar; @@ -202,6 +205,15 @@ public class ReVancedPreferenceFragment extends PreferenceFragment { .findViewById(android.R.id.content) .getParent(); + // Fix required for Android 15 + if (isSDKAbove(35)) { + rootView.setOnApplyWindowInsetsListener((v, insets) -> { + Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars()); + v.setPadding(0, statusInsets.top, 0, 0); + return insets; + }); + } + Toolbar toolbar = new Toolbar(preferenceScreen.getContext()); toolbar.setTitle(preferenceScreen.getTitle()); @@ -219,6 +231,8 @@ public class ReVancedPreferenceFragment extends PreferenceFragment { toolbarTextView.setTextColor(ThemeUtils.getForegroundColor()); } + setToolbarLayoutParams(toolbar); + rootView.addView(toolbar, 0); return false; } diff --git a/extensions/shared/src/main/java/com/google/android/apps/youtube/app/settings/videoquality/VideoQualitySettingsActivity.java b/extensions/shared/src/main/java/com/google/android/apps/youtube/app/settings/videoquality/VideoQualitySettingsActivity.java index 1d1468478..f01b05cf2 100644 --- a/extensions/shared/src/main/java/com/google/android/apps/youtube/app/settings/videoquality/VideoQualitySettingsActivity.java +++ b/extensions/shared/src/main/java/com/google/android/apps/youtube/app/settings/videoquality/VideoQualitySettingsActivity.java @@ -88,17 +88,21 @@ public class VideoQualitySettingsActivity extends Activity { fragment.filterPreferences(query); } + private static ViewGroup.LayoutParams lp; + + public static void setToolbarLayoutParams(Toolbar toolbar) { + if (lp != null) { + toolbar.setLayoutParams(lp); + } + } + private void setToolbar() { - if (!(findViewById(ResourceUtils.getIdIdentifier("revanced_toolbar_parent")) instanceof ViewGroup toolBarParent)) - return; + ViewGroup toolBarParent = findViewById(ResourceUtils.getIdIdentifier("revanced_toolbar_parent")); // Remove dummy toolbar. - for (int i = 0; i < toolBarParent.getChildCount(); i++) { - View view = toolBarParent.getChildAt(i); - if (view != null) { - toolBarParent.removeView(view); - } - } + ViewGroup dummyToolbar = toolBarParent.findViewById(ResourceUtils.getIdIdentifier("revanced_toolbar")); + lp = dummyToolbar.getLayoutParams(); + toolBarParent.removeView(dummyToolbar); Toolbar toolbar = new Toolbar(toolBarParent.getContext()); toolbar.setBackgroundColor(ThemeUtils.getToolbarBackgroundColor()); @@ -112,6 +116,7 @@ public class VideoQualitySettingsActivity extends Activity { if (toolbarTextView != null) { toolbarTextView.setTextColor(ThemeUtils.getForegroundColor()); } + setToolbarLayoutParams(toolbar); toolBarParent.addView(toolbar, 0); } diff --git a/patches/src/main/resources/youtube/settings/layout/revanced_settings_with_toolbar.xml b/patches/src/main/resources/youtube/settings/layout/revanced_settings_with_toolbar.xml index a28d8d595..97927c4fa 100644 --- a/patches/src/main/resources/youtube/settings/layout/revanced_settings_with_toolbar.xml +++ b/patches/src/main/resources/youtube/settings/layout/revanced_settings_with_toolbar.xml @@ -16,10 +16,10 @@ android:background="@color/yt_white1" android:elevation="0dp"> - From 3e6a4a390c80f61d9d2aac59c987e5ee6b53c323 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:18:54 +0900 Subject: [PATCH 41/65] fix(YouTube - SponsorBlock): Show a toast and not a dialog if segment submitted successfully (Close https://github.com/inotia00/ReVanced_Extended/issues/2598) --- .../youtube/sponsorblock/requests/SBRequester.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/sponsorblock/requests/SBRequester.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/sponsorblock/requests/SBRequester.java index f2e31a014..b0679a902 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/sponsorblock/requests/SBRequester.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/sponsorblock/requests/SBRequester.java @@ -126,8 +126,12 @@ public class SBRequester { HttpURLConnection connection = getConnectionFromRoute(SBRoutes.SUBMIT_SEGMENTS, privateUserId, videoId, category, start, end, duration); final int responseCode = connection.getResponseCode(); - String userMessage = switch (responseCode) { - case HTTP_STATUS_CODE_SUCCESS -> str("revanced_sb_submit_succeeded"); + if (responseCode == HTTP_STATUS_CODE_SUCCESS) { + Utils.showToastLong(str("revanced_sb_submit_succeeded")); + return; + } + + String userErrorMessage = switch (responseCode) { case 409 -> str("revanced_sb_submit_failed_duplicate"); case 403 -> str("revanced_sb_submit_failed_forbidden", Requester.parseErrorStringAndDisconnect(connection)); @@ -137,9 +141,10 @@ public class SBRequester { default -> str("revanced_sb_submit_failed_unknown_error", responseCode, connection.getResponseMessage()); }; + // Message might be about the users account or an error too large to show in a toast. // Use a dialog instead. - SponsorBlockUtils.showErrorDialog(userMessage); + SponsorBlockUtils.showErrorDialog(userErrorMessage); } catch (SocketTimeoutException ex) { Logger.printDebug(() -> "Timeout", ex); Utils.showToastLong(str("revanced_sb_submit_failed_timeout")); From 9265303a2939a9cb02c812b5b77652b68e249ef7 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:38:39 +0900 Subject: [PATCH 42/65] revert(Hide ads): Disable advertising id --- .../patches/video/VideoQualityPatch.java | 2 +- .../patches/shared/ads/BaseAdsPatch.kt | 39 +++++-------------- .../patches/shared/ads/Fingerprints.kt | 18 --------- 3 files changed, 10 insertions(+), 49 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/VideoQualityPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/VideoQualityPatch.java index c42125c0d..d13e2e354 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/VideoQualityPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/VideoQualityPatch.java @@ -38,7 +38,7 @@ public class VideoQualityPatch { if (videoId.equals(newlyLoadedVideoId)) return; videoId = newlyLoadedVideoId; - setVideoQuality(Settings.SKIP_PRELOADED_BUFFER.get() ? 250 : 500); + setVideoQuality(Settings.SKIP_PRELOADED_BUFFER.get() ? 250 : 750); } /** diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/ads/BaseAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/ads/BaseAdsPatch.kt index 66863f474..02cf1f243 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/ads/BaseAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/ads/BaseAdsPatch.kt @@ -10,7 +10,6 @@ import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.shared.extension.Constants.PATCHES_PATH -import app.revanced.util.fingerprint.matchOrThrow import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.getReference import app.revanced.util.getWalkerMethod @@ -33,20 +32,15 @@ fun baseAdsPatch( ) { execute { - setOf( - sslGuardFingerprint, - videoAdsFingerprint, - ).forEach { fingerprint -> - fingerprint.methodOrThrow().apply { - addInstructionsWithLabels( - 0, """ - invoke-static {}, $classDescriptor->$methodDescriptor()Z - move-result v0 - if-nez v0, :show_ads - return-void - """, ExternalLabel("show_ads", getInstruction(0)) - ) - } + videoAdsFingerprint.methodOrThrow().apply { + addInstructionsWithLabels( + 0, """ + invoke-static {}, $classDescriptor->$methodDescriptor()Z + move-result v0 + if-nez v0, :show_ads + return-void + """, ExternalLabel("show_ads", getInstruction(0)) + ) } musicAdsFingerprint.methodOrThrow().apply { @@ -67,21 +61,6 @@ fun baseAdsPatch( ) } - advertisingIdFingerprint.matchOrThrow().let { - it.method.apply { - val insertIndex = it.stringMatches!!.first().index - val insertRegister = getInstruction(insertIndex).registerA - addInstructionsWithLabels( - insertIndex, """ - invoke-static {}, $classDescriptor->$methodDescriptor()Z - move-result v$insertRegister - if-nez v$insertRegister, :enable_id - return-void - """, ExternalLabel("enable_id", getInstruction(insertIndex)) - ) - } - } - } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/ads/Fingerprints.kt index 6853546b4..9ec138962 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/ads/Fingerprints.kt @@ -4,24 +4,6 @@ import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.util.MethodUtil - -internal val advertisingIdFingerprint = legacyFingerprint( - name = "advertisingIdFingerprint", - returnType = "V", - strings = listOf("a."), - customFingerprint = { method, classDef -> - MethodUtil.isConstructor(method) && - classDef.fields.find { it.type == "Ljava/util/Random;" } != null - } -) - -internal val sslGuardFingerprint = legacyFingerprint( - name = "sslGuardFingerprint", - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - strings = listOf("Cannot initialize SslGuardSocketFactory will null"), -) internal val musicAdsFingerprint = legacyFingerprint( name = "musicAdsFingerprint", From a5c808652e8b41175ad84cf0dde4372d411ae014 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:53:25 +0900 Subject: [PATCH 43/65] feat(GmsCore support): Match with ReVanced --- .../patches/shared/gms/Fingerprints.kt | 48 +-- .../patches/shared/gms/GmsCoreSupportPatch.kt | 372 +++++++++++------- 2 files changed, 239 insertions(+), 181 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/gms/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/gms/Fingerprints.kt index 8734a722f..8a33d0807 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/gms/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/gms/Fingerprints.kt @@ -25,15 +25,6 @@ internal val castContextFetchFingerprint = legacyFingerprint( strings = listOf("Error fetching CastContext.") ) -internal val castDynamiteModuleFingerprint = legacyFingerprint( - name = "castDynamiteModuleFingerprint", - strings = listOf("com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl") -) -internal val castDynamiteModuleV2Fingerprint = legacyFingerprint( - name = "castDynamiteModuleV2Fingerprint", - strings = listOf("Failed to load module via V2: ") -) - internal val googlePlayUtilityFingerprint = legacyFingerprint( name = "castContextFetchFingerprint", returnType = "I", @@ -53,42 +44,9 @@ internal val serviceCheckFingerprint = legacyFingerprint( strings = listOf("Google Play Services not available") ) -internal val primesApiFingerprint = legacyFingerprint( - name = "primesApiFingerprint", - returnType = "V", - strings = listOf("PrimesApiImpl.java"), - customFingerprint = { method, _ -> - MethodUtil.isConstructor(method) - } -) - -internal val primesBackgroundInitializationFingerprint = legacyFingerprint( - name = "primesBackgroundInitializationFingerprint", - opcodes = listOf(Opcode.NEW_INSTANCE), - customFingerprint = { method, _ -> - method.indexOfFirstInstruction { - opcode == Opcode.CONST_STRING && - getReference() - ?.string.toString() - .startsWith("Primes init triggered from background in package:") - } >= 0 - } -) - -internal val primesLifecycleEventFingerprint = legacyFingerprint( - name = "primesLifecycleEventFingerprint", - accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, - returnType = "V", - parameters = emptyList(), - opcodes = listOf(Opcode.NEW_INSTANCE), - customFingerprint = { method, _ -> - method.indexOfFirstInstruction { - opcode == Opcode.CONST_STRING && - getReference() - ?.string.toString() - .startsWith("Primes did not observe lifecycle events in the expected order.") - } >= 0 - } +internal val primeMethodFingerprint = legacyFingerprint( + name = "primeMethodFingerprint", + strings = listOf("com.google.android.GoogleCamera", "com.android.vending") ) internal val certificateFingerprint = legacyFingerprint( diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/gms/GmsCoreSupportPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/gms/GmsCoreSupportPatch.kt index f22bd9fb4..57d27416f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/gms/GmsCoreSupportPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/gms/GmsCoreSupportPatch.kt @@ -1,9 +1,9 @@ package app.revanced.patches.shared.gms import app.revanced.patcher.Fingerprint -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatchBuilder import app.revanced.patcher.patch.BytecodePatchContext @@ -25,15 +25,12 @@ import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.mutableClassOrThrow import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction -import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.returnEarly import app.revanced.util.valueOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.StringReference @@ -233,41 +230,18 @@ fun gmsCoreSupportPatch( } } - fun transformPrimeMethod() { - setOf( - primesBackgroundInitializationFingerprint, - primesLifecycleEventFingerprint - ).forEach { fingerprint -> - fingerprint.methodOrThrow().apply { - val exceptionIndex = indexOfFirstInstructionReversedOrThrow { - opcode == Opcode.NEW_INSTANCE && - (this as? ReferenceInstruction)?.reference?.toString() == "Ljava/lang/IllegalStateException;" - } - val index = - indexOfFirstInstructionReversedOrThrow(exceptionIndex, Opcode.IF_EQZ) - val register = getInstruction(index).registerA - addInstruction( - index, - "const/4 v$register, 0x1" - ) - } - } - primesApiFingerprint.mutableClassOrThrow().methods.filter { method -> - method.name != "" && - method.returnType == "V" - }.forEach { method -> - method.apply { - val index = if (MethodUtil.isConstructor(method)) - indexOfFirstInstructionOrThrow { - opcode == Opcode.INVOKE_DIRECT && - getReference()?.name == "" - } + 1 - else 0 - addInstruction( - index, - "return-void" - ) + fun transformPrimeMethod(packageName: String) { + primeMethodFingerprint.methodOrThrow().apply { + var register = 2 + + val index = instructions.indexOfFirst { + if (it.getReference()?.string != fromPackageName) return@indexOfFirst false + + register = (it as OneRegisterInstruction).registerA + return@indexOfFirst true } + + replaceInstruction(index, "const-string v$register, \"$packageName\"") } } @@ -293,14 +267,12 @@ fun gmsCoreSupportPatch( // Return these methods early to prevent the app from crashing. setOf( castContextFetchFingerprint, - castDynamiteModuleFingerprint, - castDynamiteModuleV2Fingerprint, googlePlayUtilityFingerprint, serviceCheckFingerprint, ).forEach { it.methodOrThrow().returnEarly() } // Specific method that needs to be patched. - transformPrimeMethod() + transformPrimeMethod(packageName) // Verify GmsCore is installed and whitelisted for power optimizations and background usage. mainActivityOnCreateFingerprint.method.apply { @@ -358,134 +330,262 @@ private object Constants { * All permissions. */ val PERMISSIONS = setOf( - // C2DM / GCM "com.google.android.c2dm.permission.RECEIVE", "com.google.android.c2dm.permission.SEND", - "com.google.android.gtalkservice.permission.GTALK_SERVICE", - "com.google.android.providers.gsf.permission.READ_GSERVICES", - - // GAuth + "com.google.android.gms.auth.api.phone.permission.SEND", + "com.google.android.gms.permission.AD_ID", + "com.google.android.gms.permission.AD_ID_NOTIFICATION", + "com.google.android.gms.permission.CAR_FUEL", + "com.google.android.gms.permission.CAR_INFORMATION", + "com.google.android.gms.permission.CAR_MILEAGE", + "com.google.android.gms.permission.CAR_SPEED", + "com.google.android.gms.permission.CAR_VENDOR_EXTENSION", "com.google.android.googleapps.permission.GOOGLE_AUTH", "com.google.android.googleapps.permission.GOOGLE_AUTH.cp", "com.google.android.googleapps.permission.GOOGLE_AUTH.local", "com.google.android.googleapps.permission.GOOGLE_AUTH.mail", "com.google.android.googleapps.permission.GOOGLE_AUTH.writely", - - // Ad - "com.google.android.gms.permission.AD_ID_NOTIFICATION", - "com.google.android.gms.permission.AD_ID", + "com.google.android.gtalkservice.permission.GTALK_SERVICE", + "com.google.android.providers.gsf.permission.READ_GSERVICES", ) /** * All intent actions. */ val ACTIONS = setOf( - // location - "com.google.android.gms.location.places.ui.PICK_PLACE", - "com.google.android.gms.location.places.GeoDataApi", - "com.google.android.gms.location.places.PlacesApi", - "com.google.android.gms.location.places.PlaceDetectionApi", - "com.google.android.gms.wearable.MESSAGE_RECEIVED", - "com.google.android.gms.checkin.BIND_TO_SERVICE", - - // C2DM / GCM + "com.google.android.c2dm.intent.RECEIVE", "com.google.android.c2dm.intent.REGISTER", "com.google.android.c2dm.intent.REGISTRATION", "com.google.android.c2dm.intent.UNREGISTER", - "com.google.android.c2dm.intent.RECEIVE", - "com.google.iid.TOKEN_REQUEST", + "com.google.android.contextmanager.service.ContextManagerService.START", "com.google.android.gcm.intent.SEND", - - // car - "com.google.android.gms.car.service.START", - - // people - "com.google.android.gms.people.service.START", - - // wearable - "com.google.android.gms.wearable.BIND", - - // auth - "com.google.android.gsf.login", - "com.google.android.gsf.action.GET_GLS", - "com.google.android.gms.common.account.CHOOSE_ACCOUNT", - "com.google.android.gms.auth.login.LOGIN", + "com.google.android.gms.accounts.ACCOUNT_SERVICE", + "com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS", + "com.google.android.gms.accountsettings.action.BROWSE_SETTINGS", + "com.google.android.gms.accountsettings.action.VIEW_SETTINGS", + "com.google.android.gms.accountsettings.MY_ACCOUNT", + "com.google.android.gms.accountsettings.PRIVACY_SETTINGS", + "com.google.android.gms.accountsettings.SECURITY_SETTINGS", + "com.google.android.gms.ads.gservice.START", + "com.google.android.gms.ads.identifier.service.EVENT_ATTESTATION", + "com.google.android.gms.ads.service.CACHE", + "com.google.android.gms.ads.service.CONSENT_LOOKUP", + "com.google.android.gms.ads.service.HTTP", + "com.google.android.gms.analytics.service.START", + "com.google.android.gms.app.settings.GoogleSettingsLink", + "com.google.android.gms.appstate.service.START", + "com.google.android.gms.appusage.service.START", + "com.google.android.gms.asterism.service.START", + "com.google.android.gms.audiomodem.service.AudioModemService.START", + "com.google.android.gms.audit.service.START", + "com.google.android.gms.auth.account.authapi.START", + "com.google.android.gms.auth.account.authenticator.auto.service.START", + "com.google.android.gms.auth.account.authenticator.chromeos.START", + "com.google.android.gms.auth.account.authenticator.tv.service.START", + "com.google.android.gms.auth.account.data.service.START", "com.google.android.gms.auth.api.credentials.PICKER", "com.google.android.gms.auth.api.credentials.service.START", - "com.google.android.gms.auth.service.START", - "com.google.firebase.auth.api.gms.service.START", - "com.google.android.gms.auth.be.appcert.AppCertService", - "com.google.android.gms.credential.manager.service.firstparty.START", - "com.google.android.gms.auth.GOOGLE_SIGN_IN", - "com.google.android.gms.signin.service.START", - "com.google.android.gms.auth.api.signin.service.START", + "com.google.android.gms.auth.api.identity.service.authorization.START", + "com.google.android.gms.auth.api.identity.service.credentialsaving.START", "com.google.android.gms.auth.api.identity.service.signin.START", - "com.google.android.gms.accountsettings.action.VIEW_SETTINGS", - - // fido - "com.google.android.gms.fido.fido2.privileged.START", - - // gass - "com.google.android.gms.gass.START", - - // games - "com.google.android.gms.games.service.START", - "com.google.android.gms.games.PLAY_GAMES_UPGRADE", - "com.google.android.gms.games.internal.connect.service.START", - - // help - "com.google.android.gms.googlehelp.service.GoogleHelpService.START", - "com.google.android.gms.googlehelp.HELP", - "com.google.android.gms.feedback.internal.IFeedbackService", - - // cast + "com.google.android.gms.auth.api.phone.service.InternalService.START", + "com.google.android.gms.auth.api.signin.service.START", + "com.google.android.gms.auth.be.appcert.AppCertService", + "com.google.android.gms.auth.blockstore.service.START", + "com.google.android.gms.auth.config.service.START", + "com.google.android.gms.auth.cryptauth.cryptauthservice.START", + "com.google.android.gms.auth.GOOGLE_SIGN_IN", + "com.google.android.gms.auth.login.LOGIN", + "com.google.android.gms.auth.proximity.devicesyncservice.START", + "com.google.android.gms.auth.proximity.securechannelservice.START", + "com.google.android.gms.auth.proximity.START", + "com.google.android.gms.auth.service.START", + "com.google.android.gms.backup.ACTION_BACKUP_SETTINGS", + "com.google.android.gms.backup.G1_BACKUP", + "com.google.android.gms.backup.G1_RESTORE", + "com.google.android.gms.backup.GMS_MODULE_RESTORE", + "com.google.android.gms.beacon.internal.IBleService.START", + "com.google.android.gms.car.service.START", + "com.google.android.gms.carrierauth.service.START", "com.google.android.gms.cast.firstparty.START", + "com.google.android.gms.cast.remote_display.service.START", "com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE", - - // fonts - "com.google.android.gms.fonts", - - // phenotype - "com.google.android.gms.phenotype.service.START", - - // location - "com.google.android.gms.location.reporting.service.START", - - // misc - "com.google.android.gms.gmscompliance.service.START", - "com.google.android.gms.oss.licenses.service.START", - "com.google.android.gms.tapandpay.service.BIND", - "com.google.android.gms.measurement.START", - "com.google.android.gms.languageprofile.service.START", + "com.google.android.gms.cast_mirroring.service.START", + "com.google.android.gms.checkin.BIND_TO_SERVICE", + "com.google.android.gms.chromesync.service.START", "com.google.android.gms.clearcut.service.START", - "com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE", - "com.google.android.gms.icing.INDEX_SERVICE", - "com.google.android.gms.mdm.services.START", - - // potoken - "com.google.android.gms.potokens.service.START", - - // droidguard, safetynet + "com.google.android.gms.common.account.CHOOSE_ACCOUNT", + "com.google.android.gms.common.download.START", + "com.google.android.gms.common.service.START", + "com.google.android.gms.common.telemetry.service.START", + "com.google.android.gms.config.START", + "com.google.android.gms.constellation.service.START", + "com.google.android.gms.credential.manager.service.firstparty.START", + "com.google.android.gms.deviceconnection.service.START", + "com.google.android.gms.drive.ApiService.RESET_AFTER_BOOT", + "com.google.android.gms.drive.ApiService.START", + "com.google.android.gms.drive.ApiService.STOP", + "com.google.android.gms.droidguard.service.INIT", + "com.google.android.gms.droidguard.service.PING", "com.google.android.gms.droidguard.service.START", + "com.google.android.gms.enterprise.loader.service.START", + "com.google.android.gms.facs.cache.service.START", + "com.google.android.gms.facs.internal.service.START", + "com.google.android.gms.feedback.internal.IFeedbackService", + "com.google.android.gms.fido.credentialstore.internal_service.START", + "com.google.android.gms.fido.fido2.privileged.START", + "com.google.android.gms.fido.fido2.regular.START", + "com.google.android.gms.fido.fido2.zeroparty.START", + "com.google.android.gms.fido.sourcedevice.service.START", + "com.google.android.gms.fido.targetdevice.internal_service.START", + "com.google.android.gms.fido.u2f.privileged.START", + "com.google.android.gms.fido.u2f.thirdparty.START", + "com.google.android.gms.fido.u2f.zeroparty.START", + "com.google.android.gms.fitness.BleApi", + "com.google.android.gms.fitness.ConfigApi", + "com.google.android.gms.fitness.GoalsApi", + "com.google.android.gms.fitness.GoogleFitnessService.START", + "com.google.android.gms.fitness.HistoryApi", + "com.google.android.gms.fitness.InternalApi", + "com.google.android.gms.fitness.RecordingApi", + "com.google.android.gms.fitness.SensorsApi", + "com.google.android.gms.fitness.SessionsApi", + "com.google.android.gms.fonts.service.START", + "com.google.android.gms.freighter.service.START", + "com.google.android.gms.games.internal.connect.service.START", + "com.google.android.gms.games.PLAY_GAMES_UPGRADE", + "com.google.android.gms.games.service.START", + "com.google.android.gms.gass.START", + "com.google.android.gms.gmscompliance.service.START", + "com.google.android.gms.googlehelp.HELP", + "com.google.android.gms.googlehelp.service.GoogleHelpService.START", + "com.google.android.gms.growth.service.START", + "com.google.android.gms.herrevad.services.LightweightNetworkQualityAndroidService.START", + "com.google.android.gms.icing.INDEX_SERVICE", + "com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE", + "com.google.android.gms.identity.service.BIND", + "com.google.android.gms.inappreach.service.START", + "com.google.android.gms.instantapps.START", + "com.google.android.gms.kids.service.START", + "com.google.android.gms.languageprofile.service.START", + "com.google.android.gms.learning.internal.dynamitesupport.START", + "com.google.android.gms.learning.intservice.START", + "com.google.android.gms.learning.predictor.START", + "com.google.android.gms.learning.trainer.START", + "com.google.android.gms.learning.training.background.START", + "com.google.android.gms.location.places.GeoDataApi", + "com.google.android.gms.location.places.PlaceDetectionApi", + "com.google.android.gms.location.places.PlacesApi", + "com.google.android.gms.location.reporting.service.START", + "com.google.android.gms.location.settings.LOCATION_HISTORY", + "com.google.android.gms.location.settings.LOCATION_REPORTING_SETTINGS", + "com.google.android.gms.locationsharing.api.START", + "com.google.android.gms.locationsharingreporter.service.START", + "com.google.android.gms.lockbox.service.START", + "com.google.android.gms.matchstick.lighter.service.START", + "com.google.android.gms.mdm.services.DeviceManagerApiService.START", + "com.google.android.gms.mdm.services.START", + "com.google.android.gms.mdns.service.START", + "com.google.android.gms.measurement.START", + "com.google.android.gms.nearby.bootstrap.service.NearbyBootstrapService.START", + "com.google.android.gms.nearby.connection.service.START", + "com.google.android.gms.nearby.fastpair.START", + "com.google.android.gms.nearby.messages.service.NearbyMessagesService.START", + "com.google.android.gms.nearby.sharing.service.NearbySharingService.START", + "com.google.android.gms.nearby.sharing.START_SERVICE", + "com.google.android.gms.notifications.service.START", + "com.google.android.gms.ocr.service.internal.START", + "com.google.android.gms.ocr.service.START", + "com.google.android.gms.oss.licenses.service.START", + "com.google.android.gms.payse.service.BIND", + "com.google.android.gms.people.contactssync.service.START", + "com.google.android.gms.people.service.START", + "com.google.android.gms.phenotype.service.START", + "com.google.android.gms.photos.autobackup.service.START", + "com.google.android.gms.playlog.service.START", + "com.google.android.gms.plus.service.default.INTENT", + "com.google.android.gms.plus.service.image.INTENT", + "com.google.android.gms.plus.service.internal.START", + "com.google.android.gms.plus.service.START", + "com.google.android.gms.potokens.service.START", + "com.google.android.gms.pseudonymous.service.START", + "com.google.android.gms.rcs.START", + "com.google.android.gms.reminders.service.START", + "com.google.android.gms.romanesco.MODULE_BACKUP_AGENT", + "com.google.android.gms.romanesco.service.START", "com.google.android.gms.safetynet.service.START", + "com.google.android.gms.scheduler.ACTION_PROXY_SCHEDULE", + "com.google.android.gms.search.service.SEARCH_AUTH_START", + "com.google.android.gms.semanticlocation.service.START_ODLH", + "com.google.android.gms.sesame.service.BIND", + "com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS", + "com.google.android.gms.setup.auth.SecondDeviceAuth.START", + "com.google.android.gms.signin.service.START", + "com.google.android.gms.smartdevice.d2d.SourceDeviceService.START", + "com.google.android.gms.smartdevice.d2d.TargetDeviceService.START", + "com.google.android.gms.smartdevice.directtransfer.SourceDirectTransferService.START", + "com.google.android.gms.smartdevice.directtransfer.TargetDirectTransferService.START", + "com.google.android.gms.smartdevice.postsetup.PostSetupService.START", + "com.google.android.gms.smartdevice.setup.accounts.AccountsService.START", + "com.google.android.gms.smartdevice.wifi.START_WIFI_HELPER_SERVICE", + "com.google.android.gms.social.location.activity.service.START", + "com.google.android.gms.speech.service.START", + "com.google.android.gms.statementservice.EXECUTE", + "com.google.android.gms.stats.ACTION_UPLOAD_DROPBOX_ENTRIES", + "com.google.android.gms.tapandpay.service.BIND", + "com.google.android.gms.telephonyspam.service.START", + "com.google.android.gms.testsupport.service.START", + "com.google.android.gms.thunderbird.service.START", + "com.google.android.gms.trustagent.BridgeApi.START", + "com.google.android.gms.trustagent.StateApi.START", + "com.google.android.gms.trustagent.trustlet.trustletmanagerservice.BIND", + "com.google.android.gms.trustlet.bluetooth.service.BIND", + "com.google.android.gms.trustlet.connectionlessble.service.BIND", + "com.google.android.gms.trustlet.face.service.BIND", + "com.google.android.gms.trustlet.nfc.service.BIND", + "com.google.android.gms.trustlet.onbody.service.BIND", + "com.google.android.gms.trustlet.place.service.BIND", + "com.google.android.gms.trustlet.voiceunlock.service.BIND", + "com.google.android.gms.udc.service.START", + "com.google.android.gms.update.START_API_SERVICE", + "com.google.android.gms.update.START_SERVICE", + "com.google.android.gms.update.START_SINGLE_USER_API_SERVICE", + "com.google.android.gms.update.START_TV_API_SERVICE", + "com.google.android.gms.usagereporting.service.START", + "com.google.android.gms.userlocation.service.START", + "com.google.android.gms.vehicle.cabin.service.START", + "com.google.android.gms.vehicle.climate.service.START", + "com.google.android.gms.vehicle.info.service.START", + "com.google.android.gms.wallet.service.BIND", + "com.google.android.gms.walletp2p.service.firstparty.BIND", + "com.google.android.gms.walletp2p.service.zeroparty.BIND", + "com.google.android.gms.wearable.BIND", + "com.google.android.gms.wearable.BIND_LISTENER", + "com.google.android.gms.wearable.DATA_CHANGED", + "com.google.android.gms.wearable.MESSAGE_RECEIVED", + "com.google.android.gms.wearable.NODE_CHANGED", + "com.google.android.gsf.action.GET_GLS", + "com.google.android.location.settings.LOCATION_REPORTING_SETTINGS", + "com.google.android.mdd.service.START", + "com.google.android.mdh.service.listener.START", + "com.google.android.mdh.service.START", + "com.google.android.mobstore.service.START", + "com.google.firebase.auth.api.gms.service.START", + "com.google.firebase.dynamiclinks.service.START", + "com.google.iid.TOKEN_REQUEST", + "com.google.android.gms.location.places.ui.PICK_PLACE", ) /** * All content provider authorities. */ val AUTHORITIES = setOf( - // gsf + "com.google.android.gms.auth.accounts", + "com.google.android.gms.chimera", + "com.google.android.gms.fonts", + "com.google.android.gms.phenotype", "com.google.android.gsf.gservices", "com.google.settings", - - // auth - "com.google.android.gms.auth.accounts", - - // fonts - "com.google.android.gms.fonts", - - // phenotype - "com.google.android.gms.phenotype", ) } From f9d517055f297aae5bd0bcab97af4dde04338fe0 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:57:03 +0900 Subject: [PATCH 44/65] feat(Translations): Update translation --- .../music/translations/el-rGR/strings.xml | 9 ++- .../music/translations/es-rES/strings.xml | 1 + .../music/translations/hu-rHU/strings.xml | 15 +++- .../music/translations/ko-rKR/strings.xml | 13 +++- .../music/translations/pl-rPL/strings.xml | 7 ++ .../music/translations/pt-rBR/strings.xml | 7 +- .../music/translations/uk-rUA/strings.xml | 1 + .../music/translations/vi-rVN/strings.xml | 13 +++- .../music/translations/zh-rTW/strings.xml | 50 ++++++++++++ .../youtube/translations/ar/strings.xml | 62 +++++++++------ .../youtube/translations/bg-rBG/strings.xml | 14 ---- .../youtube/translations/de-rDE/strings.xml | 11 --- .../youtube/translations/el-rGR/strings.xml | 66 +++++++++------- .../youtube/translations/es-rES/strings.xml | 58 ++++++++------ .../youtube/translations/fr-rFR/strings.xml | 62 +++++++++------ .../youtube/translations/hu-rHU/strings.xml | 58 ++++++++------ .../youtube/translations/it-rIT/strings.xml | 72 +++++++++++------- .../youtube/translations/ja-rJP/strings.xml | 65 ++++++++++------ .../youtube/translations/ko-rKR/strings.xml | 72 ++++++++++-------- .../youtube/translations/pl-rPL/strings.xml | 58 ++++++++------ .../youtube/translations/pt-rBR/strings.xml | 46 +++++------ .../youtube/translations/ru-rRU/strings.xml | 61 +++++++++------ .../youtube/translations/tr-rTR/strings.xml | 8 -- .../youtube/translations/uk-rUA/strings.xml | 62 +++++++++------ .../youtube/translations/vi-rVN/strings.xml | 65 ++++++++++------ .../youtube/translations/zh-rCN/strings.xml | 14 ---- .../youtube/translations/zh-rTW/strings.xml | 76 +++++++++++-------- 27 files changed, 627 insertions(+), 419 deletions(-) diff --git a/patches/src/main/resources/music/translations/el-rGR/strings.xml b/patches/src/main/resources/music/translations/el-rGR/strings.xml index d45e07ea8..abfa67e4d 100644 --- a/patches/src/main/resources/music/translations/el-rGR/strings.xml +++ b/patches/src/main/resources/music/translations/el-rGR/strings.xml @@ -375,6 +375,12 @@ Απενεργοποίηση των εφέ θέματος Cairo κατά την εκκίνηση της εφαρμογής. Απενεργοποίηση ήχου DRC Απενεργοποίηση του DRC (Συμπίεση Δυναμικού Εύρους) που εφαρμόζεται στον ήχο. + Απενεργοποίηση μουσικών βίντεο στα άλμπουμ + "Όταν ένας μη-premium χρήστης παίζει ένα τραγούδι που περιλαμβάνεται σε ένα άλμπουμ, μερικές φορές αναπαράγεται το μουσικό βίντεο αντί για το επίσημο τραγούδι. + +Αν ανιχνεύεται αναπαραγωγή ενός μουσικού βίντεο που περιλαμβάνεται σε άλμπουμ, ανακατευθύνεται στο επίσημο τραγούδι. + +Χρησιμοποιείται το Piped API, και ενδέχεται να μην είναι διαθέσιμο σε ορισμένες περιοχές." Ενεργοποίηση καταγραφής σφαλμάτων Εκτύπωση του αρχείου καταγραφής σφαλμάτων. Συμπερίληψη του buffer στην καταγραφή @@ -406,7 +412,7 @@ Προεπιλεγμένο πρόγραμμα πελάτη "Καθορισμός ενός προεπιλεγμένου πρόγραμμα πελάτη για παραποίηση. -※ Όταν ορίζεται πρόγραμμα πελάτη τύπου Android, συνιστάται να το χρησιμοποιήσετε μαζί με την λειτουργία «Παραποίηση έκδοσης εφαρμογής»." +※ Όταν ορίζεται πρόγραμμα πελάτη Android, συνιστάται να το χρησιμοποιήσετε μαζί με την λειτουργία «Παραποίηση έκδοσης εφαρμογής»." Android Music 4.27.53 Android Music 5.29.53 iOS Music 6.21 @@ -419,6 +425,7 @@ Εμφάνιση στο «Στατιστικά για σπασίκλες» Εμφάνιση του προγράμματος πελάτη που χρησιμοποιείται για τη λήψη δεδομένων ροής στο μενού «Στατιστικά για σπασίκλες». Android VR + Android Music Καθαρισμός συνδέσμων κοινοποίησης Αφαίρεση των παραμέτρων παρακολούθησης από τις διευθύνσεις URL κατά την κοινοποίηση συνδέσμων. Άνοιγμα ρυθμίσεων προεπιλεγμένων εφαρμογών diff --git a/patches/src/main/resources/music/translations/es-rES/strings.xml b/patches/src/main/resources/music/translations/es-rES/strings.xml index 9e86a18fa..05b9016e6 100644 --- a/patches/src/main/resources/music/translations/es-rES/strings.xml +++ b/patches/src/main/resources/music/translations/es-rES/strings.xml @@ -415,6 +415,7 @@ Limitaciones: Mostrar en estadísticas para nerds Muestra el cliente utilizado para obtener datos de streaming en Estadísticas para nerds. Android VR + Android Music Desinfectar enlaces compartidos Elimina los parámetros de consulta de seguimiento de las URL al compartir enlaces. Abrir ajustes predeterminados de la app diff --git a/patches/src/main/resources/music/translations/hu-rHU/strings.xml b/patches/src/main/resources/music/translations/hu-rHU/strings.xml index 350a0b658..87bd26fb0 100644 --- a/patches/src/main/resources/music/translations/hu-rHU/strings.xml +++ b/patches/src/main/resources/music/translations/hu-rHU/strings.xml @@ -372,6 +372,12 @@ Kattints ide az API-kulcs megszerzéséhez." Letiltja a betöltési animációt amikor az app indul. DRC hang letiltása Letiltja a hangra alkalmazott DRC-t (dinamikatartomány-kompresszió). + Zenei videó letiltása az albumban + "Amikor egy nem prémium felhasználó lejátszik egy albumban szereplő dalt, néha a hivatalos dal helyett a klip kerül lejátszásra. + +Ha egy albumban szereplő zenei videó lejátszását észleli, a rendszer a hivatalos dalra irányítja át. + +Piped instance használatban van, és előfordulhat, hogy az API egyes régiókban nem elérhető." Hibanaplók engedélyezése Kiírja a hibanaplót. Hibakeresési puffer naplózásának engedélyezése @@ -399,25 +405,26 @@ A GmsCore akkumulátor-optimalizálás letiltása nem fogyasztja jobban az akkum Nyomj a folytatás gombra, és engedélyezd az optimalizálási módosításokat." Folytatás Kliens hamisítása - "A kliens hamisítása a lejátszási problémák elkerülése érdekében. + "Az kliens meghamisítása a lejátszási problémák megelőzése érdekében. -※ Az 'Adatfolyam meghamisítása' használata esetén lejátszási problémák léphetnek fel." +• Az 'Adatfolyam meghamisítása' funkcióval együtt használva lejátszási problémák léphetnek fel." Alapértelmezett kliens "Meghatározza az alapértelmezett klienst a hamisításhoz. -※ Az Android kliens használata esetén ajánlott a 'Alkalmazás verziójának meghamisítása' használni." +• Az Android kliens használata esetén ajánlott a 'Alkalmazás verziójának meghamisítása' használni." Android Music 4.27.53 Android Music 5.29.53 iOS Music 6.21 Adatfolyam meghamisítása "A lejátszási problémák megelőzése érdekében hamisítja a streaming-adatokat. -※ A 'Kliens hamisítása' használata esetén lejátszási problémák léphetnek fel." +• A 'Kliens hamisítása' használata esetén lejátszási problémák léphetnek fel." Alapértelmezett kliens Meghatároz egy alapértelmezett klienst, amely streaming adatokat hív le. Megjelenik a statisztikák kockáknakban Megmutatja a streaming adatok lekérdezésére használt klienst a Statisztikák kockáknakban. Android VR + Android Music Megosztási linkek tisztítása Linkek megosztásakor eltávolítja a nyomkövetési paramétereket az URL-ekből. Alapértelmezett program beállítások megnyitása diff --git a/patches/src/main/resources/music/translations/ko-rKR/strings.xml b/patches/src/main/resources/music/translations/ko-rKR/strings.xml index dbf1a0db1..56ba31420 100644 --- a/patches/src/main/resources/music/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/music/translations/ko-rKR/strings.xml @@ -376,6 +376,12 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요." 앱을 시작할 때, Cairo 스플래시 애니메이션을 비활성화합니다. DRC 오디오 비활성화 오디오에 적용된 DRC (Dynamic Range Compression)를 비활성화합니다. + 앨범에서 뮤직 비디오 비활성화 + "프리미엄이 아닌 사용자가 앨범에 포함된 노래를 재생할 때, 공식 음원이 아닌 뮤직 비디오가 재생되는 경우가 있습니다. + +이러한 뮤직 비디오가 재생되는 것이 감지되면 공식 음원으로 리디렉션됩니다. + +파이핑된 인스턴스가 사용되지만 일부 지역에서는 API를 사용하지 못할 수 있습니다." 디버그 로깅 활성화 디버그 로그를 출력합니다. 디버그 버퍼 로깅 활성화 @@ -403,23 +409,24 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요." 클라이언트 변경 "클라이언트를 변경하여 재생 문제를 방지할 수 있습니다. -※ '스트리밍 데이터 변경'과 함께 사용할 경우에 재생 문제가 발생할 수 있습니다." +• '스트리밍 데이터 변경'과 함께 사용할 경우에 재생 문제가 발생할 수 있습니다." 기본 클라이언트 "변경할 기본 클라이언트를 정의합니다. -※ Android 클라이언트를 사용할 경우에 '앱 버전 변경'과 함께 사용하는 것을 권장합니다." +• Android 클라이언트를 사용할 경우에 '앱 버전 변경'과 함께 사용하는 것을 권장합니다." Android Music 4.27.53 Android Music 5.29.53 iOS Music 6.21 스트리밍 데이터 변경 "스트리밍 데이터를 변경하여 재생 문제를 방지합니다. -※ '클라이언트 변경'과 함께 사용할 경우에 재생 문제가 발생할 수 있습니다." +• '클라이언트 변경'과 함께 사용할 경우에 재생 문제가 발생할 수 있습니다." 기본 클라이언트 스트리밍 데이터를 가져오는 데 사용되는 기본 클라이언트를 정의할 수 있습니다. 동영상 통계에서 표시 \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 동영상 통계에서 표시됩니다. Android VR + Android Music 추적 쿼리를 제거한 링크 공유 링크를 공유할 때, URL에서 추적 쿼리 매개변수를 제거합니다. 기본 앱 설정 열기 diff --git a/patches/src/main/resources/music/translations/pl-rPL/strings.xml b/patches/src/main/resources/music/translations/pl-rPL/strings.xml index ac8358637..e31bbae86 100644 --- a/patches/src/main/resources/music/translations/pl-rPL/strings.xml +++ b/patches/src/main/resources/music/translations/pl-rPL/strings.xml @@ -375,6 +375,12 @@ Kliknij, by zobaczyć, jak zgłosić klucz API." Wyłącza animację ładowania aplikacji związaną z motywem Cairo podczas otwierania aplikacji. Wyłącz audio DRC Wyłącza DRC (Dynamic Range Compression) stosowane w utworach. + Wyłącz teledyski w albumach + "Gdy użytkownik non-premium odtwarza utwór zawarty w albumie, czasami zamiast oficjalnego utworu, odtwarzany jest teledysk. + +W przypadku wykrycia odtwarzania teledysku zawartego w albumie, następuje przekierowanie do oficjalnego utworu. + +Używana jest instancja Piped, a interfejs API może nie być dostępny w niektórych regionach." Włącz logowanie debugowania Wyświetla log od debugowania. Logi do debugowania buforu @@ -422,6 +428,7 @@ Stuknij przycisk kontynuacji i zezwól na zmiany w optymalizacji." Informacja w statystykach dla nerdów Pokazuje używanego klienta do przechwytywania strumienia danych w statystykach dla nerdów. Android VR + Android Music Oczyść udostępniane linki Usuwa parametry śledzących zapytań z adresów URL podczas udostępniania linków. Otwórz systemowe ustawienia aplikacji diff --git a/patches/src/main/resources/music/translations/pt-rBR/strings.xml b/patches/src/main/resources/music/translations/pt-rBR/strings.xml index 8f5ab4cbb..9fbde53af 100644 --- a/patches/src/main/resources/music/translations/pt-rBR/strings.xml +++ b/patches/src/main/resources/music/translations/pt-rBR/strings.xml @@ -404,23 +404,24 @@ Toque no botão continuar e permita as alterações de otimização." Falsificar cliente "Falsificar o cliente para evitar problemas de reprodução. -※ Quando usado com 'Dados de streaming falsos', podem ocorrer problemas de reprodução." +• Quando usado com 'Dados de streaming falsos', podem ocorrer problemas de reprodução." Cliente padrão "Define um cliente padrão para falsificar. -※ Ao usar o cliente Android, é recomendável usá-lo com 'Falsificar versão do aplicativo'." +• Ao usar o cliente Android, é recomendado usar também 'Falsificar versão do aplicativo'." Android Music 4.27.53 Android Music 5.29.53 iOS Music 6.21 Dados de streaming falsos "Falsifique os dados de streaming para evitar problemas de reprodução. -※ Quando usado com 'Falsificar cliente', podem ocorrer problemas de reprodução." +• Quando usado com 'Falsificar cliente', podem ocorrer problemas de reprodução." Cliente padrão Define um cliente padrão que busca dados de streaming. Exibir em Estatísticas para nerds Exibir o cliente usado para buscar dados de streaming em estatísticas para nerds. Android VR + Android Music Limpar links compartilhados Remove os parâmetros de consulta de rastreamento das URLs ao compartilhar os links. Abrir configurações padrão do aplicativo diff --git a/patches/src/main/resources/music/translations/uk-rUA/strings.xml b/patches/src/main/resources/music/translations/uk-rUA/strings.xml index 8fc60cdba..bde8c6814 100644 --- a/patches/src/main/resources/music/translations/uk-rUA/strings.xml +++ b/patches/src/main/resources/music/translations/uk-rUA/strings.xml @@ -421,6 +421,7 @@ Показувати у \"Статистиці для сисадмінів\" Показує клієнт, який використовується для отримання потокових даних у \"Статистиці для сисадмінів\". Android VR + Android Music Обробляти поширення посилань Видаляє параметри запиту відстеження з URL-адрес під час обміну посиланнями. Відкрити налаштування за замовчуванням diff --git a/patches/src/main/resources/music/translations/vi-rVN/strings.xml b/patches/src/main/resources/music/translations/vi-rVN/strings.xml index 29e533a6a..5e9ea73ce 100644 --- a/patches/src/main/resources/music/translations/vi-rVN/strings.xml +++ b/patches/src/main/resources/music/translations/vi-rVN/strings.xml @@ -375,6 +375,12 @@ Nhấp vào đây để xem các bước phát hành khóa API." Vô hiệu hóa hoạt ảnh kiểu Cairo khi ứng dụng khởi chạy. Vô hiệu hoá audio DRC Vô hiệu hoá tính năng nén dải âm thanh động. + Tắt video âm nhạc trong đĩa nhạc + "Khi người dùng không mua gói Premium, đôi khi nghe nhạc có trong đĩa nhạc, video âm nhạc được phát thay vì bài hát chính thức. + +Nếu trường hợp đó xẩy ra, ứng dụng sẽ chuyển hướng đến bài hát chính thức. + +Phiên bản Piped được sử dụng và API có thể không khả dụng ở một số khu vực." Nhật ký gỡ lỗi Bật ghi nhật ký gỡ lỗi. Bật nhật ký bộ đệm gỡ lỗi @@ -404,23 +410,24 @@ Nhấn vào Tiếp tục và cho phép thay đổi lựa chọn tối ưu hoá p Giả mạo ứng dụng khách "Giả mạo ứng dụng khách nhằm khắc phục sự cố phát. -※ Khi được sử dụng đồng thời với \"Giả mạo luồng dữ liệu trực tuyến\", có thể gây ra sự cố phát." +• Khi được sử dụng đồng thời với \"Giả mạo luồng dữ liệu trực tuyến\", có thể gây ra sự cố phát." Ứng dụng khách mặc định "Xác định ứng dụng khách mặc định để giả mạo. -※ Khi sử dụng ứng dụng khách Android, tính năng này nên được sử dụng đồng thời với \"Giả mạo phiên bản ứng dụng\"." +• Khi sử dụng ứng dụng khách Android, tính năng này nên được sử dụng đồng thời với \"Giả mạo phiên bản ứng dụng\"." Android Music 4.27.53 Android Music 5.29.53 Music iOS 6.21 Giả mạo luồng dữ liệu trực tuyến "Giả mạo luồng dữ liệu trực tuyến nhằm khắc phục sự cố phát. -※ Khi được sử dụng đồng thời với \"Giả mạo ứng dụng khách\", có thể gây ra sự cố phát." +• Khi được sử dụng đồng thời với \"Giả mạo ứng dụng khách\", có thể gây ra sự cố phát." Ứng dụng khách mặc định Xác định một ứng dụng khách mặc định để nạp luồng dữ liệu trực tuyến. Hiển thị trong Thống kê chi tiết Hiển thị ứng dụng khách được sử dụng để nạp luồng dữ liệu trực tuyến trong Thống kê chi tiết. Android VR + Android Music Liên kết sạch khi chia sẻ Loại bỏ các tham số truy vấn theo dõi khỏi URL khi chia sẻ liên kết. Mở theo mặc định diff --git a/patches/src/main/resources/music/translations/zh-rTW/strings.xml b/patches/src/main/resources/music/translations/zh-rTW/strings.xml index 49eed3d20..0c902f71a 100644 --- a/patches/src/main/resources/music/translations/zh-rTW/strings.xml +++ b/patches/src/main/resources/music/translations/zh-rTW/strings.xml @@ -197,6 +197,10 @@ 隱藏位於導覽列的標籤 播放器 + 停用迷你播放器手勢 + 停用迷你播放器中的滑動切換曲目功能。 + 停用播放器手勢 + 停用播放器中的滑動切換歌曲。 啟用黑色播放器背景 將播放器背景顏色設成為黑色 啟用彩色播放列 @@ -219,6 +223,8 @@ 隱藏留言頂部的頻道指南 隱藏時間戳與表情符號按鈕 輸入留言時隱藏時間戳記和表情符號按鈕 + 隱藏連點兩下疊加濾鏡 + 隱藏點兩下以快轉或倒退時出現的深色疊加層。 隱藏全螢幕播放器中的分享按鈕 在全螢幕播放器中隱藏分享按鈕 記住重複播放狀態 @@ -233,14 +239,29 @@ "將播放器介面恢復為舊樣式 某些功能在舊的播放器介面中可能無法正常運作" + 設定選單 + 隱藏家庭中心選單 + 隱藏一般選單 + 隱藏播放選單 + 隱藏資料儲存選單 + 隱藏下載&儲存選單 + 隱藏通知選單 + 隱藏隱私權&資料選單 + 隱藏推薦選單 + 隱藏取得 Music Premium 選單 + 隱藏關於選單 影片 編輯自訂播放速度 新增或變更可以使用的播放速度 記住播放速度的變更 記住上次選擇的播放速度 + 顯示提示訊息 + 變更預設播放速度時顯示提示訊息。 記住影片畫質變更 記住上次選擇的影片畫質 + 顯示提示訊息 + 變更預設播放速度時顯示提示訊息。 自訂速度必須小於 %sx 使用預設值 自訂播放速度無效 使用預設值 將預設速度更改為 %s @@ -255,6 +276,8 @@ 將倒讚數以百分比的形式顯示 緊湊型按讚按鈕 隱藏按讚按鈕中間的分隔線 + 顯示估計喜歡的次數 + 顯示影片的喜歡次數 當API無法使用時顯示提示訊息 當 Return YouTube Dislike API 無法使用時顯示提示訊息 關於 @@ -265,7 +288,22 @@ 倒讚數無法使用 (狀態 %d) 倒讚顯示不正常(已達到客戶端 API 限制) 倒讚數無法使用 (狀態 %s) + 隱藏 + 恢復 YouTube 使用者名稱 + 啟用恢復 YouTube 使用者名稱 + 在留言中將使用者名稱取代帳號名稱。 + 顯示樣式 + 選擇使用者名稱顯示樣式。 + 使用者名稱 + 使用者名稱 (@帳號名稱) + \@帳號名稱 (使用者名稱) + YouTube 資料 API 金鑰 + 使用 YouTube 資料 API v3 的開發人員金鑰 + 關於 YouTube 資料 API 金鑰 + "需要 YouTube Data API v3 開發者金鑰才能將帳號名稱替換為使用者名稱。免費方案的 API 金鑰每日配額為 10,000 次,每替換一次留言中的帳號名稱為使用者名稱會消耗 1 次配額。點擊此處了解如何申請 API 金鑰。" + 取得 YouTube 資料 API v3 開發人員金鑰 + 1. 前往 <a href=%1$s>建立新專案&p;.<br>2.點擊<b>創建</b> 按鈕。<br>3.<br>轉到 <a href=%2$s>YouTube 資料 API v3</a>.<br>4.點選<b>啟用</b> 按鈕。<br>5.點選<b>建立憑證<b> 按鈕。 <br>6.選擇<b>公共資料</b> 選項。<br>7.點選<b>下一步</b> 按鈕。<br>8.複製 API 金鑰。<br><br>※ API 金鑰不應與其他人共用,因此它不包含在匯入/匯出設定中。 贊助區塊阻擋(SponsorBlock) 啟用SponsorBlock @@ -305,6 +343,18 @@ 此功能僅供音樂影片使用。本功能僅應該用於音樂錄影帶中並未包含其他類別的段落。 已跳過贊助 已跳過自我宣傳 + 已跳過煩人的提醒 + 已跳過開頭 + 已跳過中場休息 + 已跳過中場休息 + 已跳過結尾 + 已跳過預覽 + 已跳過預覽 + 已跳過前情提要 + 已跳過贅詞 + 已跳過非音樂片段 + 已跳過多個片段 + 自動跳過 啟用除錯紀錄 列出除錯記錄檔 diff --git a/patches/src/main/resources/youtube/translations/ar/strings.xml b/patches/src/main/resources/youtube/translations/ar/strings.xml index 8c2760391..15b1877b6 100644 --- a/patches/src/main/resources/youtube/translations/ar/strings.xml +++ b/patches/src/main/resources/youtube/translations/ar/strings.xml @@ -293,6 +293,7 @@ عام تغيير صفحة البداية تصفح القنوات + الدورات / التعلم الافتراضي اكتشف ألعاب فيديو @@ -302,12 +303,14 @@ بث مباشر أفلام موسيقى + الإشعارات البحث Shorts رياضة الاشتراكات المحتوى الرائج المشاهدة لاحقًا + فيديوهاتك تغيير نوع صفحة البداية "تتغير صفحة البدء دائمًا. @@ -322,6 +325,9 @@ تعطيل تأثيرات الحركة تم تعطيل تأثيرات الحركة. تم تمكين تأثيرات الحركة. + تعطيل شريط الحالة الشفاف + شريط الحالة غير شفاف. + شريط الحالة معتم أو شفاف. تمكين شاشة التحميل المتدرجة تم تمكين شاشة التحميل المتدرجة الملونة. تم تعطيل شاشة التحميل المتدرجة الملونة. @@ -493,6 +499,9 @@ كما لن يتم حظر الإعلانات في فيديوهات Shorts بعد الآن. إذا لم يتم تفعيل هذا الإعداد، فحاول التبديل إلى وضع التصفح المتخفي." + تمكين شريط التنقل الشفاف + شريط التنقل شفاف. + شريط التنقل غير شفاف. إخفاء شريط التنقل تم إخفاء شريط التنقل. يتم عرض شريط التنقل. @@ -907,11 +916,6 @@ تمكين تراكب التحكم المدمج لا يملأ تراكب عناصر التحكم الشاشة الكاملة. يملأ تراكب عناصر التحكم الشاشة الكاملة. - فرض ملء الشاشة - "سيتم تحويل الفيديوهات إلى وضع ملء الشاشة في المواقف التالية: - -• عند بدء تشغيل الفيديو. -• عندما يتم النقر على الطابع الزمني في التعليقات." الإبقاء على الوضع الأفقي يحافظ على الوضع الأفقي عند إيقاف تشغيل الشاشة وتشغيلها في وضع ملء الشاشة. مهلة إبقاء الوضع الأفقي @@ -1384,12 +1388,18 @@ تعطيل سطوع HDR التلقائي تم تعطيل سطوع HDR التلقائي. تم تمكين سطوع HDR التلقائي. - تعطيل إيماءات لوح المشاهدة - تم تعطيل الدخول إلى وضع ملء الشاشة عند التمرير لأسفل أسفل مشغل الفيديو. - تم تمكين الدخول إلى وضع ملء الشاشة عند التمرير لأسفل أسفل مشغل الفيديو. تعطيل التمرير لتغيير الفيديو - لن يؤدي التمرير لأعلى/لأسفل إلى تشغيل الفيديو التالي/السابق. - سيؤدي التمرير لأعلى/لأسفل إلى تشغيل الفيديو التالي/السابق. + لن يؤدي التمرير لأعلى/لأسفل في وضع ملء الشاشة إلى الانتقال إلى الفيديو التالي/السابق. + سيؤدي التمرير لأعلى/لأسفل في وضع ملء الشاشة إلى الانتقال إلى الفيديو التالي/السابق. + تعطيل التمرير للدخول إلى وضع ملء الشاشة (أسفل المشغل) + لن يؤدي التمرير لأسفل أسفل المشغل إلى الدخول إلى وضع ملء الشاشة. + سيؤدي التمرير لأسفل أسفل المشغل إلى الدخول إلى وضع ملء الشاشة. + تعطيل التمرير للدخول إلى وضع ملء الشاشة (في المشغل) + لن يؤدي التمرير لأعلى في المشغل إلى الدخول إلى وضع ملء الشاشة. + سيؤدي التمرير لأعلى في المشغل إلى الدخول إلى وضع ملء الشاشة. + تعطيل التمرير للخروج من وضع ملء الشاشة + لن يؤدي التمرير لأسفل في وضع ملء الشاشة إلى الخروج من وضع ملء الشاشة. + سيؤدي التمرير لأسفل في وضع ملء الشاشة إلى الخروج من وضع ملء الشاشة. تلقائي الفيديو @@ -1399,9 +1409,6 @@ تعطيل فيديو HDR تم تعطيل فيديو HDR. تم تمكين فيديو HDR. - تعطيل سرعة التشغيل للبث المباشر - تم تعطيل سرعة التشغيل الافتراضية للبث المباشر. - تم تمكين سرعة التشغيل الافتراضية للبث المباشر. تمكين سرعة التشغيل المخصصة تم تمكين سرعة التشغيل المخصصة. تم تعطيل سرعة التشغيل المخصصة. @@ -1426,9 +1433,6 @@ يتم عرض قائمة جودة الفيديو القديمة. لا يتم عرض قائمة جودة الفيديو القديمة. تعطيل سرعة التشغيل للموسيقى - "تم تعطيل سرعة التشغيل الافتراضية للموسيقى. - -التقييد: قد لا ينطبق هذا الإعداد على الفيديوهات التي لا تتضمن لافتة \"الاستماع على YouTube Music\"." تم تمكين سرعة التشغيل الافتراضية للموسيقى. تمكين سرعة التشغيل الافتراضية لفيديوهات Shorts تنطبق سرعة التشغيل الافتراضية على Shorts. @@ -1774,20 +1778,28 @@ "لا يتم تزييف بيانات البث. قد لا يعمل تشغيل الفيديو." إيقاف تشغيل هذا الإعداد قد يسبب مشاكل في تشغيل الفيديو. العميل الافتراضي - Android TV - Android VR - iOS - iOS TV التأثيرات الجانبية للتزييف - "• قائمة المقطع الصوتي مفقودة. -• مستوى الصوت الثابت غير متاح. -• تعطيل مقاطع الصوت التلقائية المفروضة غير متاح." - • لم يتم العثور عليه بعد. - • قد لا يتم تشغيل الأفلام أو الفيديوهات المدفوعة. + فرض iOS AVC (H.264) + يتم فرض ترميز الفيديو على AVC (H.264). + يتم تحديد ترميز الفيديو تلقائيًا. + "قد يؤدي تمكين هذا إلى تحسين عمر البطارية وإصلاح تقطيع التشغيل. + +AVC لديه حد أقصى للدقة 1080p، لا يتوفر ترميز الصوت Opus، وسوف يستخدم تشغيل الفيديو بيانات إنترنت أكثر من VP9 أو AV1." عرض في إحصاءات تقنية يتم عرض العميل المستخدم لجلب بيانات البث في إحصاءات تقنية. تم إخفاء العميل المستخدم لجلب بيانات البث في إحصاءات تقنية. + PoToken / VisitorData + استخدام PoToken + PoToken الصادرة عن BotGuard في متصفح موثوق به. + استخدام VisitorData + VisitorsData الصادرة عن BotGuard في متصفح موثوق به. + لمحة عن PoToken / VisitorData + "يتطلب بعض العملاء PoToken و VisitorData للحصول على استجابة صالحة لتدفق البيانات. + +إذا كنت تحاول استخدام iOS كعميل افتراضي، فقد تحتاج إلى هذه القيم. + +انقر لمعرفة المزيد من المعلومات." سجل المشاهدة تغيير الإعدادات المتعلقة بسجل المشاهدة. diff --git a/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml b/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml index 3876b20d3..2f433d03b 100644 --- a/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml +++ b/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml @@ -886,11 +886,6 @@ Вкл. компактни контроли По-малките стилови контроли са активирани. По-малките стилови контроли са деактивирани. - Принудително винаги на цял екран - "Видеоклиповете ще превключат в режим на цял екран в следните случаи: - -• Когато започне видео. -• Когато се натисне клеймо за време в коментарите." Запазете пейзажен режим Запазва пейзажен режим при изключване и включване на цял екран. Запазване на времето за изчакване в пейзажен режим @@ -1316,9 +1311,6 @@ Изкл. HDR клипове HDR клиповете са изключени. HDR клиповете са включени. - Деактивирайте скоростта на възпроизвеждане за потоци на живо - Скоростта на възпроизвеждане по подразбиране е деактивирана за потоци на живо. - Скоростта на възпроизвеждане по подразбиране е активирана за потоци на живо. Вкл. на скорост на видеото по избор Скоростта по избор на видеото е включена. Скоростта по избор на видеото е изключена. @@ -1343,9 +1335,6 @@ Показва се старото меню за видео качество. Старото меню за видео качество е скрито. Деактивирайте скоростта на възпроизвеждане за музика - "Скоростта на възпроизвеждане по подразбиране не се прилага за музикални видеоклипове - - Тази настройка може да не се прилага за видеоклипове, които не включват функцията „Слушане с YouTube Music“." Скоростта на възпроизвеждане по подразбиране е активирана за музика. Променете скоростта на възпроизвеждане на Shorts Скоростта на възпроизвеждане по подразбиране се прилага за Shorts. @@ -1685,9 +1674,6 @@ "Данните за поточно предаване не са подправени. Възпроизвеждането на видео може да не работи." Изключването на тази настройка може да причини проблеми с възпроизвеждането на видео. Клиент по подразбиране - Android TV - Android VR - iOS Ефекти от замяната Показване в \"Разширени статистики\" Клиентът, използван за получаване на данни за потока, се показва в Статистика за системни администратори. diff --git a/patches/src/main/resources/youtube/translations/de-rDE/strings.xml b/patches/src/main/resources/youtube/translations/de-rDE/strings.xml index 11d811cfd..61087ed4c 100644 --- a/patches/src/main/resources/youtube/translations/de-rDE/strings.xml +++ b/patches/src/main/resources/youtube/translations/de-rDE/strings.xml @@ -844,11 +844,6 @@ Einschränkung: Videotitel verschwindet beim Klicken auf den Bildschirm."Kompaktsteuerungs-Overlay aktivieren Kompaktsteuerungs-Overlay ist aktiviert Kompaktsteuerungs-Overlay ist deaktiviert - Vollbild erzwingen - "Videos werden in den folgenden Situation im Vollbild wieder gegeben: - -• Wenn ein Video gestartet wird. -• Wenn ein Zeitstempel in den Kommentaren geklickt wird." Querformat behalten Bewahrt den Querformat beim Ausschalten des Bildschirms im Vollbild. Timeout für den Wechsel zum Querformat @@ -1150,9 +1145,6 @@ Bekannte Probleme: Da dies eine Funktion in der Entwicklungsphase von Google ist Deaktiviere automatische HDR-Helligkeit Automatische HDR-Helligkeit ist deaktiviert Automatische HDR-Helligkeit ist aktiviert - Watch-Panel-Gesten deaktivieren - Wechsel in den Vollbildmodus beim Herunterwischen unter dem Videoplayer ist deaktiviert. - Wechsel in den Vollbildmodus beim Herunterwischen unter dem Videoplayer ist aktiviert. Geste zum Wechseln des Videos deaktiviern Wischen nach oben / nach unten wird nicht das nächste / vorherige Video abspielen. Wischen nach oben / unten wird das nächste / vorherige Video abspielen. @@ -1165,9 +1157,6 @@ Bekannte Probleme: Da dies eine Funktion in der Entwicklungsphase von Google ist HDR-Video deaktivieren HDR-Video ist deaktiviert HDR-Video ist aktiviert - Wiedergabegeschwindigkeit im Live-Stream deaktivieren - Standard Wiedergabegeschwindigkeit ist im Live-Stream deaktiviert - Standard Wiedergabegeschwindigkeit ist im Live-Stream aktiviert Benutzerdefinierte Wiedergabegeschwindigkeit aktivieren Benutzerdefinierte Wiedergabegeschwindigkeit ist aktiviert Benutzerdefinierte Wiedergabegeschwindigkeit ist deaktiviert diff --git a/patches/src/main/resources/youtube/translations/el-rGR/strings.xml b/patches/src/main/resources/youtube/translations/el-rGR/strings.xml index dcc71c4dc..ddcb8234f 100644 --- a/patches/src/main/resources/youtube/translations/el-rGR/strings.xml +++ b/patches/src/main/resources/youtube/translations/el-rGR/strings.xml @@ -283,12 +283,13 @@ Playlists Εμφανίζονται. "Αυτή η ρύθμιση περιορίζει τον μέγιστο αριθμό διατάξεων που μπορούν να εμφανιστούν στην οθόνη αναπαραγωγής. -Στην περίπτωση που η διάταξη της οθόνης αναπαραγωγής αλλάξει λόγω αλλαγών από πλευράς του διακομιστή, ορισμένες διατάξεις της ενδέχεται να κρυφτούν χωρίς να είναι επιθυμητό." +Στην περίπτωση που η διεπαφή της οθόνης αναπαραγωγής αλλάξει λόγω αλλαγών από πλευράς του διακομιστή, ορισμένες διατάξεις της ενδέχεται να είναι κρυμμένες χωρίς να είναι επιθυμητό." Μετατόπιση Γενικά Αλλαγή αρχικής σελίδας Περιήγηση καναλιών + Μαθήματα / Εκμάθηση Προεπιλογή Εξερεύνηση Παιχνίδια @@ -298,12 +299,14 @@ Playlists Live Ταινίες Μουσική + Ειδοποιήσεις Αναζήτηση Shorts Αθλητικά Εγγραφές Τάσεις Παρακολούθηση αργότερα + Τα κλιπ σας Αλλαγή τύπου αρχικής σελίδας "Η αρχική σελίδα αλλάζει πάντα. @@ -318,6 +321,9 @@ Playlists Απενεργοποίηση εφέ εκκίνησης εφαρμογής Το εφέ εκκίνησης της εφαρμογής είναι απενεργοποιημένο. Το εφέ εκκίνησης της εφαρμογής είναι ενεργοποιημένο. + Απενεργοποίηση διαφανούς γραμμής κατάστασης + Η γραμμή κατάστασης δεν είναι διαφανής. + Η διαφάνεια της γραμμής κατάστασης ορίζεται αυτόματα. Διαβαθμισμένη οθόνη φόρτωσης Η οθόνη φόρτωσης θα έχει σταδιακές αποχρώσεις φόντο. Η οθόνη φόρτωσης θα έχει στατική απόχρωση φόντο. @@ -490,6 +496,9 @@ Playlists Επίσης, ενδέχεται να εμφανίζονται διαφημίσεις στα Shorts. Αν η απενεργοποίηση δεν τεθεί σε ισχύ, δοκιμάστε να μεταβείτε σε λειτουργία ανώνυμης περιήγησης." + Διαφανή γραμμή πλοήγησης + Η γραμμή πλοήγησης είναι διαφανής. + Η γραμμή πλοήγησης δεν είναι διαφανής. Γραμμή πλοήγησης Κρυμμένη. Εμφανίζεται. @@ -909,11 +918,6 @@ Playlists Στοιχεία ελέγχου μικρότερου στυλ Τα στοιχεία ελέγχου μικρότερου στυλ είναι ενεργοποιημένα. Τα στοιχεία ελέγχου μικρότερου στυλ είναι απενεργοποιημένα. - Εξαναγκασμός πλήρης οθόνης πάντα - "Τα βίντεο θα αλλάξουν σε λειτουργία πλήρους οθόνης στις ακόλουθες περιπτώσεις: - -• Όταν ξεκινάει ένα βίντεο. -• Όταν πατιέται μια χρονοσήμανση στα σχόλια." Διατήρηση οριζόντιας λειτουργίας Διατήρηση της οριζόντιας λειτουργίας στο κλείσιμο και άνοιγμα της οθόνης ενώ βρίσκεστε σε λειτουργία πλήρους οθόνης. Χρονικό όριο οριζόντιας λειτουργίας @@ -1332,7 +1336,7 @@ Playlists Περιορισμοί: • Αυτή η ρύθμιση ενεργοποιεί όχι μόνο τις χρονοσφραγίδες, αλλά επιτρέπει την απόκρυψη των στοιχείων UI πατώντας στο φόντο της οθόνης αναπαραγωγής. -• Δεδομένου ότι αυτή είναι μια λειτουργία της Google που βρίσκεται ακόμη στο στάδιο ανάπτυξης, η διάταξη μπορεί να χαλάσει." +• Δεδομένου ότι αυτή είναι μια λειτουργία της Google που βρίσκεται ακόμη στο στάδιο ανάπτυξης, η διεπαφή μπορεί να χαλάσει." Οι χρονοσφραγίδες είναι απενεργοποιημένες. Ενέργεια πατήματος χρονοσφραγίδας Πατήστε παρατεταμένα την χρονοσφραγίδα για να αλλάξει η κατάσταση επανάληψης των Shorts. @@ -1398,12 +1402,18 @@ Playlists Απενεργοποίηση αυτόματης φωτεινότητας HDR Η αυτόματη φωτεινότητα HDR είναι απενεργοποιημένη. Η αυτόματη φωτεινότητα HDR είναι ενεργοποιημένη. - Απενεργοποίηση χειρονομίας εναλλαγής σε πλήρη οθόνη - Η εναλλαγή σε λειτουργία πλήρους οθόνης με σάρωση στην περιοχή κάτω από την οθόνη αναπαραγωγής είναι απενεργοποιημένη. - Η εναλλαγή σε λειτουργία πλήρους οθόνης με σάρωση στην περιοχή κάτω από την οθόνη αναπαραγωγής είναι ενεργοποιημένη. Απενεργοποίηση χειρονομίας σάρωσης για αλλαγή βίντεο - Η σάρωση προς τα πάνω / κάτω δε θα αναπαράγει το επόμενο / προηγούμενο βίντεο. - Η σάρωση προς τα πάνω / κάτω θα αναπαράγει το επόμενο / προηγούμενο βίντεο. + Η σάρωση προς τα πάνω / κάτω κατά τη λειτουργία πλήρους οθόνης δε θα αναπαράγει το επόμενο / προηγούμενο βίντεο. + Η σάρωση προς τα πάνω / κάτω κατά τη λειτουργία πλήρους οθόνης θα αναπαράγει το επόμενο / προηγούμενο βίντεο. + Απενεργοποίηση σάρωσης για εισαγωγή σε πλήρη οθόνη (κάτω από την οθόνη αναπαραγωγής) + Η σάρωση προς τα κάτω κάτω από την οθόνη αναπαραγωγής δε θα ενεργοποιήσει τη λειτουργία πλήρους οθόνης. + Η σάρωση προς τα κάτω κάτω από την οθόνη αναπαραγωγής θα ενεργοποιήσει τη λειτουργία πλήρους οθόνης. + Απενεργοποίηση σάρωσης για εισαγωγή σε πλήρη οθόνη (μέσα στην οθόνη αναπαραγωγής) + Η σάρωση προς τα πάνω στην οθόνη αναπαραγωγής δε θα ενεργοποιήσει τη λειτουργία πλήρους οθόνης. + Η σάρωση προς τα πάνω στην οθόνη αναπαραγωγής θα ενεργοποιήσει τη λειτουργία πλήρους οθόνης. + Απενεργοποίηση σάρωσης για έξοδο από πλήρη οθόνη + Η σάρωση προς τα κάτω δε θα τερματίζει τη λειτουργία πλήρους οθόνης. + Η σάρωση προς τα κάτω θα τερματίζει τη λειτουργία πλήρους οθόνης. Αυτόματη Βίντεο @@ -1413,9 +1423,6 @@ Playlists Απενεργοποίηση βίντεο HDR Τα βίντεο που υποστηρίζουν HDR δεν θα παίζουν σε HDR ποιότητα. Τα βίντεο που υποστηρίζουν HDR θα παίζουν σε HDR ποιότητα. - Απενεργοποίηση αλλαγής ταχύτητας σε ζωντανές μεταδόσεις - Η προεπιλεγμένη ταχύτητα αναπαραγωγής δεν εφαρμόζεται σε ζωντανές μεταδόσεις. - Η προεπιλεγμένη ταχύτητα αναπαραγωγής εφαρμόζεται σε ζωντανές μεταδόσεις. Προσαρμοσμένη ταχύτητα αναπαραγωγής Η προσαρμοσμένη ταχύτητα αναπαραγωγής είναι ενεργοποιημένη. Η προσαρμοσμένη ταχύτητα αναπαραγωγής είναι απενεργοποιημένη. @@ -1440,9 +1447,6 @@ Playlists Εμφανίζεται το μενού αλλαγής ποιότητας βίντεο παλιού στυλ. Εμφανίζεται το μενού αλλαγής ποιότητας βίντεο νέου στυλ. Απενεργοποίηση αλλαγής ταχύτητας σε βίντεο μουσικής - "Η προεπιλεγμένη ταχύτητα αναπαραγωγής δεν εφαρμόζεται για τα βίντεο μουσικής. - -Περιορισμός: Αυτή η ρύθμιση ενδέχεται να μην ισχύει για τα βίντεο που δεν περιλαμβάνουν την λειτουργία «Ακρόαση με YouTube Music»." Η προεπιλεγμένη ταχύτητα εφαρμόζεται σε βίντεο μουσικής. Αλλαγή προεπιλεγμένης ταχύτητας Shorts Η προεπιλεγμένη ταχύτητα αναπαραγωγής εφαρμόζεται στα Shorts. @@ -1790,20 +1794,28 @@ Playlists "Τα δεδομένα ροής δεν παραποιούνται. Η αναπαραγωγή βίντεο ενδέχεται να μη λειτουργεί σωστά." Η απενεργοποίηση αυτής της ρύθμισης ενδέχεται να προκαλέσει προβλήματα αναπαραγωγής βίντεο. Προεπιλογή - Android TV - Android VR - iOS - iOS TV Παρενέργειες παραποίησης - "• Το μενού «Κομμάτι ήχου» λείπει. -• Η λειτουργία «Σταθερή ένταση» δεν είναι διαθέσιμη. -• Η λειτουργία «Απενεργοποίηση υποχρεωτικών κομματιών ήχου» δεν είναι διαθέσιμη." - • Δεν ανακαλύφθηκαν ακόμη. - • Οι ταινίες ή τα βίντεο επί πληρωμή ενδέχεται να μην αναπαράγονται. + Εξαναγκασμός iOS AVC (H.264) + Ο κωδικοποιητής βίντεο έχει οριστεί υποχρεωτικά σε AVC (H.264). + Ο κωδικοποιητής βίντεο ορίζεται αυτόματα. + "Η ενεργοποίηση αυτής της λειτουργίας ενδέχεται να βελτιώσει τη διάρκεια ζωής της μπαταρίας και να διορθώσει κολλήματα αναπαραγωγής. + +Ο AVC έχει μέγιστη ανάλυση 1080p, ο κωδικοποιητής ήχου Opus δεν είναι διαθέσιμος και η αναπαραγωγή βίντεο θα χρησιμοποιεί περισσότερα δεδομένα ίντερνετ από τον VP9 ή τον AV1." Εμφάνιση στο «Στατιστικά για σπασίκλες» Το πρόγραμμα πελάτη που χρησιμοποιείται για τη λήψη δεδομένων ροής εμφανίζεται στο μενού «Στατιστικά για σπασίκλες». Το πρόγραμμα πελάτη που χρησιμοποιείται για τη λήψη δεδομένων ροής δεν εμφανίζεται στο μενού «Στατιστικά για σπασίκλες». + PoToken / VisitorData + PoToken προς χρήση + PoToken που εκδίδεται από το BotGuard σε ένα έμπιστο πρόγραμμα περιήγησης. + VisitorData προς χρήση + VisitorData που εκδίδεται από το BotGuard σε ένα έμπιστο πρόγραμμα περιήγησης. + Σχετικά με τα αναγνωριστικά PoToken / VisitorData + "Κάποια προγράμματα απαιτούν αναγνωριστικά PoToken και VisitorData για να λάβουν έγκυρη απόκριση δεδομένων ροής. + +Αν προσπαθείτε να χρησιμοποιήσετε το iOS ως προεπιλεγμένο πρόγραμμα-πελάτη, μπορεί να χρειαστείτε αυτές τις τιμές. + +Πατήστε για να δείτε περισσότερες πληροφορίες." Ιστορικό παρακολούθησης Διαχείριση των ρυθμίσεων που σχετίζονται με το ιστορικό παρακολούθησης. diff --git a/patches/src/main/resources/youtube/translations/es-rES/strings.xml b/patches/src/main/resources/youtube/translations/es-rES/strings.xml index 1da6cf42c..0f0df40de 100644 --- a/patches/src/main/resources/youtube/translations/es-rES/strings.xml +++ b/patches/src/main/resources/youtube/translations/es-rES/strings.xml @@ -291,6 +291,7 @@ Si el diseño de la pantalla del reproductor cambia debido a cambios en el servi General Cambiar página de inicio Explorar canales + Cursos / Aprendizaje Predeterminada Explorar Juegos @@ -300,12 +301,14 @@ Si el diseño de la pantalla del reproductor cambia debido a cambios en el servi En directo Películas Música + Notificaciones Búsqueda Shorts Deportes Suscripciones Tendencias Ver más tarde + Tus clips Cambiar tipo de página de inicio "La página de inicio siempre cambia. @@ -320,6 +323,9 @@ Limitación: Es posible que el botón Atrás de la barra de herramientas no func Desactivar animación de bienvenida La animación de bienvenida está desactivada. La animación de bienvenida está activada. + Desactivar barra de estado translúcida + La barra de estado es opaca. + La barra de estado es opaca o translúcida. Activar pantalla de carga de degradado La pantalla de carga de degradado está activada. La pantalla de carga de degradado está desactivada. @@ -492,6 +498,9 @@ Nota: Al activar esto también se ocultan forzosamente los anuncios de vídeos." Además, los anuncios ya no se bloquearán en Shorts. Si este ajuste no surte efecto, prueba a cambiar al modo incógnito." + Activar barra de navegación translúcida + La barra de navegación es translúcida. + La barra de navegación es opaca. Ocultar barra de navegación La barra de navegación está oculta. La barra de navegación está visible. @@ -906,11 +915,6 @@ Limitación: el título de vídeo desaparece cuando se pulsa." Activar superposición compacta de controles La superposición de controles no ocupa la pantalla completa. La superposición de controles ocupa la pantalla completa. - Forzar pantalla completa - "Los vídeos pasarán a pantalla completa en las siguientes situaciones: - -• Cuando se pulsa sobre una marca de tiempo en los comentarios. -• Cuando se inicia un vídeo." Mantener modo horizontal Mantiene el modo horizontal al apagar y encender la pantalla en pantalla completa. Mantener tiempo de espera del modo horizontal @@ -1371,12 +1375,18 @@ No hay márgenes en la parte superior e inferior del reproductor." Desactivar brillo HDR automático El brillo HDR automático está desactivado. El brillo HDR automático está activado. - Desactivar gestos del panel de visualización - El cambio a pantalla completa deslizando el dedo por la zona inferior del reproductor está desactivado. - El cambio a pantalla completa deslizando el dedo por la zona inferior del reproductor está activado. Desactivar deslizar para cambiar el vídeo Deslizar hacia arriba / abajo no reproducirá el vídeo siguiente / anterior. Deslizar hacia arriba / abajo reproducirá el vídeo siguiente / anterior. + Desactivar deslizamiento para entrar en modo de pantalla completa (debajo del reproductor) + Si deslizas el dedo hacia abajo por debajo del reproductor, no entrará en el modo de pantalla completa. + Si deslizas el dedo hacia abajo por debajo del reproductor, entrará en el modo de pantalla completa. + Desactivar deslizamiento para entrar en modo de pantalla completa (en el reproductor) + Si deslizas el dedo hacia arriba en el reproductor, no entrará en el modo de pantalla completa. + Si deslizas el dedo hacia arriba en el reproductor, entrará en el modo de pantalla completa. + Desactivar deslizamiento para salir del modo de pantalla completa + Si deslizas el dedo hacia abajo en pantalla completa, no saldrá del modo de pantalla completa. + Si deslizas el dedo hacia abajo en pantalla completa, saldrá del modo de pantalla completa. Automático Vídeo @@ -1386,9 +1396,6 @@ No hay márgenes en la parte superior e inferior del reproductor." Desactivar vídeo HDR El vídeo HDR está desactivado. El vídeo HDR está activado. - Desactivar la velocidad de reproducción en directo - La velocidad predeterminada de reproducción está desactivada en directo. - La velocidad predeterminada de reproducción está activada en directo. Activar velocidad personalizada de reproducción La velocidad personalizada de reproducción está activada. La velocidad personalizada de reproducción está desactivada. @@ -1413,9 +1420,6 @@ No hay márgenes en la parte superior e inferior del reproductor." El antiguo menú de calidad de vídeo está visible. El antiguo menú de calidad de vídeo está oculto. Desactivar velocidad de reproducción para música - "La velocidad predeterminada de reproducción está desactivada para la música. - -Limitación: Es posible que este ajuste no se aplique a los vídeos que no incluyan el banner \"Escuchar en YouTube Music\"." La velocidad predeterminada de reproducción está activada para la música. Activar velocidad predeterminada de reproducción de Shorts La velocidad predeterminada de reproducción se aplica a los Shorts. @@ -1759,20 +1763,28 @@ Pulsa el botón de continuar y desactiva las optimizaciones de la batería.""Los datos de transmisión no están falsificados. Es posible que la reproducción de vídeo no funcione." Desactivar este ajuste puede causar problemas de reproducción de vídeo. Cliente predeterminado - Android TV - Android VR - iOS - iOS TV Efectos secundarios de falsificación - "• Falta el menú de pista de audio. -• El volumen estable no está disponible. -• Desactivar pistas de audio automáticas forzadas no está disponible." - • Aún no encontrado. - • Las películas o vídeos de pago no pueden reproducirse. + Forzar iOS AVC (H.264) + El códec de vídeo es AVC (H.264). + El códec de vídeo se determina automáticamente. + "Activar este ajuste podría mejorar la duración de la batería y solucionar el problema de la reproducción entrecortada. + +AVC tiene una resolución máxima de 1080p, el códec de audio Opus no está disponible y la reproducción de vídeo utilizará más datos de Internet que VP9 o AV1." Mostrar en estadísticas para nerds El cliente utilizado para obtener datos de transmisión se muestra en estadísticas para nerds. El cliente utilizado para obtener datos de transmisión no se muestra en estadísticas para nerds. + PoToken / VisitorData + PoToken a utilizar + PoToken emitido por BotGuard en un navegador de confianza. + VisitorData a utilizar + VisitorData emitido por BotGuard en un navegador de confianza. + Acerca de PoToken / VisitorData + "Algunos clientes requieren PoToken y VisitorData para obtener una respuesta de datos de streaming válida. + +Si estás intentando utilizar iOS como cliente predeterminado, es posible que necesites estos valores. + +Pulsa aquí para ver más información." Historial de reproducciones Cambiar ajustes relacionados con el historial de reproducciones. diff --git a/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml b/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml index ac4b040df..6c5550a96 100644 --- a/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml +++ b/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml @@ -293,6 +293,7 @@ Si la mise en page de l'écran du lecteur change en raison de modifications côt Interface Modifier la page de démarrage Parcourir les chaînes + Savoir / Culture Par défaut Explorer Jeux vidéos @@ -302,12 +303,14 @@ Si la mise en page de l'écran du lecteur change en raison de modifications côt Direct Films Musique + Notifications Rechercher sur YouTube Shorts Sports Abonnements Tendances Regarder plus tard + Vos clips Type de modification de la page de démarrage "La page de démarrage est toujours modifiée. @@ -322,6 +325,9 @@ Limitation : Le bouton Retour de la barre d'outils peut ne pas fonctionner."Désact. l\'animation de démarrage L\'animation de démarrage est désactivé. L\'animation de démarrage est activé. + Désactiver la barre de navigation translucide + La barre de navigation est opaque. + La barre de navigation est opaque ou translucide. Activer dégradé pendant le chargement Le dégradé pendant l\'écran de chargement est activé. Le dégradé pendant l\'écran de chargement est désactivé. @@ -494,6 +500,9 @@ Note : Activer ceci masquera également les publicités vidéos." Également, les publicités ne seront plus bloquées sur les Shorts. Si ce paramètre ne fait pas effet, essayer de passer en mode Incognito." + Activer la barre de navigation translucide + La barre de navigation est translucide. + La barre de navigation est opaque. Masquer la barre de navigation La barre de navigation est masqué. La barre de navigation est affichée. @@ -908,11 +917,6 @@ Limitation : Le titre de la vidéo disparaît lorsque vous cliquez dessus."Activer le fond des contrôles compacts La voile des contrôles ne remplit pas le plein écran. La voile des contrôles remplit le plein écran. - Forcer le plein écran - "La vidéo passera en mode plein écran dans les situations suivantes : - -• Lors du démarrage de la vidéo. -• Clic sur un horodatage dans les commentaires." Maintenir le mode paysage Maintient le mode paysage lorsque l\'écran est éteint et rallumé en mode plein écran. Durée du maintien du mode paysage @@ -1377,12 +1381,18 @@ Pas de marges en haut et en bas du lecteur." Luminosité HDR automatique La luminosité HDR automatique est désactivée. La luminosité HDR automatique est activée. - Désactiver les gestes inférieurs du lecteur - Le passage plein écran en faisant glisser vers le bas sous le lecteur vidéo est désactivé. - Le passage plein écran en faisant glisser vers le bas sous le lecteur vidéo est activé. Désactiver les gestes pour changer de vidéo - Glisser vers le haut / bas ne lira pas la vidéo suivante / précédente. - Glisser vers le haut / bas pour lire la vidéo suivante / précédente. + Glisser vers le haut / bas en plein écran ne lira pas la vidéo suivante / précédente. + Glisser vers le haut / bas en plein écran lira la vidéo suivante / précédente. + Désactiver les gestes pour entrer en mode plein écran (sous le lecteur) + Glisser vers le bas sous le lecteur ne permet pas d\'entrer en mode plein écran. + Glisser vers le bas sous le lecteur permet d\'entrer en mode plein écran. + Désactiver les gestes pour entrer en mode plein écran (dans le lecteur) + Glisser vers le haut dans le lecteur ne permets pas d\'entrer en mode plein écran. + Glisser vers le haut dans le lecteur permets d\'entrer en mode plein écran. + Désactiver les gestes pour sortir du mode plein écran + Glisser vers le bas en mode plein écran ne permet pas de sortir du mode plein écran. + Glisser vers le bas en plein écran permets de sortir du mode plein écran. Auto Vitesses et qualités vidéo @@ -1392,9 +1402,6 @@ Pas de marges en haut et en bas du lecteur." Déaactiver les vidéos HDR Les vidéos en HDR sont désactivés. Les vidéos en HDR sont activés. - Désact. vitesse lecture des diffusions en direct - La vitesse de lecture par défaut est désactivée pour les diffusions en direct. - La vitesse de lecture par défaut est activée pour les diffusions en direct. Activer vitesses de lecture perso. Les vitesses de lecture personnalisées sont activées. Les vitesses de lecture personnalisées sont désactivées. @@ -1419,9 +1426,6 @@ Pas de marges en haut et en bas du lecteur." Affiche l\'ancienne interface de qualité vidéo. Masque la nouvelle interface de qualité vidéo. Désactiver la vitesse de lecture pour la musique - "La vitesse de lecture par défaut est désactivée pour la musique. - -Limitation : Ce paramètre peut ne pas s'appliquer aux vidéos qui n'incluent pas la bannière 'Écouter sur YouTube Music'." La vitesse de lecture par défaut est activée pour la musique. Activ. vitesses de lecture shorts par défaut La vitesse de lecture par défaut s\'applique aux Shorts. @@ -1768,20 +1772,28 @@ Cliquez sur le bouton Continuer et autorisez les modifications d'optimisations." "Les données de lecture en direct ne sont pas falsifiées. La lecture vidéo peut ne pas fonctionner." Désactiver ce paramètre peut entraîner des problèmes de lecture vidéo. Client par défaut - Android TV - Android VR - iOS - TV iOS Effets inconnus de la falsification - "• Le menu 'Piste Audio' est manquant. -• Le volume stable n'es pas disponible. -• La désactivation forcée des pistes audio automatiques ne sont pas disponibles." - • Pas encore trouvé. - • Les films ou vidéos payantes peuvent ne pas être lues. + Forcer le codec AVC de iOS (H.264) + Le codec vidéo est forcé sur AVC (H.264). + Le codec vidéo est déterminé automatiquement. + "Activer ceci peut améliorer la durée de vie de la batterie et résoudre les problèmes de lecture saccadée. + +AVC a une résolution maximale de 1080p, le codec audio Opus n'est pas disponible et la lecture vidéo utilisera plus de données internet que VP9 ou AV1." Afficher dans \'Statistiques pour les nerds\' Le client utilisé pour récupérer les données de lecture en direct est affiché dans \'Statistiques pour les nerds\'. Le client utilisé pour récupérer les données de lecture en direct est masqué dans \'Statistiques pour les nerds\'. + PoToken / VisitorData + PoToken à utiliser + PoToken publié par BotGuard dans un navigateur de confiance. + VisitorData à utiliser + VisitorData publié par BotGuard dans un navigateur de confiance. + À propos de PoToken / VisitorData + "Certains clients ont besoin de PoToken et de VisitorData pour obtenir une réponse de données en continu valide. + +Si vous essayez d'utiliser iOS comme client par défaut, il se peut que vous ayez besoin de ces valeurs. + +Cliquez pour plus d'informations." Historique de visionnage Modifie les paramètres liés à l\'historique de visionnage. diff --git a/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml b/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml index df912c280..730982509 100644 --- a/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml +++ b/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml @@ -293,6 +293,7 @@ Ha a lejátszó képernyőjének elrendezése a szerveroldali változtatások mi Általános Kezdőlap megváltoztatása Csatornák böngészése + Kurzusok / Tanulás Alapértelmezett Felfedezés Játékok @@ -302,12 +303,14 @@ Ha a lejátszó képernyőjének elrendezése a szerveroldali változtatások mi Élő Filmek Zene + Értesítések Keresés Shorts Sport Feliratkozások Felkapott Megnézem később + Klipjeid Kiinduló lap megváltoztatása "A kiinduló lap mindig változik. @@ -322,6 +325,9 @@ Korlátozás: Előfordulhat, hogy az eszköztár Vissza gombja nem működik."Indító animáció letiltása Az indító animáció letiltva. Az indító animáció engedélyezve. + Átlátszó állapotsor letiltása + Az állapotsor nem látszik át. + Az állapotsor átlátszatlan vagy áttetsző. Színátmenetes betöltési képernyő engedélyezése A színátmenetes betöltési képernyő engedélyezve van. A színátmenetes betöltési képernyő le van tiltva. @@ -494,6 +500,9 @@ Megjegyzés: Engedélyezés esetén a videó hirdetéseket is elrejti." Tovább, a reklámok nem lesznek tiltva a Shortokban. Ha ez a beállítás nem működik, váltson inkognító módra." + Áttetsző navigációs sáv engedélyezése + A navigációs sáv áttetsző. + A navigációs sáv nem áttetsző. Navigációs sáv elrejtése A navigációs sáv el van rejtve. A navigációs sáv látható. @@ -906,11 +915,6 @@ Korlátozás: A videó címe eltűnik, ha rákattint." Kompakt vezérlők engedélyezése A vezérlők nem töltik ki a teljes képernyőt. A vezérlők kitöltik a teljes képernyőt. - Teljes képernyő erőltetése - "A videók teljes képernyősre váltanak a következő esetekben: - -• Amikor egy videó elindul. -• Amikor egy időbélyegre kattintanak a hozzászólásokban." Tartsa a fekvő módot Megtartja a fekvő módot a képernyő ki- és bekapcsolásakor teljes képernyőn. Fekvő mód tartás időtúllépése @@ -1376,12 +1380,18 @@ Megjegyzés: Ezzel a képernyőterület méretét is megváltoztatja, ahol érz Automatikus HDR fényerő letiltása Az automatikus HDR fényerő le van tiltva. Az automatikus HDR fényerő engedélyezett. - Nézőpanel gesztusok letiltása - A teljes képernyőre való belépés a videólejátszó alatti lapozáskor letiltva. - A teljes képernyőre való belépés a videólejátszó alatti lefelé csúsztatáskor engedélyezve van. A videóváltás lapozással letiltása A felfelé/lefelé lapozás nem játssza le a következő/előző videót. A felfelé/lefelé lapozással a következő/előző videót játsza le. + Teljes képernyős módba való belépés letiltása (a lejátszó alatt) + A lejátszó alatti lefelé lapozás nem léptet be teljes képernyős módba. + A lejátszó alatt lefelé lapozással teljes képernyős módba léptet. + Teljes képernyős módba való belépés letiltása (a lejátszóban) + A lejátszóban a felfelé lapozás nem léptet be a teljes képernyős módba. + A lejátszóban a felfelé lapozás beléptet a teljes képernyős módba. + Teljes képernyős üzemmódból való kilépés lapozással letiltása + A teljes képernyőn történő lefelé lapozás nem léptet ki a teljes képernyős módból. + A teljes képernyős módból való lapozás a teljes képernyős módból való kilépéshez vezet. Automatikus Videó @@ -1391,9 +1401,6 @@ Megjegyzés: Ezzel a képernyőterület méretét is megváltoztatja, ahol érz HDR videó letiltása A HDR videó le van tiltva. A HDR videó engedélyezve van. - Lejátszási sebesség letiltása élő közvetítésnél - Az alapértelmezett lejátszási sebesség le van tiltva élő közvetítésnél. - Az alapértelmezett lejátszási sebesség engedélyezve van az élő közvetítésnél. Egyéni lejátszási sebesség engedélyezése Az egyéni lejátszási sebesség engedélyezve van. Az egyéni lejátszási sebesség le van tiltva. @@ -1418,9 +1425,6 @@ Megjegyzés: Ezzel a képernyőterület méretét is megváltoztatja, ahol érz A régi videóminőség menü jelenik meg A régi videóminőség menü nem jelenik meg Lejátszási sebesség zenéhez kiválasztás elrejtése - "A zene alapértelmezett lejátszási sebessége le van tiltva. - -Korlátozás: Előfordulhat, hogy ez a beállítás nem vonatkozik azokra a videókra, amelyek nem tartalmazzák a „Hallgassa meg a YouTube Musicon” bannert." Az alapértelmezett lejátszási sebesség engedélyezett zene lejátszásnál. Shortok alapértelmezett lejátszási sebességének engedélyezése Az alapértelmezett lejátszási sebesség vonatkozik a Shortokra. @@ -1758,20 +1762,28 @@ Kattintson az API-kulcs kiadás folyamatának megtekintéséhez." "Az adatfolyam nincs meghamisítva. Lehet, hogy a videó lejátszás nem működik." A beállítás kikapcsolása videólejátszási problémákat okozhat. Alapértelmezett kliens - Android TV - Android VR - iOS - iOS TV Hamisítás mellékhatásai - "• A hangsáv menü hiányzik. -• Stabil hangerő nem áll rendelkezésre. -• Kényszerített automatikus hangsávok kikapcsolása nem elérhető." - • Még nem található. - • Előfordulhat, hogy a filmek vagy fizetős videók nem játszódnak le. + Kényszerített iOS AVC (H.264) + A videó kodek AVC-re (H.264) van kényszerítve. + A videokodek meghatározása automatikusan történik. + "Ennek engedélyezése javíthatja az akkumulátor élettartamát és javíthatja a lejátszás akadozását. + +Az AVC maximális felbontása 1080p, az Opus hangkodek nem érhető el, és a videolejátszás több adatforgalmat igényel, mint a VP9 vagy az AV1." Megjelenítés a statisztikában kockáknak Az adatfolyam lekérésére használt kliens a statisztikában kockáknak látható. Az adatfolyam lekérésére használt kliens a statisztikában kockáknak nem látható. + PoToken / VisitorData + PoToken használatához + A BotGuard által kibocsátott PoToken egy megbízható böngészőben. + VisitorData használatához + A BotGuard által kibocsátott VisitorData egy megbízható böngészőben. + A PoTokenről / VisitorData-ról + "Néhány kliensnek PoToken és VisitorData szükséges az adatok érvényes folyamatos adatátvitelére adott válaszhoz. + +Ha az iOS-t próbálja alapértelmezett kliensként használni, szüksége lehet ezekre az értékekre. + +Kattintson a további információkért." Megtekintési előzmények A megtekintési előzményekhez kapcsolódó beállítások módosítása. diff --git a/patches/src/main/resources/youtube/translations/it-rIT/strings.xml b/patches/src/main/resources/youtube/translations/it-rIT/strings.xml index 742fd2863..cd9930937 100644 --- a/patches/src/main/resources/youtube/translations/it-rIT/strings.xml +++ b/patches/src/main/resources/youtube/translations/it-rIT/strings.xml @@ -292,6 +292,7 @@ Se l'interfaccia della schermata del riproduttore cambia a causa di modifiche la Generale Cambia la scheda iniziale Esplora canali + Apprendimento Predefinita (Home) Esplora Giochi @@ -301,12 +302,14 @@ Se l'interfaccia della schermata del riproduttore cambia a causa di modifiche la Live Film e TV Musica + Notifiche Cerca Shorts Sport Iscrizioni Tendenze Guarda più tardi + I tuoi clip Cambia il comportamento della pagina iniziale "La pagina iniziale cambia sempre. @@ -321,6 +324,9 @@ Nota: il pulsante Indietro della barra degli strumenti potrebbe non funzionare." Disattiva l\'animazione di avvio L\'animazione di avvio è disattivata. L\'animazione di avvio è attivata. + Disattiva la barra di stato traslucida + La barra di stato è opaca. + La barra di stato è opaca o traslucida. Attiva la schermata di caricamento gradiente La schermata di caricamento gradiente è attivata. La schermata di caricamento gradiente è disattivata. @@ -494,6 +500,9 @@ Nota: anche gli annunci video saranno nascosti." Inoltre, gli annunci degli Shorts non saranno più bloccati. Se questa impostazione non ha effetto, prova a passare alla navigazione in incognito." + Attiva la barra di navigazione traslucida + La barra di navigazione è traslucida. + La barra di navigazione è opaca. Nascondi la barra di navigazione La barra di navigazione è nascosta. La barra di navigazione è visibile. @@ -909,10 +918,6 @@ Nota: il titolo scompare quando lo si tocca." Attiva i controlli compatti I controlli compatti sono attivati. I controlli compatti sono disattivati. - Forza lo schermo intero - "I video passeranno automaticamente a schermo intero nelle seguenti situazioni: -• Appena un video inizia. -• Toccando su un timestamp nei commenti." Mantieni la modalità orizzontale Mantiene la modalità orizzontale quando lo schermo viene spento e acceso a schermo intero. Durata della modalità orizzontale forzata @@ -1080,8 +1085,8 @@ Questa impostazione funziona meglio con una connessione internet molto veloce."< La sezione Riepilogo Video Generato dall\'IA è nascosta. La sezione Riepilogo Video Generato dall\'IA è visibile. Nascondi le sezioni Musica, Giochi e Luoghi in Primo Piano - Le sezioni Musica, Giochi, Persone e Luoghi in Primo Piano sono nascosti. - Le sezioni Musica, Giochi, Persone e Luoghi in Primo Piano sono visibili. + Le sezioni Musica, Giochi, Persone Menzionate e Luoghi in Primo Piano sono nascoste. + Le sezioni Musica, Giochi, Persone Menzionate e Luoghi in Primo Piano sono visibili. Nascondi la sezione Capitoli La sezione Capitoli è nascosta. La sezione Capitoli è visibile. @@ -1375,12 +1380,18 @@ Note: Disattiva la luminosità HDR automatica La luminosità HDR automatica è disattivata. La luminosità HDR automatica è attivata. - Disattiva il gesto per passare a schermo intero trascinando verso il basso sotto il riproduttore - Il gesto per passare a schermo intero trascinando verso il basso sotto il riproduttore è disattivato. - Il gesto per passare a schermo intero trascinando verso il basso sotto il riproduttore è attivato. Disattiva il gesto per cambiare video - Trascinando verso l\'alto o il basso non verrà riprodotto il video successivo o precedente. - Trascinando verso l\'alto o il basso verrà riprodotto il video successivo o precedente. + Trascinando verso l\'alto o il basso a schermo intero non verrà riprodotto il video successivo o precedente. + Trascinando verso l\'alto o il basso a schermo intero verrà riprodotto il video successivo o precedente. + Disattiva il gesto per passare a schermo intero trascinando verso il basso da sotto il riproduttore + Il gesto per passare a schermo intero trascinando verso il basso da sotto il riproduttore è disattivato. + Il gesto per passare a schermo intero trascinando verso il basso da sotto il riproduttore è attivato. + Disattiva il gesto per passare a schermo intero trascinando verso l\'alto toccando il riproduttore + Il gesto per passare a schermo intero trascinando verso l\'alto toccando il riproduttore è disattivato. + Il gesto per passare a schermo intero trascinando verso l\'alto toccando il riproduttore è attivato. + Disattiva il gesto per uscire dallo schermo intero trascinando verso il basso + Il gesto per uscire dallo schermo intero trascinando verso il basso è disattivato. + Il gesto per uscire dallo schermo intero trascinando verso il basso è attivato. Automatico Video @@ -1390,9 +1401,6 @@ Note: Disattiva l\'HDR dei video L\'HDR dei video è disattivato. L\'HDR dei video è attivato. - Disattiva la velocità di riproduzione predefinita nei video live - La velocità di riproduzione predefinita nei video live è disattivata. - La velocità di riproduzione predefinita nei video live è attivata. Attiva la velocità di riproduzione personalizzata La velocità di riproduzione personalizzata è attivata. La velocità di riproduzione personalizzata è disattivata. @@ -1417,9 +1425,6 @@ Note: Il vecchio menù Qualità è attivato. Il vecchio menù Qualità è disattivato. Disattiva la velocità di riproduzione predefinita per la musica - "La velocità di riproduzione predefinita è disattivata per la musica. - -Nota: potrebbe non funzionare con i video che non hanno il banner Ascolta su YouTube Music." La velocità di riproduzione predefinita per la musica è attivata. Attiva la velocità di riproduzione predefinita negli Shorts La velocità di riproduzione predefinita negli Shorts è attivata. @@ -1764,20 +1769,35 @@ Tocca il pulsante Continua e consenti le modifiche di ottimizzazione." "I dati in streaming non sono camuffati. La riproduzione potrebbe non funzionare." La disattivazione di questa impostazione potrebbe causare problemi di riproduzione. Client predefinito - Android TV - Android VR - iOS - iOS TV Effetti collaterali del camuffamento - "• Il menù Traccia Audio è mancante. -• Il menù Volume Stabile è mancante. -• La disattivazione della traccia audio automatica forzata non funziona." - • Nessuno ancora trovato. - • I film o i video a pagamento potrebbero non essere riprodotti. + "• Manca il menù Traccia Audio. +• Il volume stabile non funziona. +• La disattivazione delle tracce audio automatiche forzate non funziona. +• I video per bambini potrebbero non essere riprodotti se si è disconnessi o in incognito." + • Ci potrebbero essere problemi di riproduzione (PoToken richiesto). + "• I film o i video a pagamento potrebbero non essere riproducibili. +• I video per bambini potrebbero non essere riprodotti se si è disconnessi o in incognito." + Forza iOS AVC (H.264) + Il codec video è forzato ad AVC (H.264). + Il codec video è determinato automaticamente. + "L'attivazione di questa impostazione potrebbe migliorare la durata della batteria e risolvere il problema della riproduzione a scatti. + +Nota: AVC ha una risoluzione massima di 1080p, il codec Opus non è disponibile e la riproduzione userà più dati internet rispetto a VP9 o AV1." Mostra nelle statistiche per nerd Il client usato per recuperare i dati in streaming è visibile nelle statistiche per nerd. Il client usato per recuperare i dati in streaming è nascosto nelle statistiche per nerd. + PoToken / VisitorData + PoToken da usare + PoToken emesso da BotGuard in un browser affidabile. + VisitorData da usare + VisitorData emesso da BotGuard in un browser affidabile. + Informazioni su PoToken e VisitorData + "Alcuni client richiedono PoToken e VisitorData per ottenere una risposta valida per i dati in streaming. + +Se stai cercando di utilizzare iOS come client predefinito, potresti aver bisogno di questi valori. + +Tocca per vedere maggiori informazioni." Cronologia Cambia le impostazioni della cronologia. diff --git a/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml b/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml index fb58966b3..c70fce9f4 100644 --- a/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml +++ b/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml @@ -292,6 +292,7 @@ DeArrow の詳細については、ここをタップしてください。"全般 起動時のページを変更 チャンネルを探す + コース / 教育 デフォルト 探索 ゲーム @@ -301,12 +302,14 @@ DeArrow の詳細については、ここをタップしてください。"ライブ 映画 音楽 + 通知 検索 ショート スポーツ 登録チャンネル トレンド 後で見る + クリップ 「起動時のページを変更」の種類 "現在の設定: 起動時のページを常に変更します。 @@ -325,6 +328,9 @@ DeArrow の詳細については、ここをタップしてください。"スプラッシュアニメーションを無効化 YouTube 起動時のスプラッシュアニメーションを無効にします。 YouTube 起動時のスプラッシュアニメーションを無効にします。 + 半透明なステータスバーを無効化 + ステータスバーを不透明にします。 + ステータスバーを不透明にします。 グラデーションの読み込み画面を有効化 アプリ起動時や動画の読み込み画面などでグラデーションを有効化します。 アプリ起動時や動画の読み込み画面などでグラデーションを有効化します。 @@ -497,6 +503,9 @@ DeArrow の詳細については、ここをタップしてください。" + 半透明のナビゲーションバーを有効化 + ナビゲーションバー (ホーム、登録チャンネルなどのボタン) を半透明にします。 + ナビゲーションバー (ホーム、登録チャンネルなどのボタン) を半透明にします。 ナビゲーションバーを非表示 ナビゲーションバー(ホーム、登録チャンネルなどのボタン)を非表示にします。 ナビゲーションバー(ホーム、登録チャンネルなどのボタン)を非表示にします。 @@ -905,11 +914,6 @@ DeArrow の詳細については、ここをタップしてください。"コンパクトなコントロールオーバーレイを有効化 コントロールのオーバーレイを全画面に表示せず、コンパクトに表示します。 コントロールのオーバーレイを全画面に表示せず、コンパクトに表示します。 - 強制的に全画面表示 - "以下の状況で全画面に切り替わります: - -・動画開始時 -・コメントのタイムスタンプをタップしたとき" 横画面モードを維持 全画面表示時に、画面をオン/オフしても、横向きモードを維持します。 横画面モードのタイムアウトを維持 @@ -1372,12 +1376,18 @@ DeArrow の詳細については、ここをタップしてください。"HDR 動画の明るさ自動調節を無効化 HDR 動画の明るさの自動調節を無効にします。 HDR 動画の明るさの自動調節を無効にします。 - 全画面表示ジェスチャーを無効化 - 動画のタイトルより下の領域を下にスワイプして全画面表示に切り替える機能を無効化します。 - 動画のタイトルより下の領域を下にスワイプして全画面表示に切り替える機能を無効化します。 スワイプして動画を切り替えるのを無効化 全画面表示時に、上/下にスワイプして次の動画/前の動画に切り替えられるようにします。 全画面表示時に、上/下にスワイプして次の動画/前の動画に切り替えられるようにします。 + スワイプして全画面表示に切り替えるのを無効化(動画のタイトルより下を下にスワイプした時) + 動画のタイトルより下をスワイプしても全画面表示に切り替えないようにします。 + 動画のタイトルより下をスワイプしても全画面表示に切り替えないようにします。 + スワイプして全画面表示に切り替えるのを無効化(プレーヤーを下にスワイプした時) + プレーヤーを下にスワイプしても全画面表示に切り替えないようにします。 + プレーヤーを下にスワイプしても全画面表示に切り替えないようにします。 + スワイプして全画面表示を終了するのを無効化 + プレーヤーを下にスワイプしても全画面表示を終了しないようにします。 + プレーヤーを下にスワイプしても全画面表示を終了しないようにします。 自動 動画 @@ -1387,9 +1397,6 @@ DeArrow の詳細については、ここをタップしてください。"HDR 動画を無効化 HDR 動画を無効化します。 HDR 動画を無効化します。 - ライブ配信でデフォルトの再生速度を無効化 - ライブ配信ではデフォルトに設定された再生速度を無効化します。 - ライブ配信ではデフォルトに設定された再生速度を無効化します。 カスタム再生速度を有効化 再生速度のカスタムを有効化します。 再生速度のカスタムを有効化します。 @@ -1414,9 +1421,6 @@ DeArrow の詳細については、ここをタップしてください。"古いスタイルの画質設定メニューを復活させます。 古いスタイルの画質設定メニューを復活させます。 音楽再生時にデフォルトの再生速度を無効化 - "音楽を再生する際に、「デフォルトの再生速度」で設定した再生速度を無効化します。 - -注意: この設定は、「YouTube Music で聴く」バナーが表示されている動画にのみ適用されます。" 音楽を再生する際に、「デフォルトの再生速度」で設定した再生速度を無効化します。\n\n注意: この設定は、「YouTube Music で聴く」バナーが表示されている動画にのみ適用されます。 ショートのデフォルト再生速度を有効化 デフォルトの再生速度をショートに適用します。 @@ -1765,20 +1769,31 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に "ストリーミングデータを偽装していない場合、動画の再生ができない可能性があります。" この設定をオフにした場合、バッファリングの問題が発生する可能性があります。 偽装するクライアントの種類 - Android TV - Android VR - iOS - iOS TV ストリーミングデータを偽装することによる副作用 - "・「音声トラック」メニューは表示されません。 -・「一定音量」は利用できません。 -・「音声トラックの強制を無効化」は利用できません。" - ・まだ見つかっていません。 - ・映画や有料動画は再生できない可能性があります。 + iOS クライアントで AVC (H.264) を強制 + iOS クライアントで AVC (H.264) を強制します。 + iOS クライアントで AVC (H.264) を強制します。 + "これを有効にすると、バッテリーの持ちが改善され、再生時のカクつきが修正される可能性があります。 + +注意: +・AVC (H.264) の最大解像度は 1080p です。 +・Opus オーディオコーデックは使用できません。 +・動画の再生時には VP9 や AV1 よりも多くの通信量を消費します。" 統計情報に偽装したクライアントを表示 - 統計情報に偽装したストリーミングデータを表示します。 - 統計情報に偽装したストリーミングデータを表示します。 + 統計情報に偽装したクライアントを表示します。 + 統計情報に偽装したクライアントを表示します。 + PoToken / VisitorData + 使用する PoToken を入力 + 信頼できるブラウザで BotGuard によって発行された PoToken です。 + 使用する VisitorData を入力 + 信頼できるブラウザで BotGuard によって発行された VisitorData です。 + PoToken / VisitorData について + "一部のクライアントでは、有効なストリーミングデータ応答を取得するために PoToken と VisitorData が必要です。 + +iOS クライアント選択する場合は、これらの値が必要になる場合があります。 + +詳細についてはここをタップしてください。" 再生履歴 再生履歴に関連する設定を変更します。 diff --git a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml index e7836e3e7..7e708e991 100644 --- a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml @@ -294,6 +294,7 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 일반 앱 시작 페이지 변경하기 채널 둘러보기 + 학습 프로그램 홈 (기본값) 탐색 게임 @@ -303,12 +304,14 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 실시간 영화 음악 + 알림 검색 Shorts 스포츠 구독 인기 급상승 나중에 볼 동영상 + 내 클립 앱 시작 페이지 유형 변경하기 "앱 시작 페이지가 항상 변경됩니다. @@ -324,6 +327,9 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 스플래시 애니메이션 비활성화하기 앱을 시작할 때, 스플래시 애니메이션을 비활성화합니다. 앱을 시작할 때, 스플래시 애니메이션을 활성화합니다. + 반투명 상태바 비활성화하기 + 상태바가 불투명합니다. + 상태바가 불투명하거나 반투명합니다. 그라데이션 색상 로딩 화면 활성화하기 그라데이션 색상 로딩 화면을 활성화합니다. 그라데이션 색상 로딩 화면을 비활성화합니다. @@ -490,6 +496,9 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 또한, Shorts에서 광고가 더 이상 숨겨지지 않습니다. 이 설정이 적용되지 않는 경우에는 시크릿 모드로 전환해 보세요." + 반투명 하단바 활성화하기 + 하단바가 반투명합니다. + 하단바가 불투명합니다. 하단바 숨기기 하단바가 숨겨집니다. 하단바가 표시됩니다. @@ -906,13 +915,6 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 컴팩트 컨트롤 오버레이 활성화하기 전체 화면에서 컨트롤 오버레이를 작게 표시합니다. 전체 화면에서 컨트롤 오버레이를 작게 표시하지 않습니다. - 전체 화면 강제 전환하기 - " -다음과 같은 상황에서 동영상이 전체 화면으로 전환됩니다: - -• 동영상이 시작되었을 경우. -• 동영상 설명에서 챕터를 선택했을 경우. -• 댓글 내용에서 타임스탬프를 눌렀을 경우." 가로 모드 유지하기 자동 회전 모드를 켜지 않고, 전체 화면으로 시청 중 화면을 껐다 켰을 때, 가로 모드를 유지합니다. 가로 모드 유지하기 제한 시간 @@ -1382,12 +1384,18 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." HDR 자동 밝기 비활성화하기 HDR 자동 밝기를 비활성화합니다. HDR 자동 밝기를 활성화합니다. - 시청 패널 제스처 비활성화하기 - 동영상 플레이어 하단에서 아래로 스와이프하여 전체 화면으로 전환하지 않습니다. - 동영상 플레이어 하단에서 아래로 스와이프하여 전체 화면으로 전환합니다. 스와이프 제스처로 동영상 전환 비활성화하기 - 스와이프 제스처로 다음/이전 동영상으로 전환하지 않습니다. - 스와이프 제스처로 다음/이전 동영상으로 전환합니다. + 전체 화면 모드에서 위로/아래로 스와이프하여 다음/이전 동영상으로 전환하지 않습니다. + 전체 화면 모드에서 위로/아래로 스와이프하여 다음/이전 동영상으로 전환합니다. + 스와이프 제스처로 전체 화면 모드로 전환 비활성화하기 (플레이어 하단) + 플레이어 하단에서 아래로 스와이프하여 전체 화면 모드로 들어가지 않습니다. + 플레이어 하단에서 아래로 스와이프하여 전체 화면 모드로 들어갑니다. + 스와이프 제스처로 전체 화면 모드 전환 비활성화하기 (플레이어 내부) + 플레이어에서 아래로 스와이프하여 전체 화면 모드로 들어가지 않습니다. + 플레이어에서 아래로 스와이프하여 전체 화면 모드로 들어갑니다. + 스와이프 제스처로 전체 화면 모드 종료 비활성화하기 + 전체 화면에서 아래로 스와이프하여 전체 화면 모드를 나가지 않습니다. + 전체 화면에서 아래로 스와이프하여 전체 화면 모드를 나갑니다. 자동 동영상 @@ -1397,9 +1405,6 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." HDR 동영상 비활성화하기 HDR 동영상을 비활성화합니다. HDR 동영상을 활성화합니다. - 실시간 스트림에서 기본 동영상 재생 속도 비활성화하기 - 실시간 스트림에서 기본 동영상 재생 속도를 비활성화합니다. - 실시간 스트림에서 기본 동영상 재생 속도를 활성화합니다. 사용자 정의 동영상 재생 속도 활성화하기 사용자 정의 동영상 재생 속도를 활성화합니다. 사용자 정의 동영상 재생 속도를 비활성화합니다. @@ -1424,10 +1429,6 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 이전 동영상 화질 설정 메뉴를 활성화합니다. 이전 동영상 화질 설정을 비활성화합니다. 음악에서 기본 동영상 재생 속도 비활성화하기 - "음악 동영상에서 기본 동영상 재생 속도를 비활성화합니다. - -알려진 문제점: -• 이 설정은 'YouTube Music에서 감상하기' 배너가 포함되지 않은 동영상에는 적용되지 않을 수 있습니다." 음악 동영상에서 기본 동영상 재생 속도를 활성화합니다. Shorts에서 기본 동영상 재생 속도 활성화하기 Shorts에서 기본 동영상 재생 속도를 활성화합니다. @@ -1490,7 +1491,7 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 정보 ReturnYouTubeDislike.com - 싫어요 수의 데이터는 Return YouTube Dislike API에 의해 제공됩니다. 자세한 내용을 보려면 여기를 누르세요. + 싫어요 수의 데이터는 Return YouTube Dislike API에 의해 제공됩니다. 자세한 정보를 보려면 여기를 누르세요. 싫어요 수를 일시적으로 표시할 수 없습니다 (응답 시간 초과). 싫어요 수를 표시할 수 없습니다 (상태 코드: %d). 싫어요 수를 표시할 수 없습니다 (클라이언트 API 제한 도달). @@ -1701,7 +1702,7 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요." 정보 sponsor.ajay.app - 건너뛸 구간의 데이터는 SponsorBlock API에 의해 제공됩니다. 자세한 내용을 보려면 여기를 누르세요. + 건너뛸 구간의 데이터는 SponsorBlock API에 의해 제공됩니다. 자세한 정보를 보려면 여기를 누르세요. 기타 디버그 로깅 활성화하기 @@ -1773,21 +1774,28 @@ GmsCore 앱 배터리 최적화를 비활성화(제한 없음)하더라도, 배 "스트리밍 데이터를 변경하지 않습니다.\n동영상 재생 문제가 발생할 수 있습니다." 이 설정을 비활성화하면 동영상 재생 문제가 발생할 수 있습니다. 기본 클라이언트 - Android TV - Android VR - iOS - iOS TV 알려진 문제점 - "• 오디오 트랙 메뉴가 표시되지 않습니다. -• 안정적인 볼륨을 사용할 수 없습니다. -• 자동 오디오 트랙을 비활성화할 수 없습니다. -• VR은 Kids // TV는 재생목록과 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다." - • 주요 문제점은 아직 발견되지 않았습니다.\n• 영화, 유료, 비공개 그리고 연령 제한 동영상에서 다른 클라이언트가 사용될 수 있습니다. - • 영화 또는 유료 동영상이 재생되지 않을 수 있습니다.\n• 안정적인 볼륨을 사용할 수 없습니다.\n• 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다. + iOS AVC (H.264) 강제로 활성화하기 + 동영상 코덱을 AVC (H.264)로 강제로 활성화합니다.\n\n• 일부 VP9 코덱 동영상에서 제거되었던 화질 값이 표시될 수 있습니다.\n• 최대 화질 값이 1080p이므로, 초고화질 동영상을 재생할 수 없습니다.\n• HDR 동영상을 재생할 수 없습니다. + 동영상 코덱을 자동으로 결정합니다.\n\n• 예전에 업로드된 동영상을 재생했는데 VP9 코덱 응답을 받았을 경우, 일부 화질값이 제거되어 360p와 1080p(Premium 기능)만 선택가능할 수 있거나 화질 메뉴를 선택불가능할 수 있습니다. + "이 설정를 활성화하면 배터리 수명이 향상되고, 동영상 재생 끊김 문제가 해결될 수 있습니다. + +AVC의 최대 화질 값은 1080p이고, OPUS 코덱을 사용불가 및 HDR 동영상을 재생할 수 없으며, 동영상을 재생했을 경우에는 VP9 또는 AV1보다 더 많은 모바일 데이터를 사용되오니 주의하세요." 전문 통계에서 표시하기 \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 전문 통계에서 표시됩니다.\n\n• 만약 선택한 기본 클라이언트가 재생할 수 없는 동영상을 재생하려하거나 클라이언트 재생 문제가 발생하면, 그 문제를 해결하기 위해 다른 클라이언트가 사용되는 경우도 있기 때문에 전문 통계에서 다르게 표시될 수 있습니다. - \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 전문 통계에서 숨겨집니다.\n\n• 만약 선택한 기본 클라이언트가 재생할 수 없는 동영상을 재생하려하거나 클라이언트 재생 문제가 발생하면 그 문제를 해결하기 위해 다른 클라이언트가 사용되는 경우도 있기 때문에 전문 통계에서 다르게 표시될 수 있습니다. + \'스트리밍 데이터를 가져오는 데 사용되는 클라이언트\'가 전문 통계에서 숨겨집니다.\n\n• 만약 선택한 기본 클라이언트가 재생할 수 없는 동영상을 재생하려하거나 클라이언트 재생 문제가 발생하면, 그 문제를 해결하기 위해 다른 클라이언트가 사용되는 경우도 있기 때문에 전문 통계에서 다르게 표시될 수 있습니다. + PoToken / VisitorData + 사용할 PoToken + \'신뢰할 수 있는 브라우저에서 BotGuard로 발행한 PoToken\'을 사용할 수 있습니다. + 사용할 VisitorData + \'신뢰할 수 있는 브라우저에서 BotGuard로 발행한 VisitorData\'를 사용할 수 있습니다. + PoToken / VisitorData에 대한 정보 + "일부 클라이언트는 유효한 스트리밍 데이터 응답을 받기 위해 PoToken과 VisitorData가 필요합니다. + +iOS를 기본 클라이언트로 사용하려는 경우에 이 값이 필요할 수 있습니다. + +자세한 정보를 보려면 여기를 누르세요." 시청 기록 시청 기록과 관련된 설정을 변경할 수 있습니다. diff --git a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml index da3713f99..edb1f5e73 100644 --- a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml +++ b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml @@ -291,6 +291,7 @@ Jeśli układ ekranu odtwarzacza zmieni się w skutek zmian po stronie serwera, Ogólne Strona startowa Przeglądaj kanały + Nauka Domyślna Odkrywanie Gry @@ -300,12 +301,14 @@ Jeśli układ ekranu odtwarzacza zmieni się w skutek zmian po stronie serwera, Na żywo Filmy Muzyka + Powiadomienia Wyszukiwanie Shortsy Sport Subskrypcje Na czasie Do obejrzenia + Twoje klipy Działanie zmieniania strony głównej "Strona główna zawsze się zmienia @@ -320,6 +323,9 @@ Ograniczenie: Przycisk wstecz na pasku narzędzi może nie działać." Animacja uruchamiania aplikacji Wyłączona Włączona + Półprzezroczystość paska statusu + Wyłączona + Włączona Kolorowy ekran ładowania Włączony Wyłączony @@ -491,6 +497,9 @@ Notka: włączenie tej opcji wymusza ukrywanie reklam w filmach." Dodatkowo, reklamy nie będą już blokowane w Shortsach. Jeśli opcja nie przynosi skutku, spróbuj przełączyć się na tryb incognito." + Wygląd paska nawigacji + Półprzezroczysty + Nieprzezroczysty Pasek nawigacji Ukryty Widoczny @@ -905,11 +914,6 @@ Ograniczenie: tytuły filmów znikają po stuknięciu w nie." Przyciski w odtwarzaczu bliżej środka Przyciski w odtwarzaczu nie zajmują całego ekranu Przyciski w odtwarzaczu zajmują cały ekran - Wymuś tryb pełnoekranowy - "Filmy zostaną przełączone w tryb pełnoekranowy w następujących sytuacjach: - -• Po rozpoczęciu filmu -• Po stuknięciu w czas filmu w komentarzach" Zachowaj tryb poziomy Zachowuje tryb poziomy, gdy wyłączysz i włączysz ekran w trybie pełnoekranowym. Limit czasu zachowania trybu poziomego @@ -1370,12 +1374,18 @@ Ograniczenia: Automatyczna jasność w filmach z HDR Wyłączona Włączona - Pełny ekran gestem przesunięcia - Wejście w tryb pełnoekranowy przesunięciem w dół poniżej odtwarzacza filmu jest wyłączone - Wejście w tryb pełnoekranowy przesunięciem w dół poniżej odtwarzacza filmu jest włączone Gest zmiany filmu przesunięciem w górę lub dół Wyłączony Włączony + Gest wejścia w tryb pełnoekranowy przesunięciem pod odtwarzaczem + Wyłączony + Włączony + Gest wejścia w tryb pełnoekranowy przesunięciem w odtwarzaczu + Wyłączony + Włączony + Gest wyjścia z trybu pełnoekranowego przesunięciem + Wyłączony + Włączony Automatyczna Filmy @@ -1385,9 +1395,6 @@ Ograniczenia: Filmy z HDR Wyłączone Włączone - Domyślna prędkość odtwarzania podczas transmisji na żywo - Wyłączona - Włączona Niestandardowa prędkość odtwarzania Włączona Wyłączona @@ -1412,9 +1419,6 @@ Ograniczenia: Widoczne Niewidoczne Domyślna prędkość odtwarzania dla muzyki - "Wyłączona - -Ograniczenie: To ustawienie może nie działać dla filmów bez baneru 'Słuchaj w YouTube Music'." Włączona Domyślna prędkość odtwarzania w Shortsach Włączona @@ -1761,20 +1765,28 @@ Stuknij przycisk kontynuacji i zezwól na zmiany w optymalizacji." "Wyłączone. Odtwarzanie filmów może nie działać" Wyłączenie tej opcji może spowodować problemy z odtwarzaniem filmów. Domyślny klient - Android TV - Android VR - iOS - iOS TV Efekty uboczne oszukiwania - "• Brakuje menu od ścieżki dźwiękowej -• Stabilna głośność nie jest dostępna -• Wyłączenie automatycznego wymuszania ścieżki dźwiękowej nie jest dostępne" - • Jeszcze nie znaleziono - • Filmy kinowe lub płatne filmy mogą się nie odtwarzać + Wymuś kodek iOS AVC (H.264) + Wymuszony + Określany automatycznie + "Włączenie tego może poprawić czas pracy baterii i naprawić zacinanie się odtwarzacza. + +AVC obsługuje maksymalnie rozdzielczość 1080p, kodek audio OPUS nie jest dostępny, a odtwarzanie wideo będzie zużywać więcej danych internetowych niż VP9 lub AV1." Informacja w statystykach dla nerdów Widoczna Ukryta + PoToken / VisitorData + PoToken do użycia + PoToken wydany przez BotGuard w zaufanej przeglądarce. + VisitorData do użycia + VisitorData wydany przez BotGuard w zaufanej przeglądarce. + O PoTokenie / VisitorData + "Niektóre klienty wymagają PoTokena lub VisitorData, by otrzymać prawidłową odpowiedź na strumień danych. + +Jeśli próbujesz użyć iOS jako domyślnego klienta, będziesz potrzebować tych wartości. + +Kliknij, by zobaczyć więcej informacji." Historia oglądania Zmień ustawienia związane z historią oglądania diff --git a/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml b/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml index 1194f88a4..5b12ea37c 100644 --- a/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml +++ b/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml @@ -291,6 +291,7 @@ Se o layout da tela do reprodutor mudar devido a alterações no lado do servido Geral Alterar a página inicial Explorar canais + Cursos / Aprendizagem Padrão Explorar Jogos @@ -300,12 +301,14 @@ Se o layout da tela do reprodutor mudar devido a alterações no lado do servido Ao Vivo Filmes Música + Notificações Buscar Shorts Esportes Inscrições Em alta Assistir mais tarde + Seus clipes Alterar tipo de página inicial "Página inicial sempre muda. @@ -492,6 +495,9 @@ Nota: Ativar isso também oculta anúncios de vídeo à força." Além disso, os anúncios não serão mais bloqueados no Shorts. Se essa configuração não surtir efeito, tente alternar para o modo anônimo." + Ativar barra de navegação transparente + A barra de navegação está transparente. + A barra de navegação está opaca. Ocultar barra de navegação A barra de navegação está oculta. A barra de navegação será exibida. @@ -906,11 +912,6 @@ Limitação: Título do vídeo desaparece quando clicado." Ativar sobreposição de controles compactos A sobreposição de controles não preenche a tela inteira. A sobreposição de controles preenche a tela inteira. - Forçar tela cheia - "O vídeo será alternado para tela cheia nas seguintes situações: - -• Quando uma marcação de tempo nos comentários é clicada. -• Quando um vídeo é iniciado." Manter o modo paisagem Mantenha o modo paisagem ao desligar e ligar em tela cheia. Tempo limite para manter o modo paisagem @@ -1372,9 +1373,6 @@ Sem margens na parte superior e inferior do reprodutor." Desativar brilho automático HDR O brilho automático HDR está desativado. O brilho automático HDR está ativado. - Desativar gestos do painel de observação - Entrar em tela cheia ao deslizar para baixo no reprodutor de vídeo está desativado. - Entrar em tela cheia ao deslizar para baixo no reprodutor de vídeo está ativado. Desativar deslizar para alterar o vídeo Deslizar para cima / baixo não reproduzirá o vídeo seguinte / anterior. Deslizar para cima / baixo reproduzirá o vídeo seguinte / anterior. @@ -1387,9 +1385,6 @@ Sem margens na parte superior e inferior do reprodutor." Desativar vídeo HDR O vídeo HDR está desativado. O vídeo HDR está ativado. - Desativar a velocidade de reprodução na transmissão ao vivo - A velocidade de reprodução padrão está desativada na transmissão ao vivo. - A velocidade de reprodução padrão está ativada na transmissão ao vivo. Ativar velocidade de reprodução personalizada A velocidade de reprodução personalizada está ativada. A velocidade de reprodução personalizada está desativada. @@ -1414,9 +1409,6 @@ Sem margens na parte superior e inferior do reprodutor." O menu antigo de qualidade de vídeo está sendo exibido. O menu antigo de qualidade de vídeo não está sendo exibido. Desativar a velocidade de reprodução para música - "A velocidade de reprodução padrão é desabilitada para música. - -Limitação: esta configuração pode não se aplicar a vídeos que não incluem o banner 'Ouvir no YouTube Music'." A velocidade de reprodução padrão está ativada para música. Ativar velocidade de reprodução padrão no Shorts A velocidade de reprodução padrão se aplica ao Shorts. @@ -1760,20 +1752,28 @@ Toque no botão continuar e desative as otimizações da bateria." "Os dados de streaming não são falsificados. A reprodução de vídeo pode não funcionar." Desativar esta configuração pode causar problemas de reprodução de vídeo. Cliente padrão - Android TV - Android VR - iOS - iOS TV Efeitos colaterais da falsificação - "• O menu de faixa de áudio está faltando. -• Volume estável não está disponível. -• Desativar faixas de áudio automático forçadas não está disponível." - • Ainda não encontrado. - • Filmes ou vídeos pagos podem não reproduzir. + Forçar iOS AVC (H.264) + O codec de vídeo é forçado para AVC (H.264). + O codec de vídeo é determinado automaticamente. + "Ativar isso pode melhorar a duração da bateria e corrigir travamentos na reprodução. + +O AVC tem uma resolução máxima de 1080p, o codec de áudio Opus não está disponível e a reprodução de vídeo usará mais dados da internet do que VP9 ou AV1." Exibir em Estatísticas para nerds O cliente usado para buscar dados de streaming é mostrado em Estatísticas para nerds. O cliente usado para buscar dados de streaming está oculto em Estatísticas para nerds. + PoToken / VisitorData + PoToken a ser utilizado + PoToken emitido pelo BotGuard em um navegador confiável. + Dados de visitante a ser utilizado + Dados de visitante emitido pelo BotGuard em um navegador confiável. + Sobre o PoToken / VisitorData + "Alguns clientes exigem PoToken e VisitorData para obter uma resposta de dados de streaming válida. + +Se você estiver tentando usar o iOS como cliente padrão, pode precisar desses valores. + +Clique para ver mais informações." Histórico de exibição Altere as configurações relacionadas ao histórico de exibição. diff --git a/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml b/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml index 83c75d092..bf54ea768 100644 --- a/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml +++ b/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml @@ -304,6 +304,7 @@ Shorts Основные настройки Начальная страница Обзор каналов + Курсы / Обучение По умолчанию Навигатор Игры @@ -313,12 +314,14 @@ Shorts Трансляции Фильмы Музыка + Уведомления Поиск Shorts Спорт Подписки В тренде Смотреть позже + Ваши клипы Тип начальной страницы "Начальная страница постоянно изменяется. Ограничение: Кнопка возврат может не работать." @@ -332,6 +335,9 @@ Shorts Анимированная заставка Анимированная заставка отключена. Анимированная заставка включена. + Полупрозрачность строки состояния + Полупрозрачность включена. + Полупрозрачность отключена. Переливающийся экран загрузки Переливающийся экран загрузки включен. Переливающийся экран загрузки отключен. @@ -504,6 +510,9 @@ Shorts Кроме того, реклама больше не будет блокироваться в Shorts. Если эта настройка не вступила в силу, попробуйте перейти в режим инкогнито." + Полупрозрачность панели навигации + Полупрозрачность включена. + Полупрозрачность отключена. Панель навигации Панель навигации скрыта. Панель навигации отображена. @@ -917,11 +926,6 @@ Shorts Компактные элементы управления Наложение элементов управления не полноэкранное. Наложение элементов управления полноэкранное. - Принудительный полноэкранный режим - "Видео будут переведены в полноэкранный режим при: - -• Нажатии на временную метку в комментариях. -• Запуске видео." Удерживать альбомный режим Удерживает альбомный режим в полноэкранном режиме. Сохранять таймаут альбомного режима @@ -1392,12 +1396,18 @@ Shorts Автояркость HDR Автояркость HDR отключена. Автояркость HDR включена. - Жесты панели просмотра - Полноэкранный режим жестом вниз отключен. - Полноэкранный режим жестом вниз включен. Переключение видео жестом Переключение видео жестами отключены. Переключение видео жестами включены. + Жест полноэкранного режима (под плеером) + Жест под плеером отключен. + Жест под плеером включен. + Жест полноэкранного режима (в плеере) + Жест в плеере отключен. + Жест в плеере включен. + Жест выхода из полноэкранного режима + Жест выхода из режима отключен. + Жест выхода из режима включен. Авто Видео @@ -1407,9 +1417,6 @@ Shorts HDR видео HDR видео отключены. HDR видео включены. - Скорость в прямых трансляциях - Скорость воспроизведения в трансляциях отключена. - Скорость воспроизведения в трансляциях включена. Пользовательская скорость воспроизведения Пользовательская скорость воспроизведения включена. Пользовательская скорость воспроизведения отключена. @@ -1434,10 +1441,6 @@ Shorts Старое меню качества отображено. Старое меню качества скрыто. Скорость воспроизведения для музыки - "Скорость воспроизведения по умолчанию для музыки отключена. - -Ограничение: -Этот параметр не может применяться к видео, которые не содержат баннер 'Слушать в YouTube Music'." Скорость воспроизведения по умолчанию для музыки включена. Скорость воспроизведения по умолчанию в Shorts Скорость воспроизведения по умолчанию в Shorts включена. @@ -1784,20 +1787,30 @@ Shorts Воспроизведение видео может не работать." Отключение этой настройки вызовет проблемы с воспроизведением видео. Клиент по умолчанию - Android TV - Android VR - iOS - iOS TV Эффекты от подмены - "• Меню аудио дорожки отсутствует. -• Стабильная громкость недоступна. -• Отключить принудительные автозвуковые дорожки недоступна." - • Еще не найдено. - • Платные видео и фильмы могут не проигрываться. + Принудительно iOS, AVC (H.264) + Принудительное использование AVC (H.264) включено. + Принудительное использование AVC (H.264) отключено. + "Включение может: +- улучшить время автономной работы +- устранить прерывания при воспроизведении. + +Максимальное разрешение видео AVC составляет 1080p. Кодек Opus недоступен. Потребление интернет трафика будет больше, чем при VP9 или AV1." Статистике для сисадминов Клиент потоковых данных отображается в Статистике для сисадминов. Клиент потоковых данных скрыт в Статистике для сисадминов. + PoToken / VisitorData + PoToken + PoToken выпущен с BotGuard в доверенном браузере. + VisitorData + VisitorData выданный с BotGuard в надежном браузере. + О PoToken / VisitorData + "Некоторые клиенты требуют PoToken и VisitorData для получения правильного потокового ответа данных. + +При использовании iOS клиента по умолчанию, эти значения могут потребоваться. + +Нажмите, чтобы увидеть дополнительную информацию." История просмотра Изменить настройки истории просмотра. diff --git a/patches/src/main/resources/youtube/translations/tr-rTR/strings.xml b/patches/src/main/resources/youtube/translations/tr-rTR/strings.xml index 04f405347..f8fe9ad57 100644 --- a/patches/src/main/resources/youtube/translations/tr-rTR/strings.xml +++ b/patches/src/main/resources/youtube/translations/tr-rTR/strings.xml @@ -834,11 +834,6 @@ Sınırlama: Tıklandığında video başlığı kayboluyor." Tam ekranda sıkışık oynatıcıyı etkinleştir Tam ekran videoda sıkışık oynatıcı etkin. Tam ekran videoda sıkışık oynatıcı etkin değil - Tam ekrana zorla - "Aşağıdaki durumlarda video tam ekrana geçecektir: - -• Yorumlardaki zaman damgasına tıklandığında. -• Video başladığında." Manzara modunu tut Ekranı tam ekranda kapatıp açarken yatay modu korur. Manzara modunu tutma zaman aşımı @@ -1186,9 +1181,6 @@ Bilinen sorunlar: HDR\'lı videolarda, HDR\'ı devre dışı bırak HDR devre dışı HDR etkin - Canlı yayınlarda varsayılan oynatma hızını devre dışı bırak - Canlı yayınlarda varsayılan oynatma hızı devre dışı - Canlı yayınlarda varsayılan oynatma hızı etkin Özel oynatma hızlarını etkinleştir Özel oynatma hızları etkin Özel oynatma hızları kapalı diff --git a/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml b/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml index 271f1b39e..aa242103c 100644 --- a/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml +++ b/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml @@ -291,6 +291,7 @@ Загальне Змінити початкову сторінку Перегляд каналів + Навчання Стандартна Що нового Ігри @@ -300,12 +301,14 @@ Наживо Фільми Музика + Сповіщення Пошук YouTube Shorts Спорт Підписки Тенденції Переглянути пізніше + Ваші кліпи Тип зміни початкової сторінки "Початкова сторінка змінюється завжди. @@ -320,6 +323,9 @@ Вимкнути сплеш анімацію Сплеш анімацію вимкнено. Сплеш анімацію увімкнено. + Вимкнути напівпрозорість рядка стану + Рядок стану непрозорий. + Рядок стану непрозорий чи напівпрозорий. Увімкнути градієнт екрану завантаження Градієнт екрану завантаження увімкнено. Градієнт екрану завантаження вимкнено. @@ -492,6 +498,9 @@ А також, рекламу більше не блокуватиметься в Shorts. Якщо це налаштування не діє, спробуйте перемкнути Анонімний режим." + Увімкнути напівпрозорість панелі навігації + Панель навігації напівпрозора. + Панель навігації непрозора. Приховати панель навігації Панель навігації приховано. Панель навігації показується. @@ -906,11 +915,6 @@ Увімкнути компактне керування Компактне керування не заповнює весь екран. Компактне керування заповнює весь екран. - Примусово на повний екран - "Відео перемикатиметься на повний екран в таких ситуаціях: - -• Натиснуто на мітку часу у коментарях. -• Відео розпочалося." Зберігати ландшафтний режим Зберігає ландшафтний режим під час вимкнення та ввімкнення екрана у повноекранному режимі. Скільки зберігати ландшафтний режим @@ -1376,12 +1380,18 @@ Вимкнути авто яскравість HDR Авто яскравість HDR вимкнено. Авто яскравість HDR увімкнено. - Вимкнути жести панелі перегляду - Перехід на повний екран при проведенні вниз під відеоплеєром вимкнено. - Перехід на повний екран при проведенні вниз під відеоплеєром увімкнено. Вимкнути зміну відео проведенням - Проведення вгору / вниз не відтворюватиме наступне / попереднє відео. - Проведення вгору / вниз відтворюватиме наступне / попереднє відео. + Проведення вгору / вниз у повноекранному режимі не змінюватиме на наступне / попереднє відео. + Проведення вгору / вниз у повноекранному режимі змінюватиме на наступне / попереднє відео. + Вимкнути проведення для переходу у повноекранний режим (знизу плеєра) + Проведенням униз не переходитиметься у повноекранний режим. + Проведенням униз переходитиметься у повноекранний режим. + Вимкнути проведення для переходу у повноекранний режим (у плеєрі) + Проведенням угору не переходитиметься у повноекранний режим. + Проведенням угору переходитиметься у повноекранний режим. + Вимкнути проведення для виходу з повноекранного режиму + Проведенням вниз не виходитиметься з повноекранного режиму. + Проведенням вниз виходитиметься з повноекранного режиму. Авто Відео @@ -1391,9 +1401,6 @@ Вимкнути HDR відео HDR відео вимкнено. HDR відео увімкнено. - Вимкнути швидкість відтворення в прямих трансляціях - Типову швидкість відтворення вимкнено в прямих трансляціях. - Типову швидкість відтворення увімкнено в прямих трансляціях. Увімкнути користувацьку швидкість відтворення Користувацьку швидкість відтворення увімкнено. Користувацьку швидкість відтворення вимкнено. @@ -1418,9 +1425,6 @@ Старе меню якості відео показується. Старе меню якості відео не показується. Вимкнути швидкість відтворення для музики - "Типову швидкість відтворення вимкнено для музики. - -Застереження: Це налаштування може не застосовуватись до відео, які не містять напис 'Слухати через YouTube Music'." Типову швидкість відтворення увімкнено для музики. Увімкнути типову швидкість відтворення Shorts Типову швидкість відтворення застосовується для Shorts. @@ -1762,20 +1766,28 @@ "Дані трансляції не підроблено. Відтворення відео може не працювати." Вимикання цього налаштування може призвести до проблем відтворення відео. Основний клієнт - Android TV - Android VR - iOS - iOS TV Побічні ефекти імітування - "• Меню звукової доріжки відсутнє. -• Стабілізація гучності недоступна. -• Вимикання примусових звукових доріжок недоступне." - • Відео для дітей можуть не відтворюватися. - • Фільми чи платні відео можуть не відтворюватися. + Примусово AVC (H.264) iOS + Примусово увімкнено відеокодек AVC (H.264). + Відеокодек визначається автоматично. + "Увімкнення може зменшити споживання акумулятора та виправити затинання відтворення. + +AVC має максимальну роздільну здатність 1080p, аудіокодек Opus недоступний, а відтворення відео використовуватиме більше інтернет-даних, ніж кодек VP9 чи AV1." Показувати в Статистика для сисадмінів Клієнт, що використовується для отримання даних трансляції показується у Статистика для сисадмінів. Клієнт, що використовується для отримання даних трансляції приховано у Статистика для сисадмінів. + PoToken / VisitorData + PoToken для використання + PoToken виданий BotGuard в довіреному браузері. + VisitorData для використання + VisitorData виданий BotGuard в довіреному браузері. + Про PoToken / VisitorData + "Деякі клієнти вимагають PoToken і VisitorData для отримання коректної відповіді даних трансляції. + +Якщо намагаєтеся використовувати клієнт iOS, можуть знадобитися ці значення. + +Натисніть, щоб переглянути більше інформації." Історія перегляду Змінити налаштування пов\'язані з історією перегляду. diff --git a/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml b/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml index de090ee13..6b39af690 100644 --- a/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml +++ b/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml @@ -294,6 +294,7 @@ Nếu bố cục của màn hình trình phát thay đổi do các thay đổi t Tổng quan Thay đổi trang khởi động Duyệt kênh + Học tập Mặc định Khám phá Trò chơi @@ -303,12 +304,14 @@ Nếu bố cục của màn hình trình phát thay đổi do các thay đổi t Trực tiếp Phim Âm nhạc + Thông báo Tìm kiếm Shorts Thể thao Kênh đăng ký Thịnh hành Xem sau + Đoạn video của bạn Thay đổi kiểu trang khởi động "Trang khởi động sẽ liên tục thay đổi. @@ -323,6 +326,9 @@ Hạn chế: Nút Quay lại trên thanh công cụ có thể không hoạt đ Tắt hoạt ảnh khi ứng dụng khởi chạy Hoạt ảnh khi ứng dụng khởi chạy đã tắt. Hoạt ảnh khi ứng dụng khởi chạy được bật. + Vô hiệu hoá thanh trạng thái trong suốt + Thanh trạng thái không còn trong suốt. + Thanh trạng thái có thể trong suốt hoặc không. Màn hình tải hiệu ứng gradient Màn hình tải hiệu ứng gradient đã bật. Màn hình tải hiệu ứng gradient đã tắt. @@ -495,6 +501,9 @@ Lưu ý: Bật tuỳ chọn này cũng sẽ ẩn các quảng cáo dạng video. Ngoài ra, quảng cáo sẽ không còn bị chặn trong trình phát Shorts. Nếu cài đặt này không có hiệu lực, hãy thử chuyển sang chế độ Ẩn danh." + Thanh điều hướng trong suốt + Thanh điều hướng trong suốt đang được áp dụng. + Thanh điều hướng mặc định đang được áp dụng. Ẩn thanh điều hướng Thanh điều hướng đã ẩn. Thanh điều hướng được hiển thị. @@ -909,11 +918,6 @@ Hạn chế: Tiêu đề video sẽ biến mất khi nhấn vào." Lớp phủ điều khiển trình phát thu gọn Lớp phủ điều khiển trình phát thu gọn đã bật. Lớp phủ điều khiển trình phát thu gọn đã tắt. - Buộc áp dụng chế độ toàn màn hình - "Video sẽ chuyển sang chế độ toàn màn hình trong các trường hợp sau: - -• Khi video bắt đầu. -• Khi nhấn vào dấu thời gian trong Phần bình luận." Giữ chế độ toàn màn hình Giữ chế độ toàn màn hình hoạt động trong lúc bạn tắt và đánh thức thiết bị khi đang xem chế độ toàn màn hình. Thời gian giữ chế độ toàn màn hình (mili giây) @@ -1376,12 +1380,18 @@ Không còn lề trên và dưới trong trình phát." Tắt độ sáng HDR tự động Độ sáng HDR tự động đã tắt. Độ sáng HDR tự động đã bật. - Tắt cử chỉ bên dưới trình phát - Cử chỉ vuốt xuống từ khu vực bên dưới trình phát để xem video ở chế độ toàn màn hình dọc đã tắt. - Cử chỉ vuốt xuống từ khu vực bên dưới trình phát để xem video ở chế độ toàn màn hình dọc được bật. Vuốt để chuyển video - Vuốt lên/xuống sẽ không phát video tiếp theo hoặc trước đó. - Vuốt lên/xuống sẽ phát video tiếp theo hoặc trước đó. + Vuốt lên/xuống trong chế độ toàn màn hình sẽ không phát video tiếp theo/trước đó. + Vuốt lên/xuống trong chế độ toàn màn hình sẽ phát video tiếp theo/trước đó. + Tắt vuốt để chuyển sang chế độ toàn màn hình (bên dưới trình phát) + Vuốt xuống bên dưới trình phát sẽ không chuyển sang chế độ toàn màn hình. + Vuốt xuống bên dưới trình phát để chuyển sang chế độ toàn màn hình. + Tắt vuốt để chuyển sang chế độ toàn màn hình (trong trình phát) + Vuốt xuống trong trình phát sẽ không chuyển sang chế độ toàn màn hình. + Vuốt xuống trong trình phát để chuyển sang chế độ toàn màn hình. + Tắt vuốt để thoát chế độ toàn màn hình + Vuốt xuống trong chế độ toàn màn hình sẽ không thoát khỏi chế độ này. + Vuốt xuống trong chế độ toàn màn hình để thoát khỏi chế độ này. Tự động Video @@ -1391,9 +1401,6 @@ Không còn lề trên và dưới trong trình phát." Tắt video HDR Video HDR đã tắt. Video HDR đã bật. - Tắt tùy chọn tốc độ phát khi xem trực tiếp - Tốc độ phát mặc định bị tắt khi xem sự kiện trực tiếp và buổi công chiếu. - Tốc độ phát mặc định được bật khi xem sự kiện trực tiếp và buổi công chiếu. Tốc độ phát tuỳ chỉnh Đang áp dụng các giá trị tốc độ phát video tuỳ chỉnh. Đang áp dụng các giá trị tốc độ phát video mặc định. @@ -1418,9 +1425,6 @@ Không còn lề trên và dưới trong trình phát." Mục chất lượng video kiểu cũ được hiển thị. Mục chất lượng video kiểu cũ không được hiển thị. Tắt tùy chọn tốc độ phát khi phát nhạc - "Tốc độ phát mặc định đã bị vô hiệu hoá khi phát nhạc. - -Hạn chế: Cài đặt này có thể không áp dụng cho các video không bao gồm biểu ngữ \"Nghe trên YouTube Music\"." Tốc độ phát mặc định được kích hoạt khi phát nhạc. Tốc độ phát mặc định cho video ngắn Tốc độ phát mặc định đã đặt đang được áp dụng khi xem Shorts. @@ -1767,20 +1771,31 @@ Nhấn vào Tiếp tục và cho phép thay đổi lựa chọn tối ưu hoá p "Luồng dữ liệu trực tuyến chưa được giả mạo. Khi phát video có thể gặp sự cố đứng hình." Tắt cài đặt này có thể gây ra sự cố phát video. Ứng dụng khách mặc định - Android TV - Android VR - iOS - iOS TV Hạn chế - "• Mục Bản âm thanh bị thiếu. -• Âm lượng ổn định không khả dụng. -• Tắt bắt buộc bản âm thanh tự động không khả dụng." - • Chưa tìm thấy. - • Phim hoặc video trả phí có thể không phát được. + Bắt buộc iOS sử dụng AVC (H.264) + Codec video bị ép buộc thành AVC (H.264). + Codec video được xác định tự động. + "Bật tính năng này giúp cải thiện thời lượng sử dụng pin và khắc phục sự cố phát video. + +Hạn chế: +• AVC có độ phân giải tối đa là 1080p. +• Codec âm thanh OPUS không khả dụng. +• Dùng nhiều dữ liệu di động hơn với VP9 hoặc AV1." Hiển thị trong Thống kê chi tiết Ứng dụng khách sử dụng để nạp luồng dữ liệu trực tuyến được hiển thị trong Thống kê chi tiết. Ứng dụng khách sử dụng để nạp luồng dữ liệu trực tuyến đã ẩn trong Thống kê chi tiết. + PoToken/VisitorData + PoToken + Được cung cấp bởi BotGuard trên trình duyệt đáng tin cậy. + VisitorData + Được cung cấp bởi BotGuard trên trình duyệt đáng tin cậy. + Giới thiệu về PoToken/VisitorData + "Một số ứng dụng khách yêu cầu PoToken và VisitorData để nhận được phản hồi dữ liệu trực tuyến hợp lệ. + +Nếu bạn đang cố sử dụng iOS làm ứng dụng khách mặc định, thì có thể bạn sẽ cần những giá trị này. + +Nhấp vào đây để biết thêm chi tiết." Nhật ký xem Thay đổi cài đặt liên quan đến nhật ký xem. diff --git a/patches/src/main/resources/youtube/translations/zh-rCN/strings.xml b/patches/src/main/resources/youtube/translations/zh-rCN/strings.xml index 2a13f2e2d..f0b70cc38 100644 --- a/patches/src/main/resources/youtube/translations/zh-rCN/strings.xml +++ b/patches/src/main/resources/youtube/translations/zh-rCN/strings.xml @@ -871,11 +871,6 @@ 启用紧凑的播放器布局叠加层 紧凑的播放器布局已启用 紧凑的播放器布局已禁用 - 强制全屏 - "在以下情况下,视频将切换为全屏: - -• 开始播放视频时 -• 点击评论中的时间戳时" 保持横屏模式 在全屏状态下关闭和打开屏幕时,保持横屏模式 保持横屏模式超时 @@ -1276,9 +1271,6 @@ HDR 视频 HDR 视频已禁用 HDR 视频已启用 - 禁用直播默认播放速度 - 直播默认播放速度已禁用 - 直播默认播放速度已启用 启用自定义播放速度 自定义播放速度已启用 自定义播放速度已禁用 @@ -1303,9 +1295,6 @@ 显示旧的视频画质菜单 不显示旧的视频画质菜单 禁用音乐播放速度 - "音乐默认播放速度已禁用 - -限制:此设置可能不适用于不包含“监听YouTube Music”广告的视频" 音乐默认播放速度已启用 启用 Shorts 默认播放速度 默认播放速度适用于 Shorts @@ -1647,9 +1636,6 @@ "流媒体数据未伪装,视频可能无法正常播放" 关闭此选项可能会导致视频不能正常播放 默认客户端 - Android TV - Android VR - iOS 伪装副作用 显示统计信息 用于获取流媒体数据的客户端已在统计信息中显示 diff --git a/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml b/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml index e23fbf872..861a1f12e 100644 --- a/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml +++ b/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml @@ -290,6 +290,7 @@ 一般設定 更改起始頁 瀏覽頻道 + 課程/學習 預設 探索 遊戲 @@ -299,12 +300,14 @@ 直播 電影 音樂 + 通知 搜尋 短片 運動 訂閱 熱門 稍後觀看 + 你的剪輯 變更起始頁類型 "起始頁總是改變。 @@ -319,6 +322,9 @@ 停用啟動動畫 啟動動畫已停用 啟動動畫已啟用 + 停用半透明狀態列 + 狀態列不透明。 + 狀態列是不透明或半透明的。 啟用漸變載入畫面 漸變載入畫面已啟用 漸變載入畫面已停用 @@ -491,6 +497,9 @@ 此外,廣告將不再在 Shorts 中被封鎖。 若此設定未生效,請嘗試切換至無痕模式。" + 啟用半透明導覽列 + 導覽列是半透明的。 + 導覽列不透明。 隱藏導覽列 導覽列已隱藏。 導覽列已顯示。 @@ -669,8 +678,8 @@ 操作建議已隱藏 操作建議已顯示 隱藏時間跳轉 - (評論)時間跳轉已隱藏 - (評論)時間跳轉已顯示 + 定時留言已隱藏。 + 定時反應已顯示。 隱藏推薦影片結束界面 "關閉自動播放時,建議的影片結束畫面會隱藏。 @@ -905,11 +914,6 @@ 啟用緊湊的播放器佈局疊加層 精簡控制選單已啟用 緊湊的播放器佈局已停用 - 強制全螢幕 - "影片將在以下情況下切換到全螢幕模式: - -・當影片開始播放時。 -・當點擊評論中的時間戳記時。" 保持橫向模式 在全螢幕模式下關閉和開啟螢幕時保持橫向模式。 保持橫向模式的超時時間 @@ -1367,12 +1371,18 @@ 停用 HDR 影片自動亮度 HDR 影片自動亮度已停用 HDR 影片自動亮度已啟用 - 停用觀看面板手勢 - 透過滑動播放器底部區域切換到全螢幕功能已停用。 - 透過滑動播放器底部區域切換到全螢幕功能已啟用。 停用滑動切換影片功能 向上/向下滑動將不會播放下一個/上一個影片。 向上/向下滑動將播放下一個/上一個影片。 + 停用滑動進入全螢幕模式(在播放器下方)。 + 向下滑動播放器下方將不會進入全螢幕模式。 + 向下滑動播放器下方將進入全螢幕模式。 + 停用滑動進入全螢幕模式(在播放器內)。 + 在播放器內向上滑動將不會進入全螢幕模式。 + 在播放器內向上滑動將進入全螢幕模式。 + 停用滑動退出全螢幕模式。 + 在全螢幕模式下向下滑動將不會退出全螢幕模式。 + 在全螢幕模式下向下滑動將退出全螢幕模式。 自動 影片 @@ -1382,9 +1392,6 @@ HDR 影片 HDR 影片已啟用 HDR 影片已停用 - 在直播中停用預設播放速度 - 直播預設播放速度已停用 - 直播預設播放速度已啟用 啟用自定義播放速度 自定義播放速度已啟用 自定義播放速度已停用 @@ -1409,15 +1416,12 @@ 顯示舊的影片畫質選單 不顯示舊的影片畫質選單 停用音樂的播放速度 - "音樂的預設播放速度被停用。 - -限制:此設定可能不適用於不包含「在 YouTube 音樂上收聽」橫幅影片。" 音樂的預設播放速度已啟用。 啟用短片預設播放速度 預設播放速度適用於短片 預設播放速度不適用於短片 - 跳過預加載緩衝 - 跳過預加載緩衝 + 跳過預載入 + 跳過預載入 "跳過影片開頭的預先載入緩衝區以立即套用預設影片品質 資訊: @@ -1549,7 +1553,7 @@ 跳過贊助內容 跳過自我宣傳 跳過交互提醒 - 跳轉至突出顯示 + 跳轉至重點部分 跳過片頭 跳過中場 跳過中場 @@ -1557,7 +1561,7 @@ 跳過預告 跳過預告 跳過總結 - 跳過灌水片段 + 跳過閒聊 跳過非音樂部分 跳過未提交片段 跳過贊助內容 @@ -1571,7 +1575,7 @@ 跳過預告 跳過預告 跳過總結 - 跳過灌水內容/笑話 + 已跳過閒聊 跳過非音樂部份 跳過未提交的片段 跳過多個片段 @@ -1606,9 +1610,9 @@ 如果 API 無法使用,則顯示提示訊息 如果 SponsorBlock 無法使用,顯示提示訊息 如果 SponsorBlock 無法使用,不顯示提示訊息 - 啟用跳過計數跟蹤 + 啟用跳過計數追蹤 允許 SponsorBlock 排行榜了解節省了多少時間每次跳過片段時都會向排行榜發送訊息 - 未啟用跳過計數跟蹤 + 不啟用跳過計數追蹤 最短片段持續時間 小於此值(以秒為單位)的片段將不會顯示或跳過 持續時間無效。 @@ -1762,20 +1766,28 @@ "串流資料未偽裝。 影片可能無法播放。" 關閉此設定可能會導致影片播放問題。 預設客戶端 - Android 電視 - Android VR - iOS - iOS TV 偽裝副作用 - "• 音軌選單缺失。 -• 穩定音量不可用。 -• 停用強制自動音軌不可用。" - • 尚未找到。 - • 電影或付費影片可能無法播放。 + 強制 iOS AVC (H.264) + 影片編解碼器強制為 AVC (H.264)。 + 影片編解碼器是自動決定的。 + "啟用此功能可能會延長電池壽命並修復播放卡頓問題。 + +AVC 的最大解析度為 1080p,Opus 音訊編解碼器不可用,影片播放將使用比 VP9 或 AV1 更多的網路資料。" 顯示統計資料 用於取得串流資料的用戶端顯示在統計資料中。 用於獲取串流資料的用戶端隱藏在統計資料中。 + Potoken / 訪客數據 + 使用PoToken + PoToken 由 BotGuard 在受信任的瀏覽器中頒發。 + 使用訪客數據 + 由 BotGuard 在受信任的瀏覽器中發布的訪客數據。 + 關於PoToken / 訪客數據 + "某些用戶端需要 PoToken 和 訪客數據才能取得有效的串流資料回應。 + +如果您嘗試使用 iOS 作為預設用戶端,則可能需要這些值。 + +點擊查看更多資訊。" 觀看歷史記錄 變更與觀看歷史記錄相關的設定。 From 697a5193658935e0b21529a77aa9f3408717ad2f Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:58:35 +0900 Subject: [PATCH 45/65] bump 5.2.1-dev.2 --- README.md | 1 + gradle.properties | 2 +- patches.json | 28 +++++++++++++++++++++++++++- patches/api/patches.api | 15 +++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dcc4825c8..1d83e5cd5 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm | `Disable DRC audio` | Adds an option to disable DRC (Dynamic Range Compression) audio. | 6.20.51 ~ 7.25.53 | | `Disable auto captions` | Adds an option to disable captions from being automatically enabled. | 6.20.51 ~ 7.25.53 | | `Disable dislike redirection` | Adds an option to disable redirection to the next track when clicking the Dislike button. | 6.20.51 ~ 7.25.53 | +| `Disable music video in album` | Adds option to redirect music videos from albums. | 6.20.51 ~ 7.25.53 | | `Enable OPUS codec` | Adds an options to enable the OPUS audio codec if the player response includes. | 6.20.51 ~ 7.25.53 | | `Enable debug logging` | Adds an option to enable debug logging. | 6.20.51 ~ 7.25.53 | | `Enable landscape mode` | Adds an option to enable landscape mode when rotating the screen on phones. | 6.20.51 ~ 7.25.53 | diff --git a/gradle.properties b/gradle.properties index 2c56af065..2d0166f07 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,5 +4,5 @@ org.gradle.parallel = true android.useAndroidX = true kotlin.code.style = official kotlin.jvm.target.validation.mode = IGNORE -version = 5.2.1-dev.1 +version = 5.2.1-dev.2 diff --git a/patches.json b/patches.json index 297f13633..c65cf0cee 100644 --- a/patches.json +++ b/patches.json @@ -819,6 +819,28 @@ }, "options": [] }, + { + "name": "Disable music video in album", + "description": "Adds option to redirect music videos from albums.", + "use": false, + "dependencies": [ + "Settings for YouTube Music", + "BytecodePatch", + "BytecodePatch", + "ResourcePatch" + ], + "compatiblePackages": { + "com.google.android.apps.youtube.music": [ + "6.20.51", + "6.29.59", + "6.42.55", + "6.51.53", + "7.16.53", + "7.25.53" + ] + }, + "options": [] + }, { "name": "Disable resuming Shorts on startup", "description": "Adds an option to disable the Shorts player from resuming on app startup when Shorts were last being watched.", @@ -1087,6 +1109,9 @@ "Settings for YouTube", "BytecodePatch", "BytecodePatch", + "BytecodePatch", + "BytecodePatch", + "BytecodePatch", "ResourcePatch", "ResourcePatch" ], @@ -1493,7 +1518,8 @@ "BytecodePatch", "ResourcePatch", "BytecodePatch", - "BytecodePatch" + "BytecodePatch", + "ResourcePatch" ], "compatiblePackages": { "com.google.android.youtube": [ diff --git a/patches/api/patches.api b/patches/api/patches.api index ee38b4f51..19af90be9 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -90,6 +90,10 @@ public final class app/revanced/patches/music/layout/visual/VisualPreferencesIco public static final fun getVisualPreferencesIconsPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } +public final class app/revanced/patches/music/misc/album/AlbumMusicVideoPatchKt { + public static final fun getAlbumMusicVideoPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/music/misc/backgroundplayback/BackgroundPlaybackPatchKt { public static final fun getBackgroundPlaybackPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -138,6 +142,10 @@ public final class app/revanced/patches/music/player/components/PlayerComponents public static final fun getPlayerComponentsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/music/utils/dismiss/DismissQueueHookPatchKt { + public static final fun getDismissQueueHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/music/utils/extension/SharedExtensionPatchKt { public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -183,6 +191,7 @@ public final class app/revanced/patches/music/utils/playservice/VersionCheckPatc public static final fun is_6_27_or_greater ()Z public static final fun is_6_36_or_greater ()Z public static final fun is_6_42_or_greater ()Z + public static final fun is_7_03_or_greater ()Z public static final fun is_7_06_or_greater ()Z public static final fun is_7_13_or_greater ()Z public static final fun is_7_17_or_greater ()Z @@ -432,6 +441,8 @@ public final class app/revanced/patches/shared/mainactivity/BaseMainActivityReso public static final fun getMainActivityMutableClass ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass; public static final fun getOnConfigurationChangedMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; public static final fun getOnCreateMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; + public static final fun getOnStartMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; + public static final fun getOnStopMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; } public final class app/revanced/patches/shared/mapping/ResourceElement { @@ -834,6 +845,10 @@ public final class app/revanced/patches/youtube/utils/flyoutmenu/FlyoutMenuHookP public static final fun getFlyoutMenuHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/youtube/utils/fullscreen/FullscreenButtonHookPatchKt { + public static final fun getFullscreenButtonHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/youtube/utils/gms/GmsCoreSupportPatchKt { public static final fun getGmsCoreSupportPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } From 6a9ad25d30c75800573a171f6993697963b2aabe Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:09:10 +0900 Subject: [PATCH 46/65] fix(YouTube Music - Spoof streaming data): Sometimes the app crashes when connected to Wi-Fi --- .../extension/shared/patches/PatchStatus.java | 5 - .../spoof/SpoofStreamingDataPatch.java | 91 ++++++++++++++++--- .../music/misc/album/AlbumMusicVideoPatch.kt | 17 +--- .../patches/music/misc/album/Fingerprints.kt | 55 ----------- .../streamingdata/SpoofStreamingDataPatch.kt | 12 +++ .../video/playerresponse/Fingerprints.kt | 61 +++++++++++++ .../PlayerResponseMethodHookPatch.kt | 40 ++++++++ .../BaseSpoofStreamingDataPatch.kt | 9 -- 8 files changed, 196 insertions(+), 94 deletions(-) create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/video/playerresponse/Fingerprints.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/video/playerresponse/PlayerResponseMethodHookPatch.kt diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java index 468528831..20bf9d5e0 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java @@ -6,11 +6,6 @@ public class PatchStatus { return false; } - public static boolean SpoofStreamingData() { - // Replace this with true If the Spoof streaming data patch succeeds - return false; - } - public static boolean SpoofStreamingDataMusic() { // Replace this with true If the Spoof streaming data patch succeeds in YouTube Music return false; diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java index 860728123..fc888b116 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java @@ -1,6 +1,6 @@ package app.revanced.extension.shared.patches.spoof; -import static app.revanced.extension.shared.patches.PatchStatus.SpoofStreamingData; +import static app.revanced.extension.shared.patches.PatchStatus.SpoofStreamingDataMusic; import android.net.Uri; import android.text.TextUtils; @@ -21,7 +21,9 @@ import app.revanced.extension.shared.utils.Utils; @SuppressWarnings("unused") public class SpoofStreamingDataPatch { - private static final boolean SPOOF_STREAMING_DATA = SpoofStreamingData() && BaseSettings.SPOOF_STREAMING_DATA.get(); + private static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_STREAMING_DATA.get(); + private static final boolean SPOOF_STREAMING_DATA_YOUTUBE = SPOOF_STREAMING_DATA && !SpoofStreamingDataMusic(); + private static final boolean SPOOF_STREAMING_DATA_MUSIC = SPOOF_STREAMING_DATA && SpoofStreamingDataMusic(); private static final String PO_TOKEN = BaseSettings.SPOOF_STREAMING_DATA_PO_TOKEN.get(); private static final String VISITOR_DATA = @@ -59,16 +61,19 @@ public class SpoofStreamingDataPatch { */ public static Uri blockGetWatchRequest(Uri playerRequestUri) { if (SPOOF_STREAMING_DATA) { - try { - String path = playerRequestUri.getPath(); + // An exception may be thrown when the /get_watch request is blocked when connected to Wi-Fi in YouTube Music. + if (SPOOF_STREAMING_DATA_YOUTUBE || Utils.getNetworkType() == Utils.NetworkType.MOBILE) { + try { + String path = playerRequestUri.getPath(); - if (path != null && path.contains("get_watch")) { - Logger.printDebug(() -> "Blocking 'get_watch' by returning unreachable uri"); + if (path != null && path.contains("get_watch")) { + Logger.printDebug(() -> "Blocking 'get_watch' by returning unreachable uri"); - return UNREACHABLE_HOST_URI; + return UNREACHABLE_HOST_URI; + } + } catch (Exception ex) { + Logger.printException(() -> "blockGetWatchRequest failure", ex); } - } catch (Exception ex) { - Logger.printException(() -> "blockGetWatchRequest failure", ex); } } @@ -117,10 +122,72 @@ public class SpoofStreamingDataPatch { return false; } + private static volatile String auth = ""; + private static volatile Map requestHeader; + + private static final String AUTHORIZATION_HEADER = "Authorization"; + + private static final String[] REQUEST_HEADER_KEYS = { + AUTHORIZATION_HEADER, + "X-GOOG-API-FORMAT-VERSION", + "X-Goog-Visitor-Id" + }; + + /** + * If the /get_watch request is not blocked, + * fetchRequest will not be invoked at the point where the video starts. + *

+ * An additional method is used to invoke fetchRequest in YouTube Music: + * 1. Save the requestHeader in a field. + * 2. Invoke fetchRequest with the videoId used in PlaybackStartDescriptor. + *

+ * @param requestHeaders Save the request Headers used for login to a field. + * Only used in YouTube Music where login is required. + */ + private static void setRequestHeaders(Map requestHeaders) { + if (SPOOF_STREAMING_DATA_MUSIC) { + try { + // Save requestHeaders whenever an account is switched. + String authorization = requestHeaders.get(AUTHORIZATION_HEADER); + if (authorization == null || auth.equals(authorization)) { + return; + } + for (String key : REQUEST_HEADER_KEYS) { + if (requestHeaders.get(key) == null) { + return; + } + } + auth = authorization; + requestHeader = requestHeaders; + } catch (Exception ex) { + Logger.printException(() -> "setRequestHeaders failure", ex); + } + } + } + + /** + * Injection point. + */ + public static void fetchStreams(@NonNull String videoId) { + if (SPOOF_STREAMING_DATA_MUSIC) { + try { + if (requestHeader != null) { + StreamingDataRequest.fetchRequest(videoId, requestHeader, VISITOR_DATA, PO_TOKEN, droidGuardPoToken); + } else { + Logger.printDebug(() -> "Ignoring request with no header."); + } + } catch (Exception ex) { + Logger.printException(() -> "fetchStreams failure", ex); + } + } + } + /** * Injection point. */ public static void fetchStreams(String url, Map requestHeaders) { + setRequestHeaders(requestHeaders); + if (SPOOF_STREAMING_DATA) { try { Uri uri = Uri.parse(url); @@ -146,7 +213,7 @@ public class SpoofStreamingDataPatch { StreamingDataRequest.fetchRequest(id, requestHeaders, VISITOR_DATA, PO_TOKEN, droidGuardPoToken); } catch (Exception ex) { - Logger.printException(() -> "buildRequest failure", ex); + Logger.printException(() -> "fetchStreams failure", ex); } } } @@ -196,7 +263,7 @@ public class SpoofStreamingDataPatch { * Called after {@link #getStreamingData(String)}. */ public static void setApproxDurationMs(String videoId, long approxDurationMs) { - if (approxDurationMs != Long.MAX_VALUE) { + if (SPOOF_STREAMING_DATA_YOUTUBE && approxDurationMs != Long.MAX_VALUE) { approxDurationMsMap.put(videoId, approxDurationMs); Logger.printDebug(() -> "New approxDurationMs loaded, video id: " + videoId + ", video length: " + approxDurationMs); } @@ -218,7 +285,7 @@ public class SpoofStreamingDataPatch { * Called after {@link #getStreamingData(String)}. */ public static long getApproxDurationMs(String videoId) { - if (SPOOF_STREAMING_DATA && videoId != null) { + if (SPOOF_STREAMING_DATA_YOUTUBE && videoId != null) { final Long approxDurationMs = approxDurationMsMap.get(videoId); if (approxDurationMs != null) { Logger.printDebug(() -> "Replacing video length: " + approxDurationMs + " for videoId: " + videoId); diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt index 900ec0f75..51bf2d4c1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt @@ -7,14 +7,14 @@ import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKA import app.revanced.patches.music.utils.dismiss.dismissQueueHookPatch import app.revanced.patches.music.utils.extension.Constants.MISC_PATH import app.revanced.patches.music.utils.patch.PatchList.DISABLE_MUSIC_VIDEO_IN_ALBUM -import app.revanced.patches.music.utils.playservice.is_7_03_or_greater -import app.revanced.patches.music.utils.playservice.versionCheckPatch import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus import app.revanced.patches.music.utils.settings.addSwitchPreference import app.revanced.patches.music.utils.settings.settingsPatch import app.revanced.patches.music.video.information.videoIdHook import app.revanced.patches.music.video.information.videoInformationPatch +import app.revanced.patches.music.video.playerresponse.hookPlayerResponse +import app.revanced.patches.music.video.playerresponse.playerResponseMethodHookPatch import app.revanced.util.fingerprint.methodOrThrow private const val EXTENSION_CLASS_DESCRIPTOR = @@ -32,23 +32,14 @@ val albumMusicVideoPatch = bytecodePatch( settingsPatch, dismissQueueHookPatch, videoInformationPatch, - versionCheckPatch, + playerResponseMethodHookPatch, ) execute { // region hook player response - val fingerprint = if (is_7_03_or_greater) { - playerParameterBuilderFingerprint - } else { - playerParameterBuilderLegacyFingerprint - } - - fingerprint.methodOrThrow().addInstruction( - 0, - "invoke-static {p1, p4, p5}, $EXTENSION_CLASS_DESCRIPTOR->newPlayerResponse(Ljava/lang/String;Ljava/lang/String;I)V" - ) + hookPlayerResponse("$EXTENSION_CLASS_DESCRIPTOR->newPlayerResponse(Ljava/lang/String;Ljava/lang/String;I)V") // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt index e77dc2012..e91201b8c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt @@ -3,62 +3,7 @@ package app.revanced.patches.music.misc.album import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -/** - * For targets 7.03 and later. - */ -internal val playerParameterBuilderFingerprint = legacyFingerprint( - name = "playerParameterBuilderFingerprint", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "L", - parameters = listOf( - "Ljava/lang/String;", // VideoId. - "[B", - "Ljava/lang/String;", // Player parameters proto buffer. - "Ljava/lang/String;", // PlaylistId. - "I", // PlaylistIndex. - "I", - "L", - "Ljava/util/Set;", - "Ljava/lang/String;", - "Ljava/lang/String;", - "L", - "Z", - "Z", - "Z", // Appears to indicate if the video id is being opened or is currently playing. - ), - strings = listOf("psps") -) - -/** - * For targets 7.02 and earlier. - */ -internal val playerParameterBuilderLegacyFingerprint = legacyFingerprint( - name = "playerParameterBuilderLegacyFingerprint", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "L", - parameters = listOf( - "Ljava/lang/String;", // VideoId. - "[B", - "Ljava/lang/String;", // Player parameters proto buffer. - "Ljava/lang/String;", // PlaylistId. - "I", // PlaylistIndex. - "I", - "Ljava/util/Set;", - "Ljava/lang/String;", - "Ljava/lang/String;", - "L", - "Z", - "Z", // Appears to indicate if the video id is being opened or is currently playing. - ), - opcodes = listOf( - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.INVOKE_INTERFACE - ) -) internal val snackBarParentFingerprint = legacyFingerprint( name = "snackBarParentFingerprint", diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatch.kt index 7bab56e59..a30c435c2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatch.kt @@ -9,11 +9,17 @@ import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus import app.revanced.patches.music.utils.settings.addPreferenceWithIntent import app.revanced.patches.music.utils.settings.addSwitchPreference import app.revanced.patches.music.utils.settings.settingsPatch +import app.revanced.patches.music.video.playerresponse.hookPlayerResponse +import app.revanced.patches.music.video.playerresponse.playerResponseMethodHookPatch import app.revanced.patches.shared.extension.Constants.PATCHES_PATH +import app.revanced.patches.shared.extension.Constants.SPOOF_PATH import app.revanced.patches.shared.spoof.streamingdata.baseSpoofStreamingDataPatch import app.revanced.patches.shared.spoof.useragent.baseSpoofUserAgentPatch import app.revanced.util.findMethodOrThrow +const val EXTENSION_CLASS_DESCRIPTOR = + "$SPOOF_PATH/SpoofStreamingDataPatch;" + @Suppress("unused") val spoofStreamingDataPatch = baseSpoofStreamingDataPatch( { @@ -22,6 +28,7 @@ val spoofStreamingDataPatch = baseSpoofStreamingDataPatch( dependsOn( baseSpoofUserAgentPatch(YOUTUBE_MUSIC_PACKAGE_NAME), settingsPatch, + playerResponseMethodHookPatch, ) }, { @@ -32,6 +39,11 @@ val spoofStreamingDataPatch = baseSpoofStreamingDataPatch( "const/4 v0, 0x1" ) + hookPlayerResponse( + "$EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;)V", + true + ) + addSwitchPreference( CategoryType.MISC, "revanced_spoof_streaming_data", diff --git a/patches/src/main/kotlin/app/revanced/patches/music/video/playerresponse/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/video/playerresponse/Fingerprints.kt new file mode 100644 index 000000000..0564715e1 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/video/playerresponse/Fingerprints.kt @@ -0,0 +1,61 @@ +package app.revanced.patches.music.video.playerresponse + +import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.or +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +/** + * For targets 7.03 and later. + */ +internal val playerParameterBuilderFingerprint = legacyFingerprint( + name = "playerParameterBuilderFingerprint", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "L", + parameters = listOf( + "Ljava/lang/String;", // VideoId. + "[B", + "Ljava/lang/String;", // Player parameters proto buffer. + "Ljava/lang/String;", // PlaylistId. + "I", // PlaylistIndex. + "I", + "L", + "Ljava/util/Set;", + "Ljava/lang/String;", + "Ljava/lang/String;", + "L", + "Z", + "Z", + "Z", // Appears to indicate if the video id is being opened or is currently playing. + ), + strings = listOf("psps") +) + +/** + * For targets 7.02 and earlier. + */ +internal val playerParameterBuilderLegacyFingerprint = legacyFingerprint( + name = "playerParameterBuilderLegacyFingerprint", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "L", + parameters = listOf( + "Ljava/lang/String;", // VideoId. + "[B", + "Ljava/lang/String;", // Player parameters proto buffer. + "Ljava/lang/String;", // PlaylistId. + "I", // PlaylistIndex. + "I", + "Ljava/util/Set;", + "Ljava/lang/String;", + "Ljava/lang/String;", + "L", + "Z", + "Z", // Appears to indicate if the video id is being opened or is currently playing. + ), + opcodes = listOf( + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_INTERFACE + ) +) \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/music/video/playerresponse/PlayerResponseMethodHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/video/playerresponse/PlayerResponseMethodHookPatch.kt new file mode 100644 index 000000000..8570097d0 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/video/playerresponse/PlayerResponseMethodHookPatch.kt @@ -0,0 +1,40 @@ +package app.revanced.patches.music.video.playerresponse + +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.music.utils.playservice.is_7_03_or_greater +import app.revanced.patches.music.utils.playservice.versionCheckPatch +import app.revanced.util.fingerprint.methodOrThrow + +private const val REGISTER_VIDEO_ID = "p1" +private const val REGISTER_PLAYLIST_ID = "p4" +private const val REGISTER_PLAYLIST_INDEX = "p5" + +private lateinit var playerResponseMethod: MutableMethod + +val playerResponseMethodHookPatch = bytecodePatch( + description = "playerResponseMethodHookPatch" +) { + dependsOn(versionCheckPatch) + + execute { + playerResponseMethod = if (is_7_03_or_greater) { + playerParameterBuilderFingerprint + } else { + playerParameterBuilderLegacyFingerprint + }.methodOrThrow() + } +} + +fun hookPlayerResponse( + descriptor: String, + onlyVideoId: Boolean = false +) { + val smaliInstruction = if (onlyVideoId) + "invoke-static {$REGISTER_VIDEO_ID}, $descriptor" + else + "invoke-static {$REGISTER_VIDEO_ID, $REGISTER_PLAYLIST_ID, $REGISTER_PLAYLIST_INDEX}, $descriptor" + + playerResponseMethod.addInstruction(0, smaliInstruction) +} diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt index 8c023ac2c..2f34434c4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt @@ -6,13 +6,11 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatchBuilder import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patches.shared.extension.Constants.PATCHES_PATH import app.revanced.patches.shared.extension.Constants.SPOOF_PATH import app.revanced.patches.shared.formatStreamModelConstructorFingerprint import app.revanced.util.findInstructionIndicesReversedOrThrow @@ -381,13 +379,6 @@ fun baseSpoofStreamingDataPatch( // endregion - findMethodOrThrow("$PATCHES_PATH/PatchStatus;") { - name == "SpoofStreamingData" - }.replaceInstruction( - 0, - "const/4 v0, 0x1" - ) - executeBlock() } From b69a041d5d1ab3fbb9bf428ceaebc9bbd9f761d0 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:12:22 +0900 Subject: [PATCH 47/65] fix(YouTube): Patched app crashes after first launch or clearing data --- .../extension/shared/utils/ResourceUtils.java | 18 ++++++- .../extension/shared/utils/StringRef.java | 6 ++- .../extension/shared/utils/Utils.java | 22 ++++---- .../youtube/patches/general/GeneralPatch.java | 50 +++++++------------ .../utils/extension/SharedExtensionPatch.kt | 2 + .../hooks/MainActivityBaseContextHook.kt | 35 +++++++++++++ .../PlayerResponseMethodHookPatch.kt | 2 +- 7 files changed, 89 insertions(+), 46 deletions(-) create mode 100644 patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/hooks/MainActivityBaseContextHook.kt diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/ResourceUtils.java b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/ResourceUtils.java index 55b7c1ac6..e3252ef9a 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/ResourceUtils.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/ResourceUtils.java @@ -1,5 +1,6 @@ package app.revanced.extension.shared.utils; +import android.app.Activity; import android.content.Context; import android.graphics.drawable.Drawable; import android.view.animation.Animation; @@ -16,12 +17,25 @@ public class ResourceUtils extends Utils { } // utility class public static int getIdentifier(@NonNull String str, @NonNull ResourceType resourceType) { - return getIdentifier(str, resourceType, getContext()); + Activity mActivity = getActivity(); + Context mContext = mActivity != null + ? mActivity + : getContext(); + if (mContext == null) { + handleException(str, resourceType); + return 0; + } + return getIdentifier(str, resourceType, mContext); } public static int getIdentifier(@NonNull String str, @NonNull ResourceType resourceType, @NonNull Context context) { - return getResources().getIdentifier(str, resourceType.getType(), context.getPackageName()); + try { + return context.getResources().getIdentifier(str, resourceType.getType(), context.getPackageName()); + } catch (Exception ex) { + handleException(str, resourceType); + } + return 0; } public static int getAnimIdentifier(@NonNull String str) { diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/StringRef.java b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/StringRef.java index f51b49ed0..902e354e2 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/StringRef.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/StringRef.java @@ -1,6 +1,7 @@ package app.revanced.extension.shared.utils; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.res.Resources; @@ -104,7 +105,10 @@ public class StringRef extends Utils { public String toString() { if (!resolved) { try { - Context context = getContext(); + Activity mActivity = getActivity(); + Context context = mActivity != null + ? mActivity + : getContext(); if (resources == null) { resources = getResources(); } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java index 3d500e657..ed3e96428 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/utils/Utils.java @@ -54,8 +54,6 @@ public class Utils { @SuppressLint("StaticFieldLeak") public static Context context; - private static Resources resources; - protected Utils() { } // utility class @@ -282,11 +280,15 @@ public class Utils { } public static Resources getResources() { - if (resources == null) { - return getLocalizedContextAndSetResources(getContext()).getResources(); - } else { - return resources; + Activity mActivity = activityRef.get(); + if (mActivity != null) { + return mActivity.getResources(); } + Context mContext = getContext(); + if (mContext != null) { + return mContext.getResources(); + } + throw new IllegalStateException("Get resources failed"); } /** @@ -304,6 +306,9 @@ public class Utils { if (mActivity == null) { return mContext; } + if (mContext == null) { + return null; + } // Locale of MainActivity. Locale applicationLocale; @@ -321,7 +326,6 @@ public class Utils { // If they are identical, no need to override them. if (applicationLocale == contextLocale) { - resources = mActivity.getResources(); return mContext; } @@ -329,9 +333,7 @@ public class Utils { Locale.setDefault(applicationLocale); Configuration configuration = new Configuration(mContext.getResources().getConfiguration()); configuration.setLocale(applicationLocale); - Context localizedContext = mContext.createConfigurationContext(configuration); - resources = localizedContext.getResources(); - return localizedContext; + return mContext.createConfigurationContext(configuration); } public static void setActivity(Activity mainActivity) { diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java index af5337825..1223d4115 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/general/GeneralPatch.java @@ -40,7 +40,6 @@ import java.util.EnumMap; import java.util.Map; import java.util.Objects; -import app.revanced.extension.shared.utils.Logger; import app.revanced.extension.shared.utils.ResourceUtils; import app.revanced.extension.shared.utils.Utils; import app.revanced.extension.youtube.settings.Settings; @@ -109,12 +108,7 @@ public class GeneralPatch { // region [Disable splash animation] patch public static boolean disableSplashAnimation(boolean original) { - try { - return !Settings.DISABLE_SPLASH_ANIMATION.get() && original; - } catch (Exception ex) { - Logger.printException(() -> "Failed to load disableSplashAnimation", ex); - } - return original; + return !Settings.DISABLE_SPLASH_ANIMATION.get() && original; } // endregion @@ -130,12 +124,7 @@ public class GeneralPatch { // region [Hide layout components] patch public static boolean disableTranslucentStatusBar(boolean original) { - try { - return !Settings.DISABLE_TRANSLUCENT_STATUS_BAR.get() && original; - } catch (Exception ex) { - Logger.printException(() -> "Failed to load disableTranslucentStatusBar", ex); - } - return original; + return !Settings.DISABLE_TRANSLUCENT_STATUS_BAR.get() && original; } private static String[] accountMenuBlockList; @@ -240,12 +229,7 @@ public class GeneralPatch { } public static boolean switchCreateWithNotificationButton(boolean original) { - try { - return Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get() || original; - } catch (Exception ex) { - Logger.printException(() -> "switchCreateWithNotificationButton Failed", ex); - } - return original; + return Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get() || original; } public static void navigationTabCreated(NavigationButton button, View tabView) { @@ -327,6 +311,9 @@ public class GeneralPatch { // region [Toolbar components] patch + private static final int generalHeaderAttributeId = ResourceUtils.getAttrIdentifier("ytWordmarkHeader"); + private static final int premiumHeaderAttributeId = ResourceUtils.getAttrIdentifier("ytPremiumWordmarkHeader"); + public static void setDrawerNavigationHeader(View lithoView) { final int headerAttributeId = getHeaderAttributeId(); @@ -344,8 +331,8 @@ public class GeneralPatch { public static int getHeaderAttributeId() { return Settings.CHANGE_YOUTUBE_HEADER.get() - ? ResourceUtils.getAttrIdentifier("ytPremiumWordmarkHeader") - : ResourceUtils.getAttrIdentifier("ytWordmarkHeader"); + ? premiumHeaderAttributeId + : generalHeaderAttributeId; } public static boolean overridePremiumHeader() { @@ -357,6 +344,11 @@ public class GeneralPatch { return ResourceUtils.getDrawable(""); } + private static final int searchBarId = ResourceUtils.getIdIdentifier("search_bar"); + private static final int youtubeTextId = ResourceUtils.getIdIdentifier("youtube_text"); + private static final int searchBoxId = ResourceUtils.getIdIdentifier("search_box"); + private static final int searchIconId = ResourceUtils.getIdIdentifier("search_icon"); + private static final boolean wideSearchbarEnabled = Settings.ENABLE_WIDE_SEARCH_BAR.get(); // Loads the search bar deprecated by Google. private static final boolean wideSearchbarWithHeaderEnabled = Settings.ENABLE_WIDE_SEARCH_BAR_WITH_HEADER.get(); @@ -396,17 +388,12 @@ public class GeneralPatch { if (!wideSearchbarEnabled) return; - final int searchBarId = ResourceUtils.getIdIdentifier("search_bar"); if (!(view.findViewById(searchBarId) instanceof RelativeLayout searchBarView)) return; // When the deprecated search bar is loaded, two search bars overlap. // Manually hides another search bar. if (wideSearchbarWithHeaderEnabled) { - final int youtubeTextId = ResourceUtils.getIdIdentifier("youtube_text"); - final int searchBoxId = ResourceUtils.getIdIdentifier("search_box"); - final int searchIconId = ResourceUtils.getIdIdentifier("search_icon"); - final View searchIconView = searchBarView.findViewById(searchIconId); final View searchBoxView = searchBarView.findViewById(searchBoxId); final View textView = searchBarView.findViewById(youtubeTextId); @@ -521,14 +508,16 @@ public class GeneralPatch { imageView.setImageDrawable(drawable); } + private static final int settingsDrawableId = + ResourceUtils.getDrawableIdentifier("yt_outline_gear_black_24"); + private static final int settingsCairoDrawableId = + ResourceUtils.getDrawableIdentifier("yt_outline_gear_cairo_black_24"); + public static int getCreateButtonDrawableId(int original) { if (!Settings.REPLACE_TOOLBAR_CREATE_BUTTON.get()) { return original; } - final int settingsDrawableId = - ResourceUtils.getDrawableIdentifier("yt_outline_gear_black_24"); - if (settingsDrawableId == 0) { return original; } @@ -539,9 +528,6 @@ public class GeneralPatch { return settingsDrawableId; } - final int settingsCairoDrawableId = - ResourceUtils.getDrawableIdentifier("yt_outline_gear_cairo_black_24"); - return settingsCairoDrawableId == 0 ? settingsDrawableId : settingsCairoDrawableId; diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/SharedExtensionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/SharedExtensionPatch.kt index bab6ee3da..263d4fb8c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/SharedExtensionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/SharedExtensionPatch.kt @@ -2,8 +2,10 @@ package app.revanced.patches.youtube.utils.extension import app.revanced.patches.shared.extension.sharedExtensionPatch import app.revanced.patches.youtube.utils.extension.hooks.applicationInitHook +import app.revanced.patches.youtube.utils.extension.hooks.mainActivityBaseContextHook // TODO: Move this to a "Hook.kt" file. Same for other extension hook patches. val sharedExtensionPatch = sharedExtensionPatch( applicationInitHook, + mainActivityBaseContextHook, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/hooks/MainActivityBaseContextHook.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/hooks/MainActivityBaseContextHook.kt new file mode 100644 index 000000000..7543cc3d8 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/hooks/MainActivityBaseContextHook.kt @@ -0,0 +1,35 @@ +package app.revanced.patches.youtube.utils.extension.hooks + +import app.revanced.patches.shared.extension.extensionHook +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +private var attachBaseContextIndex = -1 + +internal val mainActivityBaseContextHook = extensionHook( + insertIndexResolver = { method -> + attachBaseContextIndex = method.indexOfFirstInstructionOrThrow { + getReference()?.name == "attachBaseContext" + } + + attachBaseContextIndex + 1 + }, + contextRegisterResolver = { method -> + val overrideInstruction = method.implementation!!.instructions.elementAt(attachBaseContextIndex) + as FiveRegisterInstruction + "v${overrideInstruction.registerD}" + }, +) { + returns("V") + parameters("Landroid/content/Context;") + custom { method, classDef -> + method.name == "attachBaseContext" && + ( + classDef.endsWith("/MainActivity;") || + // Old versions of YouTube called this class "WatchWhileActivity" instead. + classDef.endsWith("/WatchWhileActivity;") + ) + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt index 901ef8d7a..ae9c22223 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt @@ -70,7 +70,7 @@ val playerResponseMethodHookPatch = bytecodePatch( """ invoke-static {$registerVideoId, $registerPlayerParameter, $registerPlaylistId, $registerIsShortAndOpeningOrPlaying}, $hook move-result-object $registerPlayerParameter - """, + """, ) numberOfInstructionsAdded += 2 } From 88435902ff5daa876fccb176fa3f7c827928fc58 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:18:10 +0900 Subject: [PATCH 48/65] feat(YouTube Music - Disable music video in album): Add redirection option --- .../patches/misc/AlbumMusicVideoPatch.java | 134 +++++++++++++++--- .../extension/music/settings/Settings.java | 3 + .../ReVancedPreferenceFragment.java | 7 +- .../music/misc/album/AlbumMusicVideoPatch.kt | 48 +++++++ .../patches/music/misc/album/Fingerprints.kt | 20 +++ .../music/settings/host/values/arrays.xml | 16 +++ .../music/settings/host/values/strings.xml | 12 +- 7 files changed, 217 insertions(+), 23 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java index d7ccccbad..08fca8a31 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java @@ -1,20 +1,58 @@ package app.revanced.extension.music.patches.misc; +import android.view.View; + +import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import app.revanced.extension.music.patches.misc.requests.PipedRequester; import app.revanced.extension.music.settings.Settings; +import app.revanced.extension.music.shared.VideoInformation; import app.revanced.extension.music.utils.VideoUtils; import app.revanced.extension.shared.utils.Logger; @SuppressWarnings("unused") public class AlbumMusicVideoPatch { - private static final String YOUTUBE_MUSIC_ALBUM_PREFIX = "OLAK"; + + public enum RedirectType { + REDIRECT_DISMISS(true), + REDIRECT(false), + ON_CLICK_DISMISS(true), + ON_CLICK(false), + ON_LONG_CLICK_DISMISS(true), + ON_LONG_CLICK(false); + + public final boolean dismissQueue; + + RedirectType(boolean dismissQueue) { + this.dismissQueue = dismissQueue; + } + } + + private static final RedirectType REDIRECT_TYPE = + Settings.DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE.get(); + private static final boolean DISABLE_MUSIC_VIDEO_IN_ALBUM = Settings.DISABLE_MUSIC_VIDEO_IN_ALBUM.get(); + private static final boolean DISMISS_QUEUE = + DISABLE_MUSIC_VIDEO_IN_ALBUM && REDIRECT_TYPE.dismissQueue; + + private static final boolean REDIRECT = + REDIRECT_TYPE == RedirectType.REDIRECT || REDIRECT_TYPE == RedirectType.REDIRECT_DISMISS; + + private static final boolean ON_CLICK = + REDIRECT_TYPE == RedirectType.ON_CLICK || REDIRECT_TYPE == RedirectType.ON_CLICK_DISMISS; + + private static final boolean ON_LONG_CLICK = + REDIRECT_TYPE == RedirectType.ON_LONG_CLICK || REDIRECT_TYPE == RedirectType.ON_LONG_CLICK_DISMISS; + + private static final String YOUTUBE_MUSIC_ALBUM_PREFIX = "OLAK"; + private static final AtomicBoolean isVideoLaunched = new AtomicBoolean(false); @NonNull @@ -23,6 +61,16 @@ public class AlbumMusicVideoPatch { @NonNull private static volatile String currentVideoId = ""; + @GuardedBy("itself") + private static final Map lastVideoIds = new LinkedHashMap<>() { + private static final int NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK = 5; + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK; + } + }; + /** * Injection point. */ @@ -41,7 +89,7 @@ public class AlbumMusicVideoPatch { } playerResponseVideoId = videoId; - // Fetch from piped instances. + // Fetch Piped instance. PipedRequester.fetchRequestIfNeeded(videoId, playlistId, playlistIndex); } @@ -56,13 +104,10 @@ public class AlbumMusicVideoPatch { return; } currentVideoId = videoId; - - // If the user is using a not fast enough internet connection, there will be a slight delay. - // Otherwise, the video may open repeatedly. - VideoUtils.runOnMainThreadDelayed(() -> openOfficialMusicIfNeeded(videoId), 750); + checkVideo(videoId); } - private static void openOfficialMusicIfNeeded(@NonNull String videoId) { + private static void checkVideo(@NonNull String videoId) { try { PipedRequester request = PipedRequester.getRequestForVideoId(videoId); if (request == null) { @@ -72,13 +117,46 @@ public class AlbumMusicVideoPatch { if (songId == null) { return; } + synchronized (lastVideoIds) { + if (lastVideoIds.put(videoId, songId) == null) { + Logger.printDebug(() -> "Official song found, videoId: " + videoId + ", songId: " + songId); + if (REDIRECT) { + openMusic(songId); + } + } + } + } catch (Exception ex) { + Logger.printException(() -> "check failure", ex); + } + } - // It is handled by YouTube Music's internal code. - // There is a slight delay before the dismiss request is reflected. - VideoUtils.dismissQueue(); + /** + * Injection point. + */ + public static boolean openMusic() { + if (DISABLE_MUSIC_VIDEO_IN_ALBUM && ON_CLICK) { + try { + String videoId = VideoInformation.getVideoId(); + synchronized (lastVideoIds) { + String songId = lastVideoIds.get(videoId); + if (songId != null) { + openMusic(songId); + return true; + } + } + } catch (Exception ex) { + Logger.printException(() -> "openMusic failure", ex); + } + } + return false; + } + + private static void openMusic(@NonNull String songId) { + try { + if (DISMISS_QUEUE) { + VideoUtils.dismissQueue(); + } - // Every time a new video is opened, a snack bar appears indicating that the account has been switched. - // To prevent this, hide the snack bar while a new video is opening. isVideoLaunched.compareAndSet(false, true); // The newly opened video is not a music video. @@ -87,12 +165,33 @@ public class AlbumMusicVideoPatch { playerResponseVideoId = songId; currentVideoId = songId; VideoUtils.openInYouTubeMusic(songId); - }, 750); + }, 500); - // If a new video is opened, the snack bar will be shown. VideoUtils.runOnMainThreadDelayed(() -> isVideoLaunched.compareAndSet(true, false), 1500); } catch (Exception ex) { - Logger.printException(() -> "openOfficialMusicIfNeeded failure", ex); + Logger.printException(() -> "openMusic failure", ex); + } + } + + /** + * Injection point. + */ + public static void setAudioVideoSwitchToggleOnLongClickListener(View view) { + if (DISABLE_MUSIC_VIDEO_IN_ALBUM && ON_LONG_CLICK) { + view.setOnLongClickListener(v -> { + try { + String videoId = VideoInformation.getVideoId(); + synchronized (lastVideoIds) { + String songId = lastVideoIds.get(videoId); + if (songId != null) { + openMusic(songId); + } + } + } catch (Exception ex) { + Logger.printException(() -> "onLongClickListener failure", ex); + } + return true; + }); } } @@ -100,10 +199,7 @@ public class AlbumMusicVideoPatch { * Injection point. */ public static boolean hideSnackBar() { - if (!DISABLE_MUSIC_VIDEO_IN_ALBUM) { - return false; - } - return isVideoLaunched.get(); + return DISABLE_MUSIC_VIDEO_IN_ALBUM && isVideoLaunched.get(); } } diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java index 4ff5dc57e..f2638e371 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java @@ -6,6 +6,7 @@ import static app.revanced.extension.music.sponsorblock.objects.CategoryBehaviou import androidx.annotation.NonNull; +import app.revanced.extension.music.patches.misc.AlbumMusicVideoPatch.RedirectType; import app.revanced.extension.music.patches.misc.client.AppClient.ClientType; import app.revanced.extension.music.patches.utils.PatchStatus; import app.revanced.extension.music.sponsorblock.SponsorBlockSettings; @@ -179,6 +180,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting DISABLE_CAIRO_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_cairo_splash_animation", FALSE, true); public static final BooleanSetting DISABLE_DRC_AUDIO = new BooleanSetting("revanced_disable_drc_audio", FALSE, true); public static final BooleanSetting DISABLE_MUSIC_VIDEO_IN_ALBUM = new BooleanSetting("revanced_disable_music_video_in_album", FALSE, true); + public static final EnumSetting DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE = new EnumSetting<>("revanced_disable_music_video_in_album_redirect_type", RedirectType.REDIRECT_DISMISS, true); public static final BooleanSetting ENABLE_OPUS_CODEC = new BooleanSetting("revanced_enable_opus_codec", FALSE, true); public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false); public static final BooleanSetting SPOOF_CLIENT = new BooleanSetting("revanced_spoof_client", FALSE, true); @@ -248,6 +250,7 @@ public class Settings extends BaseSettings { CHANGE_START_PAGE.key, CUSTOM_FILTER_STRINGS.key, CUSTOM_PLAYBACK_SPEEDS.key, + DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE.key, EXTERNAL_DOWNLOADER_PACKAGE_NAME.key, HIDE_ACCOUNT_MENU_FILTER_STRINGS.key, SB_API_URL.key, diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ReVancedPreferenceFragment.java b/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ReVancedPreferenceFragment.java index 313588ef9..1245e8dce 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ReVancedPreferenceFragment.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ReVancedPreferenceFragment.java @@ -4,6 +4,7 @@ import static app.revanced.extension.music.settings.Settings.BYPASS_IMAGE_REGION import static app.revanced.extension.music.settings.Settings.CHANGE_START_PAGE; import static app.revanced.extension.music.settings.Settings.CUSTOM_FILTER_STRINGS; import static app.revanced.extension.music.settings.Settings.CUSTOM_PLAYBACK_SPEEDS; +import static app.revanced.extension.music.settings.Settings.DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE; import static app.revanced.extension.music.settings.Settings.EXTERNAL_DOWNLOADER_PACKAGE_NAME; import static app.revanced.extension.music.settings.Settings.HIDE_ACCOUNT_MENU_FILTER_STRINGS; import static app.revanced.extension.music.settings.Settings.OPEN_DEFAULT_APP_SETTINGS; @@ -160,9 +161,11 @@ public class ReVancedPreferenceFragment extends PreferenceFragment { Logger.printDebug(() -> "Failed to find the right value: " + dataString); } } else if (settings instanceof EnumSetting enumSetting) { - if (settings.equals(RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT) + if (settings.equals(DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE) + || settings.equals(RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT) || settings.equals(SPOOF_CLIENT_TYPE) - || settings.equals(SPOOF_STREAMING_DATA_TYPE)) { + || settings.equals(SPOOF_STREAMING_DATA_TYPE) + ) { ResettableListPreference.showDialog(mActivity, enumSetting, 0); } } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt index 51bf2d4c1..1479cc65f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt @@ -2,6 +2,7 @@ package app.revanced.patches.music.misc.album import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.music.utils.dismiss.dismissQueueHookPatch @@ -9,13 +10,21 @@ import app.revanced.patches.music.utils.extension.Constants.MISC_PATH import app.revanced.patches.music.utils.patch.PatchList.DISABLE_MUSIC_VIDEO_IN_ALBUM import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus +import app.revanced.patches.music.utils.settings.addPreferenceWithIntent import app.revanced.patches.music.utils.settings.addSwitchPreference import app.revanced.patches.music.utils.settings.settingsPatch import app.revanced.patches.music.video.information.videoIdHook import app.revanced.patches.music.video.information.videoInformationPatch import app.revanced.patches.music.video.playerresponse.hookPlayerResponse import app.revanced.patches.music.video.playerresponse.playerResponseMethodHookPatch +import app.revanced.util.findMethodOrThrow import app.revanced.util.fingerprint.methodOrThrow +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionReversedOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference private const val EXTENSION_CLASS_DESCRIPTOR = "$MISC_PATH/AlbumMusicVideoPatch;" @@ -64,11 +73,50 @@ val albumMusicVideoPatch = bytecodePatch( // endregion + // region patch for setOnClick / setOnLongClick listener + + audioVideoSwitchToggleConstructorFingerprint.methodOrThrow().apply { + val onClickListenerIndex = indexOfAudioVideoSwitchSetOnClickListenerInstruction(this) + val viewRegister = getInstruction(onClickListenerIndex).registerC + + addInstruction( + onClickListenerIndex + 1, + "invoke-static { v$viewRegister }, " + + "$EXTENSION_CLASS_DESCRIPTOR->setAudioVideoSwitchToggleOnLongClickListener(Landroid/view/View;)V" + ) + + val onClickListenerSyntheticIndex = indexOfFirstInstructionReversedOrThrow(onClickListenerIndex) { + opcode == Opcode.INVOKE_DIRECT && + getReference()?.name == "" + } + val onClickListenerSyntheticClass = (getInstruction(onClickListenerSyntheticIndex).reference as MethodReference).definingClass + + findMethodOrThrow(onClickListenerSyntheticClass) { + name == "onClick" + }.addInstructionsWithLabels( + 0, """ + invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->openMusic()Z + move-result v0 + if-eqz v0, :ignore + return-void + :ignore + nop + """ + ) + } + + // endregion + addSwitchPreference( CategoryType.MISC, "revanced_disable_music_video_in_album", "false" ) + addPreferenceWithIntent( + CategoryType.MISC, + "revanced_disable_music_video_in_album_redirect_type", + "revanced_disable_music_video_in_album" + ) updatePatchStatus(DISABLE_MUSIC_VIDEO_IN_ALBUM) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt index e91201b8c..52f0bf163 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/Fingerprints.kt @@ -1,9 +1,29 @@ package app.revanced.patches.music.misc.album import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.reference.MethodReference +internal val audioVideoSwitchToggleConstructorFingerprint = legacyFingerprint( + name = "audioVideoSwitchToggleConstructorFingerprint", + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + returnType = "V", + opcodes = listOf(Opcode.INVOKE_DIRECT), + customFingerprint = { method, _ -> + indexOfAudioVideoSwitchSetOnClickListenerInstruction(method) >= 0 + } +) + +internal fun indexOfAudioVideoSwitchSetOnClickListenerInstruction(method: Method) = + method.indexOfFirstInstruction { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.toString() == "Lcom/google/android/apps/youtube/music/player/AudioVideoSwitcherToggleView;->setOnClickListener(Landroid/view/View${'$'}OnClickListener;)V" + } internal val snackBarParentFingerprint = legacyFingerprint( name = "snackBarParentFingerprint", diff --git a/patches/src/main/resources/music/settings/host/values/arrays.xml b/patches/src/main/resources/music/settings/host/values/arrays.xml index e61708942..97897dac9 100644 --- a/patches/src/main/resources/music/settings/host/values/arrays.xml +++ b/patches/src/main/resources/music/settings/host/values/arrays.xml @@ -14,6 +14,22 @@ FEmusic_library_landing FEmusic_library_corpus_artists + + @string/revanced_disable_music_video_in_album_redirect_type_entry_redirect_dismiss + @string/revanced_disable_music_video_in_album_redirect_type_entry_redirect + @string/revanced_disable_music_video_in_album_redirect_type_entry_on_click_dismiss + @string/revanced_disable_music_video_in_album_redirect_type_entry_on_click + @string/revanced_disable_music_video_in_album_redirect_type_entry_on_long_click_dismiss + @string/revanced_disable_music_video_in_album_redirect_type_entry_on_long_click + + + REDIRECT_DISMISS + REDIRECT + ON_CLICK_DISMISS + ON_CLICK + ON_LONG_CLICK_DISMISS + ON_LONG_CLICK + @string/revanced_extended_settings_export_as_file @string/revanced_extended_settings_import_as_file diff --git a/patches/src/main/resources/music/settings/host/values/strings.xml b/patches/src/main/resources/music/settings/host/values/strings.xml index ef3c97f92..e93faecae 100644 --- a/patches/src/main/resources/music/settings/host/values/strings.xml +++ b/patches/src/main/resources/music/settings/host/values/strings.xml @@ -423,9 +423,17 @@ Click to see how to issue a API key." Disable music video in album "When a non-premium user plays a song included in an album, the music video is sometimes played instead of the official song. -If such a music video is detected playing, it is redirected to the official song. +Find the official song if a music video is detected playing from an album. -A piped instance is used, but the API may not be available in some regions." +• Powered by Piped Instance API." + Redirection type + Specifies how to redirect to official song. + Redirect (Dismiss queue) + Redirect + Tap Audio / Video toggle (Dismiss queue) + Tap Audio / Video toggle + Tap and hold Audio / Video toggle (Dismiss queue) + Tap and hold Audio / Video toggle Enable debug logging Prints the debug log. Enable debug buffer logging From 244774c94cbdf28bcaa01c3c6a2d8b2e3e72878b Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:23:39 +0900 Subject: [PATCH 49/65] feat(Translations): Update translation --- .../music/translations/es-rES/strings.xml | 8 +++- .../music/translations/ko-rKR/strings.xml | 18 ++++++--- .../music/translations/uk-rUA/strings.xml | 6 +++ .../youtube/translations/ar/strings.xml | 28 +++++++++++++ .../youtube/translations/bg-rBG/strings.xml | 7 ++++ .../youtube/translations/el-rGR/strings.xml | 28 +++++++++++++ .../youtube/translations/es-rES/strings.xml | 28 +++++++++++++ .../youtube/translations/it-rIT/strings.xml | 23 ++++++++++- .../youtube/translations/ko-rKR/strings.xml | 39 +++++++++++++++++-- .../youtube/translations/pl-rPL/strings.xml | 28 +++++++++++++ .../youtube/translations/uk-rUA/strings.xml | 28 +++++++++++++ .../youtube/translations/vi-rVN/strings.xml | 28 +++++++++++++ .../youtube/translations/zh-rTW/strings.xml | 28 +++++++++++++ 13 files changed, 286 insertions(+), 11 deletions(-) diff --git a/patches/src/main/resources/music/translations/es-rES/strings.xml b/patches/src/main/resources/music/translations/es-rES/strings.xml index 05b9016e6..1d014b9ec 100644 --- a/patches/src/main/resources/music/translations/es-rES/strings.xml +++ b/patches/src/main/resources/music/translations/es-rES/strings.xml @@ -68,7 +68,7 @@ Descarga %2$s desde el sitio web." "Activa el diálogo compacto en el teléfono. Problemas conocidos: -- La carátula del álbum en la estantería de la biblioteca también se hace más pequeña. +- Las carátulas de los álbumes en la página de biblioteca se hacen pequeñas cuando se organizan por cuadrícula. - El diseño del temporizador puede parecer inusual." Añadir interruptor para recortar silencios "Añade un interruptor para recortar silencios en el menú desplegable de velocidad de reproducción. @@ -372,6 +372,12 @@ Toca para ver cómo crear una clave de API." Deshabilita la animación de bienvenida \"Cairo\" cuando se inicia la aplicación. Desactivar audio DRC Deshabilita DRC (Dynamic Range Compression) aplicado al audio. + Desactivar vídeo de música en el álbum + "Cuando un usuario no premium escoge una canción incluida en un álbum, un vídeo musical a veces se muestra en lugar de la canción original. + +Si este video se detecta durante la reproducción, será redireccionado a la canción original. + +Se usa una instancia redireccionada, pero la API puede no estar disponible en algunas regiones." Activar registro de depuración Imprime el registro de depuración. Incluir búfer en registro de depuración diff --git a/patches/src/main/resources/music/translations/ko-rKR/strings.xml b/patches/src/main/resources/music/translations/ko-rKR/strings.xml index 56ba31420..11178e9ff 100644 --- a/patches/src/main/resources/music/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/music/translations/ko-rKR/strings.xml @@ -220,8 +220,8 @@ 동영상 플레이어의 색상을 회색조로 설정해 눈의 피로를 줄입니다. 팟캐스트에서 집중 모드 활성화 팟캐스트에서 집중 모드를 활성화합니다. - \'노래↔동영상\' 전환 토글 제거 - 플레이어에서 \'노래↔동영상\' 전환 토글을 숨깁니다. + \'노래↔동영상\' 토글 제거 + 플레이어에서 \'노래↔동영상\' 토글을 숨깁니다. 커뮤니티 가이드라인 제거 댓글 섹션 상단에서 커뮤니티 가이드라인을 숨깁니다. 타임스탬프, 이모지 버튼 제거 @@ -377,11 +377,19 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요." DRC 오디오 비활성화 오디오에 적용된 DRC (Dynamic Range Compression)를 비활성화합니다. 앨범에서 뮤직 비디오 비활성화 - "프리미엄이 아닌 사용자가 앨범에 포함된 노래를 재생할 때, 공식 음원이 아닌 뮤직 비디오가 재생되는 경우가 있습니다. + "프리미엄이 아닌 사용자가 앨범에 포함된 노래를 재생할 때, 간혹 공식 음악 대신 뮤직 비디오가 재생되는 경우가 있습니다. -이러한 뮤직 비디오가 재생되는 것이 감지되면 공식 음원으로 리디렉션됩니다. +앨범에서 뮤직 비디오가 재생되는 것이 감지되면 공식 음원을 찾아줍니다. -파이핑된 인스턴스가 사용되지만 일부 지역에서는 API를 사용하지 못할 수 있습니다." +• 파이핑된 인스턴스 API로 구동됩니다." + 리다이렉션 유형 + 공식 음원으로 리다이렉션하는 방법을 지정할 수 있습니다. + 리다이렉션 (대기목록 해제) + 리다이렉션 + \'노래↔동영상\' 토글 누르기 (대기목록 해제) + \'노래↔동영상\' 토글 누르기 + \'노래↔동영상\' 토글 길게 누르기 (대기목록 해제) + \'노래↔동영상\' 토글 길게 누르기 디버그 로깅 활성화 디버그 로그를 출력합니다. 디버그 버퍼 로깅 활성화 diff --git a/patches/src/main/resources/music/translations/uk-rUA/strings.xml b/patches/src/main/resources/music/translations/uk-rUA/strings.xml index bde8c6814..97bace25a 100644 --- a/patches/src/main/resources/music/translations/uk-rUA/strings.xml +++ b/patches/src/main/resources/music/translations/uk-rUA/strings.xml @@ -375,6 +375,12 @@ Вимикає сплеш анімацію Каїр під час запуску застосунку. Вимкнути DRC аудіо Вимикає DRC (стиснення динамічного діапазону), застосованого до аудіо. + Вимкнути музичні відео в альбомі + "Коли користувач без преміуму відтворює пісню з альбому, іноді замість офіційної пісні відтворюється музичне відео. + +Якщо буде виявлено відтворення музичного відео, буде перенаправлено на офіційну пісню. + +Використовується \"piped instance\", але API може бути недоступним у деяких регіонах." Увімкнути протоколи налагодження Виводить протокол налагодження. Увімкнути ведення журналу буфера налагодження diff --git a/patches/src/main/resources/youtube/translations/ar/strings.xml b/patches/src/main/resources/youtube/translations/ar/strings.xml index 15b1877b6..3c502fb8f 100644 --- a/patches/src/main/resources/youtube/translations/ar/strings.xml +++ b/patches/src/main/resources/youtube/translations/ar/strings.xml @@ -861,6 +861,16 @@ تعطيل لوحة المشاركة تم تعطيل لوحة المشاركة. تم تمكين لوحة المشاركة. + الدخول إلى وضع ملء الشاشة عند بدء تشغيل الفيديو + الدخول إلى وضع ملء الشاشة عند بدء تشغيل الفيديو. + +القيود: لا يعمل إذا تم تصغير المشغل أو في وضع صورة داخل صورة أو في الخلفية. + لا تدخل وضع ملء الشاشة عند بدء تشغيل الفيديو. + الخروج من وضع ملء الشاشة في نهاية الفيديو + معطَّل + بالطول + بالعرض + بالطول و العرض عرض قسم عنوان الفيديو "يعرض قسم عنوان الفيديو في وضع ملء الشاشة. @@ -1433,7 +1443,11 @@ يتم عرض قائمة جودة الفيديو القديمة. لا يتم عرض قائمة جودة الفيديو القديمة. تعطيل سرعة التشغيل للموسيقى + تم تعطيل سرعة التشغيل الافتراضية للموسيقى. تم تمكين سرعة التشغيل الافتراضية للموسيقى. + التحقق باستخدام الفئات + سيتم تعطيل سرعة التشغيل الافتراضية إذا كانت فئة الفيديو هي موسيقى. + تم تعطيل سرعة التشغيل الافتراضية لمقاطع الفيديو القابلة للتشغيل على YouTube Music. تمكين سرعة التشغيل الافتراضية لفيديوهات Shorts تنطبق سرعة التشغيل الافتراضية على Shorts. لا تنطبق سرعة التشغيل الافتراضية على Shorts. @@ -1778,7 +1792,21 @@ "لا يتم تزييف بيانات البث. قد لا يعمل تشغيل الفيديو." إيقاف تشغيل هذا الإعداد قد يسبب مشاكل في تشغيل الفيديو. العميل الافتراضي + "Android TV +(يتطلب تسجيل الدخول)" + Android VR + "iOS +(يتطلب PoToken)" + "iOS TV +(يتطلب تسجيل الدخول)" التأثيرات الجانبية للتزييف + "• قائمة المقطع الصوتي مفقودة. +• مستوى الصوت الثابت غير متاح. +• لا يتوفر تعطيل المقطع الصوتي التلقائي المفروض. +• قد لا يتم تشغيل الفيديوهات المخصصة للأطفال عند تسجيل الخروج أو في وضع التصفح المتخفي." + • قد تكون هناك مشكلات في التشغيل (يتطلب PoToken). + "• قد لا يتم تشغيل الأفلام أو الفيديوهات المدفوعة. +• قد لا يتم تشغيل الفيديوهات المخصصة للأطفال عند تسجيل الخروج أو في وضع التصفح المتخفي." فرض iOS AVC (H.264) يتم فرض ترميز الفيديو على AVC (H.264). يتم تحديد ترميز الفيديو تلقائيًا. diff --git a/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml b/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml index 2f433d03b..e25171826 100644 --- a/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml +++ b/patches/src/main/resources/youtube/translations/bg-rBG/strings.xml @@ -290,6 +290,7 @@ На Живо Филми Музика + Известия Търсене Shorts Спорт @@ -829,6 +830,9 @@ Панел за взаимодействие Панелът за взаимодействие е деактивиран. Панелът за взаимодействие е активиран. + Изключено + Портрет + Пейзаж Показване на раздел със заглавие на видеоклипа "Показва раздела със заглавието на видеоклипа на цял екран. @@ -1235,6 +1239,9 @@ Сърце (цветно) Скрит + Персонализирани действия + Копиране адреса на видеото + Външна програма за изтегляне Активиране на дата и час "Времевите показатели са активирани. diff --git a/patches/src/main/resources/youtube/translations/el-rGR/strings.xml b/patches/src/main/resources/youtube/translations/el-rGR/strings.xml index ddcb8234f..cfcf3695e 100644 --- a/patches/src/main/resources/youtube/translations/el-rGR/strings.xml +++ b/patches/src/main/resources/youtube/translations/el-rGR/strings.xml @@ -859,6 +859,16 @@ Playlists Απενεργοποίηση πίνακα αλληλεπίδρασης Ο πίνακας αλληλεπίδρασης είναι απενεργοποιημένος. Ο πίνακας αλληλεπίδρασης είναι ενεργοποιημένος. + Άνοιγμα των βίντεο σε λειτουργία πλήρους οθόνης + Γίνεται εισαγωγή σε πλήρη οθόνη κατά την έναρξη των βίντεο. + +Περιορισμός: Δεν ισχύει αν το βίντεο είναι ελαχιστοποιημένο, σε λειτουργία PiP, ή στο παρασκήνιο. + Δεν γίνεται εισαγωγή σε πλήρη οθόνη κατά την έναρξη των βίντεο. + Έξοδος από τη λειτουργία πλήρους οθόνης στο τέλος του βίντεο + Απενεργοποιημένο + Κατακόρυφη + Οριζόντια + Κατακόρυφη και οριζόντια Εμφάνιση τίτλου βίντεο "Εμφάνιση τίτλου του βίντεο σε πλήρη οθόνη. @@ -1447,7 +1457,11 @@ Playlists Εμφανίζεται το μενού αλλαγής ποιότητας βίντεο παλιού στυλ. Εμφανίζεται το μενού αλλαγής ποιότητας βίντεο νέου στυλ. Απενεργοποίηση αλλαγής ταχύτητας σε βίντεο μουσικής + Η προεπιλεγμένη ταχύτητα δεν εφαρμόζεται σε βίντεο μουσικής. Η προεπιλεγμένη ταχύτητα εφαρμόζεται σε βίντεο μουσικής. + Επικύρωση με βάση τις κατηγορίες + Η προεπιλεγμένη ταχύτητα αναπαραγωγής είναι απενεργοποιημένη αν η κατηγορία βίντεο είναι μουσική. + Η προεπιλεγμένη ταχύτητα αναπαραγωγής είναι απενεργοποιημένη για βίντεο που μπορούν να αναπαραχθούν στο YouTube Music. Αλλαγή προεπιλεγμένης ταχύτητας Shorts Η προεπιλεγμένη ταχύτητα αναπαραγωγής εφαρμόζεται στα Shorts. Η προεπιλεγμένη ταχύτητα αναπαραγωγής δεν εφαρμόζεται στα Shorts. @@ -1794,7 +1808,21 @@ Playlists "Τα δεδομένα ροής δεν παραποιούνται. Η αναπαραγωγή βίντεο ενδέχεται να μη λειτουργεί σωστά." Η απενεργοποίηση αυτής της ρύθμισης ενδέχεται να προκαλέσει προβλήματα αναπαραγωγής βίντεο. Προεπιλογή + "Android TV +(Απαιτείται σύνδεση)" + Android VR + "iOS +(Απαιτείται αναγνωριστικό PoToken)" + "iOS TV +(Απαιτείται σύνδεση)" Παρενέργειες παραποίησης + "• Το μενού «Κομμάτι ήχου» λείπει. +• Η λειτουργία «Σταθερή ένταση» δεν είναι διαθέσιμη. +• Η λειτουργία «Απενεργοποίηση υποχρεωτικών κομματιών ήχου» δεν είναι διαθέσιμη. +• Τα βίντεο για παιδιά ενδέχεται να μην αναπαράγονται αν είστε αποσυνδεμένοι ή σε λειτουργία ανώνυμης περιήγησης." + • Ενδέχεται να υπάρχουν προβλήματα αναπαραγωγής (Απαιτείται αναγνωριστικό PoToken). + "• Οι ταινίες ή τα επί πληρωμή βίντεο ενδέχεται να μην αναπαράγονται. +• Τα βίντεο για παιδιά ενδέχεται να μην αναπαράγονται αν είστε αποσυνδεμένοι ή σε λειτουργία ανώνυμης περιήγησης." Εξαναγκασμός iOS AVC (H.264) Ο κωδικοποιητής βίντεο έχει οριστεί υποχρεωτικά σε AVC (H.264). Ο κωδικοποιητής βίντεο ορίζεται αυτόματα. diff --git a/patches/src/main/resources/youtube/translations/es-rES/strings.xml b/patches/src/main/resources/youtube/translations/es-rES/strings.xml index 0f0df40de..ed5850775 100644 --- a/patches/src/main/resources/youtube/translations/es-rES/strings.xml +++ b/patches/src/main/resources/youtube/translations/es-rES/strings.xml @@ -860,6 +860,16 @@ La reproducción automática se puede cambiar en la configuración de YouTube: Desactivar panel de interacción El panel de interacción está desactivado. El panel de interacción está activado. + Entrar en modo de pantalla completa cuando se inicia el vídeo + Entra en modo de pantalla completa cuando se inicia el vídeo. + +Limitación: No funciona si el reproductor está minimizado, en modo PiP o en segundo plano. + No entra en modo de pantalla completa cuando se inicia el vídeo. + Salir del modo de pantalla completa al final del vídeo + Desactivado + Vertical + Horizontal + Vertical y horizontal Mostrar sección de título de vídeo "Muestra la sección de título de vídeo en pantalla completa. @@ -1420,7 +1430,11 @@ No hay márgenes en la parte superior e inferior del reproductor." El antiguo menú de calidad de vídeo está visible. El antiguo menú de calidad de vídeo está oculto. Desactivar velocidad de reproducción para música + La velocidad predeterminada de reproducción está desactivada para la música. La velocidad predeterminada de reproducción está activada para la música. + Validar mediante categorías + La velocidad predeterminada de reproducción se desactiva si la categoría de vídeo es Música. + La velocidad predeterminada de reproducción está desactivada para los vídeos reproducibles en YouTube Music. Activar velocidad predeterminada de reproducción de Shorts La velocidad predeterminada de reproducción se aplica a los Shorts. La velocidad predeterminada de reproducción no se aplica a los Shorts. @@ -1763,7 +1777,21 @@ Pulsa el botón de continuar y desactiva las optimizaciones de la batería.""Los datos de transmisión no están falsificados. Es posible que la reproducción de vídeo no funcione." Desactivar este ajuste puede causar problemas de reproducción de vídeo. Cliente predeterminado + "Android TV +(Inicio de sesión requerido)" + Android VR + "iOS +(PoToken requerido)" + "iOS TV +(Inicio de sesión requerido)" Efectos secundarios de falsificación + "• Falta el menú de la pista de audio. +• El volumen estable no está disponible. +• Desactivar pistas de audio automáticas forzadas no está disponible. +• Es posible que los vídeos infantiles no se reproduzcan al cerrar la sesión o en modo incógnito." + • Puede haber problemas de reproducción (PoToken requerido). + "• Es posible que las películas o los vídeos de pago no se reproduzcan. +• Es posible que los vídeos infantiles no se reproduzcan al cerrar la sesión o en modo incógnito." Forzar iOS AVC (H.264) El códec de vídeo es AVC (H.264). El códec de vídeo se determina automáticamente. diff --git a/patches/src/main/resources/youtube/translations/it-rIT/strings.xml b/patches/src/main/resources/youtube/translations/it-rIT/strings.xml index cd9930937..448e09e95 100644 --- a/patches/src/main/resources/youtube/translations/it-rIT/strings.xml +++ b/patches/src/main/resources/youtube/translations/it-rIT/strings.xml @@ -863,6 +863,16 @@ Impostazioni → Riproduzione automatica → Telefono cellulare/tablet" Disattiva il pannello di coinvolgimento Il pannello di coinvolgimento è disattivato. Il pannello di coinvolgimento è attivato. + Passa a schermo intero all\'avvio dei video + Passa a schermo intero all\'avvio dei video. + +Nota: non funziona se il riproduttore è minimizzato, in modalità PiP o in background. + Non passa a schermo intero all\'avvio dei video. + Esci da schermo intero alla fine dei video + Disattivato + Verticale + Orizzontale + Verticale e orizzontale Mostra il titolo dei video "Mostra il titolo dei video a schermo intero. @@ -1425,7 +1435,11 @@ Note: Il vecchio menù Qualità è attivato. Il vecchio menù Qualità è disattivato. Disattiva la velocità di riproduzione predefinita per la musica + La velocità di riproduzione predefinita per la musica è disattivata. La velocità di riproduzione predefinita per la musica è attivata. + Convalida usando le categorie + La velocità di riproduzione predefinita è disattivata se la categoria video è Musica. + La velocità di riproduzione predefinita è attivata se la categoria video è Musica. Attiva la velocità di riproduzione predefinita negli Shorts La velocità di riproduzione predefinita negli Shorts è attivata. La velocità di riproduzione predefinita negli Shorts è disattivata. @@ -1769,8 +1783,15 @@ Tocca il pulsante Continua e consenti le modifiche di ottimizzazione." "I dati in streaming non sono camuffati. La riproduzione potrebbe non funzionare." La disattivazione di questa impostazione potrebbe causare problemi di riproduzione. Client predefinito + "Android TV +(Accesso richiesto)" + Android VR + "iOS +(PoToken richiesto)" + "iOS TV +(Accesso richiesto)" Effetti collaterali del camuffamento - "• Manca il menù Traccia Audio. + "• Il menù Traccia Audio è nascosto. • Il volume stabile non funziona. • La disattivazione delle tracce audio automatiche forzate non funziona. • I video per bambini potrebbero non essere riprodotti se si è disconnessi o in incognito." diff --git a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml index 7e708e991..525f7005e 100644 --- a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml @@ -1,7 +1,7 @@ - 플레이어에 접근성 컨트롤을 표시하시겠습니까? + 플레이어에서 접근성 컨트롤을 표시하시겠습니까? 접근성 서비스가 켜져있기 때문에 플레이어 컨트롤을 변경합니다. ReVanced Extended 설정 @@ -859,6 +859,17 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 참여 패널 비활성화하기 참여 패널을 비활성화합니다. 참여 패널을 활성화합니다. + 동영상이 시작할 때, 전체 화면 모드로 들어가기 + 동영상이 시작할 때, 전체 화면 모드로 들어갑니다. + +알려진 문제점: +플레이어가 최소화되어 있거나 PiP 모드 또는 백그라운드 재생에 있는 경우에는 작동되지 않습니다. + 동영상이 시작할 때, 전체 화면 모드로 들어가지 않습니다. + 동영상이 종료할 때, 전체 화면 모드에서 나가기 + 사용 안함 + 세로 모드 + 가로 모드 + 세로 및 가로 모드 동영상 제목 섹션 표시하기 "전체 화면에서 동영상 제목 섹션을 표시합니다. @@ -1387,12 +1398,12 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 스와이프 제스처로 동영상 전환 비활성화하기 전체 화면 모드에서 위로/아래로 스와이프하여 다음/이전 동영상으로 전환하지 않습니다. 전체 화면 모드에서 위로/아래로 스와이프하여 다음/이전 동영상으로 전환합니다. - 스와이프 제스처로 전체 화면 모드로 전환 비활성화하기 (플레이어 하단) + 스와이프 제스처로 전체 화면 모드 전환 비활성화하기 (플레이어 하단) 플레이어 하단에서 아래로 스와이프하여 전체 화면 모드로 들어가지 않습니다. 플레이어 하단에서 아래로 스와이프하여 전체 화면 모드로 들어갑니다. 스와이프 제스처로 전체 화면 모드 전환 비활성화하기 (플레이어 내부) - 플레이어에서 아래로 스와이프하여 전체 화면 모드로 들어가지 않습니다. - 플레이어에서 아래로 스와이프하여 전체 화면 모드로 들어갑니다. + 플레이어 내부에서 아래로 스와이프하여 전체 화면 모드로 들어가지 않습니다. + 플레이어 내부에서 아래로 스와이프하여 전체 화면 모드로 들어갑니다. 스와이프 제스처로 전체 화면 모드 종료 비활성화하기 전체 화면에서 아래로 스와이프하여 전체 화면 모드를 나가지 않습니다. 전체 화면에서 아래로 스와이프하여 전체 화면 모드를 나갑니다. @@ -1429,7 +1440,11 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 이전 동영상 화질 설정 메뉴를 활성화합니다. 이전 동영상 화질 설정을 비활성화합니다. 음악에서 기본 동영상 재생 속도 비활성화하기 + 음악 동영상에서 기본 동영상 재생 속도를 비활성화합니다. 음악 동영상에서 기본 동영상 재생 속도를 활성화합니다. + 카테고리를 사용하여 유효성 검사하기 + 동영상 카테고리가 음악인 경우에는 기본 동영상 재생 속도를 비활성화합니다. + YouTube Music에서 재생할 수 있는 동영상인 경우에는 기본 동영상 재생 속도를 비활성화합니다. Shorts에서 기본 동영상 재생 속도 활성화하기 Shorts에서 기본 동영상 재생 속도를 활성화합니다. Shorts에서 기본 동영상 재생 속도를 비활성화합니다. @@ -1774,7 +1789,23 @@ GmsCore 앱 배터리 최적화를 비활성화(제한 없음)하더라도, 배 "스트리밍 데이터를 변경하지 않습니다.\n동영상 재생 문제가 발생할 수 있습니다." 이 설정을 비활성화하면 동영상 재생 문제가 발생할 수 있습니다. 기본 클라이언트 + "Android TV +(로그인이 요구됨)" + Android VR + "iOS +(PoToken이 요구됨)" + "iOS TV +(로그인 요구됨)" 알려진 문제점 + "• 오디오 트랙 메뉴가 표시되지 않습니다. +• 안정적인 볼륨을 사용할 수 없습니다. +• 자동 오디오 트랙을 비활성화할 수 없습니다 +• 로그아웃이 되어있거나 시크릿 모드에서는 Kids 동영상이 재생되지 않을 수 있습니다. +• VR은 Kids // TV는 재생목록과 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다." + • 재생 문제가 발생할 수 있습니다 (PoToken이 요구됨).\n• 영화, 유료, 비공개 그리고 연령 제한 동영상에서 다른 클라이언트가 사용될 수 있습니다. + "• 영화 또는 유료 동영상이 재생되지 않을 수 있습니다. +• 로그아웃이 되어있거나 시크릿 모드에서는 Kids 동영상이 재생되지 않을 수 있습니다. +• 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다." iOS AVC (H.264) 강제로 활성화하기 동영상 코덱을 AVC (H.264)로 강제로 활성화합니다.\n\n• 일부 VP9 코덱 동영상에서 제거되었던 화질 값이 표시될 수 있습니다.\n• 최대 화질 값이 1080p이므로, 초고화질 동영상을 재생할 수 없습니다.\n• HDR 동영상을 재생할 수 없습니다. 동영상 코덱을 자동으로 결정합니다.\n\n• 예전에 업로드된 동영상을 재생했는데 VP9 코덱 응답을 받았을 경우, 일부 화질값이 제거되어 360p와 1080p(Premium 기능)만 선택가능할 수 있거나 화질 메뉴를 선택불가능할 수 있습니다. diff --git a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml index edb1f5e73..565890038 100644 --- a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml +++ b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml @@ -859,6 +859,16 @@ Autoodtwarzanie można zmienić w ustawieniach YouTube: Panel zaangażowania Ukryty Widoczny + Pełny ekran po rozpoczęciu filmu + Włączony + +Ograniczenie: nie działa jeśli odtwarzacz jest zminimalizowany, w trybie PiP lub w tle + Wyłączony + Wyjście z pełnego ekranu po zakończeniu filmu + Wyłączone + Tryb pionowy + Tryb poziomy + Tryb pionowy i poziomy Tytuły filmów "Tytuły filmów w trybie pełnoekranowym są widoczne. @@ -1419,7 +1429,11 @@ Ograniczenia: Widoczne Niewidoczne Domyślna prędkość odtwarzania dla muzyki + Wyłączona Włączona + Sprawdzaj przy użyciu kategorii + Wyłączone dla filmów z kategorią muzyki + Wyłączone dla filmów odtwarzalnych w YouTube Music Domyślna prędkość odtwarzania w Shortsach Włączona Wyłączona @@ -1765,7 +1779,21 @@ Stuknij przycisk kontynuacji i zezwól na zmiany w optymalizacji." "Wyłączone. Odtwarzanie filmów może nie działać" Wyłączenie tej opcji może spowodować problemy z odtwarzaniem filmów. Domyślny klient + "Android TV +(Wymagane zalogowanie)" + Android VR + "iOS +(Wymagany PoToken)" + "iOS TV +(Wymagane zalogowanie)" Efekty uboczne oszukiwania + "• Brakuje menu od ścieżki dźwiękowej +• Stabilna głośność nie jest dostępna +• Automatyczne wymuszenie ścieżki dźwiękowej nie jest dostępne +• Filmy dla dzieci mogą się nie odtwarzać będąc zalogowanym lub w trybie incognito" + • Mogą wystąpić problemy z odtwarzaniem (wymagany PoToken) + "• Filmy kinowe lub płatne mogą się nie odtwarzać +• Filmy dla dzieci mogą się nie odtwarzać będąc zalogowanym lub w trybie incognito" Wymuś kodek iOS AVC (H.264) Wymuszony Określany automatycznie diff --git a/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml b/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml index aa242103c..5ca05fceb 100644 --- a/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml +++ b/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml @@ -860,6 +860,16 @@ Вимкнути панель залучення Панель залучення вимкнено. Панель залучення увімкнено. + Переходити у повноекранний режим при запуску відео + Переходиться у повноекранний режим при запуску відео. + +Застереження: Не працюватиме якщо плеєр мінімізовано, у режимі PiP, чи у фоні. + Не переходиться у повноекранний режим при запуску відео. + Виходити з повноекранного режиму в кінці відео + Вимкнено + Портретна + Ландшафтна + Портретна та ландшафтна Показувати секцію назви відео "Показується секцію назви відео в повноекранному режимі. @@ -1425,7 +1435,11 @@ Старе меню якості відео показується. Старе меню якості відео не показується. Вимкнути швидкість відтворення для музики + Типову швидкість відтворення вимкнено для музики. Типову швидкість відтворення увімкнено для музики. + Перевіряти за допомогою категорій + Типову швидкість відтворення вимкнено якщо категорія відео Музика. + Типову швидкість відтворення вимкнено для відтворення відео на YouTube Music. Увімкнути типову швидкість відтворення Shorts Типову швидкість відтворення застосовується для Shorts. Типову швидкість відтворення не застосовується для Shorts. @@ -1766,7 +1780,21 @@ "Дані трансляції не підроблено. Відтворення відео може не працювати." Вимикання цього налаштування може призвести до проблем відтворення відео. Основний клієнт + "Android TV +(Потрібна авторизація)" + Android VR + "iOS +(Потрібен PoToken)" + "iOS TV +(Потрібна авторизація)" Побічні ефекти імітування + "• Меню звукової доріжки відсутнє. +• Стабілізація гучності недоступна. +• Вимкнення примусових авто звукових доріжок недоступне. +• Відео для дітей можуть не відтворюватися коли вийшли з системи або в анонімному режимі." + • Можуть бути проблеми з відтворенням (Потрібен PoToken). + "• Фільми та платні відео можуть не відтворюватися. +• Відео для дітей можуть не відтворюватися коли вийшли з системи або в анонімному режимі." Примусово AVC (H.264) iOS Примусово увімкнено відеокодек AVC (H.264). Відеокодек визначається автоматично. diff --git a/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml b/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml index 6b39af690..0f99ac103 100644 --- a/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml +++ b/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml @@ -863,6 +863,16 @@ Cài đặt → Tự động phát → Tự động phát video tiếp theo."Tắt bảng tương tác Bảng tương tác đã tắt. Bảng điều khiển tương tác được bật. + Vào chế độ toàn màn hình khi video bắt đầu + Vào chế độ toàn màn hình khi video bắt đầu. + +Hạn chế: Không hoạt động nếu trình phát đang thu nhỏ, trong chế độ Hình trong hình, hoặc phát trong nền. + Không vào chế độ toàn màn hình khi video bắt đầu. + Thoát chế độ màn hình khi video kết thúc + Tắt + Dọc + Ngang + Cả dọc và ngang Hiển thị phần tiêu đề video "Hiển thị phần tiêu đề video ở chế độ toàn màn hình. @@ -1425,7 +1435,11 @@ Không còn lề trên và dưới trong trình phát." Mục chất lượng video kiểu cũ được hiển thị. Mục chất lượng video kiểu cũ không được hiển thị. Tắt tùy chọn tốc độ phát khi phát nhạc + Tốc độ phát mặc định đã tắt khi phát nhạc. Tốc độ phát mặc định được kích hoạt khi phát nhạc. + Dựa vào danh mục + Tốc độ phát mặc định đã tắt nếu video thuộc danh mục Âm nhạc. + Tốc độ phát mặc định đã tắt đối với các video chơi game trên Youtube Music. Tốc độ phát mặc định cho video ngắn Tốc độ phát mặc định đã đặt đang được áp dụng khi xem Shorts. Tốc độ phát mặc định đã đặt không áp dụng cho Shorts. @@ -1771,7 +1785,21 @@ Nhấn vào Tiếp tục và cho phép thay đổi lựa chọn tối ưu hoá p "Luồng dữ liệu trực tuyến chưa được giả mạo. Khi phát video có thể gặp sự cố đứng hình." Tắt cài đặt này có thể gây ra sự cố phát video. Ứng dụng khách mặc định + "Android TV +(Yêu cầu Đăng nhập)" + Android VR + "iOS +(Yêu cầu PoToken)" + "iOS TV +(Yêu cầu Đăng nhập)" Hạn chế + "• Mục Bản âm thanh bị thiếu. +• Âm lượng ổn định không khả dụng. +• Tắt bắt buộc Bản âm thanh tự động không khả dụng. +• Video dành cho trẻ em có thể không phát được khi bạn đã đăng xuất hoặc bật chế độ ẩn danh." + • Có thể xẩy ra sự cố phát (Yêu cầu PoToken). + "• Phim hoặc video trả phí có thể không phát được. +• Video dành cho trẻ em có thể không phát được khi bạn đã đăng xuất hoặc bật chế độ ẩn danh." Bắt buộc iOS sử dụng AVC (H.264) Codec video bị ép buộc thành AVC (H.264). Codec video được xác định tự động. diff --git a/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml b/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml index 861a1f12e..eda40a9d0 100644 --- a/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml +++ b/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml @@ -859,6 +859,16 @@ 停用互動面板 停用互動面板 啟用互動面板 + 影片開始時進入全螢幕模式 + \"影片開始時進入全螢幕模式。 + +限制:如果播放器最小化、處於畫中畫模式或處於後台,則不起作用。 + 影片開始時請勿進入全螢幕模式。 + 影片結束時退出全螢幕模式 + 已停用 + 縱向 + 橫向 + 縱向和橫向 顯示影片標題部份 "在全螢幕模式下顯示影片標題部分 @@ -1416,7 +1426,11 @@ 顯示舊的影片畫質選單 不顯示舊的影片畫質選單 停用音樂的播放速度 + 音樂的預設播放速度被禁用。 音樂的預設播放速度已啟用。 + 使用類別進行驗證 + 如果影片類別為音樂,則預設播放速度將被停用。 + YouTube 音樂上可播放的影片的預設播放速度為停用。 啟用短片預設播放速度 預設播放速度適用於短片 預設播放速度不適用於短片 @@ -1766,7 +1780,21 @@ "串流資料未偽裝。 影片可能無法播放。" 關閉此設定可能會導致影片播放問題。 預設客戶端 + "Android TV +(需要登入)" + Android VR + "iOS +(需要 PoToken)" + "iOS TV +(需要登入)" 偽裝副作用 + "• 音軌選單遺失。 +• 無法獲得穩定的音量。 +• 停用強制自動音軌無法使用。 +• 登出或處於隱身模式時可能無法播放兒童影片。" + • 可能有播放問題 (需要PoToken)。 + "• 電影或付費影片可能無法播放。 +• 登出或處於隱身模式時可能無法播放兒童影片。" 強制 iOS AVC (H.264) 影片編解碼器強制為 AVC (H.264)。 影片編解碼器是自動決定的。 From ae32f50ea5c7cfde8b06d86e3728693815b92a75 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:24:11 +0900 Subject: [PATCH 50/65] bump 5.2.1-dev.3 --- gradle.properties | 2 +- patches.json | 5 +++-- patches/api/patches.api | 7 +++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2d0166f07..26f84248b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,5 +4,5 @@ org.gradle.parallel = true android.useAndroidX = true kotlin.code.style = official kotlin.jvm.target.validation.mode = IGNORE -version = 5.2.1-dev.2 +version = 5.2.1-dev.3 diff --git a/patches.json b/patches.json index c65cf0cee..d75696759 100644 --- a/patches.json +++ b/patches.json @@ -827,7 +827,7 @@ "Settings for YouTube Music", "BytecodePatch", "BytecodePatch", - "ResourcePatch" + "BytecodePatch" ], "compatiblePackages": { "com.google.android.apps.youtube.music": [ @@ -2557,7 +2557,8 @@ "use": true, "dependencies": [ "BytecodePatch", - "Settings for YouTube Music" + "Settings for YouTube Music", + "BytecodePatch" ], "compatiblePackages": { "com.google.android.apps.youtube.music": [ diff --git a/patches/api/patches.api b/patches/api/patches.api index 19af90be9..59f48b136 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -167,6 +167,7 @@ public final class app/revanced/patches/music/utils/fix/fileprovider/FileProvide } public final class app/revanced/patches/music/utils/fix/streamingdata/SpoofStreamingDataPatchKt { + public static final field EXTENSION_CLASS_DESCRIPTOR Ljava/lang/String; public static final fun getSpoofStreamingDataPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -287,6 +288,12 @@ public final class app/revanced/patches/music/video/playback/VideoPlaybackPatchK public static final fun getVideoPlaybackPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/music/video/playerresponse/PlayerResponseMethodHookPatchKt { + public static final fun getPlayerResponseMethodHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch; + public static final fun hookPlayerResponse (Ljava/lang/String;Z)V + public static synthetic fun hookPlayerResponse$default (Ljava/lang/String;ZILjava/lang/Object;)V +} + public final class app/revanced/patches/reddit/ad/AdsPatchKt { public static final fun getAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } From aeb675006311d0eda8481989ebf5bca011028afb Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:12:28 +0900 Subject: [PATCH 51/65] fix(Spoof streaming data): Requests sent in incorrect client order --- .../shared/patches/client/AppClient.kt | 20 ++++++++++++++++-- .../shared/patches/client/WebClient.kt | 2 +- .../spoof/requests/StreamingDataRequest.kt | 21 ++++--------------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt index 731203771..6fac8a9bb 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt @@ -3,6 +3,7 @@ package app.revanced.extension.shared.patches.client import android.os.Build import app.revanced.extension.shared.patches.PatchStatus import app.revanced.extension.shared.settings.BaseSettings +import org.apache.commons.lang3.ArrayUtils /** * Used to fetch streaming data. @@ -173,12 +174,27 @@ object AppClient { return BaseSettings.SPOOF_STREAMING_DATA_IOS_FORCE_AVC.get() } - val availableClientTypes: Array - get() = if (PatchStatus.SpoofStreamingDataMusic()) + fun availableClientTypes(preferredClient: ClientType): Array { + val availableClientTypes = if (PatchStatus.SpoofStreamingDataMusic()) ClientType.CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC else ClientType.CLIENT_ORDER_TO_USE_YOUTUBE + if (ArrayUtils.contains(availableClientTypes, preferredClient)) { + val clientToUse: Array = arrayOfNulls(availableClientTypes.size) + clientToUse[0] = preferredClient + var i = 1 + for (c in availableClientTypes) { + if (c != preferredClient) { + clientToUse[i++] = c + } + } + return clientToUse.filterNotNull().toTypedArray() + } else { + return availableClientTypes + } + } + enum class ClientType( /** * [YouTube client type](https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/WebClient.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/WebClient.kt index b77806c81..f39a56c60 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/WebClient.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/WebClient.kt @@ -34,7 +34,7 @@ object WebClient { ), WEB_REMIX( id = 29, - clientVersion = "1.20241127.01.00", + clientVersion = "1.20241218.01.00", ); @JvmField diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt index 3732774a4..0e0542f67 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt @@ -88,7 +88,6 @@ class StreamingDataRequest private constructor( } companion object { - private var CLIENT_ORDER_TO_USE: Array private const val AUTHORIZATION_HEADER = "Authorization" private const val VISITOR_ID_HEADER = "X-Goog-Visitor-Id" private val REQUEST_HEADER_KEYS = arrayOf( @@ -96,6 +95,10 @@ class StreamingDataRequest private constructor( "X-GOOG-API-FORMAT-VERSION", VISITOR_ID_HEADER ) + + private val CLIENT_ORDER_TO_USE: Array = + availableClientTypes(BaseSettings.SPOOF_STREAMING_DATA_TYPE.get()) + private var lastSpoofedClientType: AppClient.ClientType? = null @@ -131,22 +134,6 @@ class StreamingDataRequest private constructor( ?.friendlyName ?: "Unknown" - init { - val allClientTypes: Array = availableClientTypes - val preferredClient = BaseSettings.SPOOF_STREAMING_DATA_TYPE.get() - - CLIENT_ORDER_TO_USE = allClientTypes - if (ArrayUtils.indexOf(allClientTypes, preferredClient) >= 0) { - CLIENT_ORDER_TO_USE[0] = preferredClient - var i = 1 - for (c in allClientTypes) { - if (c != preferredClient) { - CLIENT_ORDER_TO_USE[i++] = c - } - } - } - } - @JvmStatic fun fetchRequest( videoId: String, fetchHeaders: Map, visitorId: String, From 8663436d3d53b217ebdb93dd6ab1cbfd5152d656 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:18:04 +0900 Subject: [PATCH 52/65] fix(YouTube - Spoof streaming data): Enhanced bitrate not available on `Android VR`, `Android TV` --- .../shared/patches/client/AppClient.kt | 45 +++++++++++++++++-- .../spoof/SpoofStreamingDataPatch.java | 2 +- .../patches/spoof/requests/PlayerRoutes.kt | 21 ++++++--- .../spoof/requests/StreamingDataRequest.kt | 2 +- .../patches/video/requests/MusicRequest.kt | 4 +- 5 files changed, 61 insertions(+), 13 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt index 6fac8a9bb..17f0f53d5 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt @@ -28,6 +28,8 @@ object AppClient { else "19.29.1" + private const val DEVICE_MAKE_IOS = "Apple" + private const val OS_NAME_IOS = "iOS" /** * The device machine id for the iPhone 15 Pro Max (iPhone16,2), * used to get HDR with AV1 hardware decoding. @@ -95,6 +97,7 @@ object AppClient { * See [this GitLab](https://dumps.tadiphone.dev/dumps/oculus/eureka) for more information. */ private const val DEVICE_MODEL_ANDROID_VR = "Quest 3" + private const val DEVICE_MAKE_ANDROID_VR = "Oculus" private const val OS_VERSION_ANDROID_VR = "12" /** @@ -119,6 +122,7 @@ object AppClient { * See [this GitLab](https://dumps.tadiphone.dev/dumps/google/kirkwood) for more information. */ private const val DEVICE_MODEL_ANDROID_UNPLUGGED = "Google TV Streamer" + private const val DEVICE_MAKE_ANDROID_UNPLUGGED = "Google" private const val OS_VERSION_ANDROID_UNPLUGGED = "14" private const val ANDROID_SDK_VERSION_ANDROID_UNPLUGGED = "34" private val USER_AGENT_ANDROID_UNPLUGGED = androidUserAgent( @@ -128,6 +132,20 @@ object AppClient { ) + // ANDROID CREATOR + /** + * Video not playable: Livestream / HDR + * Note: Audio track is not available + */ + private const val PACKAGE_NAME_ANDROID_CREATOR = "com.google.android.apps.youtube.creator" + private const val CLIENT_VERSION_ANDROID_CREATOR = "23.47.101" + + private val USER_AGENT_ANDROID_CREATOR = androidUserAgent( + PACKAGE_NAME_ANDROID_CREATOR, + CLIENT_VERSION_ANDROID_CREATOR + ) + + // ANDROID MUSIC /** * Video not playable: All videos that can't be played on YouTube Music @@ -139,7 +157,6 @@ object AppClient { * It is not the default client yet, as it requires sufficient testing. */ private const val CLIENT_VERSION_ANDROID_MUSIC = "4.27.53" - private val ANDROID_SDK_VERSION_ANDROID_MUSIC = Build.VERSION.SDK_INT.toString() private val USER_AGENT_ANDROID_MUSIC = androidUserAgent( PACKAGE_NAME_ANDROID_MUSIC, CLIENT_VERSION_ANDROID_MUSIC @@ -195,15 +212,24 @@ object AppClient { } } + @Suppress("DEPRECATION") enum class ClientType( /** * [YouTube client type](https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients) */ val id: Int, + /** + * Device model, equivalent to [Build.MANUFACTURER] (System property: ro.product.vendor.manufacturer) + */ + val deviceMake: String = Build.MANUFACTURER, /** * Device model, equivalent to [Build.MODEL] (System property: ro.product.model) */ val deviceModel: String = Build.MODEL, + /** + * Device OS name. + */ + val osName: String = "Android", /** * Device OS version, equivalent to [Build.VERSION.RELEASE] (System property: ro.system.build.version.release) */ @@ -216,7 +242,7 @@ object AppClient { * Android SDK version, equivalent to [Build.VERSION.SDK] (System property: ro.build.version.sdk) * Field is null if not applicable. */ - val androidSdkVersion: String? = null, + val androidSdkVersion: String = Build.VERSION.SDK, /** * App version. */ @@ -242,6 +268,7 @@ object AppClient { ) { ANDROID_VR( id = 28, + deviceMake = DEVICE_MAKE_ANDROID_VR, deviceModel = DEVICE_MODEL_ANDROID_VR, osVersion = OS_VERSION_ANDROID_VR, userAgent = USER_AGENT_ANDROID_VR, @@ -251,6 +278,7 @@ object AppClient { ), ANDROID_UNPLUGGED( id = 29, + deviceMake = DEVICE_MAKE_ANDROID_UNPLUGGED, deviceModel = DEVICE_MODEL_ANDROID_UNPLUGGED, osVersion = OS_VERSION_ANDROID_UNPLUGGED, userAgent = USER_AGENT_ANDROID_UNPLUGGED, @@ -259,9 +287,18 @@ object AppClient { requireAuth = true, friendlyName = "Android TV" ), + ANDROID_CREATOR( + id = 14, + userAgent = USER_AGENT_ANDROID_CREATOR, + clientVersion = CLIENT_VERSION_ANDROID_CREATOR, + requireAuth = true, + friendlyName = "Android Studio" + ), IOS_UNPLUGGED( id = 33, + deviceMake = DEVICE_MAKE_IOS, deviceModel = DEVICE_MODEL_IOS, + osName = OS_NAME_IOS, osVersion = OS_VERSION_IOS, userAgent = USER_AGENT_IOS_UNPLUGGED, clientVersion = CLIENT_VERSION_IOS_UNPLUGGED, @@ -273,7 +310,9 @@ object AppClient { ), IOS( id = 5, + deviceMake = DEVICE_MAKE_IOS, deviceModel = DEVICE_MODEL_IOS, + osName = OS_NAME_IOS, osVersion = OS_VERSION_IOS, userAgent = USER_AGENT_IOS, clientVersion = CLIENT_VERSION_IOS, @@ -287,7 +326,6 @@ object AppClient { ANDROID_MUSIC( id = 21, userAgent = USER_AGENT_ANDROID_MUSIC, - androidSdkVersion = ANDROID_SDK_VERSION_ANDROID_MUSIC, clientVersion = CLIENT_VERSION_ANDROID_MUSIC, requireAuth = true, friendlyName = "Android Music" @@ -300,6 +338,7 @@ object AppClient { ANDROID_VR, ANDROID_UNPLUGGED, IOS_UNPLUGGED, + ANDROID_CREATOR, IOS, ) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java index fc888b116..a94f79810 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java @@ -207,7 +207,7 @@ public class SpoofStreamingDataPatch { String id = uri.getQueryParameter("id"); if (id == null) { - Logger.printException(() -> "Ignoring request with no id. Url: " + url); + Logger.printException(() -> "Ignoring request with no id: " + url); return; } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt index 666e04858..9f43b02bd 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt @@ -62,14 +62,12 @@ object PlayerRoutes { val client = JSONObject() client.put("clientName", clientType.clientName) client.put("clientVersion", clientType.clientVersion) + client.put("deviceMake", clientType.deviceMake) client.put("deviceModel", clientType.deviceModel) + client.put("osName", clientType.osName) client.put("osVersion", clientType.osVersion) - if (clientType.androidSdkVersion != null) { + if (clientType.osName == "Android") { client.put("androidSdkVersion", clientType.androidSdkVersion) - client.put("osName", "Android") - } else { - client.put("deviceMake", "Apple") - client.put("osName", "iOS") } if (!clientType.supportsCookies) { client.put("hl", LOCALE_LANGUAGE) @@ -130,12 +128,22 @@ object PlayerRoutes { } @JvmStatic + fun getPlayerResponseConnectionFromRoute(route: CompiledRoute, clientType: AppClient.ClientType): HttpURLConnection { + return getPlayerResponseConnectionFromRoute(route, clientType.userAgent, clientType.id.toString()) + } + + @JvmStatic + fun getPlayerResponseConnectionFromRoute(route: CompiledRoute, clientType: WebClient.ClientType): HttpURLConnection { + return getPlayerResponseConnectionFromRoute(route, clientType.userAgent, clientType.id.toString()) + } + @Throws(IOException::class) - fun getPlayerResponseConnectionFromRoute(route: CompiledRoute, userAgent: String): HttpURLConnection { + fun getPlayerResponseConnectionFromRoute(route: CompiledRoute, userAgent: String, clientVersion: String): HttpURLConnection { val connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route) connection.setRequestProperty("Content-Type", "application/json") connection.setRequestProperty("User-Agent", userAgent) + connection.setRequestProperty("X-YouTube-Client-Version", clientVersion) connection.useCaches = false connection.doOutput = true @@ -144,4 +152,5 @@ object PlayerRoutes { connection.readTimeout = CONNECTION_TIMEOUT_MILLISECONDS return connection } + } \ No newline at end of file diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt index 0e0542f67..5423e0653 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt @@ -171,7 +171,7 @@ class StreamingDataRequest private constructor( Logger.printDebug { "Fetching video streams for: $videoId using client: $clientType" } try { - val connection = getPlayerResponseConnectionFromRoute(GET_STREAMING_DATA, clientType.userAgent) + val connection = getPlayerResponseConnectionFromRoute(GET_STREAMING_DATA, clientType) connection.connectTimeout = HTTP_TIMEOUT_MILLISECONDS connection.readTimeout = HTTP_TIMEOUT_MILLISECONDS diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt index 72d765c16..91711bd7c 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt @@ -121,7 +121,7 @@ class MusicRequest private constructor(private val videoId: String, private val Logger.printDebug { "Fetching playlist request for: $videoId using client: $clientTypeName" } try { - val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(PlayerRoutes.GET_PLAYLIST_PAGE, clientType.userAgent) + val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(PlayerRoutes.GET_PLAYLIST_PAGE, clientType) val requestBody = PlayerRoutes.createApplicationRequestBody(clientType, videoId, "RD$videoId") @@ -158,7 +158,7 @@ class MusicRequest private constructor(private val videoId: String, private val Logger.printDebug { "Fetching playability request for: $videoId using client: $clientTypeName" } try { - val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(PlayerRoutes.GET_CATEGORY, clientType.userAgent) + val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(PlayerRoutes.GET_CATEGORY, clientType) val requestBody = PlayerRoutes.createWebInnertubeBody(clientType, videoId) From 1ce4c05173218bfbe68530edcd1f35e581106951 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:21:41 +0900 Subject: [PATCH 53/65] chroe(YouTube - Video playback): `Disable music playback speed` is applied a little faster --- .../extension/shared/patches/spoof/requests/PlayerRoutes.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt index 9f43b02bd..61fe440cb 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt @@ -20,14 +20,16 @@ object PlayerRoutes { val GET_CATEGORY: CompiledRoute = Route( Route.Method.POST, "player" + - "?fields=microformat.playerMicroformatRenderer.category" + "?prettyPrint=false" + + "&fields=microformat.playerMicroformatRenderer.category" ).compile() @JvmField val GET_PLAYLIST_PAGE: CompiledRoute = Route( Route.Method.POST, "next" + - "?fields=contents.singleColumnWatchNextResults.playlist.playlist" + "?prettyPrint=false" + + "&fields=contents.singleColumnWatchNextResults.playlist.playlist" ).compile() @JvmField From f02ea01ebeb5dea439a1fd7b139515d0ecab008a Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:24:02 +0900 Subject: [PATCH 54/65] feat(YouTube Music - Disable music video in album): Remove `Dismiss queue` options --- .../patches/misc/AlbumMusicVideoPatch.java | 33 ++++--------------- .../extension/music/settings/Settings.java | 2 +- .../music/misc/album/AlbumMusicVideoPatch.kt | 2 -- .../music/settings/host/values/arrays.xml | 6 ---- .../music/settings/host/values/strings.xml | 3 -- 5 files changed, 8 insertions(+), 38 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java index 08fca8a31..b6489c720 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/AlbumMusicVideoPatch.java @@ -19,18 +19,9 @@ import app.revanced.extension.shared.utils.Logger; public class AlbumMusicVideoPatch { public enum RedirectType { - REDIRECT_DISMISS(true), - REDIRECT(false), - ON_CLICK_DISMISS(true), - ON_CLICK(false), - ON_LONG_CLICK_DISMISS(true), - ON_LONG_CLICK(false); - - public final boolean dismissQueue; - - RedirectType(boolean dismissQueue) { - this.dismissQueue = dismissQueue; - } + REDIRECT, + ON_CLICK, + ON_LONG_CLICK } private static final RedirectType REDIRECT_TYPE = @@ -39,17 +30,11 @@ public class AlbumMusicVideoPatch { private static final boolean DISABLE_MUSIC_VIDEO_IN_ALBUM = Settings.DISABLE_MUSIC_VIDEO_IN_ALBUM.get(); - private static final boolean DISMISS_QUEUE = - DISABLE_MUSIC_VIDEO_IN_ALBUM && REDIRECT_TYPE.dismissQueue; + private static final boolean REDIRECT = REDIRECT_TYPE == RedirectType.REDIRECT; - private static final boolean REDIRECT = - REDIRECT_TYPE == RedirectType.REDIRECT || REDIRECT_TYPE == RedirectType.REDIRECT_DISMISS; + private static final boolean ON_CLICK = REDIRECT_TYPE == RedirectType.ON_CLICK; - private static final boolean ON_CLICK = - REDIRECT_TYPE == RedirectType.ON_CLICK || REDIRECT_TYPE == RedirectType.ON_CLICK_DISMISS; - - private static final boolean ON_LONG_CLICK = - REDIRECT_TYPE == RedirectType.ON_LONG_CLICK || REDIRECT_TYPE == RedirectType.ON_LONG_CLICK_DISMISS; + private static final boolean ON_LONG_CLICK = REDIRECT_TYPE == RedirectType.ON_LONG_CLICK; private static final String YOUTUBE_MUSIC_ALBUM_PREFIX = "OLAK"; @@ -63,7 +48,7 @@ public class AlbumMusicVideoPatch { @GuardedBy("itself") private static final Map lastVideoIds = new LinkedHashMap<>() { - private static final int NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK = 5; + private static final int NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK = 10; @Override protected boolean removeEldestEntry(Map.Entry eldest) { @@ -153,10 +138,6 @@ public class AlbumMusicVideoPatch { private static void openMusic(@NonNull String songId) { try { - if (DISMISS_QUEUE) { - VideoUtils.dismissQueue(); - } - isVideoLaunched.compareAndSet(false, true); // The newly opened video is not a music video. diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java index f2638e371..75c636200 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java @@ -180,7 +180,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting DISABLE_CAIRO_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_cairo_splash_animation", FALSE, true); public static final BooleanSetting DISABLE_DRC_AUDIO = new BooleanSetting("revanced_disable_drc_audio", FALSE, true); public static final BooleanSetting DISABLE_MUSIC_VIDEO_IN_ALBUM = new BooleanSetting("revanced_disable_music_video_in_album", FALSE, true); - public static final EnumSetting DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE = new EnumSetting<>("revanced_disable_music_video_in_album_redirect_type", RedirectType.REDIRECT_DISMISS, true); + public static final EnumSetting DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE = new EnumSetting<>("revanced_disable_music_video_in_album_redirect_type", RedirectType.REDIRECT, true); public static final BooleanSetting ENABLE_OPUS_CODEC = new BooleanSetting("revanced_enable_opus_codec", FALSE, true); public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false); public static final BooleanSetting SPOOF_CLIENT = new BooleanSetting("revanced_spoof_client", FALSE, true); diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt index 1479cc65f..e24c51738 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt @@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE -import app.revanced.patches.music.utils.dismiss.dismissQueueHookPatch import app.revanced.patches.music.utils.extension.Constants.MISC_PATH import app.revanced.patches.music.utils.patch.PatchList.DISABLE_MUSIC_VIDEO_IN_ALBUM import app.revanced.patches.music.utils.settings.CategoryType @@ -39,7 +38,6 @@ val albumMusicVideoPatch = bytecodePatch( dependsOn( settingsPatch, - dismissQueueHookPatch, videoInformationPatch, playerResponseMethodHookPatch, ) diff --git a/patches/src/main/resources/music/settings/host/values/arrays.xml b/patches/src/main/resources/music/settings/host/values/arrays.xml index 97897dac9..c1adaccde 100644 --- a/patches/src/main/resources/music/settings/host/values/arrays.xml +++ b/patches/src/main/resources/music/settings/host/values/arrays.xml @@ -15,19 +15,13 @@ FEmusic_library_corpus_artists - @string/revanced_disable_music_video_in_album_redirect_type_entry_redirect_dismiss @string/revanced_disable_music_video_in_album_redirect_type_entry_redirect - @string/revanced_disable_music_video_in_album_redirect_type_entry_on_click_dismiss @string/revanced_disable_music_video_in_album_redirect_type_entry_on_click - @string/revanced_disable_music_video_in_album_redirect_type_entry_on_long_click_dismiss @string/revanced_disable_music_video_in_album_redirect_type_entry_on_long_click - REDIRECT_DISMISS REDIRECT - ON_CLICK_DISMISS ON_CLICK - ON_LONG_CLICK_DISMISS ON_LONG_CLICK diff --git a/patches/src/main/resources/music/settings/host/values/strings.xml b/patches/src/main/resources/music/settings/host/values/strings.xml index e93faecae..c3479c6a5 100644 --- a/patches/src/main/resources/music/settings/host/values/strings.xml +++ b/patches/src/main/resources/music/settings/host/values/strings.xml @@ -428,11 +428,8 @@ Find the official song if a music video is detected playing from an album. • Powered by Piped Instance API." Redirection type Specifies how to redirect to official song. - Redirect (Dismiss queue) Redirect - Tap Audio / Video toggle (Dismiss queue) Tap Audio / Video toggle - Tap and hold Audio / Video toggle (Dismiss queue) Tap and hold Audio / Video toggle Enable debug logging Prints the debug log. From ac0fea1cb73108d469a7db8fe68ff7dbe2593ff2 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:24:42 +0900 Subject: [PATCH 55/65] chore: Lint code --- .../extension/youtube/patches/utils/PatchStatus.java | 5 ----- .../preference/ReVancedSettingsPreference.java | 11 ----------- 2 files changed, 16 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PatchStatus.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PatchStatus.java index 309415c0d..10fefa0e2 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PatchStatus.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PatchStatus.java @@ -7,11 +7,6 @@ public class PatchStatus { return false; } - public static boolean MinimalHeader() { - // Replace this with true If the Custom header patch succeeds and the patch option was `youtube_minimal_header` - return false; - } - public static boolean PlayerButtons() { // Replace this with true if the Hide player buttons patch succeeds return false; diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java index dc13a6bb6..a3987e7b9 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedSettingsPreference.java @@ -46,7 +46,6 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment { enableDisablePreferences(); AmbientModePreferenceLinks(); - ChangeHeaderPreferenceLinks(); ExternalDownloaderPreferenceLinks(); FullScreenPanelPreferenceLinks(); MiniPlayerPreferenceLinks(); @@ -70,16 +69,6 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment { ); } - /** - * Enable/Disable Preference related to Change header - */ - private static void ChangeHeaderPreferenceLinks() { - enableDisablePreferences( - PatchStatus.MinimalHeader(), - Settings.CHANGE_YOUTUBE_HEADER - ); - } - /** * Enable/Disable Preference for External downloader settings */ From d748b6d12f4e84cff67d1aa31c07be53fc6d4995 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:33:17 +0900 Subject: [PATCH 56/65] feat(YouTube Music): Add `Dark theme` patch, Remove `Amoled` patch --- .../patches/navigation/NavigationPatch.java | 7 +- .../patches/utils/DrawableColorPatch.java | 39 ++++- .../music/patches/utils/PatchStatus.java | 5 + .../music/general/amoled/AmoledPatch.kt | 46 ------ .../music/layout/theme/DarkThemePatch.kt | 151 ++++++++++++++++++ .../music/layout/theme/Fingerprints.kt | 15 ++ .../patches/music/utils/patch/PatchList.kt | 10 +- .../utils/resourceid/SharedResourceIdPatch.kt | 6 + .../materialyou/BaseMaterialYouPatch.kt | 130 +++++++++++++++ .../youtube/layout/theme/MaterialYouPatch.kt | 115 +------------ .../materialyou/host/values-v31/colors.xml | 20 +++ .../drawable/revanced_header_gradient.xml | 5 + 12 files changed, 375 insertions(+), 174 deletions(-) delete mode 100644 patches/src/main/kotlin/app/revanced/patches/music/general/amoled/AmoledPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/layout/theme/DarkThemePatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/layout/theme/Fingerprints.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/shared/materialyou/BaseMaterialYouPatch.kt create mode 100644 patches/src/main/resources/music/materialyou/host/values-v31/colors.xml create mode 100644 patches/src/main/resources/music/theme/drawable/revanced_header_gradient.xml diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/navigation/NavigationPatch.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/navigation/NavigationPatch.java index bf99b8fe6..904aced74 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/patches/navigation/NavigationPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/navigation/NavigationPatch.java @@ -8,13 +8,16 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import app.revanced.extension.music.patches.utils.PatchStatus; import app.revanced.extension.music.settings.Settings; import app.revanced.extension.shared.utils.ResourceUtils; @SuppressWarnings("unused") public class NavigationPatch { - private static final int colorGrey12 = - ResourceUtils.getColor("revanced_color_grey_12"); + private static final int colorGrey12 = PatchStatus.DarkTheme() + ? ResourceUtils.getColor("ytm_color_grey_12") + : ResourceUtils.getColor("revanced_color_grey_12"); + public static Enum lastPivotTab; public static int enableBlackNavigationBar() { diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/DrawableColorPatch.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/DrawableColorPatch.java index ddb7b0101..febdf3cb3 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/DrawableColorPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/DrawableColorPatch.java @@ -1,21 +1,44 @@ package app.revanced.extension.music.patches.utils; +import android.graphics.drawable.Drawable; +import android.view.ViewGroup; +import android.widget.ImageView; + +import org.apache.commons.lang3.ArrayUtils; + +import app.revanced.extension.shared.utils.ResourceUtils; +import app.revanced.extension.shared.utils.Utils; + @SuppressWarnings("unused") public class DrawableColorPatch { private static final int[] DARK_VALUES = { - -14606047 // comments box background + -14606047, // comments box background + -16579837, // button container background in album + -16777216, // button container background in playlist }; - public static int getLithoColor(int originalValue) { - if (anyEquals(originalValue, DARK_VALUES)) - return -16777215; + // background colors + private static final Drawable headerGradient = + ResourceUtils.getDrawable("revanced_header_gradient"); + private static final int blackColor = + ResourceUtils.getColor("yt_black1"); - return originalValue; + public static int getLithoColor(int originalValue) { + return ArrayUtils.contains(DARK_VALUES, originalValue) + ? blackColor + : originalValue; } - private static boolean anyEquals(int value, int... of) { - for (int v : of) if (value == v) return true; - return false; + public static void setHeaderGradient(ViewGroup viewGroup) { + viewGroup.getViewTreeObserver().addOnGlobalLayoutListener(() -> Utils.runOnMainThreadDelayed(() -> { + if (!(viewGroup.getChildAt(0) instanceof ViewGroup parentViewGroup)) + return; + if (!(parentViewGroup.getChildAt(0) instanceof ImageView gradientView)) + return; + if (headerGradient != null) { + gradientView.setForeground(headerGradient); + } + }, 0)); } } diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/PatchStatus.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/PatchStatus.java index 08abcf94a..1976df37c 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/PatchStatus.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/PatchStatus.java @@ -2,6 +2,11 @@ package app.revanced.extension.music.patches.utils; @SuppressWarnings("unused") public class PatchStatus { + public static boolean DarkTheme() { + // Replace this with true if the Dark theme patch succeeds + return false; + } + public static boolean SpoofAppVersionDefaultBoolean() { return false; } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/general/amoled/AmoledPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/general/amoled/AmoledPatch.kt deleted file mode 100644 index c2a79075d..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/music/general/amoled/AmoledPatch.kt +++ /dev/null @@ -1,46 +0,0 @@ -package app.revanced.patches.music.general.amoled - -import app.revanced.patcher.patch.resourcePatch -import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE -import app.revanced.patches.music.utils.extension.Constants.UTILS_PATH -import app.revanced.patches.music.utils.patch.PatchList.AMOLED -import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus -import app.revanced.patches.music.utils.settings.settingsPatch -import app.revanced.patches.shared.drawable.addDrawableColorHook -import app.revanced.patches.shared.drawable.drawableColorHookPatch -import org.w3c.dom.Element - -@Suppress("unused") -val amoledPatch = resourcePatch( - AMOLED.title, - AMOLED.summary, -) { - compatibleWith(COMPATIBLE_PACKAGE) - - dependsOn( - drawableColorHookPatch, - settingsPatch - ) - - execute { - addDrawableColorHook("$UTILS_PATH/DrawableColorPatch;->getLithoColor(I)I") - - document("res/values/colors.xml").use { document -> - val resourcesNode = document.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", "ytm_color_grey_12", "material_grey_850" -> "@android:color/black" - - else -> continue - } - } - } - - updatePatchStatus(AMOLED) - - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/DarkThemePatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/DarkThemePatch.kt new file mode 100644 index 000000000..c13c3e7e7 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/DarkThemePatch.kt @@ -0,0 +1,151 @@ +package app.revanced.patches.music.layout.theme + +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.booleanOption +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.patch.resourcePatch +import app.revanced.patcher.patch.stringOption +import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE +import app.revanced.patches.music.utils.extension.Constants.PATCH_STATUS_CLASS_DESCRIPTOR +import app.revanced.patches.music.utils.extension.Constants.UTILS_PATH +import app.revanced.patches.music.utils.patch.PatchList.DARK_THEME +import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch +import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus +import app.revanced.patches.music.utils.settings.settingsPatch +import app.revanced.patches.shared.drawable.addDrawableColorHook +import app.revanced.patches.shared.drawable.drawableColorHookPatch +import app.revanced.patches.shared.materialyou.baseMaterialYou +import app.revanced.util.ResourceGroup +import app.revanced.util.copyResources +import app.revanced.util.findMethodOrThrow +import app.revanced.util.fingerprint.methodOrThrow +import app.revanced.util.indexOfFirstInstructionReversedOrThrow +import app.revanced.util.valueOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import org.w3c.dom.Element + +private const val EXTENSION_CLASS_DESCRIPTOR = + "$UTILS_PATH/DrawableColorPatch;" + +private val darkThemeBytecodePatch = bytecodePatch( + description = "darkThemeBytecodePatch" +) { + dependsOn( + settingsPatch, + sharedResourceIdPatch, + drawableColorHookPatch, + ) + + execute { + addDrawableColorHook("$EXTENSION_CLASS_DESCRIPTOR->getLithoColor(I)I") + + elementsContainerFingerprint.methodOrThrow().apply { + val index = indexOfFirstInstructionReversedOrThrow(Opcode.CHECK_CAST) + val register = getInstruction(index).registerA + + addInstruction( + index + 1, + "invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->setHeaderGradient(Landroid/view/ViewGroup;)V" + ) + } + + findMethodOrThrow(PATCH_STATUS_CLASS_DESCRIPTOR) { + name == "DarkTheme" + }.replaceInstruction( + 0, + "const/4 v0, 0x1" + ) + } +} + +val DARK_COLOR = arrayOf( + "yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", + "yt_black2", "yt_black3", "yt_black4","yt_black_pure", + "yt_black_pure_opacity80", "yt_status_bar_background_dark", + "ytm_color_grey_12", "material_grey_800", "material_grey_850", +) + +@Suppress("unused") +val darkThemePatch = resourcePatch( + DARK_THEME.title, + DARK_THEME.summary, +) { + compatibleWith(COMPATIBLE_PACKAGE) + + dependsOn(darkThemeBytecodePatch) + + val amoledBlackColor = "@android:color/black" + + val darkThemeBackgroundColor = stringOption( + key = "darkThemeBackgroundColor", + default = amoledBlackColor, + values = mapOf( + "Amoled Black" to amoledBlackColor, + "Catppuccin (Mocha)" to "#FF181825", + "Dark Pink" to "#FF290025", + "Dark Blue" to "#FF001029", + "Dark Green" to "#FF002905", + "Dark Yellow" to "#FF282900", + "Dark Orange" to "#FF291800", + "Dark Red" to "#FF290000", + ), + title = "Dark theme background color", + description = "Can be a hex color (#AARRGGBB) or a color resource reference.", + ) + + val materialYou by booleanOption( + key = "materialYou", + default = false, + title = "MaterialYou", + description = "Applies the MaterialYou theme for Android 12+ devices.", + required = true + ) + + execute { + // Check patch options first. + val darkThemeColor = darkThemeBackgroundColor + .valueOrThrow() + + document("res/values/colors.xml").use { document -> + val resourcesNode = document.getElementsByTagName("resources").item(0) as Element + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + val colorName = node.getAttribute("name") + + if (DARK_COLOR.contains(colorName)) { + node.textContent = darkThemeColor + } + } + } + + arrayOf( + ResourceGroup( + "drawable", + "revanced_header_gradient.xml", + ) + ).forEach { resourceGroup -> + copyResources("music/theme", resourceGroup) + } + + if (materialYou == true) { + baseMaterialYou() + + document("res/values-v31/colors.xml").use { document -> + DARK_COLOR.forEach { name -> + val colorElement = document.createElement("color") + colorElement.setAttribute("name", name) + colorElement.textContent = "@android:color/system_neutral1_900" + + document.getElementsByTagName("resources").item(0).appendChild(colorElement) + } + } + } + + updatePatchStatus(DARK_THEME) + + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/Fingerprints.kt new file mode 100644 index 000000000..7b5a00b94 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/Fingerprints.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.music.layout.theme + +import app.revanced.patches.music.utils.resourceid.elementsContainer +import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.or +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal val elementsContainerFingerprint = legacyFingerprint( + name = "elementsContainerFingerprint", + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + opcodes = listOf(Opcode.INVOKE_DIRECT_RANGE), + literals = listOf(elementsContainer) +) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt index 2ec3454ce..11d02b637 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/patch/PatchList.kt @@ -5,10 +5,6 @@ internal enum class PatchList( val summary: String, var included: Boolean? = false ) { - AMOLED( - "Amoled", - "Applies a pure black theme to some components." - ), BITRATE_DEFAULT_VALUE( "Bitrate default value", "Sets the audio quality to 'Always High' when you first install the app." @@ -41,6 +37,10 @@ internal enum class PatchList( "Custom header for YouTube Music", "Applies a custom header in the top left corner within the app." ), + DARK_THEME( + "Dark theme", + "Changes the app's dark theme to the values specified in patch options." + ), DISABLE_CAIRO_SPLASH_ANIMATION( "Disable Cairo splash animation", "Adds an option to disable Cairo splash animation." @@ -59,7 +59,7 @@ internal enum class PatchList( ), DISABLE_MUSIC_VIDEO_IN_ALBUM( "Disable music video in album", - "Adds option to redirect music videos from albums." + "Adds option to redirect music videos from albums for non-premium users." ), ENABLE_OPUS_CODEC( "Enable OPUS codec", diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt index 94d001193..3363e56b0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt @@ -33,6 +33,8 @@ var darkBackground = -1L private set var designBottomSheetDialog = -1L private set +var elementsContainer = -1L + private set var endButtonsContainer = -1L private set var floatingLayout = -1L @@ -150,6 +152,10 @@ internal val sharedResourceIdPatch = resourcePatch( LAYOUT, "design_bottom_sheet_dialog" ] + elementsContainer = resourceMappings[ + ID, + "elements_container" + ] endButtonsContainer = resourceMappings[ ID, "end_buttons_container" diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/materialyou/BaseMaterialYouPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/materialyou/BaseMaterialYouPatch.kt new file mode 100644 index 000000000..d95d24c3c --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/shared/materialyou/BaseMaterialYouPatch.kt @@ -0,0 +1,130 @@ +package app.revanced.patches.shared.materialyou + +import app.revanced.patcher.patch.PatchException +import app.revanced.patcher.patch.ResourcePatchContext +import app.revanced.util.copyXmlNode +import app.revanced.util.inputStreamFromBundledResource +import org.w3c.dom.Element +import org.w3c.dom.Node +import java.io.File +import java.nio.file.Files +import java.nio.file.StandardCopyOption +import javax.xml.parsers.DocumentBuilderFactory +import javax.xml.transform.OutputKeys +import javax.xml.transform.TransformerFactory +import javax.xml.transform.dom.DOMSource +import javax.xml.transform.stream.StreamResult + +private fun ResourcePatchContext.patchXmlFile( + fromDir: String, + toDir: String, + xmlFileName: String, + parentNode: String, + targetNode: String? = null, + attribute: String, + newValue: String +) { + val resourceDirectory = get("res") + val fromDirectory = resourceDirectory.resolve(fromDir) + val toDirectory = resourceDirectory.resolve(toDir) + + if (!toDirectory.isDirectory) Files.createDirectories(toDirectory.toPath()) + + val fromXmlFile = fromDirectory.resolve(xmlFileName) + val toXmlFile = toDirectory.resolve(xmlFileName) + + if (!fromXmlFile.exists()) { + return + } + + if (!toXmlFile.exists()) { + Files.copy( + fromXmlFile.toPath(), + toXmlFile.toPath() + ) + } + + document("res/$toDir/$xmlFileName").use { document -> + val parentList = document.getElementsByTagName(parentNode).item(0) as Element + + if (targetNode != null) { + for (i in 0 until parentList.childNodes.length) { + val node = parentList.childNodes.item(i) as? Element ?: continue + + if (node.nodeName == targetNode && node.hasAttribute(attribute)) { + node.getAttributeNode(attribute).textContent = newValue + } + } + } else { + if (parentList.hasAttribute(attribute)) { + parentList.getAttributeNode(attribute).textContent = newValue + } + } + } +} + +fun ResourcePatchContext.baseMaterialYou() { + patchXmlFile( + "drawable", + "drawable-night-v31", + "new_content_dot_background.xml", + "shape", + "solid", + "android:color", + "@android:color/system_accent1_100" + ) + patchXmlFile( + "drawable", + "drawable-night-v31", + "new_content_dot_background_cairo.xml", + "shape", + "solid", + "android:color", + "@android:color/system_accent1_100" + ) + patchXmlFile( + "drawable", + "drawable-v31", + "new_content_dot_background.xml", + "shape", + "solid", + "android:color", + "@android:color/system_accent1_200" + ) + patchXmlFile( + "drawable", + "drawable-v31", + "new_content_dot_background_cairo.xml", + "shape", + "solid", + "android:color", + "@android:color/system_accent1_200" + ) + patchXmlFile( + "drawable", + "drawable-v31", + "new_content_count_background.xml", + "shape", + "solid", + "android:color", + "@android:color/system_accent1_100" + ) + patchXmlFile( + "drawable", + "drawable-v31", + "new_content_count_background_cairo.xml", + "shape", + "solid", + "android:color", + "@android:color/system_accent1_100" + ) + patchXmlFile( + "layout", + "layout-v31", + "new_content_count.xml", + "TextView", + null, + "android:textColor", + "@android:color/system_neutral1_900" + ) +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/MaterialYouPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/MaterialYouPatch.kt index 9688864a0..c148fcb4d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/MaterialYouPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/MaterialYouPatch.kt @@ -1,14 +1,13 @@ package app.revanced.patches.youtube.layout.theme import app.revanced.patcher.patch.resourcePatch +import app.revanced.patches.shared.materialyou.baseMaterialYou import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.patch.PatchList.MATERIALYOU import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusTheme import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.util.copyXmlNode -import org.w3c.dom.Element -import java.nio.file.Files @Suppress("unused") val materialYouPatch = resourcePatch( @@ -24,117 +23,7 @@ val materialYouPatch = resourcePatch( ) execute { - fun patchXmlFile( - fromDir: String, - toDir: String, - xmlFileName: String, - parentNode: String, - targetNode: String? = null, - attribute: String, - newValue: String - ) { - val resourceDirectory = get("res") - val fromDirectory = resourceDirectory.resolve(fromDir) - val toDirectory = resourceDirectory.resolve(toDir) - - if (!toDirectory.isDirectory) Files.createDirectories(toDirectory.toPath()) - - val fromXmlFile = fromDirectory.resolve(xmlFileName) - val toXmlFile = toDirectory.resolve(xmlFileName) - - if (!fromXmlFile.exists()) { - return - } - - if (!toXmlFile.exists()) { - Files.copy( - fromXmlFile.toPath(), - toXmlFile.toPath() - ) - } - - document("res/$toDir/$xmlFileName").use { document -> - val parentList = document.getElementsByTagName(parentNode).item(0) as Element - - if (targetNode != null) { - for (i in 0 until parentList.childNodes.length) { - val node = parentList.childNodes.item(i) as? Element ?: continue - - if (node.nodeName == targetNode && node.hasAttribute(attribute)) { - node.getAttributeNode(attribute).textContent = newValue - } - } - } else { - if (parentList.hasAttribute(attribute)) { - parentList.getAttributeNode(attribute).textContent = newValue - } - } - } - } - - patchXmlFile( - "drawable", - "drawable-night-v31", - "new_content_dot_background.xml", - "shape", - "solid", - "android:color", - "@android:color/system_accent1_100" - ) - patchXmlFile( - "drawable", - "drawable-night-v31", - "new_content_dot_background_cairo.xml", - "shape", - "solid", - "android:color", - "@android:color/system_accent1_100" - ) - patchXmlFile( - "drawable", - "drawable-v31", - "new_content_dot_background.xml", - "shape", - "solid", - "android:color", - "@android:color/system_accent1_200" - ) - patchXmlFile( - "drawable", - "drawable-v31", - "new_content_dot_background_cairo.xml", - "shape", - "solid", - "android:color", - "@android:color/system_accent1_200" - ) - patchXmlFile( - "drawable", - "drawable-v31", - "new_content_count_background.xml", - "shape", - "solid", - "android:color", - "@android:color/system_accent1_100" - ) - patchXmlFile( - "drawable", - "drawable-v31", - "new_content_count_background_cairo.xml", - "shape", - "solid", - "android:color", - "@android:color/system_accent1_100" - ) - patchXmlFile( - "layout", - "layout-v31", - "new_content_count.xml", - "TextView", - null, - "android:textColor", - "@android:color/system_neutral1_900" - ) + baseMaterialYou() copyXmlNode("youtube/materialyou/host", "values-v31/colors.xml", "resources") diff --git a/patches/src/main/resources/music/materialyou/host/values-v31/colors.xml b/patches/src/main/resources/music/materialyou/host/values-v31/colors.xml new file mode 100644 index 000000000..16d8f326d --- /dev/null +++ b/patches/src/main/resources/music/materialyou/host/values-v31/colors.xml @@ -0,0 +1,20 @@ + + + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + diff --git a/patches/src/main/resources/music/theme/drawable/revanced_header_gradient.xml b/patches/src/main/resources/music/theme/drawable/revanced_header_gradient.xml new file mode 100644 index 000000000..f024c86f5 --- /dev/null +++ b/patches/src/main/resources/music/theme/drawable/revanced_header_gradient.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file From 1ec68183d6be5bfd246a281805fb77e70026e92d Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:35:56 +0900 Subject: [PATCH 57/65] feat(YouTube Music - Navigation bar components): Change default value of `Enable black navigation bar` to off --- .../java/app/revanced/extension/music/settings/Settings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java index 75c636200..0bd1fd28b 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java @@ -117,7 +117,7 @@ public class Settings extends BaseSettings { // PreferenceScreen: Navigation bar - public static final BooleanSetting ENABLE_BLACK_NAVIGATION_BAR = new BooleanSetting("revanced_enable_black_navigation_bar", TRUE); + public static final BooleanSetting ENABLE_BLACK_NAVIGATION_BAR = new BooleanSetting("revanced_enable_black_navigation_bar", FALSE); public static final BooleanSetting HIDE_NAVIGATION_HOME_BUTTON = new BooleanSetting("revanced_hide_navigation_home_button", FALSE, true); public static final BooleanSetting HIDE_NAVIGATION_SAMPLES_BUTTON = new BooleanSetting("revanced_hide_navigation_samples_button", FALSE, true); public static final BooleanSetting HIDE_NAVIGATION_EXPLORE_BUTTON = new BooleanSetting("revanced_hide_navigation_explore_button", FALSE, true); From ec0107d6aefa6a3eeaf48b9141a89bd291c52a38 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:37:21 +0900 Subject: [PATCH 58/65] fix(YouTube Music - Player components): `Restore old comments popup panels` not working on YouTube Music 7.25.53 --- .../patches/music/player/components/Fingerprints.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt index ea0046e1b..bf5204063 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt @@ -11,6 +11,7 @@ import app.revanced.patches.music.utils.resourceid.miniPlayerViewPager import app.revanced.patches.music.utils.resourceid.playerViewPager import app.revanced.patches.music.utils.resourceid.remixGenericButtonSize import app.revanced.patches.music.utils.resourceid.tapBloomView +import app.revanced.util.containsLiteralInstruction import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction @@ -50,10 +51,11 @@ internal val engagementPanelHeightFingerprint = legacyFingerprint( ), parameters = emptyList(), customFingerprint = { method, _ -> - method.indexOfFirstInstruction { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "booleanValue" - } >= 0 + method.containsLiteralInstruction(1) && + method.indexOfFirstInstruction { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.name == "booleanValue" + } >= 0 } ) From 8817c86306e7626d08c58a45bb6e9e701313b24d Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:38:48 +0900 Subject: [PATCH 59/65] fix(YouTube - Settings): No line break characters are used. --- .../src/main/resources/youtube/settings/host/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index d60cd55a4..3b0b6825a 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -929,7 +929,7 @@ Settings → Autoplay → Autoplay next video" Enter fullscreen mode when video starts "Enter fullscreen mode when the video starts. -Limitation: Does not work if the player is minimized, in PiP mode, or in the background. +Limitation: Does not work if the player is minimized, in PiP mode, or in the background." Do not enter fullscreen mode when the video starts. Exit fullscreen mode at end of video Disabled From daf4d1df1608682405da4ff7cdc62a31ea940ef2 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:39:00 +0900 Subject: [PATCH 60/65] feat(Translations): Update translation --- .../music/translations/es-rES/strings.xml | 5 ++ .../music/translations/ja-rJP/strings.xml | 14 +++ .../music/translations/ko-rKR/strings.xml | 3 - .../music/translations/pl-rPL/strings.xml | 9 +- .../music/translations/pt-rBR/strings.xml | 11 +++ .../music/translations/ru-rRU/strings.xml | 7 ++ .../music/translations/uk-rUA/strings.xml | 9 +- .../music/translations/vi-rVN/strings.xml | 13 ++- .../youtube/translations/ar/strings.xml | 4 +- .../youtube/translations/el-rGR/strings.xml | 4 +- .../youtube/translations/es-rES/strings.xml | 4 +- .../youtube/translations/fr-rFR/strings.xml | 28 ++++++ .../youtube/translations/it-rIT/strings.xml | 4 +- .../youtube/translations/ja-rJP/strings.xml | 89 ++++++++++++------- .../youtube/translations/ko-rKR/strings.xml | 19 ++-- .../youtube/translations/pl-rPL/strings.xml | 4 +- .../youtube/translations/pt-rBR/strings.xml | 40 +++++++++ .../youtube/translations/ru-rRU/strings.xml | 31 +++++++ .../youtube/translations/uk-rUA/strings.xml | 4 +- .../youtube/translations/vi-rVN/strings.xml | 10 +-- .../youtube/translations/zh-rTW/strings.xml | 4 +- 21 files changed, 244 insertions(+), 72 deletions(-) diff --git a/patches/src/main/resources/music/translations/es-rES/strings.xml b/patches/src/main/resources/music/translations/es-rES/strings.xml index 1d014b9ec..a6d0ee1c7 100644 --- a/patches/src/main/resources/music/translations/es-rES/strings.xml +++ b/patches/src/main/resources/music/translations/es-rES/strings.xml @@ -378,6 +378,11 @@ Toca para ver cómo crear una clave de API." Si este video se detecta durante la reproducción, será redireccionado a la canción original. Se usa una instancia redireccionada, pero la API puede no estar disponible en algunas regiones." + Tipo de redirección + Especifica cómo redirigir a la canción oficial. + Redirigir + Interruptor de Audio / Video + Mantén pulsado el interruptor de Audio / Video Activar registro de depuración Imprime el registro de depuración. Incluir búfer en registro de depuración diff --git a/patches/src/main/resources/music/translations/ja-rJP/strings.xml b/patches/src/main/resources/music/translations/ja-rJP/strings.xml index 5b125cea7..ffea0491d 100644 --- a/patches/src/main/resources/music/translations/ja-rJP/strings.xml +++ b/patches/src/main/resources/music/translations/ja-rJP/strings.xml @@ -369,6 +369,13 @@ API キーの発行方法については、ここをタップしてください Cairo スプラッシュアニメーションを無効にする アプリ起動時のCairo のスプラッシュアニメーションを無効にします。 DRCオーディオを無効にする + 音声に適用されるDRC (Dynamic Range Compression) を無効にします。 + アルバム内のミュージックビデオを無効にする + "非プレミアムユーザーがアルバムに含まれる曲を再生すると、公式の楽曲でなくMVが再生されることがあります。 + +アルバムからMVの再生が検出された場合、公式の楽曲を検索します。 + +• Piped Instance APIを利用しています。" デバッグログ デバッグログを出力します。 デバッグバッファログを有効化 @@ -392,7 +399,14 @@ API キーの発行方法については、ここをタップしてください • OPUSオーディオコーデックはサポートされていない可能性があります。 • シークバーのサムネイルが表示されない場合があります。 • 再生履歴はブランドアカウントでは動作しません。" + 既定のクライアント + Android Music 4.27.53 + Android Music 5.29.53 + iOS Music 6.21 + ストリーミングデータを偽装 + 既定のクライアント Android VR + Android Music 共有リンクのクリーンアップ リンクを共有する際に、URL からトラッキングクエリパラメーターを削除します。 「デフォルトで開く」の設定 diff --git a/patches/src/main/resources/music/translations/ko-rKR/strings.xml b/patches/src/main/resources/music/translations/ko-rKR/strings.xml index 11178e9ff..c54c2a638 100644 --- a/patches/src/main/resources/music/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/music/translations/ko-rKR/strings.xml @@ -384,11 +384,8 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요." • 파이핑된 인스턴스 API로 구동됩니다." 리다이렉션 유형 공식 음원으로 리다이렉션하는 방법을 지정할 수 있습니다. - 리다이렉션 (대기목록 해제) 리다이렉션 - \'노래↔동영상\' 토글 누르기 (대기목록 해제) \'노래↔동영상\' 토글 누르기 - \'노래↔동영상\' 토글 길게 누르기 (대기목록 해제) \'노래↔동영상\' 토글 길게 누르기 디버그 로깅 활성화 디버그 로그를 출력합니다. diff --git a/patches/src/main/resources/music/translations/pl-rPL/strings.xml b/patches/src/main/resources/music/translations/pl-rPL/strings.xml index e31bbae86..7def1c10f 100644 --- a/patches/src/main/resources/music/translations/pl-rPL/strings.xml +++ b/patches/src/main/resources/music/translations/pl-rPL/strings.xml @@ -378,9 +378,14 @@ Kliknij, by zobaczyć, jak zgłosić klucz API." Wyłącz teledyski w albumach "Gdy użytkownik non-premium odtwarza utwór zawarty w albumie, czasami zamiast oficjalnego utworu, odtwarzany jest teledysk. -W przypadku wykrycia odtwarzania teledysku zawartego w albumie, następuje przekierowanie do oficjalnego utworu. +Opcja znajduje oficjalny utwór, jeśli wykryje odtwarzanie teledysku z albumu. -Używana jest instancja Piped, a interfejs API może nie być dostępny w niektórych regionach." +• Obsługiwane przez Piped Instance API." + Typ przekierowania + Określa, w jaki sposób przekierowuje do oficjalnego utworu + Przekieruj + Kliknij przełącznik utwór-teledysk + Kliknij i przytrzymaj przełącznik utwór-teledysk Włącz logowanie debugowania Wyświetla log od debugowania. Logi do debugowania buforu diff --git a/patches/src/main/resources/music/translations/pt-rBR/strings.xml b/patches/src/main/resources/music/translations/pt-rBR/strings.xml index 9fbde53af..2b97da865 100644 --- a/patches/src/main/resources/music/translations/pt-rBR/strings.xml +++ b/patches/src/main/resources/music/translations/pt-rBR/strings.xml @@ -375,6 +375,17 @@ Clique para ver como emitir uma chave de API." Desabilita a animação inicial do Cairo quando o aplicativo é iniciado. Desativar áudio DRC Desativa o DRC (Compressão de faixa dinâmica) aplicada ao áudio. + Desativar vídeo da música no álbum + "Quando um usuário não premium toca uma música incluída em um álbum, o videoclipe às vezes é tocado em vez da música oficial. + +Encontre a música oficial se um videoclipe for detectado tocando de um álbum. + +• Desenvolvido pela API de instância do Piped." + Tipo de redirecionamento + Especifica como redirecionar para a música oficial. + Redirecionar + Tocar alternador de Áudio / Vídeo + Tocar e segurar alternador de Áudio / Vídeo Ativar o relatório de depuração Imprime o relatório de depuração Ativar o registro de depuração do buffer diff --git a/patches/src/main/resources/music/translations/ru-rRU/strings.xml b/patches/src/main/resources/music/translations/ru-rRU/strings.xml index 81522a725..4ecd962a8 100644 --- a/patches/src/main/resources/music/translations/ru-rRU/strings.xml +++ b/patches/src/main/resources/music/translations/ru-rRU/strings.xml @@ -372,6 +372,12 @@ Отключает анимацию Кайро при запуске приложения. Отключить DRC аудио Выключает DRC (сжатие динамического диапазона), применяемого к аудио. + Отключить музыкальные видео в альбоме + "Когда пользователь без премиума воспроизводит песню из альбома, иногда вместо официальной песни воспроизводится музыкальное видео. + +Если будет обнаружено воспроизведение музыкального видео, будет перенаправлено на официальную песню. + +• Используется \"Piped Instance\", но в некоторых регионах API может быть недоступен." Ведение журнала отладки Выводит журнал отладки. Ведение журналов отладки буфера @@ -419,6 +425,7 @@ Показывать в \"Статистике для сисадминов\" Показывает клиент, используемый для получения потоковых данных в Статистике для сисадминов. Android VR + Android Music Подчищать ссылки Убирает параметры отслеживания запросов из адресов при отправке ссылки. Открыть настройки по умолчанию diff --git a/patches/src/main/resources/music/translations/uk-rUA/strings.xml b/patches/src/main/resources/music/translations/uk-rUA/strings.xml index 97bace25a..5266c6e64 100644 --- a/patches/src/main/resources/music/translations/uk-rUA/strings.xml +++ b/patches/src/main/resources/music/translations/uk-rUA/strings.xml @@ -378,9 +378,14 @@ Вимкнути музичні відео в альбомі "Коли користувач без преміуму відтворює пісню з альбому, іноді замість офіційної пісні відтворюється музичне відео. -Якщо буде виявлено відтворення музичного відео, буде перенаправлено на офіційну пісню. +Знайти офіційну пісню, якщо виявлено музичне відео з альбому. -Використовується \"piped instance\", але API може бути недоступним у деяких регіонах." +• На базі Piped Instance API." + Тип перенаправлення + Визначає спосіб перенаправлення до офіційної пісні. + Перенаправлення + Натиснення перемикача \"пісня | відео\" + Натиснення та утримання перемикача \"пісня | відео\" Увімкнути протоколи налагодження Виводить протокол налагодження. Увімкнути ведення журналу буфера налагодження diff --git a/patches/src/main/resources/music/translations/vi-rVN/strings.xml b/patches/src/main/resources/music/translations/vi-rVN/strings.xml index 5e9ea73ce..018f9d3dc 100644 --- a/patches/src/main/resources/music/translations/vi-rVN/strings.xml +++ b/patches/src/main/resources/music/translations/vi-rVN/strings.xml @@ -172,8 +172,8 @@ Hạn chế: Giả mạo phiên bản ứng dụng "Giả mạo phiên bản YouTube Music hiện tại thành phiên bản cũ. -Lưu ý:\n- Tuỳ chọn này sẽ thay đổi giao diện ứng dụng, tuy nhiên có thể xảy ra các sự cố chưa xác định khác. -- Nếu tắt tuỳ chọn này sau đó, giao diện cũ có thể vẫn tồn tại cho đến khi bạn xoá dữ liệu ứng dụng." +• Tuỳ chọn này sẽ làm thay đổi giao diện của ứng dụng, tuy nhiên có thể xảy ra các sự cố chưa xác định khác. +• Nếu tắt tuỳ chọn này sau đó, giao diện cũ có thể vẫn tồn tại cho đến khi bạn xoá dữ liệu ứng dụng." Phiên bản giả mạo Chọn phiên bản YouTube Music mà bạn muốn giả mạo. 4.27.53 - Tắt chế độ Đài phát ở một số vùng của Canada @@ -378,9 +378,14 @@ Nhấp vào đây để xem các bước phát hành khóa API." Tắt video âm nhạc trong đĩa nhạc "Khi người dùng không mua gói Premium, đôi khi nghe nhạc có trong đĩa nhạc, video âm nhạc được phát thay vì bài hát chính thức. -Nếu trường hợp đó xẩy ra, ứng dụng sẽ chuyển hướng đến bài hát chính thức. +Trong trường hợp đó, hệ thống sẽ tìm và chuyển hướng tới bài hát chính thức. -Phiên bản Piped được sử dụng và API có thể không khả dụng ở một số khu vực." +• Được hỗ trợ bởi API của Piped Instance." + Kiểu chuyển hướng + Xác định cách chuyển tới bài hát chính thức. + Chuyển hướng + Nhấn vào nút chuyển đổi giữa Bài hát và Video + Nhấn và giữ nút chuyển đổi giữa Bài hát và Video Nhật ký gỡ lỗi Bật ghi nhật ký gỡ lỗi. Bật nhật ký bộ đệm gỡ lỗi diff --git a/patches/src/main/resources/youtube/translations/ar/strings.xml b/patches/src/main/resources/youtube/translations/ar/strings.xml index 3c502fb8f..1de084fcb 100644 --- a/patches/src/main/resources/youtube/translations/ar/strings.xml +++ b/patches/src/main/resources/youtube/translations/ar/strings.xml @@ -862,9 +862,9 @@ تم تعطيل لوحة المشاركة. تم تمكين لوحة المشاركة. الدخول إلى وضع ملء الشاشة عند بدء تشغيل الفيديو - الدخول إلى وضع ملء الشاشة عند بدء تشغيل الفيديو. + "الدخول إلى وضع ملء الشاشة عند بدء تشغيل الفيديو. -القيود: لا يعمل إذا تم تصغير المشغل أو في وضع صورة داخل صورة أو في الخلفية. +القيود: لا يعمل إذا تم تصغير المشغل أو في وضع صورة داخل صورة أو في الخلفية." لا تدخل وضع ملء الشاشة عند بدء تشغيل الفيديو. الخروج من وضع ملء الشاشة في نهاية الفيديو معطَّل diff --git a/patches/src/main/resources/youtube/translations/el-rGR/strings.xml b/patches/src/main/resources/youtube/translations/el-rGR/strings.xml index cfcf3695e..3566bd07a 100644 --- a/patches/src/main/resources/youtube/translations/el-rGR/strings.xml +++ b/patches/src/main/resources/youtube/translations/el-rGR/strings.xml @@ -860,9 +860,9 @@ Playlists Ο πίνακας αλληλεπίδρασης είναι απενεργοποιημένος. Ο πίνακας αλληλεπίδρασης είναι ενεργοποιημένος. Άνοιγμα των βίντεο σε λειτουργία πλήρους οθόνης - Γίνεται εισαγωγή σε πλήρη οθόνη κατά την έναρξη των βίντεο. + "Γίνεται εισαγωγή σε πλήρη οθόνη κατά την έναρξη των βίντεο. -Περιορισμός: Δεν ισχύει αν το βίντεο είναι ελαχιστοποιημένο, σε λειτουργία PiP, ή στο παρασκήνιο. +Περιορισμός: Δεν ισχύει αν το βίντεο είναι ελαχιστοποιημένο, σε λειτουργία PiP, ή στο παρασκήνιο." Δεν γίνεται εισαγωγή σε πλήρη οθόνη κατά την έναρξη των βίντεο. Έξοδος από τη λειτουργία πλήρους οθόνης στο τέλος του βίντεο Απενεργοποιημένο diff --git a/patches/src/main/resources/youtube/translations/es-rES/strings.xml b/patches/src/main/resources/youtube/translations/es-rES/strings.xml index ed5850775..cfbb1cdbb 100644 --- a/patches/src/main/resources/youtube/translations/es-rES/strings.xml +++ b/patches/src/main/resources/youtube/translations/es-rES/strings.xml @@ -861,9 +861,9 @@ La reproducción automática se puede cambiar en la configuración de YouTube: El panel de interacción está desactivado. El panel de interacción está activado. Entrar en modo de pantalla completa cuando se inicia el vídeo - Entra en modo de pantalla completa cuando se inicia el vídeo. + "Entra en modo de pantalla completa cuando se inicia el vídeo. -Limitación: No funciona si el reproductor está minimizado, en modo PiP o en segundo plano. +Limitación: No funciona si el reproductor está minimizado, en modo PiP o en segundo plano." No entra en modo de pantalla completa cuando se inicia el vídeo. Salir del modo de pantalla completa al final del vídeo Desactivado diff --git a/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml b/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml index 6c5550a96..c541557a9 100644 --- a/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml +++ b/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml @@ -862,6 +862,16 @@ La lecture automatique peut être modifiée dans les paramètres de YouTube : Désactiver description en plein écran La description en plein écran est désactivée. La description en plein écran est activée. + Passer en mode plein écran au démarrage de la vidéo + "\"Passer en mode plein écran lorsque la vidéo démarre. + +Limitation : Ne fonctionne pas si le lecteur est minimisé, en mode PiP ou en arrière-plan." + Ne pas passer en mode plein écran au démarrage de la vidéo. + Quitter le mode plein écran à la fin de la vidéo + Désactivé + Portrait + Paysage + Portrait et paysage Afficher la section titre de la vidéo "Affiche la section du titre de la vidéo en plein écran. @@ -1426,7 +1436,11 @@ Pas de marges en haut et en bas du lecteur." Affiche l\'ancienne interface de qualité vidéo. Masque la nouvelle interface de qualité vidéo. Désactiver la vitesse de lecture pour la musique + La vitesse de lecture par défaut est activée pour la musique. La vitesse de lecture par défaut est activée pour la musique. + Valider en utilisant les catégories + La vitesse de lecture par défaut est désactivée si la catégorie de la vidéo est Musique. + La vitesse de lecture par défaut est désactivée pour les vidéos lues sur YouTube Music. Activ. vitesses de lecture shorts par défaut La vitesse de lecture par défaut s\'applique aux Shorts. La vitesse de lecture par défaut ne s\'applique pas aux Shorts. @@ -1772,7 +1786,21 @@ Cliquez sur le bouton Continuer et autorisez les modifications d'optimisations." "Les données de lecture en direct ne sont pas falsifiées. La lecture vidéo peut ne pas fonctionner." Désactiver ce paramètre peut entraîner des problèmes de lecture vidéo. Client par défaut + "Android TV +(Connexion requise)" + Android VR + "iOS +(PoToken requis)" + "iOS TV +(Connexion requise)" Effets inconnus de la falsification + "• Le menu 'piste audio' n'est pas disponible. +• Le volume stable n'est pas disponible. +• La désactivation forcée des pistes audio automatiques n'est pas disponible. +• Les vidéos pour enfants peuvent ne pas être lues en cas de déconnexion ou en mode incognito." + • Il peut y avoir des problèmes de lecture (PoToken required). + "• Les films ou vidéos payantes peut ne pas être lus. +• Les vidéos pour enfants peuvent ne pas être lues en cas de déconnexion ou en mode incognito." Forcer le codec AVC de iOS (H.264) Le codec vidéo est forcé sur AVC (H.264). Le codec vidéo est déterminé automatiquement. diff --git a/patches/src/main/resources/youtube/translations/it-rIT/strings.xml b/patches/src/main/resources/youtube/translations/it-rIT/strings.xml index 448e09e95..73d0687d0 100644 --- a/patches/src/main/resources/youtube/translations/it-rIT/strings.xml +++ b/patches/src/main/resources/youtube/translations/it-rIT/strings.xml @@ -864,9 +864,9 @@ Impostazioni → Riproduzione automatica → Telefono cellulare/tablet" Il pannello di coinvolgimento è disattivato. Il pannello di coinvolgimento è attivato. Passa a schermo intero all\'avvio dei video - Passa a schermo intero all\'avvio dei video. + "Passa a schermo intero all'avvio dei video. -Nota: non funziona se il riproduttore è minimizzato, in modalità PiP o in background. +Nota: non funziona se il riproduttore è minimizzato, in modalità PiP o in background." Non passa a schermo intero all\'avvio dei video. Esci da schermo intero alla fine dei video Disattivato diff --git a/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml b/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml index c70fce9f4..99828dab3 100644 --- a/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml +++ b/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml @@ -56,9 +56,9 @@ プレーヤーと動画の説明の間に表示される YouTube Premium のバナーを非表示にします。 代替サムネイル - [ホーム]タブ - [登録チャンネル]タブ - [マイページ]タブ + [ホーム] タブ + [登録チャンネル] タブ + [マイページ] タブ 再生リスト、おすすめ 検索結果 オリジナルサムネイル @@ -66,7 +66,7 @@ DeArrow & 静止画サムネイル 静止画サムネイル DeArrow - "DeArrow は、YouTube 動画のサムネイルをクラウドソーシングで提供する機能です。DeArrow のサムネイルは、YouTube が提供するサムネイルよりも適切なことが多いです。 これを有効にすると、動画のURLが API サーバーに送信されますが、他のデータは送信されません。 動画に DeArrow サムネイルがない場合は、オリジナルまたは静止画サムネイルが表示されます。 + "DeArrow は、YouTube 動画のサムネイルをクラウドソーシングで提供する機能です。DeArrow のサムネイルは、YouTube が提供するサムネイルよりも適切なことが多いです。これを有効にすると、動画のURLが API サーバーに送信されますが、他のデータは送信されません。動画に DeArrow サムネイルがない場合は、オリジナルまたは静止画サムネイルが表示されます。 DeArrow の詳細については、ここをタップしてください。" API が利用できない場合にトーストを表示 @@ -98,12 +98,12 @@ DeArrow の詳細については、ここをタップしてください。"アーティストの概要欄の下部に表示されるアルバムカードを非表示にします。 おすすめ欄を非表示 "以下の欄を非表示にします: -• ニュース速報 -• 続きを見る -• もう一度見る -• もう一度聴く -• 他のチャンネルを探す -• ショッピング" +・ニュース速報 +・続きを見る +・もう一度見る +・もう一度聴く +・他のチャンネルを探す +・ショッピング" チップ欄を非表示 フィードに表示される、似ている動画のチップ欄を非表示にします。 フィードに表示される、似ている動画のチップ欄を非表示にします。 @@ -237,9 +237,9 @@ DeArrow の詳細については、ここをタップしてください。""ホーム / 登録チャンネル / 検索結果 は、キーワードやフレーズに一致するコンテンツを非表示にするようにフィルタリングされます。 注意: -• 一部のショート動画は非表示にならない場合があります。 -• 一部の UI コンポーネントは非表示にならない場合があります。 -• キーワードで検索しても結果が表示されない場合があります。" +・一部のショート動画は非表示にならない場合があります。 +・一部の UI コンポーネントは非表示にならない場合があります。 +・キーワードで検索しても結果が表示されない場合があります。" 単語全体を一致させる キーワードやフレーズを二重引用符 (\" \") で囲むことで、動画のタイトルやチャンネル名の部分一致を防ぐことができます。<br><br>例えば、<br><b>\"ai\"</b> とすると、動画 <b>「AI はどのように機能するのか?」</b><br> は表示されなくなりますが、<b>「フェアユースとは何か? (What does f“ai”r use mean?) 」</b> は表示されます。 無効なキーワードです。\'%s\' はフィルターとして使用できません @@ -252,9 +252,9 @@ DeArrow の詳細については、ここをタップしてください。"おすすめ動画を非表示 "以下のおすすめ動画を非表示にします: -• 「メンバーシップ限定」タグの付いた動画 -• 動画の下部に「他のユーザーも視聴しています」などのフレーズがある動画 -• 登録していないチャンネルからアップロードされた、再生回数が 1,000 回未満の動画" +・「メンバーシップ限定」タグの付いた動画 +・動画の下部に「他のユーザーも視聴しています」などのフレーズがある動画 +・登録していないチャンネルからアップロードされた、再生回数が 1,000 回未満の動画" 再生回数が少ない動画を非表示 登録していないチャンネルからアップロードされた、再生回数が 1,000 回未満の動画をホームフィードから非表示にします。 @@ -279,7 +279,7 @@ DeArrow の詳細については、ここをタップしてください。""ホーム / 登録チャンネル / 検索結果はフィルタリングされ、設定した値よりも少ない再生回数の動画を非表示にします。 注意: -・ショート動画は非表示にできません。 +・ショートは非表示にできません。 ・再生回数が 0 の動画はフィルタリングされません。" 関連動画を非表示 ホームフィードから関連動画を非表示にします。 @@ -859,6 +859,16 @@ DeArrow の詳細については、ここをタップしてください。"エンゲージメントパネルを無効化 エンゲージメントパネルを無効化します。 エンゲージメントパネルを無効化します。 + 動画開始時に全画面表示を開始 + "動画の再生開始時に全画面表示に切り替えます。 + +注意: ミニプレーヤーで再生している、ピクチャーインピクチャーモードになっている、またはバックグラウンド再生をしている場合は動作しません。" + 動画の再生開始時に全画面表示に切り替えます。\n\n注意: ミニプレーヤーで再生している、ピクチャーインピクチャーモードになっている、またはバックグラウンド再生をしている場合は動作しません。 + 動画終了時に全画面表示を終了 + 無効 + 縦向きの動画のみ + 横向きの動画のみ + 縦向きの動画と横向きの動画 タイトル欄を表示 "全画面表示時にタイトルを表示します。 @@ -1105,8 +1115,8 @@ DeArrow の詳細については、ここをタップしてください。"概要欄の操作を無効化 "概要欄が展開されている場合、以下のインタラクションを無効にします: -• タップしてスクロールする。 -• タップしたままテキストを選択する。" +• タップしてスクロール +• タップしたままテキストを選択" 概要欄を自動で展開 概要欄を自動で展開します。 概要欄を自動で展開します。 @@ -1421,16 +1431,20 @@ DeArrow の詳細については、ここをタップしてください。"古いスタイルの画質設定メニューを復活させます。 古いスタイルの画質設定メニューを復活させます。 音楽再生時にデフォルトの再生速度を無効化 + 音楽を再生する際に「デフォルトの再生速度」で設定した再生速度を無効化します。 音楽を再生する際に、「デフォルトの再生速度」で設定した再生速度を無効化します。\n\n注意: この設定は、「YouTube Music で聴く」バナーが表示されている動画にのみ適用されます。 + 自動的にデフォルトの再生速度を無効化 + 動画のカテゴリが「音楽」の場合、デフォルトの再生速度を無効にします。 + 動画のカテゴリが「音楽」の場合、デフォルトの再生速度を無効にします。 ショートのデフォルト再生速度を有効化 デフォルトの再生速度をショートに適用します。 デフォルトの再生速度をショートに適用します。 プリロードバッファをスキップしました。 プリロードバッファをスキップ - "動画開始時に予め読み込まれたバッファをスキップして、デフォルトの画質強制の遅延を回避します。 + "動画開始時に予め読み込まれたバッファをスキップして、デフォルトの画質を即座に適用します。 注意: -・動画開始時に約 0.3 秒の遅延が発生しますが、デフォルトの画質はすぐに適用されます。 +・動画開始時に約 0.3 秒の遅延が発生します。 ・HDR 動画、ライブ配信、15 秒未満の動画には適用されません。" この設定をオンにした場合、バッファリングの問題が発生する可能性があります。 スキップ時にトーストを表示 @@ -1443,16 +1457,15 @@ DeArrow の詳細については、ここをタップしてください。""VP9 コーデックを無効化します。 注意: -• 最大解像度は 1080p です。 -• 動画を再生する際には VP9 コーデックよりも多くの通信量を消費します。 -• HDR 再生を可能にするために、HDR 動画では引き続き VP9 コーデックが使用されます。" - VP9 コーデックを無効化します。\n\n注意: \n -• 最大解像度は 1080p です。\n• 動画を再生する際には VP9 コーデックよりも多くの通信量を消費します。\n • HDR 再生を可能にするために、HDR 動画では引き続き VP9 コーデックが使用されます。 +・最大解像度は 1080p です。 +・動画を再生する際には VP9 コーデックよりも多くの通信量を消費します。 +・HDR 再生を可能にするために、HDR 動画では引き続き VP9 コーデックが使用されます。" + VP9 コーデックを無効化します。\n\n注意: \n・最大解像度は 1080p です。\n・動画を再生する際には VP9 コーデックよりも多くの通信量を消費します。\n・HDR 再生を可能にするために、HDR 動画では引き続き VP9 コーデックが使用されます。 AV1 コーデックを置換 AV1 コーデックを VP9 コーデックに置き換えます。 AV1 コーデックの応答を拒否 "AV1 コーデック応答を強制的に拒否します。 -約20秒間のバッファリングの後、異なるコーデックに切り替わります。" +約 20 秒間のバッファリングの後、異なるコーデックに切り替わります。" フォールバック処理で約20秒のバッファリングが発生します。 デフォルトの再生速度を %s に変更しました。 モバイルネットワーク使用時のデフォルト画質を %s に変更しました。 @@ -1769,7 +1782,21 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に "ストリーミングデータを偽装していない場合、動画の再生ができない可能性があります。" この設定をオフにした場合、バッファリングの問題が発生する可能性があります。 偽装するクライアントの種類 + "Android TV +(Google アカウントへのログインが必要)" + Android VR + "iOS +(PoToken が必要)" + "iOS TV +(Google アカウントへのログインが必要)" ストリーミングデータを偽装することによる副作用 + "・「音声トラック」メニューは表示されません。 +・「一定音量」は使用できません。 +・「音声トラックの強制を無効化」は利用できません。 +・ログインをしていない or シークレットモードを有効化している場合、子供向け動画は再生できない可能性があります。" + ・動画が再生できない可能性があります(PoToken が必要です)。 + "・映画や有料動画は再生できない可能性があります。 +・ログインをしていない or シークレットモードを有効化している場合、子供向け動画は再生できない可能性があります。" iOS クライアントで AVC (H.264) を強制 iOS クライアントで AVC (H.264) を強制します。 iOS クライアントで AVC (H.264) を強制します。 @@ -1804,10 +1831,10 @@ iOS クライアント選択する場合は、これらの値が必要になる ドメインを置換 再生履歴をブロック 再生履歴のステータス - • 再生履歴をブロックします。 - • Google アカウントの再生履歴の設定に従います。 - "• Google アカウントの再生履歴の設定に従います。 -• DNS や VPN が原因で再生履歴が動作しない可能性があります。" + ・再生履歴をブロックします。 + ・Google アカウントの再生履歴の設定に従います。 + "・Google アカウントの再生履歴の設定に従います。 +・DNS や VPN が原因で再生履歴が動作しない可能性があります。" パッチ情報 diff --git a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml index 525f7005e..872936ec9 100644 --- a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml @@ -433,7 +433,7 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 드래그 & 드롭 활성화하기 "드래그 & 드롭을 활성화합니다. • 미니 플레이어를 화면 구석으로 드래그 할 수 있습니다." - 드래그 & 드롭을 비활성화합니다.\n• YouTube v19.44.39 에서는 드래그 & 드롭을 비활성화한 상태에서 모던 스타일 1, 2, 3을 사용하면, 미니 플레이어 상태에서 \'위로 스와이프하여 화면 펼치기\'와 \'아래로 스와이프하여 화면 닫기\'를 사용할 수 없습니다.\n• YouTube v19.16.39 에서는 위에 설명된 기능은 전부 사용할 수는 있지만, 드래그 & 드롭 기능이 지원되지 않습니다. + 드래그 & 드롭을 비활성화합니다.\n• YouTube v19.44.39 에서는 드래그 & 드롭을 비활성화하고 모던 스타일 1, 2, 3을 사용하면, 미니 플레이어 상태에서 \'위로 스와이프하여 화면 펼치기\'와 \'아래로 스와이프하여 화면 닫기\'를 사용할 수 없습니다.\n• YouTube v19.16.39 에서는 위에 설명된 기능은 전부 사용할 수는 있지만, 드래그 & 드롭 기능이 지원되지 않습니다. 수평 드래그 제스처 활성화하기 "수평 드래그 제스처를 활성화합니다. @@ -860,10 +860,7 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 참여 패널을 비활성화합니다. 참여 패널을 활성화합니다. 동영상이 시작할 때, 전체 화면 모드로 들어가기 - 동영상이 시작할 때, 전체 화면 모드로 들어갑니다. - -알려진 문제점: -플레이어가 최소화되어 있거나 PiP 모드 또는 백그라운드 재생에 있는 경우에는 작동되지 않습니다. + "동영상이 시작할 때, 전체 화면 모드로 들어갑니다.\n\n알려진 문제점: \n• 플레이어가 최소화되어 있거나 PIP 모드 또는 백그라운드 재생에 있는 경우에는 작동되지 않습니다." 동영상이 시작할 때, 전체 화면 모드로 들어가지 않습니다. 동영상이 종료할 때, 전체 화면 모드에서 나가기 사용 안함 @@ -1402,8 +1399,8 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 플레이어 하단에서 아래로 스와이프하여 전체 화면 모드로 들어가지 않습니다. 플레이어 하단에서 아래로 스와이프하여 전체 화면 모드로 들어갑니다. 스와이프 제스처로 전체 화면 모드 전환 비활성화하기 (플레이어 내부) - 플레이어 내부에서 아래로 스와이프하여 전체 화면 모드로 들어가지 않습니다. - 플레이어 내부에서 아래로 스와이프하여 전체 화면 모드로 들어갑니다. + 플레이어 내부에서 위로 스와이프하여 전체 화면 모드로 들어가지 않습니다. + 플레이어 내부에서 위로 스와이프하여 전체 화면 모드로 들어갑니다. 스와이프 제스처로 전체 화면 모드 종료 비활성화하기 전체 화면에서 아래로 스와이프하여 전체 화면 모드를 나가지 않습니다. 전체 화면에서 아래로 스와이프하여 전체 화면 모드를 나갑니다. @@ -1795,16 +1792,16 @@ GmsCore 앱 배터리 최적화를 비활성화(제한 없음)하더라도, 배 "iOS (PoToken이 요구됨)" "iOS TV -(로그인 요구됨)" +(로그인이 요구됨)" 알려진 문제점 "• 오디오 트랙 메뉴가 표시되지 않습니다. • 안정적인 볼륨을 사용할 수 없습니다. -• 자동 오디오 트랙을 비활성화할 수 없습니다 -• 로그아웃이 되어있거나 시크릿 모드에서는 Kids 동영상이 재생되지 않을 수 있습니다. +• 자동 오디오 트랙을 비활성화할 수 없습니다. +• 사용자가 로그인을 하지 않았거나 시크릿 모드에서는 Kids 동영상이 재생되지 않을 수 있습니다. • VR은 Kids // TV는 재생목록과 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다." • 재생 문제가 발생할 수 있습니다 (PoToken이 요구됨).\n• 영화, 유료, 비공개 그리고 연령 제한 동영상에서 다른 클라이언트가 사용될 수 있습니다. "• 영화 또는 유료 동영상이 재생되지 않을 수 있습니다. -• 로그아웃이 되어있거나 시크릿 모드에서는 Kids 동영상이 재생되지 않을 수 있습니다. +• 사용자가 로그인을 하지 않았거나 시크릿 모드에서는 Kids 동영상이 재생되지 않을 수 있습니다. • 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다." iOS AVC (H.264) 강제로 활성화하기 동영상 코덱을 AVC (H.264)로 강제로 활성화합니다.\n\n• 일부 VP9 코덱 동영상에서 제거되었던 화질 값이 표시될 수 있습니다.\n• 최대 화질 값이 1080p이므로, 초고화질 동영상을 재생할 수 없습니다.\n• HDR 동영상을 재생할 수 없습니다. diff --git a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml index 565890038..02d5c762c 100644 --- a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml +++ b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml @@ -860,9 +860,9 @@ Autoodtwarzanie można zmienić w ustawieniach YouTube: Ukryty Widoczny Pełny ekran po rozpoczęciu filmu - Włączony + "Włączony -Ograniczenie: nie działa jeśli odtwarzacz jest zminimalizowany, w trybie PiP lub w tle +Ograniczenie: nie działa jeśli odtwarzacz jest zminimalizowany, w trybie PiP lub w tle" Wyłączony Wyjście z pełnego ekranu po zakończeniu filmu Wyłączone diff --git a/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml b/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml index 5b12ea37c..ac0936b66 100644 --- a/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml +++ b/patches/src/main/resources/youtube/translations/pt-rBR/strings.xml @@ -323,6 +323,9 @@ Limitação: O botão voltar na barra de ferramentas pode não funcionar."Desativar animação inicial A animação inicial está desativada. A animação do inicial está ativada. + Desativar barra de status transparente + A barra de status está opaca. + A barra de status está opaca ou transparente. Ativar tela de carregamento gradiente A tela de carregamento gradiente está ativada. A tela de carregamento gradiente está desativada. @@ -857,6 +860,16 @@ A reprodução automática pode ser alterada nas configurações do YouTube: Desativar painel de engajamento O painel de engajamento está desativado. O painel de engajamento está ativado. + Entrar no modo de tela cheia quando o vídeo iniciar + "\"Entre no modo tela cheia quando o vídeo é iniciado. + +Limitação: não funciona se o reprodutor estiver minimizado, no modo PiP ou em segundo plano." + Não entre em modo de tela cheia quando o vídeo iniciar. + Sair do modo de tela cheia ao final do vídeo + Desativado + Retrato + Paisagem + Retrato e paisagem Exibir seção de título do vídeo "Exibe a seção de título do vídeo em tela cheia. @@ -1376,6 +1389,15 @@ Sem margens na parte superior e inferior do reprodutor." Desativar deslizar para alterar o vídeo Deslizar para cima / baixo não reproduzirá o vídeo seguinte / anterior. Deslizar para cima / baixo reproduzirá o vídeo seguinte / anterior. + Desativar deslizar para entrar no modo de tela cheia (abaixo do reprodutor) + Deslizar para baixo no reprodutor não entrará no modo de tela cheia. + Deslizar para baixo no reprodutor entrará no modo de tela cheia. + Desativar deslizar para entrar no modo de tela cheia (no reprodutor) + Deslizar para cima no reprodutor não entrará no modo de tela cheia. + Deslizar para cima no reprodutor entrará no modo de tela cheia. + Desativar deslizar para sair do modo tela cheia + Deslizar para baixo na tela cheia não sairá do modo de tela cheia. + Deslizar para baixo na tela cheia sairá do modo de tela cheia. Automático Vídeo @@ -1409,7 +1431,11 @@ Sem margens na parte superior e inferior do reprodutor." O menu antigo de qualidade de vídeo está sendo exibido. O menu antigo de qualidade de vídeo não está sendo exibido. Desativar a velocidade de reprodução para música + A velocidade de reprodução padrão está desativada para música. A velocidade de reprodução padrão está ativada para música. + Validar usando categorias + A velocidade de reprodução padrão está desativada se a categoria de vídeo for Música. + A velocidade padrão de reprodução está desativada para vídeos reproduzíveis no YouTube. Ativar velocidade de reprodução padrão no Shorts A velocidade de reprodução padrão se aplica ao Shorts. A velocidade de reprodução padrão não se aplica ao Shorts. @@ -1752,7 +1778,21 @@ Toque no botão continuar e desative as otimizações da bateria." "Os dados de streaming não são falsificados. A reprodução de vídeo pode não funcionar." Desativar esta configuração pode causar problemas de reprodução de vídeo. Cliente padrão + "Android TV +(é necessário logar)" + Android VR + "iOS +(requer PoToken)" + "iOS TV +(é necessário logar)" Efeitos colaterais da falsificação + "• O menu de faixa de áudio está faltando. +• Volume estável não está disponível. +• Desativar faixas de áudio automático forçadas não estão disponíveis. +• Os vídeos para crianças podem não reproduzir quando desconectado ou em modo incógnito." + • Pode haver problemas de reprodução (PoToken necessário). + "• Filmes ou vídeos pagos podem não reproduzir. +• Os vídeos para crianças podem não ser reproduzidos quando desconectado ou em modo incógnito." Forçar iOS AVC (H.264) O codec de vídeo é forçado para AVC (H.264). O codec de vídeo é determinado automaticamente. diff --git a/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml b/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml index bf54ea768..6649a1390 100644 --- a/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml +++ b/patches/src/main/resources/youtube/translations/ru-rRU/strings.xml @@ -871,6 +871,19 @@ Shorts Панель взаимодействия Панель взаимодействия отключена. Панель взаимодействия включена. + Полноэкранный режим при запуске видео + "Полноэкранный режим при запуске видео включен. + +Не работает когда: +- плеер свернут +- картинка в картинке (PiP) +- фоновый режим." + Полноэкранный режим при запуске видео отключен. + Полноэкранный режим в конце видео + Отключено + Портретный вид + Альбомный вид + Авто поворот Секция заголовка видео "Показывает секцию заголовка видео в полноэкранном режиме. @@ -1441,7 +1454,11 @@ Shorts Старое меню качества отображено. Старое меню качества скрыто. Скорость воспроизведения для музыки + Скорость по умолчанию для категории YouTube Музыка включена. Скорость воспроизведения по умолчанию для музыки включена. + Выбирать скорость ориентируясь на категории + Скорость по умолчанию для категории YouTube Музыка отключена. + Скорость по умолчанию для категории YouTube Музыка включена. Скорость воспроизведения по умолчанию в Shorts Скорость воспроизведения по умолчанию в Shorts включена. Скорость воспроизведения по умолчанию в Shorts отключена. @@ -1787,7 +1804,21 @@ Shorts Воспроизведение видео может не работать." Отключение этой настройки вызовет проблемы с воспроизведением видео. Клиент по умолчанию + "Android TV +(Требуется вход)" + Android VR + "iOS +(Необходим PoToken)" + "iOS +(Необходим вход)" Эффекты от подмены + "• Меню аудио дорожки отсутствует. +• Стабильная громкость недоступна. +• Отключить принудительные авто звуковые дорожки недоступна. +• Детские видео не могут воспроизводиться в режиме инкогнито или выхода." + • Возможно проблемы (требуется PoToken). + "• Фильмы или платные видео могут не воспроизводиться. +• Детские видео могут не воспроизводиться при выходе из системы или в режиме инкогнито." Принудительно iOS, AVC (H.264) Принудительное использование AVC (H.264) включено. Принудительное использование AVC (H.264) отключено. diff --git a/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml b/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml index 5ca05fceb..8925f43dd 100644 --- a/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml +++ b/patches/src/main/resources/youtube/translations/uk-rUA/strings.xml @@ -861,9 +861,9 @@ Панель залучення вимкнено. Панель залучення увімкнено. Переходити у повноекранний режим при запуску відео - Переходиться у повноекранний режим при запуску відео. + "Переходиться у повноекранний режим при запуску відео. -Застереження: Не працюватиме якщо плеєр мінімізовано, у режимі PiP, чи у фоні. +Застереження: Не працюватиме якщо плеєр мінімізовано, у режимі PiP, чи у фоні." Не переходиться у повноекранний режим при запуску відео. Виходити з повноекранного режиму в кінці відео Вимкнено diff --git a/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml b/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml index 0f99ac103..0f23eab8e 100644 --- a/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml +++ b/patches/src/main/resources/youtube/translations/vi-rVN/strings.xml @@ -95,9 +95,9 @@ Nhấn vào đây để tìm hiểu thêm về DeArrow." Sử dụng máy chủ lưu trữ hình ảnh gốc.\n\nBật tính năng này có thể khắc phục tình trạng hình ảnh bị chặn ở một số khu vực. Bảng tin - Ẩn Đĩa nhạc - Đĩa nhạc đã ẩn khỏi kết quả tìm kiếm. - Đĩa nhạc được hiển thị trong kết quả tìm kiếm. + Ẩn thẻ Đĩa nhạc + Thẻ đĩa nhạc đã ẩn khỏi kết quả tìm kiếm. + Thẻ đĩa nhạc được hiển thị trong kết quả tìm kiếm. Ẩn các kệ được cá nhân hoá "Ẩn các kệ sau: @@ -864,9 +864,9 @@ Cài đặt → Tự động phát → Tự động phát video tiếp theo."Bảng tương tác đã tắt. Bảng điều khiển tương tác được bật. Vào chế độ toàn màn hình khi video bắt đầu - Vào chế độ toàn màn hình khi video bắt đầu. + "Vào chế độ toàn màn hình khi video bắt đầu. -Hạn chế: Không hoạt động nếu trình phát đang thu nhỏ, trong chế độ Hình trong hình, hoặc phát trong nền. +Hạn chế: Không hoạt động nếu trình phát đang thu nhỏ, trong chế độ Hình trong hình, hoặc phát trong nền." Không vào chế độ toàn màn hình khi video bắt đầu. Thoát chế độ màn hình khi video kết thúc Tắt diff --git a/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml b/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml index eda40a9d0..6d101351e 100644 --- a/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml +++ b/patches/src/main/resources/youtube/translations/zh-rTW/strings.xml @@ -860,9 +860,9 @@ 停用互動面板 啟用互動面板 影片開始時進入全螢幕模式 - \"影片開始時進入全螢幕模式。 + "\"影片開始時進入全螢幕模式。 -限制:如果播放器最小化、處於畫中畫模式或處於後台,則不起作用。 +限制:如果播放器最小化、處於畫中畫模式或處於後台,則不起作用。" 影片開始時請勿進入全螢幕模式。 影片結束時退出全螢幕模式 已停用 From 07d31c08e9b40920644243edbe4a2fa7a574492d Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:39:25 +0900 Subject: [PATCH 61/65] bump 5.2.1-dev.4 --- README.md | 4 +-- gradle.properties | 2 +- patches.json | 70 ++++++++++++++++++++++++++++------------- patches/api/patches.api | 14 ++++++--- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 1d83e5cd5..c9f8a3daa 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,6 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm | 💊 Patch | 📜 Description | 🏹 Target Version | |:--------:|:--------------:|:-----------------:| -| `Amoled` | Applies a pure black theme to some components. | 6.20.51 ~ 7.25.53 | | `Bitrate default value` | Sets the audio quality to 'Always High' when you first install the app. | 6.20.51 ~ 7.25.53 | | `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 6.20.51 ~ 7.25.53 | | `Certificate spoof` | Enables YouTube Music to work with Android Auto by spoofing the YouTube Music certificate. | 6.20.51 ~ 7.25.53 | @@ -89,11 +88,12 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm | `Custom branding icon for YouTube Music` | Changes the YouTube Music app icon to the icon specified in patch options. | 6.20.51 ~ 7.25.53 | | `Custom branding name for YouTube Music` | Renames the YouTube Music app to the name specified in patch options. | 6.20.51 ~ 7.25.53 | | `Custom header for YouTube Music` | Applies a custom header in the top left corner within the app. | 6.20.51 ~ 7.25.53 | +| `Dark theme` | Changes the app's dark theme to the values specified in patch options. | 6.20.51 ~ 7.25.53 | | `Disable Cairo splash animation` | Adds an option to disable Cairo splash animation. | 7.06.54 ~ 7.25.53 | | `Disable DRC audio` | Adds an option to disable DRC (Dynamic Range Compression) audio. | 6.20.51 ~ 7.25.53 | | `Disable auto captions` | Adds an option to disable captions from being automatically enabled. | 6.20.51 ~ 7.25.53 | | `Disable dislike redirection` | Adds an option to disable redirection to the next track when clicking the Dislike button. | 6.20.51 ~ 7.25.53 | -| `Disable music video in album` | Adds option to redirect music videos from albums. | 6.20.51 ~ 7.25.53 | +| `Disable music video in album` | Adds option to redirect music videos from albums for non-premium users. | 6.20.51 ~ 7.25.53 | | `Enable OPUS codec` | Adds an options to enable the OPUS audio codec if the player response includes. | 6.20.51 ~ 7.25.53 | | `Enable debug logging` | Adds an option to enable debug logging. | 6.20.51 ~ 7.25.53 | | `Enable landscape mode` | Adds an option to enable landscape mode when rotating the screen on phones. | 6.20.51 ~ 7.25.53 | diff --git a/gradle.properties b/gradle.properties index 26f84248b..8e3ac8785 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,5 +4,5 @@ org.gradle.parallel = true android.useAndroidX = true kotlin.code.style = official kotlin.jvm.target.validation.mode = IGNORE -version = 5.2.1-dev.3 +version = 5.2.1-dev.4 diff --git a/patches.json b/patches.json index d75696759..dccb9d4e1 100644 --- a/patches.json +++ b/patches.json @@ -43,26 +43,6 @@ }, "options": [] }, - { - "name": "Amoled", - "description": "Applies a pure black theme to some components.", - "use": true, - "dependencies": [ - "BytecodePatch", - "Settings for YouTube Music" - ], - "compatiblePackages": { - "com.google.android.apps.youtube.music": [ - "6.20.51", - "6.29.59", - "6.42.55", - "6.51.53", - "7.16.53", - "7.25.53" - ] - }, - "options": [] - }, { "name": "Bitrate default value", "description": "Sets the audio quality to \u0027Always High\u0027 when you first install the app.", @@ -636,6 +616,53 @@ } ] }, + { + "name": "Dark theme", + "description": "Changes the app\u0027s dark theme to the values specified in patch options.", + "use": true, + "dependencies": [ + "BytecodePatch" + ], + "compatiblePackages": { + "com.google.android.apps.youtube.music": [ + "6.20.51", + "6.29.59", + "6.42.55", + "6.51.53", + "7.16.53", + "7.25.53" + ] + }, + "options": [ + { + "key": "darkThemeBackgroundColor", + "title": "Dark theme background color", + "description": "Can be a hex color (#AARRGGBB) or a color resource reference.", + "required": false, + "type": "kotlin.String", + "default": "@android:color/black", + "values": { + "Amoled Black": "@android:color/black", + "Catppuccin (Mocha)": "#FF181825", + "Dark Pink": "#FF290025", + "Dark Blue": "#FF001029", + "Dark Green": "#FF002905", + "Dark Yellow": "#FF282900", + "Dark Orange": "#FF291800", + "Dark Red": "#FF290000" + } + }, + { + "key": "materialYou", + "title": "MaterialYou", + "description": "Applies the MaterialYou theme for Android 12+ devices.", + "required": true, + "type": "kotlin.Boolean", + "default": false, + "values": null + } + ] + }, { "name": "Description components", "description": "Adds options to hide and disable description components.", @@ -821,12 +848,11 @@ }, { "name": "Disable music video in album", - "description": "Adds option to redirect music videos from albums.", + "description": "Adds option to redirect music videos from albums for non-premium users.", "use": false, "dependencies": [ "Settings for YouTube Music", "BytecodePatch", - "BytecodePatch", "BytecodePatch" ], "compatiblePackages": { diff --git a/patches/api/patches.api b/patches/api/patches.api index 59f48b136..440ced4f9 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -22,10 +22,6 @@ public final class app/revanced/patches/music/flyoutmenu/components/FlyoutMenuCo public static final fun getFlyoutMenuComponentsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/music/general/amoled/AmoledPatchKt { - public static final fun getAmoledPatch ()Lapp/revanced/patcher/patch/ResourcePatch; -} - public final class app/revanced/patches/music/general/autocaptions/AutoCaptionsPatchKt { public static final fun getAutoCaptionsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -82,6 +78,11 @@ public final class app/revanced/patches/music/layout/playeroverlay/PlayerOverlay public static final fun getPlayerOverlayFilterPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } +public final class app/revanced/patches/music/layout/theme/DarkThemePatchKt { + public static final fun getDARK_COLOR ()[Ljava/lang/String; + public static final fun getDarkThemePatch ()Lapp/revanced/patcher/patch/ResourcePatch; +} + public final class app/revanced/patches/music/layout/translations/TranslationsPatchKt { public static final fun getTranslationsPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } @@ -213,6 +214,7 @@ public final class app/revanced/patches/music/utils/resourceid/SharedResourceIdP public static final fun getColorGrey ()J public static final fun getDarkBackground ()J public static final fun getDesignBottomSheetDialog ()J + public static final fun getElementsContainer ()J public static final fun getEndButtonsContainer ()J public static final fun getFloatingLayout ()J public static final fun getHistoryMenuItem ()J @@ -491,6 +493,10 @@ public final class app/revanced/patches/shared/mapping/ResourceType : java/lang/ public static fun values ()[Lapp/revanced/patches/shared/mapping/ResourceType; } +public final class app/revanced/patches/shared/materialyou/BaseMaterialYouPatchKt { + public static final fun baseMaterialYou (Lapp/revanced/patcher/patch/ResourcePatchContext;)V +} + public final class app/revanced/patches/shared/opus/BaseOpusCodecsPatchKt { public static final fun baseOpusCodecsPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch; } From bcc9547b5fb3a077b575b747e017ae6c34864e00 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:02:07 +0900 Subject: [PATCH 62/65] fix(YouTube Music - Dark theme): Gradient applied to wrong image --- .../patches/utils/DrawableColorPatch.java | 16 ++++++++++----- .../music/layout/theme/DarkThemePatch.kt | 4 +++- .../materialyou/host/values-v31/colors.xml | 20 ------------------- 3 files changed, 14 insertions(+), 26 deletions(-) delete mode 100644 patches/src/main/resources/music/materialyou/host/values-v31/colors.xml diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/DrawableColorPatch.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/DrawableColorPatch.java index febdf3cb3..1c79d233d 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/DrawableColorPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/utils/DrawableColorPatch.java @@ -2,12 +2,12 @@ package app.revanced.extension.music.patches.utils; import android.graphics.drawable.Drawable; import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.ImageView; import org.apache.commons.lang3.ArrayUtils; import app.revanced.extension.shared.utils.ResourceUtils; -import app.revanced.extension.shared.utils.Utils; @SuppressWarnings("unused") public class DrawableColorPatch { @@ -22,6 +22,8 @@ public class DrawableColorPatch { ResourceUtils.getDrawable("revanced_header_gradient"); private static final int blackColor = ResourceUtils.getColor("yt_black1"); + private static final int elementsContainerIdentifier = + ResourceUtils.getIdIdentifier("elements_container"); public static int getLithoColor(int originalValue) { return ArrayUtils.contains(DARK_VALUES, originalValue) @@ -30,15 +32,19 @@ public class DrawableColorPatch { } public static void setHeaderGradient(ViewGroup viewGroup) { - viewGroup.getViewTreeObserver().addOnGlobalLayoutListener(() -> Utils.runOnMainThreadDelayed(() -> { - if (!(viewGroup.getChildAt(0) instanceof ViewGroup parentViewGroup)) + viewGroup.getViewTreeObserver().addOnGlobalLayoutListener(() -> { + if (!(viewGroup instanceof FrameLayout frameLayout)) + return; + if (!(frameLayout.getChildAt(0) instanceof ViewGroup parentViewGroup)) return; if (!(parentViewGroup.getChildAt(0) instanceof ImageView gradientView)) return; - if (headerGradient != null) { + // For some reason, it sometimes applies to other lithoViews. + // To prevent this, check the viewId before applying the gradient. + if (headerGradient != null && viewGroup.getId() == elementsContainerIdentifier) { gradientView.setForeground(headerGradient); } - }, 0)); + }); } } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/DarkThemePatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/DarkThemePatch.kt index c13c3e7e7..45f85b967 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/DarkThemePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/theme/DarkThemePatch.kt @@ -42,6 +42,8 @@ private val darkThemeBytecodePatch = bytecodePatch( execute { addDrawableColorHook("$EXTENSION_CLASS_DESCRIPTOR->getLithoColor(I)I") + // The images in the playlist and album headers have a black gradient (probably applied server-side). + // Applies a new gradient to the images in the playlist and album headers. elementsContainerFingerprint.methodOrThrow().apply { val index = indexOfFirstInstructionReversedOrThrow(Opcode.CHECK_CAST) val register = getInstruction(index).registerA @@ -63,7 +65,7 @@ private val darkThemeBytecodePatch = bytecodePatch( val DARK_COLOR = arrayOf( "yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", - "yt_black2", "yt_black3", "yt_black4","yt_black_pure", + "yt_black2", "yt_black3", "yt_black4", "yt_black_pure", "yt_black_pure_opacity80", "yt_status_bar_background_dark", "ytm_color_grey_12", "material_grey_800", "material_grey_850", ) diff --git a/patches/src/main/resources/music/materialyou/host/values-v31/colors.xml b/patches/src/main/resources/music/materialyou/host/values-v31/colors.xml deleted file mode 100644 index 16d8f326d..000000000 --- a/patches/src/main/resources/music/materialyou/host/values-v31/colors.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - @android:color/system_neutral1_900 - From a0329d28f5f3993d0c3eaaf7154e8dd92eb837aa Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:06:31 +0900 Subject: [PATCH 63/65] chore: Lint code --- .../shared/patches/client/AppClient.kt | 2 +- .../spoof/SpoofStreamingDataPatch.java | 5 ++-- .../patches/spoof/requests/PlayerRoutes.kt | 28 +++++++++++++++---- .../spoof/requests/StreamingDataRequest.kt | 15 ++++++---- .../requests/ReturnYouTubeDislikeApi.java | 6 ++++ .../patches/video/requests/MusicRequest.kt | 15 ++++++++-- .../VideoQualitySettingsActivity.java | 1 - .../generator/JsonPatchesFileGenerator.kt | 4 ++- .../music/misc/album/AlbumMusicVideoPatch.kt | 15 ++++++---- .../patches/shared/gms/Fingerprints.kt | 3 -- .../materialyou/BaseMaterialYouPatch.kt | 11 -------- .../BaseSpoofStreamingDataPatch.kt | 11 ++++++-- .../spoof/streamingdata/Fingerprints.kt | 6 +++- .../general/toolbar/ToolBarComponentsPatch.kt | 9 +++--- .../overlaybuttons/OverlayButtonsPatch.kt | 2 +- .../player/seekbar/SeekbarComponentsPatch.kt | 4 ++- .../hooks/MainActivityBaseContextHook.kt | 5 ++-- .../fullscreen/FullscreenButtonHookPatch.kt | 12 +++++--- 18 files changed, 100 insertions(+), 54 deletions(-) diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt index 17f0f53d5..4dcb61c31 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.kt @@ -30,6 +30,7 @@ object AppClient { private const val DEVICE_MAKE_IOS = "Apple" private const val OS_NAME_IOS = "iOS" + /** * The device machine id for the iPhone 15 Pro Max (iPhone16,2), * used to get HDR with AV1 hardware decoding. @@ -240,7 +241,6 @@ object AppClient { val userAgent: String, /** * Android SDK version, equivalent to [Build.VERSION.SDK] (System property: ro.build.version.sdk) - * Field is null if not applicable. */ val androidSdkVersion: String = Build.VERSION.SDK, /** diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java index a94f79810..6bf264184 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java @@ -141,8 +141,9 @@ public class SpoofStreamingDataPatch { * 1. Save the requestHeader in a field. * 2. Invoke fetchRequest with the videoId used in PlaybackStartDescriptor. *

- * @param requestHeaders Save the request Headers used for login to a field. - * Only used in YouTube Music where login is required. + * + * @param requestHeaders Save the request Headers used for login to a field. + * Only used in YouTube Music where login is required. */ private static void setRequestHeaders(Map requestHeaders) { if (SPOOF_STREAMING_DATA_MUSIC) { diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt index 61fe440cb..fca54e4f2 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.kt @@ -130,17 +130,35 @@ object PlayerRoutes { } @JvmStatic - fun getPlayerResponseConnectionFromRoute(route: CompiledRoute, clientType: AppClient.ClientType): HttpURLConnection { - return getPlayerResponseConnectionFromRoute(route, clientType.userAgent, clientType.id.toString()) + fun getPlayerResponseConnectionFromRoute( + route: CompiledRoute, + clientType: AppClient.ClientType + ): HttpURLConnection { + return getPlayerResponseConnectionFromRoute( + route, + clientType.userAgent, + clientType.id.toString() + ) } @JvmStatic - fun getPlayerResponseConnectionFromRoute(route: CompiledRoute, clientType: WebClient.ClientType): HttpURLConnection { - return getPlayerResponseConnectionFromRoute(route, clientType.userAgent, clientType.id.toString()) + fun getPlayerResponseConnectionFromRoute( + route: CompiledRoute, + clientType: WebClient.ClientType + ): HttpURLConnection { + return getPlayerResponseConnectionFromRoute( + route, + clientType.userAgent, + clientType.id.toString() + ) } @Throws(IOException::class) - fun getPlayerResponseConnectionFromRoute(route: CompiledRoute, userAgent: String, clientVersion: String): HttpURLConnection { + fun getPlayerResponseConnectionFromRoute( + route: CompiledRoute, + userAgent: String, + clientVersion: String + ): HttpURLConnection { val connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route) connection.setRequestProperty("Content-Type", "application/json") diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt index 5423e0653..6389ac1ea 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/StreamingDataRequest.kt @@ -9,7 +9,6 @@ import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.getPlay import app.revanced.extension.shared.settings.BaseSettings import app.revanced.extension.shared.utils.Logger import app.revanced.extension.shared.utils.Utils -import org.apache.commons.lang3.ArrayUtils import org.apache.commons.lang3.StringUtils import java.io.BufferedInputStream import java.io.ByteArrayOutputStream @@ -111,6 +110,7 @@ class StreamingDataRequest private constructor( * Any arbitrarily large value, but must be at least twice [.HTTP_TIMEOUT_MILLISECONDS] */ private const val MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000 + @GuardedBy("itself") val cache: MutableMap = Collections.synchronizedMap( object : LinkedHashMap(100) { @@ -171,11 +171,13 @@ class StreamingDataRequest private constructor( Logger.printDebug { "Fetching video streams for: $videoId using client: $clientType" } try { - val connection = getPlayerResponseConnectionFromRoute(GET_STREAMING_DATA, clientType) + val connection = + getPlayerResponseConnectionFromRoute(GET_STREAMING_DATA, clientType) connection.connectTimeout = HTTP_TIMEOUT_MILLISECONDS connection.readTimeout = HTTP_TIMEOUT_MILLISECONDS - val usePoToken = clientType.requirePoToken && !StringUtils.isAnyEmpty(botGuardPoToken, visitorId) + val usePoToken = + clientType.requirePoToken && !StringUtils.isAnyEmpty(botGuardPoToken, visitorId) for (key in REQUEST_HEADER_KEYS) { var value = playerHeaders[key] @@ -248,7 +250,8 @@ class StreamingDataRequest private constructor( // Retry with different client if empty response body is received. for (clientType in CLIENT_ORDER_TO_USE) { if (clientType.requireAuth && - playerHeaders[AUTHORIZATION_HEADER] == null) { + playerHeaders[AUTHORIZATION_HEADER] == null + ) { Logger.printDebug { "Skipped login-required client (incognito mode or not logged in)\nClient: $clientType\nVideo: $videoId" } continue } @@ -270,7 +273,9 @@ class StreamingDataRequest private constructor( ByteArrayOutputStream().use { stream -> val buffer = ByteArray(2048) var bytesRead: Int - while ((inputStream.read(buffer).also { bytesRead = it }) >= 0) { + while ((inputStream.read(buffer) + .also { bytesRead = it }) >= 0 + ) { stream.write(buffer, 0, bytesRead) } lastSpoofedClientType = clientType diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java b/extensions/shared/src/main/java/app/revanced/extension/shared/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java index 0f8623fd7..9cbf96c86 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java @@ -121,21 +121,27 @@ public class ReturnYouTubeDislikeApi { public static long getFetchCallResponseTimeLast() { return fetchCallResponseTimeLast; } + public static long getFetchCallResponseTimeMin() { return fetchCallResponseTimeMin; } + public static long getFetchCallResponseTimeMax() { return fetchCallResponseTimeMax; } + public static long getFetchCallResponseTimeAverage() { return fetchCallCount == 0 ? 0 : (fetchCallResponseTimeTotal / fetchCallCount); } + public static int getFetchCallCount() { return fetchCallCount; } + public static int getFetchCallNumberOfFailures() { return fetchCallNumberOfFailures; } + public static int getNumberOfRateLimitRequestsEncountered() { return numberOfRateLimitRequestsEncountered; } diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt index 91711bd7c..8299757fc 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/MusicRequest.kt @@ -19,7 +19,10 @@ import java.util.concurrent.Future import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException -class MusicRequest private constructor(private val videoId: String, private val checkCategory: Boolean) { +class MusicRequest private constructor( + private val videoId: String, + private val checkCategory: Boolean +) { /** * Time this instance and the fetch future was created. */ @@ -121,7 +124,10 @@ class MusicRequest private constructor(private val videoId: String, private val Logger.printDebug { "Fetching playlist request for: $videoId using client: $clientTypeName" } try { - val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(PlayerRoutes.GET_PLAYLIST_PAGE, clientType) + val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute( + PlayerRoutes.GET_PLAYLIST_PAGE, + clientType + ) val requestBody = PlayerRoutes.createApplicationRequestBody(clientType, videoId, "RD$videoId") @@ -158,7 +164,10 @@ class MusicRequest private constructor(private val videoId: String, private val Logger.printDebug { "Fetching playability request for: $videoId using client: $clientTypeName" } try { - val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(PlayerRoutes.GET_CATEGORY, clientType) + val connection = PlayerRoutes.getPlayerResponseConnectionFromRoute( + PlayerRoutes.GET_CATEGORY, + clientType + ) val requestBody = PlayerRoutes.createWebInnertubeBody(clientType, videoId) diff --git a/extensions/shared/src/main/java/com/google/android/apps/youtube/app/settings/videoquality/VideoQualitySettingsActivity.java b/extensions/shared/src/main/java/com/google/android/apps/youtube/app/settings/videoquality/VideoQualitySettingsActivity.java index f01b05cf2..14d19be64 100644 --- a/extensions/shared/src/main/java/com/google/android/apps/youtube/app/settings/videoquality/VideoQualitySettingsActivity.java +++ b/extensions/shared/src/main/java/com/google/android/apps/youtube/app/settings/videoquality/VideoQualitySettingsActivity.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.TypedValue; -import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.SearchView; diff --git a/patches/src/main/kotlin/app/revanced/generator/JsonPatchesFileGenerator.kt b/patches/src/main/kotlin/app/revanced/generator/JsonPatchesFileGenerator.kt index 2e916af51..3a7b29342 100644 --- a/patches/src/main/kotlin/app/revanced/generator/JsonPatchesFileGenerator.kt +++ b/patches/src/main/kotlin/app/revanced/generator/JsonPatchesFileGenerator.kt @@ -30,7 +30,9 @@ internal class JsonPatchesFileGenerator : PatchesFileGenerator { }, ) }.let { - patchesJson.writeText(GsonBuilder().serializeNulls().setPrettyPrinting().create().toJson(it)) + patchesJson.writeText( + GsonBuilder().serializeNulls().setPrettyPrinting().create().toJson(it) + ) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt index e24c51738..f72a914ee 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/album/AlbumMusicVideoPatch.kt @@ -75,7 +75,8 @@ val albumMusicVideoPatch = bytecodePatch( audioVideoSwitchToggleConstructorFingerprint.methodOrThrow().apply { val onClickListenerIndex = indexOfAudioVideoSwitchSetOnClickListenerInstruction(this) - val viewRegister = getInstruction(onClickListenerIndex).registerC + val viewRegister = + getInstruction(onClickListenerIndex).registerC addInstruction( onClickListenerIndex + 1, @@ -83,11 +84,13 @@ val albumMusicVideoPatch = bytecodePatch( "$EXTENSION_CLASS_DESCRIPTOR->setAudioVideoSwitchToggleOnLongClickListener(Landroid/view/View;)V" ) - val onClickListenerSyntheticIndex = indexOfFirstInstructionReversedOrThrow(onClickListenerIndex) { - opcode == Opcode.INVOKE_DIRECT && - getReference()?.name == "" - } - val onClickListenerSyntheticClass = (getInstruction(onClickListenerSyntheticIndex).reference as MethodReference).definingClass + val onClickListenerSyntheticIndex = + indexOfFirstInstructionReversedOrThrow(onClickListenerIndex) { + opcode == Opcode.INVOKE_DIRECT && + getReference()?.name == "" + } + val onClickListenerSyntheticClass = + (getInstruction(onClickListenerSyntheticIndex).reference as MethodReference).definingClass findMethodOrThrow(onClickListenerSyntheticClass) { name == "onClick" diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/gms/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/gms/Fingerprints.kt index 8a33d0807..1cff11b8f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/gms/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/gms/Fingerprints.kt @@ -5,11 +5,8 @@ import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.iface.reference.StringReference -import com.android.tools.smali.dexlib2.util.MethodUtil const val GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME = "getGmsCoreVendorGroupId" diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/materialyou/BaseMaterialYouPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/materialyou/BaseMaterialYouPatch.kt index d95d24c3c..ca07af5af 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/materialyou/BaseMaterialYouPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/materialyou/BaseMaterialYouPatch.kt @@ -1,19 +1,8 @@ package app.revanced.patches.shared.materialyou -import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.ResourcePatchContext -import app.revanced.util.copyXmlNode -import app.revanced.util.inputStreamFromBundledResource import org.w3c.dom.Element -import org.w3c.dom.Node -import java.io.File import java.nio.file.Files -import java.nio.file.StandardCopyOption -import javax.xml.parsers.DocumentBuilderFactory -import javax.xml.transform.OutputKeys -import javax.xml.transform.TransformerFactory -import javax.xml.transform.dom.DOMSource -import javax.xml.transform.stream.StreamResult private fun ResourcePatchContext.patchXmlFile( fromDir: String, diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt index 2f34434c4..6d9012f87 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt @@ -116,15 +116,20 @@ fun baseSpoofStreamingDataPatch( // region Replace the streaming data. val approxDurationMsReference = formatStreamModelConstructorFingerprint.matchOrThrow().let { - with (it.method) { + with(it.method) { getInstruction(it.patternMatch!!.startIndex).reference } } - val streamingDataFormatsReference = with(videoStreamingDataConstructorFingerprint.methodOrThrow(videoStreamingDataToStringFingerprint)) { + val streamingDataFormatsReference = with( + videoStreamingDataConstructorFingerprint.methodOrThrow( + videoStreamingDataToStringFingerprint + ) + ) { val getFormatsFieldIndex = indexOfGetFormatsFieldInstruction(this) val longMaxValueIndex = indexOfLongMaxValueInstruction(this, getFormatsFieldIndex) - val longMaxValueRegister = getInstruction(longMaxValueIndex).registerA + val longMaxValueRegister = + getInstruction(longMaxValueIndex).registerA val videoIdIndex = indexOfFirstInstructionOrThrow(longMaxValueIndex) { val reference = getReference() diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/Fingerprints.kt index c120b5d4e..265b1c245 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/Fingerprints.kt @@ -209,6 +209,10 @@ internal val poTokenToStringFingerprint = legacyFingerprint( classDef.fields.find { it.type == "[B" } != null && // In YouTube, this field's type is 'Lcom/google/android/gms/potokens/PoToken;'. // In YouTube Music, this class name is obfuscated. - classDef.fields.find { it.accessFlags == AccessFlags.PRIVATE.value && it.type.startsWith("L") } != null + classDef.fields.find { + it.accessFlags == AccessFlags.PRIVATE.value && it.type.startsWith( + "L" + ) + } != null }, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt index 74f762141..46233d174 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt @@ -342,10 +342,11 @@ val toolBarComponentsPatch = bytecodePatch( opcode == Opcode.INVOKE_VIRTUAL && getReference()?.toString() == voiceInputControllerActivityMethodCall } - val setOnClickListenerIndex = indexOfFirstInstructionOrThrow(voiceInputControllerActivityIndex) { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "setOnClickListener" - } + val setOnClickListenerIndex = + indexOfFirstInstructionOrThrow(voiceInputControllerActivityIndex) { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.name == "setOnClickListener" + } val viewRegister = getInstruction(setOnClickListenerIndex).registerC diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt index ea6446abd..3c07be84b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt @@ -249,7 +249,7 @@ val overlayButtonsPatch = resourcePatch( ) val isButton = if (is_19_17_or_greater) - // Note: Do not modify fullscreen button and multiview button + // Note: Do not modify fullscreen button and multiview button id.endsWith("_button") && id != "@id/multiview_button" else id.endsWith("_button") || id == "@id/youtube_controls_fullscreen_button_stub" diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt index ada482215..f3f587372 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt @@ -271,7 +271,9 @@ val seekbarComponentsPatch = bytecodePatch( ).forEach { method -> method.apply { val literalIndex = - indexOfFirstLiteralInstructionOrThrow(launchScreenLayoutTypeLotteFeatureFlag) + indexOfFirstLiteralInstructionOrThrow( + launchScreenLayoutTypeLotteFeatureFlag + ) val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT) val register = getInstruction(resultIndex).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/hooks/MainActivityBaseContextHook.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/hooks/MainActivityBaseContextHook.kt index 7543cc3d8..1f17ed305 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/hooks/MainActivityBaseContextHook.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/extension/hooks/MainActivityBaseContextHook.kt @@ -17,8 +17,9 @@ internal val mainActivityBaseContextHook = extensionHook( attachBaseContextIndex + 1 }, contextRegisterResolver = { method -> - val overrideInstruction = method.implementation!!.instructions.elementAt(attachBaseContextIndex) - as FiveRegisterInstruction + val overrideInstruction = + method.implementation!!.instructions.elementAt(attachBaseContextIndex) + as FiveRegisterInstruction "v${overrideInstruction.registerD}" }, ) { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fullscreen/FullscreenButtonHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fullscreen/FullscreenButtonHookPatch.kt index 5cac3b8f6..489b38a11 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fullscreen/FullscreenButtonHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fullscreen/FullscreenButtonHookPatch.kt @@ -31,18 +31,21 @@ val fullscreenButtonHookPatch = bytecodePatch( dependsOn(sharedExtensionPatch) execute { - val (referenceClass, fullscreenActionClass) = with (nextGenWatchLayoutFullscreenModeFingerprint.methodOrThrow()) { + val (referenceClass, fullscreenActionClass) = with( + nextGenWatchLayoutFullscreenModeFingerprint.methodOrThrow() + ) { val targetIndex = indexOfFirstInstructionReversedOrThrow { opcode == Opcode.INVOKE_DIRECT && getReference()?.parameterTypes?.size == 2 } - val targetReference = getInstruction(targetIndex).reference as MethodReference + val targetReference = + getInstruction(targetIndex).reference as MethodReference Pair(targetReference.definingClass, targetReference.parameterTypes[1].toString()) } val (enterFullscreenReference, exitFullscreenReference, opcodeName) = - with (findMethodOrThrow(referenceClass) { parameters == listOf("I") }) { + with(findMethodOrThrow(referenceClass) { parameters == listOf("I") }) { val enterFullscreenIndex = indexOfFirstInstructionOrThrow { val reference = getReference() reference?.returnType == "V" && @@ -62,7 +65,8 @@ val fullscreenButtonHookPatch = bytecodePatch( getInstruction(exitFullscreenIndex).reference val opcode = getInstruction(enterFullscreenIndex).opcode - val enterFullscreenClass = (enterFullscreenReference as MethodReference).definingClass + val enterFullscreenClass = + (enterFullscreenReference as MethodReference).definingClass enterFullscreenMethod = if (opcode == Opcode.INVOKE_INTERFACE) { classes.find { classDef -> classDef.interfaces.contains(enterFullscreenClass) } From 37141712a8342ffc7d8859b4956f3f797bfc1b04 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:14:30 +0900 Subject: [PATCH 64/65] feat(Translations): Update translation --- .../music/translations/el-rGR/strings.xml | 7 ++- .../music/translations/ja-rJP/strings.xml | 3 + .../music/translations/ru-rRU/strings.xml | 5 ++ .../youtube/translations/fr-rFR/strings.xml | 4 +- .../youtube/translations/hu-rHU/strings.xml | 60 ++++++++++++++----- .../youtube/translations/ja-rJP/strings.xml | 17 +++--- .../youtube/translations/ko-rKR/strings.xml | 12 +++- .../youtube/translations/pl-rPL/strings.xml | 2 +- 8 files changed, 79 insertions(+), 31 deletions(-) diff --git a/patches/src/main/resources/music/translations/el-rGR/strings.xml b/patches/src/main/resources/music/translations/el-rGR/strings.xml index abfa67e4d..28a5a435f 100644 --- a/patches/src/main/resources/music/translations/el-rGR/strings.xml +++ b/patches/src/main/resources/music/translations/el-rGR/strings.xml @@ -380,7 +380,12 @@ Αν ανιχνεύεται αναπαραγωγή ενός μουσικού βίντεο που περιλαμβάνεται σε άλμπουμ, ανακατευθύνεται στο επίσημο τραγούδι. -Χρησιμοποιείται το Piped API, και ενδέχεται να μην είναι διαθέσιμο σε ορισμένες περιοχές." +• Χρησιμοποιείται το Piped Instance API." + Τύπος ανακατεύθυνσης + Καθορισμός του τρόπου ανακατεύθυνσης στο επίσημο τραγούδι. + Ανακατεύθυνση + Πάτημα εναλλαγής ήχου / βίντεο + Παρατεταμένο πάτημα εναλλαγής ήχου / βίντεο Ενεργοποίηση καταγραφής σφαλμάτων Εκτύπωση του αρχείου καταγραφής σφαλμάτων. Συμπερίληψη του buffer στην καταγραφή diff --git a/patches/src/main/resources/music/translations/ja-rJP/strings.xml b/patches/src/main/resources/music/translations/ja-rJP/strings.xml index ffea0491d..26e984459 100644 --- a/patches/src/main/resources/music/translations/ja-rJP/strings.xml +++ b/patches/src/main/resources/music/translations/ja-rJP/strings.xml @@ -376,6 +376,9 @@ API キーの発行方法については、ここをタップしてください アルバムからMVの再生が検出された場合、公式の楽曲を検索します。 • Piped Instance APIを利用しています。" + リダイレクトのタイプ + 公式楽曲にリダイレクトする方法を指定します。 + リダイレクト デバッグログ デバッグログを出力します。 デバッグバッファログを有効化 diff --git a/patches/src/main/resources/music/translations/ru-rRU/strings.xml b/patches/src/main/resources/music/translations/ru-rRU/strings.xml index 4ecd962a8..49e4a7a57 100644 --- a/patches/src/main/resources/music/translations/ru-rRU/strings.xml +++ b/patches/src/main/resources/music/translations/ru-rRU/strings.xml @@ -378,6 +378,11 @@ Если будет обнаружено воспроизведение музыкального видео, будет перенаправлено на официальную песню. • Используется \"Piped Instance\", но в некоторых регионах API может быть недоступен." + Тип перенаправления + Определение способа перенаправления на официальную песню. + Перенаправление + Нажмите на переключатель Аудио/Видео + Нажмите и удерживайте переключатель Аудио/Видео Ведение журнала отладки Выводит журнал отладки. Ведение журналов отладки буфера diff --git a/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml b/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml index c541557a9..2b353da0b 100644 --- a/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml +++ b/patches/src/main/resources/youtube/translations/fr-rFR/strings.xml @@ -863,9 +863,9 @@ La lecture automatique peut être modifiée dans les paramètres de YouTube : La description en plein écran est désactivée. La description en plein écran est activée. Passer en mode plein écran au démarrage de la vidéo - "\"Passer en mode plein écran lorsque la vidéo démarre. + "Passer en mode plein écran lorsque la vidéo démarre. -Limitation : Ne fonctionne pas si le lecteur est minimisé, en mode PiP ou en arrière-plan." +Limitation : Ne fonctionne pas si le lecteur est minimisé, en mode PiP, ou en arrière-plan." Ne pas passer en mode plein écran au démarrage de la vidéo. Quitter le mode plein écran à la fin de la vidéo Désactivé diff --git a/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml b/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml index 730982509..9df129e67 100644 --- a/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml +++ b/patches/src/main/resources/youtube/translations/hu-rHU/strings.xml @@ -860,6 +860,16 @@ Beállítások → Automatikus lejátszás → Következő videó automatikus le Interakciós panel letiltása Az interakciós panel le van tiltva. Az interakciós panel engedélyezve. + Videó indításakor lépjen be teljes képernyős módba + "Videó indításakor lépjen be teljes képernyős módba. + +Korlátozás: Nem működik, ha a lejátszó kicsinyített, PiP módban vagy a háttérben van." + Ne lépjen teljes képernyős módba, amikor a videó elindul. + Lépjen ki a teljes képernyős módból a videó végén + Letiltva + Álló mód + Fekvő mód + Álló- és fekvő mód Videócím rész megjelenítése "Megjeleníti a videócím részt teljes képernyős módban. @@ -1044,13 +1054,13 @@ Információ: Érvénytelen keresősáv színértéke. Érintés engedélyezése a kereső sávon A keresősávon történő érintés engedélyezett. - A keresősávon történő érintés ki van kapcsolva. - Folyamatsáv elrejtése a videólejátszóban - A videólejátszó folyamatsávja el van rejtve - A videólejátszó folyamatsávja megjelenik + A keresősávon történő érintés le van tiltva. + Keresősáv elrejtése a videólejátszóban + A videólejátszó folyamatsávja el van rejtve. + A videólejátszó folyamatsávja látható. Folyamatsáv elrejtése a minilejátszóban - A minilejátszó folyamatsávja el van rejtve - A minilejátszó folyamatsávja megjelenik + A minilejátszó folyamatsávja el van rejtve. + A minilejátszó folyamatsávja látható. Keresősáv fejezeteinek letiltása A keresősáv fejezetei le vannak tiltva. A keresősáv fejezetei engedélyezettek. @@ -1060,9 +1070,9 @@ Információ: Időbélyeg elrejtése Az időbélyeg el van rejtve. Az időbélyeg látható. - Régi keresősáv bélyegképek visszaállítása - A keresősáv bélyegképei megjelennek a keresősáv felett - A keresősáv bélyegképei megjelennek a teljes képernyőn + Régi folyamatsáv bélyegképek visszaállítása + A folyamatsáv bélyegképei megjelennek a keresősáv felett. + A folyamatsáv bélyegképei megjelennek teljes képernyőn. Jó minőségű miniatűrök engedélyezése A keresősáv bélyegképei kiváló minőségűek. A keresősáv bélyegképei közepes minőségűek. @@ -1090,20 +1100,20 @@ Ez a funkció nagyon gyors internetkapcsolat mellett működik a legjobban."A tartalom készítésének módja rész elrejtve. A tartalom készítésének módja rész látható. Infó kártyák rész elrejtése - Az infó kártyák rész el van rejtve - Az infó kártyák rész látható + Az infó kártyák rész el van rejtve. + Az infó kártyák rész látható. Kulcs koncepciók rész elrejtése A kulcs koncepciók rész elrejtve. A kulcs koncepciók rész látható. Podcast rész elrejtése A podcast rész el van rejtve. A podcast rész látható. - Vásárlási linkek elrejtése a videó leírásában - A vásárlási linkek rejtve vannak - A vásárlási linkek láthatóak + Vásárlási linkek elrejtése + A vásárlási linkek el vannak rejtve. + A vásárlási linkek láthatóak. Átirat rész elrejtése - Az átirat rész el van rejtve - Az átirat rész megjelenik + Az átirat rész el van rejtve. + Az átirat rész látható. Videoleírás interakció letiltása "Letiltja a következő interakciókat, ha a videoleírás kibővítve van: @@ -1425,7 +1435,11 @@ Megjegyzés: Ezzel a képernyőterület méretét is megváltoztatja, ahol érz A régi videóminőség menü jelenik meg A régi videóminőség menü nem jelenik meg Lejátszási sebesség zenéhez kiválasztás elrejtése + Az alapértelmezett lejátszási sebesség le van tiltva zene lejátszásnál. Az alapértelmezett lejátszási sebesség engedélyezett zene lejátszásnál. + Érvényesítés kategóriák használatával + Az alapértelmezett lejátszási sebesség le van tiltva, ha a videó kategóriája zene. + Az alapértelmezett lejátszási sebesség le van tiltva a YouTube Music szolgáltatásban lejátszható videóknál. Shortok alapértelmezett lejátszási sebességének engedélyezése Az alapértelmezett lejátszási sebesség vonatkozik a Shortokra. Az alapértelmezett lejátszási sebesség nem vonatkozik a Shortokra. @@ -1762,7 +1776,21 @@ Kattintson az API-kulcs kiadás folyamatának megtekintéséhez." "Az adatfolyam nincs meghamisítva. Lehet, hogy a videó lejátszás nem működik." A beállítás kikapcsolása videólejátszási problémákat okozhat. Alapértelmezett kliens + "Android TV +(Belépés szükséges)" + Android VR + "iOS +(PoToken szükséges)" + "iOS TV +(Belépés szükséges)" Hamisítás mellékhatásai + "• A hangsáv menü hiányzik. +• A stabil hangerő nem áll rendelkezésre. +• A kényszerített automatikus hangsávok letiltása nem elérhető. +• Előfordulhat, hogy a gyerekeknek szánt tartalmat nem lehet lejátszani, ha ki van jelentkezve vagy inkognitó módban van." + • Lejátszási problémák lehetnek (PoToken szükséges). + "• Előfordulhat, hogy a filmeket vagy a fizetős videókat nem lehet lejátszani. +• Előfordulhat, hogy a gyerekeknek szánt tartalmat nem lehet lejátszani, ha ki van jelentkezve vagy inkognitó módban van." Kényszerített iOS AVC (H.264) A videó kodek AVC-re (H.264) van kényszerítve. A videokodek meghatározása automatikusan történik. diff --git a/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml b/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml index 99828dab3..82e87fb09 100644 --- a/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml +++ b/patches/src/main/resources/youtube/translations/ja-rJP/strings.xml @@ -1,8 +1,8 @@ - 動画プレーヤーのアクセシビリティコントロールを有効化しますか? - ユーザー補助サービスがオンになっているため、操作方法が変わります。 + 動画プレーヤーのアクセシビリティコントロールを有効にしますか? + ユーザー補助サービスが有効化されているため、操作方法が変わります。 ReVanced Extended 設定を検索 @@ -273,7 +273,7 @@ DeArrow の詳細については、ここをタップしてください。"再生回数が少ない動画を非表示 この数値より少ない再生回数の動画を非表示にします。 キーを表示 - UIの各動画の下に表示される再生回数の言語テンプレートを設定します。各キー (言語の文字/単語) -> 値 (キーの意味) は、改行して記述する必要があります。キーは「->」記号の前に記述します。言語設定を更新した場合は、この設定をリセットする必要があります。\n\n例:\n英語: 10K views = K -> 1000、views -> 回\nスペイン語: 10 K vistas = K -> 1000、vistas -> 回 + UI の各動画の下に表示される再生回数の言語テンプレートを設定します。各キー (言語の文字/単語) -> 値 (キーの意味) は、改行して記述する必要があります。キーは「->」記号の前に記述します。言語設定を更新した場合は、この設定をリセットする必要があります。\n\n例:\n英語: 10K views = K -> 1000、views -> 回\nスペイン語: 10 K vistas = K -> 1000、vistas -> 回 万 -> 10 000\n億 -> 100 000 000\n回視聴 -> views 再生回数のフィルタリングについて "ホーム / 登録チャンネル / 検索結果はフィルタリングされ、設定した値よりも少ない再生回数の動画を非表示にします。 @@ -345,7 +345,8 @@ DeArrow の詳細については、ここをタップしてください。"共有からリンクをコピーした際などに画面下部に表示されるポップアップを非表示にします。 年齢制限ダイアログを削除 "年齢制限ダイアログを削除します。 -これにより年齢制限を回避することはできませんが、自動的に同意します。" + +注意: 年齢制限を回避することはできませんが、自動的に同意します。" レイアウトを変更 オリジナル スマホ @@ -353,13 +354,13 @@ DeArrow の詳細については、ここをタップしてください。"タブレット タブレット(最小 600 dp) アプリのバージョンを偽装 - アプリのバージョンは偽装されています。 - アプリのバージョンは偽装されていません。 + アプリのバージョンを偽装できます。 + アプリのバージョンを偽装できます。 "アプリのバージョンを以前のバージョンに偽装します。 これによりアプリの外観や機能が変更されますが、予期しない副作用が発生する可能性があります。 -後でこの機能をオフにする場合は、UIのバグを防ぐためにアプリのデータを消去することをお勧めします。" +後でこの機能をオフにする場合は、UI のバグを防ぐためにアプリのデータを消去することをおすすめします。" 偽装するアプリのバージョンを編集 偽装するバージョンを入力してください。 偽装するバージョン @@ -1367,7 +1368,7 @@ DeArrow の詳細については、ここをタップしてください。"スワイプジェスチャーを「画面のロック」モードで有効化します。 スワイプジェスチャーを「画面のロック」モードで有効化します。 スワイプオーバーレイの背景の透明度 - 背景の不透明度の値は 0 ~255 の間で、0 が透明です。 + 背景の不透明度の値は 0 ~ 255 の間で、0 が透明です。 スワイプ可能な領域のしきい値 スワイプとして検出する量のしきい値です。 スワイプオーバーレイのテキストサイズ diff --git a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml index 872936ec9..abba0802d 100644 --- a/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml +++ b/patches/src/main/resources/youtube/translations/ko-rKR/strings.xml @@ -860,7 +860,10 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요." 참여 패널을 비활성화합니다. 참여 패널을 활성화합니다. 동영상이 시작할 때, 전체 화면 모드로 들어가기 - "동영상이 시작할 때, 전체 화면 모드로 들어갑니다.\n\n알려진 문제점: \n• 플레이어가 최소화되어 있거나 PIP 모드 또는 백그라운드 재생에 있는 경우에는 작동되지 않습니다." + "동영상이 시작할 때, 전체 화면 모드로 들어갑니다. + +알려진 문제점: +• 플레이어가 최소화되어 있거나 PIP 모드 또는 백그라운드 재생에 있는 경우에는 작동되지 않습니다." 동영상이 시작할 때, 전체 화면 모드로 들어가지 않습니다. 동영상이 종료할 때, 전체 화면 모드에서 나가기 사용 안함 @@ -1798,11 +1801,14 @@ GmsCore 앱 배터리 최적화를 비활성화(제한 없음)하더라도, 배 • 안정적인 볼륨을 사용할 수 없습니다. • 자동 오디오 트랙을 비활성화할 수 없습니다. • 사용자가 로그인을 하지 않았거나 시크릿 모드에서는 Kids 동영상이 재생되지 않을 수 있습니다. -• VR은 Kids // TV는 재생목록과 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다." +• VR은 Kids // TV는 재생목록과 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다. +• TV는 AV1 코덱이 지원되지 않습니다." • 재생 문제가 발생할 수 있습니다 (PoToken이 요구됨).\n• 영화, 유료, 비공개 그리고 연령 제한 동영상에서 다른 클라이언트가 사용될 수 있습니다. "• 영화 또는 유료 동영상이 재생되지 않을 수 있습니다. +• 안정적인 볼륨을 사용할 수 없습니다. • 사용자가 로그인을 하지 않았거나 시크릿 모드에서는 Kids 동영상이 재생되지 않을 수 있습니다. -• 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다." +• 음악 동영상에서 다른 클라이언트가 사용될 수 있습니다. +• AV1 코덱이 지원되지 않습니다." iOS AVC (H.264) 강제로 활성화하기 동영상 코덱을 AVC (H.264)로 강제로 활성화합니다.\n\n• 일부 VP9 코덱 동영상에서 제거되었던 화질 값이 표시될 수 있습니다.\n• 최대 화질 값이 1080p이므로, 초고화질 동영상을 재생할 수 없습니다.\n• HDR 동영상을 재생할 수 없습니다. 동영상 코덱을 자동으로 결정합니다.\n\n• 예전에 업로드된 동영상을 재생했는데 VP9 코덱 응답을 받았을 경우, 일부 화질값이 제거되어 360p와 1080p(Premium 기능)만 선택가능할 수 있거나 화질 메뉴를 선택불가능할 수 있습니다. diff --git a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml index 02d5c762c..71413f0f1 100644 --- a/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml +++ b/patches/src/main/resources/youtube/translations/pl-rPL/strings.xml @@ -862,7 +862,7 @@ Autoodtwarzanie można zmienić w ustawieniach YouTube: Pełny ekran po rozpoczęciu filmu "Włączony -Ograniczenie: nie działa jeśli odtwarzacz jest zminimalizowany, w trybie PiP lub w tle" +Ograniczenie: nie działa jeśli odtwarzacz jest zminimalizowany, w trybie PiP lub w tle." Wyłączony Wyjście z pełnego ekranu po zakończeniu filmu Wyłączone From 2bed1424e3cd9b9073ecdca5697ea97751b4a125 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:15:07 +0900 Subject: [PATCH 65/65] bump 5.2.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8e3ac8785..5de17c401 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,5 +4,5 @@ org.gradle.parallel = true android.useAndroidX = true kotlin.code.style = official kotlin.jvm.target.validation.mode = IGNORE -version = 5.2.1-dev.4 +version = 5.2.1