chore: Merge branch dev to main (#6820)

Co-authored-by: PlayDay <18056374+playday3008@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: Dawid Krajcarz <80264606+drobotk@users.noreply.github.com>
Co-authored-by: Kofhisho <github@alphexo.dev>
Co-authored-by: rospino74 <34315725+rospino74@users.noreply.github.com>
Co-authored-by: ADudeCalledLeo <7997354+Leo40Git@users.noreply.github.com>
Co-authored-by: Aaron Mompié <github@aaronmompie.com>
Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com>
This commit is contained in:
oSumAtrIX 2026-03-18 16:50:48 +01:00 committed by GitHub
commit fca2470990
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 1124 additions and 363 deletions

View file

@ -32,6 +32,7 @@ jobs:
- name: Process strings - name: Process strings
run: | run: |
chmod -R 777 patches/src/main/resources
./gradlew processStringsFromCrowdin ./gradlew processStringsFromCrowdin
env: env:
ORG_GRADLE_PROJECT_githubPackagesUsername: ${{ github.actor }} ORG_GRADLE_PROJECT_githubPackagesUsername: ${{ github.actor }}

View file

@ -1,3 +1,44 @@
# [6.1.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v6.1.0-dev.3...v6.1.0-dev.4) (2026-03-18)
### Bug Fixes
* **YouTube - Custom branding:** Fix double icons and change default branding to ReVanced ([#6806](https://github.com/ReVanced/revanced-patches/issues/6806)) ([e51c529](https://github.com/ReVanced/revanced-patches/commit/e51c5292c171325e7cfa0f5ee85474d9b3961a34))
### Features
* Add `Spoof root of trust` and `Spoof keystore security level` patch ([#6751](https://github.com/ReVanced/revanced-patches/issues/6751)) ([4bc8c7c](https://github.com/ReVanced/revanced-patches/commit/4bc8c7c0f60a095533f07dc281f0320f8eb22f3c))
* **Instagram:** Add `Enable location sticker redesign` patch ([#6808](https://github.com/ReVanced/revanced-patches/issues/6808)) ([4b699da](https://github.com/ReVanced/revanced-patches/commit/4b699da220e5d1527c390792b6228e2d9cffedb7))
# [6.1.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v6.1.0-dev.2...v6.1.0-dev.3) (2026-03-18)
### Features
* **Spoof video streams:** Add Android Reel client to fix playback issues ([#6830](https://github.com/ReVanced/revanced-patches/issues/6830)) ([4b6c3e3](https://github.com/ReVanced/revanced-patches/commit/4b6c3e312328fbf6a1c7065e27d8ff04573e58be))
# [6.1.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v6.1.0-dev.1...v6.1.0-dev.2) (2026-03-17)
### Features
* **Announcements:** Support ReVanced API v5 announcements ([a05386e](https://github.com/ReVanced/revanced-patches/commit/a05386e8bc24c085b5c74f3674c402c5dd5ad468))
# [6.1.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v6.0.2-dev.1...v6.1.0-dev.1) (2026-03-16)
### Features
* Change contact email in patches about ([df1c3a4](https://github.com/ReVanced/revanced-patches/commit/df1c3a4a70fd2595d77b539299f1f7301bc60d24))
## [6.0.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v6.0.1...v6.0.2-dev.1) (2026-03-16)
### Bug Fixes
* **Export internal data documents provider:** Correct S_IFLNK constant and symlink detection mask ([#6819](https://github.com/ReVanced/revanced-patches/issues/6819)) ([252617b](https://github.com/ReVanced/revanced-patches/commit/252617b8dd3f24e1ff9a04ba1d91b43dc29bd757))
## [6.0.1](https://github.com/ReVanced/revanced-patches/compare/v6.0.0...v6.0.1) (2026-03-15) ## [6.0.1](https://github.com/ReVanced/revanced-patches/compare/v6.0.0...v6.0.1) (2026-03-15)

View file

@ -31,7 +31,10 @@ public class InternalDataDocumentsProvider extends DocumentsProvider {
private static final String[] directoryColumns = private static final String[] directoryColumns =
{"document_id", "mime_type", "_display_name", "last_modified", "flags", {"document_id", "mime_type", "_display_name", "last_modified", "flags",
"_size", "full_path", "lstat_info"}; "_size", "full_path", "lstat_info"};
private static final int S_IFLNK = 0x8000; @SuppressWarnings("OctalInteger")
private static final int S_IFMT = 0170000;
@SuppressWarnings("OctalInteger")
private static final int S_IFLNK = 0120000;
private String packageName; private String packageName;
private File dataDirectory; private File dataDirectory;
@ -47,7 +50,7 @@ public class InternalDataDocumentsProvider extends DocumentsProvider {
if (root.isDirectory()) { if (root.isDirectory()) {
try { try {
// Only delete recursively if the directory is not a symlink // Only delete recursively if the directory is not a symlink
if ((Os.lstat(root.getPath()).st_mode & S_IFLNK) != S_IFLNK) { if ((Os.lstat(root.getPath()).st_mode & S_IFMT) != S_IFLNK) {
File[] files = root.listFiles(); File[] files = root.listFiles();
if (files != null) { if (files != null) {
for (File file : files) { for (File file : files) {
@ -324,7 +327,7 @@ public class InternalDataDocumentsProvider extends DocumentsProvider {
sb.append(";"); sb.append(";");
sb.append(lstat.st_gid); sb.append(lstat.st_gid);
// Append symlink target if it is a symlink // Append symlink target if it is a symlink
if ((lstat.st_mode & S_IFLNK) == S_IFLNK) { if ((lstat.st_mode & S_IFMT) == S_IFLNK) {
sb.append(";"); sb.append(";");
sb.append(Os.readlink(path)); sb.append(Os.readlink(path));
} }

View file

@ -1,4 +1,4 @@
package app.revanced.extension.playintegrity; package app.revanced.extension.play;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;

View file

@ -1,7 +1,7 @@
package app.revanced.extension.music.patches.spoof; package app.revanced.extension.music.patches.spoof;
import static app.revanced.extension.music.settings.Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE; import static app.revanced.extension.music.settings.Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_NO_SDK; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_REEL;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
import static app.revanced.extension.shared.spoof.ClientType.VISIONOS; import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
@ -18,8 +18,8 @@ public class SpoofVideoStreamsPatch {
*/ */
public static void setClientOrderToUse() { public static void setClientOrderToUse() {
List<ClientType> availableClients = List.of( List<ClientType> availableClients = List.of(
ANDROID_REEL,
ANDROID_VR_1_43_32, ANDROID_VR_1_43_32,
ANDROID_NO_SDK,
VISIONOS, VISIONOS,
ANDROID_VR_1_61_48 ANDROID_VR_1_61_48
); );

View file

@ -35,7 +35,7 @@ public class Settings extends YouTubeAndMusicSettings {
// Miscellaneous // Miscellaneous
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type",
ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS)); ClientType.ANDROID_REEL, true, parent(SPOOF_VIDEO_STREAMS));
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", TRUE, true); public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", TRUE, true);
} }

View file

@ -1,5 +1,5 @@
plugins { plugins {
alias(libs.plugins.android.library) alias(libs.plugins.android.library)
} }
android { android {
@ -19,4 +19,6 @@ android {
dependencies { dependencies {
compileOnly(libs.annotation) compileOnly(libs.annotation)
compileOnly(libs.okhttp) compileOnly(libs.okhttp)
compileOnly(libs.protobuf.javalite)
implementation(project(":extensions:shared:protobuf", configuration = "shadowRuntimeElements"))
} }

View file

@ -114,7 +114,7 @@ public class CustomBrandingPatch {
/** /**
* Injection point. * Injection point.
* * <p>
* The total number of app name aliases, including dummy aliases. * The total number of app name aliases, including dummy aliases.
*/ */
private static int numberOfPresetAppNames() { private static int numberOfPresetAppNames() {
@ -146,13 +146,13 @@ public class CustomBrandingPatch {
public static int getDefaultAppNameIndex() { public static int getDefaultAppNameIndex() {
return userProvidedCustomName() return userProvidedCustomName()
? numberOfPresetAppNames() ? numberOfPresetAppNames()
: 1; : 2;
} }
public static BrandingTheme getDefaultIconStyle() { public static BrandingTheme getDefaultIconStyle() {
return userProvidedCustomIcon() return userProvidedCustomIcon()
? BrandingTheme.CUSTOM ? BrandingTheme.CUSTOM
: BrandingTheme.ORIGINAL; : BrandingTheme.ROUNDED;
} }
/** /**

View file

@ -47,7 +47,7 @@ public class BaseSettings {
// //
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message"); public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message");
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS)); public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_video_streams_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS));
public static final BooleanSetting SANITIZE_SHARING_LINKS = new BooleanSetting("revanced_sanitize_sharing_links", TRUE); public static final BooleanSetting SANITIZE_SHARING_LINKS = new BooleanSetting("revanced_sanitize_sharing_links", TRUE);
public static final BooleanSetting REPLACE_MUSIC_LINKS_WITH_YOUTUBE = new BooleanSetting("revanced_replace_music_with_youtube", FALSE); public static final BooleanSetting REPLACE_MUSIC_LINKS_WITH_YOUTUBE = new BooleanSetting("revanced_replace_music_with_youtube", FALSE);

View file

@ -9,9 +9,34 @@ import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
@SuppressWarnings("ConstantLocale") @SuppressWarnings("ConstantLocale")
public enum ClientType { public enum ClientType {
/**
* Video not playable: Paid, Movie, Private, Age-restricted.
* Uses non-adaptive bitrate.
* AV1 codec available.
*/
ANDROID_REEL(
3,
"ANDROID",
"com.google.android.youtube",
Build.MANUFACTURER,
Build.MODEL,
"Android",
Build.VERSION.RELEASE,
String.valueOf(Build.VERSION.SDK_INT),
Build.ID,
"20.44.38",
// This client has been used by most open-source YouTube stream extraction tools since 2024, including NewPipe Extractor, SmartTube, and Grayjay.
// This client can log in, but if an access token is used in the request, GVS can more easily identify the request as coming from ReVanced.
// This means that the GVS server can strengthen its validation of the ANDROID_REEL client.
true,
true,
false,
"Android Reel"
),
/** /**
* Video not playable: Kids / Paid / Movie / Private / Age-restricted. * Video not playable: Kids / Paid / Movie / Private / Age-restricted.
* This client can only be used when logged out. * This client can only be used when logged out.
@ -28,10 +53,10 @@ public enum ClientType {
// Android 12.1 // Android 12.1
"32", "32",
"SQ3A.220605.009.A1", "SQ3A.220605.009.A1",
"132.0.6808.3",
"1.61.48", "1.61.48",
false, false,
false, false,
true,
"Android VR 1.61" "Android VR 1.61"
), ),
/** /**
@ -48,39 +73,12 @@ public enum ClientType {
ANDROID_VR_1_61_48.osVersion, ANDROID_VR_1_61_48.osVersion,
Objects.requireNonNull(ANDROID_VR_1_61_48.androidSdkVersion), Objects.requireNonNull(ANDROID_VR_1_61_48.androidSdkVersion),
Objects.requireNonNull(ANDROID_VR_1_61_48.buildId), Objects.requireNonNull(ANDROID_VR_1_61_48.buildId),
"107.0.5284.2",
"1.43.32", "1.43.32",
ANDROID_VR_1_61_48.useAuth, ANDROID_VR_1_61_48.useAuth,
ANDROID_VR_1_61_48.supportsMultiAudioTracks, ANDROID_VR_1_61_48.supportsMultiAudioTracks,
ANDROID_VR_1_61_48.usePlayerEndpoint,
"Android VR 1.43" "Android VR 1.43"
), ),
/**
* Video not playable: Paid / Movie / Private / Age-restricted.
* Note: The 'Authorization' key must be excluded from the header.
*
* According to TeamNewPipe in 2022, if the 'androidSdkVersion' field is missing,
* the GVS did not return a valid response:
* [NewPipe#8713 (comment)](https://github.com/TeamNewPipe/NewPipe/issues/8713#issuecomment-1207443550).
*
* According to the latest commit in yt-dlp, the GVS returns a valid response
* even if the 'androidSdkVersion' field is missing:
* [yt-dlp#14693](https://github.com/yt-dlp/yt-dlp/pull/14693).
*
* For some reason, PoToken is not required.
*/
ANDROID_NO_SDK(
3,
"ANDROID",
"",
"",
"",
Build.VERSION.RELEASE,
"20.05.46",
"com.google.android.youtube/20.05.46 (Linux; U; Android " + Build.VERSION.RELEASE + ") gzip",
false,
true,
"Android No SDK"
),
/** /**
* Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children". * Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children".
* <a href="https://dumps.tadiphone.dev/dumps/google/barbet">Google Pixel 9 Pro Fold</a> * <a href="https://dumps.tadiphone.dev/dumps/google/barbet">Google Pixel 9 Pro Fold</a>
@ -95,10 +93,10 @@ public enum ClientType {
"15", "15",
"35", "35",
"AP3A.241005.015.A2", "AP3A.241005.015.A2",
"132.0.6779.0",
"23.47.101", "23.47.101",
true, true,
false, false,
true,
"Android Studio" "Android Studio"
), ),
/** /**
@ -114,32 +112,8 @@ public enum ClientType {
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
false, false,
false, false,
"visionOS"
),
/**
* The device machine id for the iPad 6th Gen (iPad7,6).
* AV1 hardware decoding is not supported.
* See [this GitHub Gist](https://gist.github.com/adamawolf/3048717) for more information.
*
* Based on Google's actions to date, PoToken may not be required on devices with very low specs.
* For example, suppose the User-Agent for a PlayStation 3 (with 256MB of RAM) is used.
* Accessing 'Web' (https://www.youtube.com) will redirect to 'TV' (https://www.youtube.com/tv).
* 'TV' target devices with very low specs, such as embedded devices, game consoles, and blu-ray players, so PoToken is not required.
*
* For this reason, the device machine id for the iPad 6th Gen (with 2GB of RAM),
* the lowest spec device capable of running iPadOS 17, was used.
*/
IPADOS(5,
"IOS",
"Apple",
"iPad7,6",
"iPadOS",
"17.7.10.21H450",
"19.22.3",
"com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")",
false,
true, true,
"iPadOS" "visionOS"
); );
/** /**
@ -195,13 +169,6 @@ public enum ClientType {
@Nullable @Nullable
private final String buildId; private final String buildId;
/**
* Cronet release version, as found in decompiled client apk.
* Field is null if not applicable.
*/
@Nullable
private final String cronetVersion;
/** /**
* App version. * App version.
*/ */
@ -217,6 +184,11 @@ public enum ClientType {
*/ */
public final boolean supportsMultiAudioTracks; public final boolean supportsMultiAudioTracks;
/**
* If the client should use the player endpoint for stream extraction.
*/
public final boolean usePlayerEndpoint;
/** /**
* Friendly name displayed in stats for nerds. * Friendly name displayed in stats for nerds.
*/ */
@ -234,10 +206,10 @@ public enum ClientType {
String osVersion, String osVersion,
@NonNull String androidSdkVersion, @NonNull String androidSdkVersion,
@NonNull String buildId, @NonNull String buildId,
@NonNull String cronetVersion,
String clientVersion, String clientVersion,
boolean useAuth, boolean useAuth,
boolean supportsMultiAudioTracks, boolean supportsMultiAudioTracks,
boolean usePlayerEndpoint,
String friendlyName) { String friendlyName) {
this.id = id; this.id = id;
this.clientName = clientName; this.clientName = clientName;
@ -248,21 +220,20 @@ public enum ClientType {
this.osVersion = osVersion; this.osVersion = osVersion;
this.androidSdkVersion = androidSdkVersion; this.androidSdkVersion = androidSdkVersion;
this.buildId = buildId; this.buildId = buildId;
this.cronetVersion = cronetVersion;
this.clientVersion = clientVersion; this.clientVersion = clientVersion;
this.useAuth = useAuth; this.useAuth = useAuth;
this.supportsMultiAudioTracks = supportsMultiAudioTracks; this.supportsMultiAudioTracks = supportsMultiAudioTracks;
this.usePlayerEndpoint = usePlayerEndpoint;
this.friendlyName = friendlyName; this.friendlyName = friendlyName;
Locale defaultLocale = Locale.getDefault(); Locale defaultLocale = Locale.getDefault();
this.userAgent = String.format("%s/%s (Linux; U; Android %s; %s; %s; Build/%s; Cronet/%s)", this.userAgent = String.format("%s/%s (Linux; U; Android %s; %s; %s; Build/%s)",
packageName, packageName,
clientVersion, clientVersion,
osVersion, osVersion,
defaultLocale, defaultLocale,
deviceModel, deviceModel,
Objects.requireNonNull(buildId), buildId
Objects.requireNonNull(cronetVersion)
); );
Logger.printDebug(() -> "userAgent: " + this.userAgent); Logger.printDebug(() -> "userAgent: " + this.userAgent);
} }
@ -278,6 +249,7 @@ public enum ClientType {
String userAgent, String userAgent,
boolean useAuth, boolean useAuth,
boolean supportsMultiAudioTracks, boolean supportsMultiAudioTracks,
boolean usePlayerEndpoint,
String friendlyName) { String friendlyName) {
this.id = id; this.id = id;
this.clientName = clientName; this.clientName = clientName;
@ -289,10 +261,10 @@ public enum ClientType {
this.userAgent = userAgent; this.userAgent = userAgent;
this.useAuth = useAuth; this.useAuth = useAuth;
this.supportsMultiAudioTracks = supportsMultiAudioTracks; this.supportsMultiAudioTracks = supportsMultiAudioTracks;
this.usePlayerEndpoint = usePlayerEndpoint;
this.friendlyName = friendlyName; this.friendlyName = friendlyName;
this.packageName = null; this.packageName = null;
this.androidSdkVersion = null; this.androidSdkVersion = null;
this.buildId = null; this.buildId = null;
this.cronetVersion = null;
} }
} }

View file

@ -5,7 +5,6 @@ import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -39,7 +38,7 @@ public class SpoofVideoStreamsPatch {
@Nullable @Nullable
private static volatile AppLanguage languageOverride; private static volatile AppLanguage languageOverride;
private static volatile ClientType preferredClient = ClientType.ANDROID_VR_1_43_32; private static volatile ClientType preferredClient = ClientType.ANDROID_REEL;
/** /**
* @return If this patch was included during patching. * @return If this patch was included during patching.
@ -250,7 +249,7 @@ public class SpoofVideoStreamsPatch {
* Called after {@link #fetchStreams(String, Map)}. * Called after {@link #fetchStreams(String, Map)}.
*/ */
@Nullable @Nullable
public static ByteBuffer getStreamingData(String videoId) { public static byte[] getStreamingData(String videoId) {
if (SPOOF_STREAMING_DATA) { if (SPOOF_STREAMING_DATA) {
try { try {
StreamingDataRequest request = StreamingDataRequest.getRequestForVideoId(videoId); StreamingDataRequest request = StreamingDataRequest.getRequestForVideoId(videoId);

View file

@ -15,13 +15,20 @@ import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch; import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
final class PlayerRoutes { final class PlayerRoutes {
static final Route.CompiledRoute GET_STREAMING_DATA = new Route( static final Route.CompiledRoute GET_PLAYER_STREAMING_DATA = new Route(
Route.Method.POST, Route.Method.POST,
"player" + "player" +
"?fields=streamingData" + "?fields=streamingData" +
"&alt=proto" "&alt=proto"
).compile(); ).compile();
static final Route.CompiledRoute GET_REEL_STREAMING_DATA = new Route(
Route.Method.POST,
"reel/reel_item_watch" +
"?fields=playerResponse.playabilityStatus,playerResponse.streamingData" +
"&alt=proto"
).compile();
private static final String YT_API_URL = "https://youtubei.googleapis.com/youtubei/v1/"; private static final String YT_API_URL = "https://youtubei.googleapis.com/youtubei/v1/";
/** /**
@ -47,6 +54,7 @@ final class PlayerRoutes {
Locale streamLocale = language.getLocale(); Locale streamLocale = language.getLocale();
JSONObject client = new JSONObject(); JSONObject client = new JSONObject();
client.put("deviceMake", clientType.deviceMake); client.put("deviceMake", clientType.deviceMake);
client.put("deviceModel", clientType.deviceModel); client.put("deviceModel", clientType.deviceModel);
client.put("clientName", clientType.clientName); client.put("clientName", clientType.clientName);
@ -61,9 +69,19 @@ final class PlayerRoutes {
context.put("client", client); context.put("client", client);
innerTubeBody.put("context", context); innerTubeBody.put("context", context);
innerTubeBody.put("contentCheckOk", true);
innerTubeBody.put("racyCheckOk", true); if (clientType.usePlayerEndpoint) {
innerTubeBody.put("videoId", videoId); innerTubeBody.put("contentCheckOk", true);
innerTubeBody.put("racyCheckOk", true);
innerTubeBody.put("videoId", videoId);
} else {
JSONObject playerRequest = new JSONObject();
playerRequest.put("contentCheckOk", true);
playerRequest.put("racyCheckOk", true);
playerRequest.put("videoId", videoId);
innerTubeBody.put("playerRequest", playerRequest);
innerTubeBody.put("disablePlayerResponse", false);
}
} catch (JSONException e) { } catch (JSONException e) {
Logger.printException(() -> "Failed to create innerTubeBody", e); Logger.printException(() -> "Failed to create innerTubeBody", e);
} }

View file

@ -1,18 +1,17 @@
package app.revanced.extension.shared.spoof.requests; package app.revanced.extension.shared.spoof.requests;
import static app.revanced.extension.shared.ByteTrieSearch.convertStringsToBytes; import static app.revanced.extension.shared.ByteTrieSearch.convertStringsToBytes;
import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_STREAMING_DATA; import static app.revanced.extension.shared.Utils.isNotEmpty;
import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_PLAYER_STREAMING_DATA;
import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_REEL_STREAMING_DATA;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -27,6 +26,11 @@ import java.util.concurrent.TimeoutException;
import app.revanced.extension.shared.ByteTrieSearch; import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.innertube.PlayerResponseOuterClass;
import app.revanced.extension.shared.innertube.PlayerResponseOuterClass.PlayerResponse;
import app.revanced.extension.shared.innertube.PlayerResponseOuterClass.StreamingData;
import app.revanced.extension.shared.innertube.ReelItemWatchResponseOuterClass.ReelItemWatchResponse;
import app.revanced.extension.shared.requests.Route;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.spoof.ClientType; import app.revanced.extension.shared.spoof.ClientType;
@ -41,7 +45,7 @@ import app.revanced.extension.shared.spoof.ClientType;
*/ */
public class StreamingDataRequest { public class StreamingDataRequest {
private static volatile ClientType[] clientOrderToUse = ClientType.values(); private static volatile ClientType[] clientOrderToUse = ClientType.values();
public static void setClientOrderToUse(List<ClientType> availableClients, ClientType preferredClient) { public static void setClientOrderToUse(List<ClientType> availableClients, ClientType preferredClient) {
Objects.requireNonNull(preferredClient); Objects.requireNonNull(preferredClient);
@ -111,7 +115,7 @@ public class StreamingDataRequest {
private final String videoId; private final String videoId;
private final Future<ByteBuffer> future; private final Future<byte[]> future;
private StreamingDataRequest(String videoId, Map<String, String> playerHeaders) { private StreamingDataRequest(String videoId, Map<String, String> playerHeaders) {
Objects.requireNonNull(playerHeaders); Objects.requireNonNull(playerHeaders);
@ -134,6 +138,12 @@ public class StreamingDataRequest {
Logger.printInfo(() -> toastMessage, ex); Logger.printInfo(() -> toastMessage, ex);
} }
private static void handleDebugToast(String toastMessage, ClientType clientType) {
if (BaseSettings.DEBUG.get() && BaseSettings.DEBUG_TOAST_ON_ERROR.get()) {
Utils.showToastShort(String.format(toastMessage, clientType));
}
}
@Nullable @Nullable
private static HttpURLConnection send(ClientType clientType, private static HttpURLConnection send(ClientType clientType,
String videoId, String videoId,
@ -146,7 +156,10 @@ public class StreamingDataRequest {
final long startTime = System.currentTimeMillis(); final long startTime = System.currentTimeMillis();
try { try {
HttpURLConnection connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(GET_STREAMING_DATA, clientType); Route.CompiledRoute route = clientType.usePlayerEndpoint ?
GET_PLAYER_STREAMING_DATA : GET_REEL_STREAMING_DATA;
HttpURLConnection connection = PlayerRoutes.getPlayerResponseConnectionFromRoute(route, clientType);
connection.setConnectTimeout(HTTP_TIMEOUT_MILLISECONDS); connection.setConnectTimeout(HTTP_TIMEOUT_MILLISECONDS);
connection.setReadTimeout(HTTP_TIMEOUT_MILLISECONDS); connection.setReadTimeout(HTTP_TIMEOUT_MILLISECONDS);
@ -203,7 +216,7 @@ public class StreamingDataRequest {
return null; return null;
} }
private static ByteBuffer fetch(String videoId, Map<String, String> playerHeaders) { private static byte[] fetch(String videoId, Map<String, String> playerHeaders) {
final boolean debugEnabled = BaseSettings.DEBUG.get(); final boolean debugEnabled = BaseSettings.DEBUG.get();
// Retry with different client if empty response body is received. // Retry with different client if empty response body is received.
@ -214,33 +227,11 @@ public class StreamingDataRequest {
HttpURLConnection connection = send(clientType, videoId, playerHeaders, showErrorToast); HttpURLConnection connection = send(clientType, videoId, playerHeaders, showErrorToast);
if (connection != null) { if (connection != null) {
try { byte[] playerResponseBuffer = buildPlayerResponseBuffer(clientType, connection);
// gzip encoding doesn't response with content length (-1), if (playerResponseBuffer != null) {
// but empty response body does. lastSpoofedClientType = clientType;
if (connection.getContentLength() == 0) {
if (BaseSettings.DEBUG.get() && BaseSettings.DEBUG_TOAST_ON_ERROR.get()) {
Utils.showToastShort("Debug: Ignoring empty spoof stream client " + clientType);
}
} else {
try (InputStream inputStream = new BufferedInputStream(connection.getInputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[2048]; return playerResponseBuffer;
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) >= 0) {
baos.write(buffer, 0, bytesRead);
}
if (clientType == ClientType.ANDROID_CREATOR && liveStreamBufferSearch.matches(buffer)) {
Logger.printDebug(() -> "Skipping Android Studio as video is a livestream: " + videoId);
} else {
lastSpoofedClientType = clientType;
return ByteBuffer.wrap(baos.toByteArray());
}
}
}
} catch (IOException ex) {
Logger.printException(() -> "Fetch failed while processing response data", ex);
} }
} }
} }
@ -250,12 +241,61 @@ public class StreamingDataRequest {
return null; return null;
} }
@Nullable
private static byte[] buildPlayerResponseBuffer(ClientType clientType,
HttpURLConnection connection) {
// gzip encoding doesn't response with content length (-1),
// but empty response body does.
if (connection.getContentLength() == 0) {
handleDebugToast("Debug: Ignoring empty spoof stream client (%s)", clientType);
return null;
}
try (InputStream inputStream = connection.getInputStream()) {
PlayerResponse playerResponse = clientType.usePlayerEndpoint
? PlayerResponse.parseFrom(inputStream)
: ReelItemWatchResponse.parseFrom(inputStream).getPlayerResponse();
var playabilityStatus = playerResponse.getPlayabilityStatus();
if (playabilityStatus.getStatus() != PlayerResponseOuterClass.Status.OK) {
handleDebugToast("Debug: Ignoring unplayable video (%s)", clientType);
String reason = playabilityStatus.getReason();
if (isNotEmpty(reason)) {
Logger.printDebug(() -> String.format("Debug: Ignoring unplayable video (%s), reason: %s", clientType, reason));
}
return null;
}
PlayerResponse.Builder responseBuilder = playerResponse.toBuilder();
if (!playerResponse.hasStreamingData()) {
handleDebugToast("Debug: Ignoring empty streaming data (%s)", clientType);
return null;
}
// Android Studio only supports the HLS protocol for live streams.
// HLS protocol can theoretically be played with ExoPlayer,
// but the related code has not yet been implemented.
// If DASH protocol is not available, the client will be skipped.
StreamingData streamingData = playerResponse.getStreamingData();
if (streamingData.getAdaptiveFormatsCount() == 0) {
handleDebugToast("Debug: Ignoring empty adaptiveFormat (%s)", clientType);
return null;
}
return responseBuilder.build().toByteArray();
} catch (IOException ex) {
Logger.printException(() -> "Failed to write player response to buffer array", ex);
return null;
}
}
public boolean fetchCompleted() { public boolean fetchCompleted() {
return future.isDone(); return future.isDone();
} }
@Nullable @Nullable
public ByteBuffer getStream() { public byte[] getStream() {
try { try {
return future.get(MAX_MILLISECONDS_TO_WAIT_FOR_FETCH, TimeUnit.MILLISECONDS); return future.get(MAX_MILLISECONDS_TO_WAIT_FOR_FETCH, TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) { } catch (TimeoutException ex) {

View file

@ -0,0 +1,55 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
kotlin("jvm")
alias(libs.plugins.protobuf)
alias(libs.plugins.shadow)
}
val shade: Configuration by configurations.creating {
configurations.getByName("compileClasspath").extendsFrom(this)
configurations.getByName("runtimeClasspath").extendsFrom(this)
}
dependencies {
compileOnly(libs.annotation)
compileOnly(libs.okhttp)
shade(libs.protobuf.javalite)
}
sourceSets {
// Make sure generated proto sources are compiled and end up in the shaded jar
main {
java.srcDir("$buildDir/generated/source/proto/main/java")
}
}
protobuf {
protoc {
artifact = libs.protobuf.protoc.get().toString()
}
generateProtoTasks {
all().forEach { task ->
task.builtins {
named("java") {
option("lite")
}
}
}
}
}
val shadowJar = tasks.named<ShadowJar>("shadowJar") {
configurations = listOf(shade)
relocate("com.google.protobuf", "app.revanced.com.google.protobuf")
}
configurations.named("runtimeElements") {
isCanBeConsumed = true
isCanBeResolved = false
outgoing.artifacts.clear()
outgoing.artifact(shadowJar)
}!!.let { artifacts { add(it.name, shadowJar) } }

View file

@ -0,0 +1,42 @@
syntax = "proto3";
package app.revanced.extension.shared.innertube;
option optimize_for = LITE_RUNTIME;
option java_package = "app.revanced.extension.shared.innertube";
message PlayerResponse {
oneof data {
PlayabilityStatus playability_status = 2;
StreamingData streaming_data = 4;
}
}
message PlayabilityStatus {
Status status = 1;
string reason = 2;
}
enum Status {
OK = 0;
ERROR = 1;
UNPLAYABLE = 2;
LOGIN_REQUIRED = 3;
CONTENT_CHECK_REQUIRED = 4;
AGE_CHECK_REQUIRED = 5;
LIVE_STREAM_OFFLINE = 6;
FULLSCREEN_ONLY = 7;
GL_PLAYBACK_REQUIRED = 8;
AGE_VERIFICATION_REQUIRED = 9;
}
message StreamingData {
repeated Format formats = 2;
repeated Format adaptiveFormats = 3;
string serverAbrStreamingUrl = 15;
}
message Format {
string url = 2;
string signatureCipher = 48;
}

View file

@ -0,0 +1,14 @@
syntax = "proto3";
import "app/revanced/extension/shared/innertube/player_response.proto";
package app.revanced.extension.shared.innertube;
option optimize_for = LITE_RUNTIME;
option java_package = "app.revanced.extension.shared.innertube";
message ReelItemWatchResponse {
oneof data {
PlayerResponse player_response = 4;
}
}

View file

@ -14,7 +14,9 @@ import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import app.revanced.extension.shared.ui.CustomDialog; import app.revanced.extension.shared.ui.CustomDialog;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
@ -29,9 +31,20 @@ import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class AnnouncementsPatch { public final class AnnouncementsPatch {
private static final String[] ANNOUNCEMENT_TAGS = {
"\uD83C\uDF9E\uFE0F YouTube",
};
private AnnouncementsPatch() { private AnnouncementsPatch() {
} }
private static boolean hasSupportedTag(String wrapperTag) {
if (wrapperTag == null) return false;
for (var tag : ANNOUNCEMENT_TAGS) if (tag.equals(wrapperTag)) return true;
return false;
}
private static boolean isLatestAlready() throws IOException { private static boolean isLatestAlready() throws IOException {
HttpURLConnection connection = HttpURLConnection connection =
AnnouncementsRoutes.getAnnouncementsConnectionFromRoute(GET_LATEST_ANNOUNCEMENT_IDS); AnnouncementsRoutes.getAnnouncementsConnectionFromRoute(GET_LATEST_ANNOUNCEMENT_IDS);
@ -56,19 +69,30 @@ public final class AnnouncementsPatch {
var jsonString = Requester.parseStringAndDisconnect(connection); var jsonString = Requester.parseStringAndDisconnect(connection);
// Parse the ID. Fall-back to raw string if it fails. var id = -1;
int id = Settings.ANNOUNCEMENT_LAST_ID.defaultValue;
try { try {
final var announcementIDs = new JSONArray(jsonString); final var announcementIDTagPairs = new JSONArray(jsonString);
if (announcementIDs.length() == 0) return true; if (announcementIDTagPairs.length() == 0) return true;
id = announcementIDs.getJSONObject(0).getInt("id"); JSONObject latest = null;
for (int i = 0, entryCount = announcementIDTagPairs.length(); i < entryCount; i++) {
var pair = announcementIDTagPairs.optJSONObject(i);
if (pair != null && hasSupportedTag(pair.optString("tag", null))) {
latest = pair;
break;
}
}
if (latest == null || latest.isNull("id")) return true;
id = latest.getInt("id");
} catch (Throwable ex) { } catch (Throwable ex) {
Logger.printException(() -> "Failed to parse announcement ID", ex); Logger.printException(() -> "Failed to parse announcement ID", ex);
return true;
} }
// Do not show the announcement, if the last announcement id is the same as the current one. // Do not show the announcement, if the last announcement id is the same as the current one.
return Settings.ANNOUNCEMENT_LAST_ID.get() == id; return Settings.ANNOUNCEMENT_LAST_ID.get().equals(id);
} }
public static void showAnnouncement(final Activity context) { public static void showAnnouncement(final Activity context) {
@ -95,7 +119,22 @@ public final class AnnouncementsPatch {
LocalDateTime archivedAt = LocalDateTime.MAX; LocalDateTime archivedAt = LocalDateTime.MAX;
Level level = Level.INFO; Level level = Level.INFO;
try { try {
final var announcement = new JSONArray(jsonString).getJSONObject(0); final var announcements = new JSONArray(jsonString);
JSONObject latestAnnouncement = null;
for (int i = 0, entryCount = announcements.length(); i < entryCount; i++) {
var announcementTagPair = announcements.optJSONObject(i);
if (announcementTagPair != null && hasSupportedTag(announcementTagPair.optString("tag", null))) {
latestAnnouncement = announcementTagPair;
break;
}
}
if (latestAnnouncement == null || latestAnnouncement.isNull("announcement")) {
Logger.printDebug(() -> "No YouTube announcement found in latest announcements response");
return;
}
final var announcement = latestAnnouncement.getJSONObject("announcement");
id = announcement.getInt("id"); id = announcement.getInt("id");
title = announcement.getString("title"); title = announcement.getString("title");

View file

@ -9,9 +9,9 @@ import java.net.HttpURLConnection;
import static app.revanced.extension.shared.requests.Route.Method.GET; import static app.revanced.extension.shared.requests.Route.Method.GET;
public class AnnouncementsRoutes { public class AnnouncementsRoutes {
private static final String ANNOUNCEMENTS_PROVIDER = "https://api.revanced.app/v4"; private static final String ANNOUNCEMENTS_PROVIDER = "https://api.revanced.app/v5";
public static final Route GET_LATEST_ANNOUNCEMENT_IDS = new Route(GET, "/announcements/latest/id?tag=\uD83C\uDF9E\uFE0F%20YouTube"); public static final Route GET_LATEST_ANNOUNCEMENT_IDS = new Route(GET, "/announcements/latest/id");
public static final Route GET_LATEST_ANNOUNCEMENTS = new Route(GET, "/announcements/latest?tag=\uD83C\uDF9E\uFE0F%20YouTube"); public static final Route GET_LATEST_ANNOUNCEMENTS = new Route(GET, "/announcements/latest");
private AnnouncementsRoutes() { private AnnouncementsRoutes() {
} }

View file

@ -1,10 +1,9 @@
package app.revanced.extension.youtube.patches.spoof; package app.revanced.extension.youtube.patches.spoof;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_CREATOR; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_CREATOR;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_NO_SDK;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
import static app.revanced.extension.shared.spoof.ClientType.IPADOS; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_REEL;
import static app.revanced.extension.shared.spoof.ClientType.VISIONOS; import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
import java.util.List; import java.util.List;
@ -44,11 +43,11 @@ public class SpoofVideoStreamsPatch {
} }
List<ClientType> availableClients = List.of( List<ClientType> availableClients = List.of(
VISIONOS, ANDROID_REEL,
ANDROID_CREATOR,
ANDROID_VR_1_43_32, ANDROID_VR_1_43_32,
ANDROID_NO_SDK, VISIONOS,
IPADOS); ANDROID_CREATOR
);
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse( app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
availableClients, client); availableClients, client);

View file

@ -19,7 +19,7 @@ import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings({"deprecation", "unused"}) @SuppressWarnings({"deprecation", "unused"})
public class SpoofStreamingDataSideEffectsPreference extends Preference { public class SpoofVideoStreamsSideEffectsPreference extends Preference {
@Nullable @Nullable
private ClientType currentClientType; private ClientType currentClientType;
@ -33,19 +33,19 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
Utils.runOnMainThread(this::updateUI); Utils.runOnMainThread(this::updateUI);
}; };
public SpoofStreamingDataSideEffectsPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { public SpoofVideoStreamsSideEffectsPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes); super(context, attrs, defStyleAttr, defStyleRes);
} }
public SpoofStreamingDataSideEffectsPreference(Context context, AttributeSet attrs, int defStyleAttr) { public SpoofVideoStreamsSideEffectsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
} }
public SpoofStreamingDataSideEffectsPreference(Context context, AttributeSet attrs) { public SpoofVideoStreamsSideEffectsPreference(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
public SpoofStreamingDataSideEffectsPreference(Context context) { public SpoofVideoStreamsSideEffectsPreference(Context context) {
super(context); super(context);
} }
@ -88,27 +88,23 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
+ '\n' + str("revanced_spoof_video_streams_about_no_stable_volume") + '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
+ '\n' + str("revanced_spoof_video_streams_about_no_av1") + '\n' + str("revanced_spoof_video_streams_about_no_av1")
+ '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio"); + '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio");
case ANDROID_REEL ->
summary = str("revanced_spoof_video_streams_about_playback_failure");
// VR 1.61 is not exposed in the UI and should never be reached here. // VR 1.61 is not exposed in the UI and should never be reached here.
case ANDROID_VR_1_43_32, ANDROID_VR_1_61_48 -> case ANDROID_VR_1_43_32, ANDROID_VR_1_61_48 ->
summary = str("revanced_spoof_video_streams_about_no_audio_tracks")
+ '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
case ANDROID_NO_SDK ->
summary = str("revanced_spoof_video_streams_about_playback_failure");
case IPADOS ->
summary = str("revanced_spoof_video_streams_about_playback_failure") summary = str("revanced_spoof_video_streams_about_playback_failure")
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");
case VISIONOS ->
summary = str("revanced_spoof_video_streams_about_experimental")
+ '\n' + str("revanced_spoof_video_streams_about_no_audio_tracks") + '\n' + str("revanced_spoof_video_streams_about_no_audio_tracks")
+ '\n' + str("revanced_spoof_video_streams_about_no_av1"); + '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
case VISIONOS -> summary = str("revanced_spoof_video_streams_about_experimental")
+ '\n' + str("revanced_spoof_video_streams_about_playback_failure")
+ '\n' + str("revanced_spoof_video_streams_about_no_audio_tracks")
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");
default -> Logger.printException(() -> "Unknown client: " + clientType); default -> Logger.printException(() -> "Unknown client: " + clientType);
} }
// Only iPadOS can play children videos in incognito, but it commonly fails at 1 minute // Only Android Reel and Android VR supports 360° VR immersive mode.
// or doesn't start playback at all. List the side effect for other clients if (!clientType.name().startsWith("ANDROID_VR") && clientType != ClientType.ANDROID_REEL) {
// since they will fall over to iPadOS. summary += '\n' + str("revanced_spoof_video_streams_about_no_immersive_mode");
if (clientType != ClientType.IPADOS && clientType != ClientType.ANDROID_NO_SDK) {
summary += '\n' + str("revanced_spoof_video_streams_about_kids_videos");
} }
// Use better formatting for bullet points. // Use better formatting for bullet points.

View file

@ -4,4 +4,4 @@ org.gradle.parallel = true
android.useAndroidX = true android.useAndroidX = true
android.uniquePackageNames = false android.uniquePackageNames = false
kotlin.code.style = official kotlin.code.style = official
version = 6.0.1 version = 6.1.0-dev.4

View file

@ -10,6 +10,10 @@ okhttp = "5.3.2"
retrofit = "3.0.0" retrofit = "3.0.0"
guava = "33.5.0-jre" guava = "33.5.0-jre"
apksig = "9.0.1" apksig = "9.0.1"
# TODO: Adjust once https://github.com/google/protobuf-gradle-plugin/pull/797 is merged.
protobuf = "master-SNAPSHOT"
protoc = "4.34.0"
shadow = "9.4.0"
[libraries] [libraries]
annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" } annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" }
@ -18,6 +22,10 @@ okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
guava = { module = "com.google.guava:guava", version.ref = "guava" } guava = { module = "com.google.guava:guava", version.ref = "guava" }
apksig = { group = "com.android.tools.build", name = "apksig", version.ref = "apksig" } apksig = { group = "com.android.tools.build", name = "apksig", version.ref = "apksig" }
protobuf-javalite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protoc" }
protobuf-protoc = { module = "com.google.protobuf:protoc", version.ref = "protoc" }
[plugins] [plugins]
android-library = { id = "com.android.library" } android-library = { id = "com.android.library" }
protobuf = { id = "com.google.protobuf", version.ref = "protobuf" }
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }

View file

@ -89,10 +89,14 @@ public final class app/revanced/patches/all/misc/packagename/ChangePackageNamePa
public static final fun setOrGetFallbackPackageName (Ljava/lang/String;)Ljava/lang/String; public static final fun setOrGetFallbackPackageName (Ljava/lang/String;)Ljava/lang/String;
} }
public final class app/revanced/patches/all/misc/playintegrity/DisablePlayIntegrityKt { public final class app/revanced/patches/all/misc/play/DisablePlayIntegrityKt {
public static final fun getDisablePlayIntegrityPatch ()Lapp/revanced/patcher/patch/Patch; public static final fun getDisablePlayIntegrityPatch ()Lapp/revanced/patcher/patch/Patch;
} }
public final class app/revanced/patches/all/misc/play/SpoofPlayAgeSignalsKt {
public static final fun getSpoofPlayAgeSignalsPatch ()Lapp/revanced/patcher/patch/Patch;
}
public final class app/revanced/patches/all/misc/resources/AddResourcesPatchKt { public final class app/revanced/patches/all/misc/resources/AddResourcesPatchKt {
public static final fun addResource (Ljava/lang/String;Lapp/revanced/util/resource/BaseResource;)Z public static final fun addResource (Ljava/lang/String;Lapp/revanced/util/resource/BaseResource;)Z
public static final fun addResources (Lapp/revanced/patcher/patch/Patch;Lkotlin/jvm/functions/Function1;)Z public static final fun addResources (Lapp/revanced/patcher/patch/Patch;Lkotlin/jvm/functions/Function1;)Z
@ -125,6 +129,14 @@ public final class app/revanced/patches/all/misc/spoof/EnableRomSignatureSpoofin
public static final fun getEnableROMSignatureSpoofingPatch ()Lapp/revanced/patcher/patch/Patch; public static final fun getEnableROMSignatureSpoofingPatch ()Lapp/revanced/patcher/patch/Patch;
} }
public final class app/revanced/patches/all/misc/spoof/SpoofKeystoreSecurityLevelPatchKt {
public static final fun getSpoofKeystoreSecurityLevelPatch ()Lapp/revanced/patcher/patch/Patch;
}
public final class app/revanced/patches/all/misc/spoof/SpoofRootOfTrustPatchKt {
public static final fun getSpoofRootOfTrustPatch ()Lapp/revanced/patcher/patch/Patch;
}
public final class app/revanced/patches/all/misc/targetSdk/SetTargetSdkVersion34Kt { public final class app/revanced/patches/all/misc/targetSdk/SetTargetSdkVersion34Kt {
public static final fun getSetTargetSDKVersion34Patch ()Lapp/revanced/patcher/patch/Patch; public static final fun getSetTargetSDKVersion34Patch ()Lapp/revanced/patcher/patch/Patch;
} }
@ -365,6 +377,10 @@ public final class app/revanced/patches/instagram/story/flipping/DisableStoryAut
public static final fun getDisableStoryAutoFlippingPatch ()Lapp/revanced/patcher/patch/Patch; public static final fun getDisableStoryAutoFlippingPatch ()Lapp/revanced/patcher/patch/Patch;
} }
public final class app/revanced/patches/instagram/story/locationsticker/EnableLocationStickerRedesignPatchKt {
public static final fun getEnableLocationStickerRedesignPatch ()Lapp/revanced/patcher/patch/Patch;
}
public final class app/revanced/patches/irplus/ad/RemoveAdsPatchKt { public final class app/revanced/patches/irplus/ad/RemoveAdsPatchKt {
public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/Patch; public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/Patch;
} }

View file

@ -6,7 +6,7 @@ patches {
description = "Patches for ReVanced" description = "Patches for ReVanced"
source = "git@github.com:revanced/revanced-patches.git" source = "git@github.com:revanced/revanced-patches.git"
author = "ReVanced" author = "ReVanced"
contact = "contact@revanced.app" contact = "patches@revanced.app"
website = "https://revanced.app" website = "https://revanced.app"
license = "GNU General Public License v3.0" license = "GNU General Public License v3.0"
} }

View file

@ -6,7 +6,8 @@ import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.intOption import app.revanced.patcher.patch.intOption
import app.revanced.patcher.patch.stringOption import app.revanced.patcher.patch.stringOption
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch import app.revanced.util.forEachInstructionAsSequence
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction 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.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@ -33,7 +34,8 @@ val spoofSIMProviderPatch = bytecodePatch(
validator = { it: String? -> it == null || it.uppercase() in countries.values }, validator = { it: String? -> it == null || it.uppercase() in countries.values },
) )
fun isMccMncValid(it: Int?): Boolean = it == null || (it >= 10000 && it <= 999999) fun isMccMncValid(it: Int?) = it == null || (it in 10000..999999)
fun isNumericValid(it: String?, length: Int) = it.isNullOrBlank() || it.equals("random", true) || it.length == length
val networkCountryIso by isoCountryPatchOption("Network ISO country code") val networkCountryIso by isoCountryPatchOption("Network ISO country code")
@ -61,46 +63,119 @@ val spoofSIMProviderPatch = bytecodePatch(
description = "The full name of the SIM operator.", description = "The full name of the SIM operator.",
) )
val imei by stringOption(
name = "IMEI value",
description = "15-digit IMEI to spoof, blank to skip, or 'random'.",
validator = { isNumericValid(it, 15) },
)
val meid by stringOption(
name = "MEID value",
description = "14-char hex MEID to spoof, blank to skip, or 'random'.",
validator = { isNumericValid(it, 14) },
)
val imsi by stringOption(
name = "IMSI (Subscriber ID)",
description = "15-digit IMSI to spoof, blank to skip, or 'random'.",
validator = { isNumericValid(it, 15) },
)
val iccid by stringOption(
name = "ICCID (SIM Serial)",
description = "19-digit ICCID to spoof, blank to skip, or 'random'.",
validator = { isNumericValid(it, 19) },
)
val phone by stringOption(
name = "Phone number",
description = "Phone number to spoof, blank to skip, or 'random'.",
validator = { it.isNullOrBlank() || it.equals("random", ignoreCase = true) || it.startsWith("+") },
)
dependsOn( dependsOn(
transformInstructionsPatch( bytecodePatch {
filterMap = { _, _, instruction, instructionIndex -> apply {
if (instruction !is ReferenceInstruction) return@transformInstructionsPatch null fun generateRandomNumeric(length: Int) = (1..length).map { ('0'..'9').random() }.joinToString("")
val reference = instruction.reference as? MethodReference ?: return@transformInstructionsPatch null fun String?.computeSpoof(randomizer: () -> String): String? {
if (this.isNullOrBlank()) return null
val match = MethodCall.entries.firstOrNull { search -> if (this.equals("random", ignoreCase = true)) return randomizer()
MethodUtil.methodSignaturesMatch(reference, search.reference) return this
} ?: return@transformInstructionsPatch null
val replacement = when (match) {
MethodCall.NetworkCountryIso -> networkCountryIso?.lowercase()
MethodCall.NetworkOperator -> networkOperator?.toString()
MethodCall.NetworkOperatorName -> networkOperatorName
MethodCall.SimCountryIso -> simCountryIso?.lowercase()
MethodCall.SimOperator -> simOperator?.toString()
MethodCall.SimOperatorName -> simOperatorName
} }
replacement?.let { instructionIndex to it }
}, // Calculate the Luhn checksum (mod 10) to generate a valid 15th digit, standard for IMEI numbers.
transform = ::transformMethodCall, // Structure of an IMEI is as follows:
), // TAC (Type Allocation Code): First 8 digits (e.g., "86" + 6 digits)
// SNR (Serial Number): Next 6 digits
// CD (Check Digit): The 15th digit
val computedImei = imei.computeSpoof {
val prefix = "86" + generateRandomNumeric(12)
val sum = prefix.mapIndexed { i, c ->
var d = c.digitToInt()
// Double every second digit (index 1, 3, 5...).
if (i % 2 != 0) {
d *= 2
// If result is two digits (e.g. 14), sum them (1+4=5).
// This is mathematically equivalent to d - 9.
if (d > 9) d -= 9
}
d
}.sum()
// Append the calculated check digit to the 14-digit prefix.
prefix + ((10 - (sum % 10)) % 10)
}
val computedMeid = meid.computeSpoof { (1..14).map { "0123456789ABCDEF".random() }.joinToString("") }?.uppercase()
val computedImsi = imsi.computeSpoof { generateRandomNumeric(15) }
val computedIccid = iccid.computeSpoof { "89" + generateRandomNumeric(17) }
val computedPhone = phone.computeSpoof { "+" + generateRandomNumeric(11) }
forEachInstructionAsSequence(
match = { _, _, instruction, instructionIndex ->
if (instruction !is ReferenceInstruction) return@forEachInstructionAsSequence null
val reference = instruction.reference as? MethodReference ?: return@forEachInstructionAsSequence null
val match = MethodCall.entries.firstOrNull { search ->
MethodUtil.methodSignaturesMatch(reference, search.reference)
} ?: return@forEachInstructionAsSequence null
val replacement = when (match) {
MethodCall.NetworkCountryIso -> networkCountryIso?.lowercase()
MethodCall.NetworkOperator -> networkOperator?.toString()
MethodCall.NetworkOperatorName -> networkOperatorName
MethodCall.SimCountryIso -> simCountryIso?.lowercase()
MethodCall.SimOperator -> simOperator?.toString()
MethodCall.SimOperatorName -> simOperatorName
MethodCall.Imei, MethodCall.ImeiWithSlot, MethodCall.DeviceId, MethodCall.DeviceIdWithSlot -> computedImei
MethodCall.Meid, MethodCall.MeidWithSlot -> computedMeid
MethodCall.SubscriberId, MethodCall.SubscriberIdWithSlot -> computedImsi
MethodCall.SimSerialNumber, MethodCall.SimSerialNumberWithSlot -> computedIccid
MethodCall.Line1Number, MethodCall.Line1NumberWithSlot -> computedPhone
}
replacement?.let { instructionIndex to it }
},
transform = ::transformMethodCall
)
}
},
) )
} }
private fun transformMethodCall( private fun transformMethodCall(mutableMethod: MutableMethod, entry: Pair<Int, String>) {
mutableMethod: MutableMethod, val (index, value) = entry
entry: Pair<Int, String>, val nextInstr = mutableMethod.getInstruction<Instruction>(index + 1)
) {
val (instructionIndex, methodCallValue) = entry
// Get the register which would have contained the return value if (nextInstr.opcode.name != "move-result-object") {
val register = mutableMethod.getInstruction<OneRegisterInstruction>(instructionIndex + 1).registerA mutableMethod.replaceInstruction(index, "nop")
return
}
// Replace the move-result instruction with our fake value val register = (nextInstr as OneRegisterInstruction).registerA
mutableMethod.replaceInstruction( mutableMethod.replaceInstruction(index, "const-string v$register, \"$value\"")
instructionIndex + 1, mutableMethod.replaceInstruction(index + 1, "nop")
"const-string v$register, \"$methodCallValue\"",
)
} }
private enum class MethodCall( private enum class MethodCall(
@ -154,4 +229,100 @@ private enum class MethodCall(
"Ljava/lang/String;", "Ljava/lang/String;",
), ),
), ),
Imei(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getImei",
emptyList(),
"Ljava/lang/String;"
),
),
ImeiWithSlot(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getImei",
listOf("I"),
"Ljava/lang/String;"
),
),
DeviceId(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getDeviceId",
emptyList(),
"Ljava/lang/String;"
),
),
DeviceIdWithSlot(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getDeviceId",
listOf("I"),
"Ljava/lang/String;"
),
),
Meid(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getMeid",
emptyList(),
"Ljava/lang/String;"
),
),
MeidWithSlot(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getMeid",
listOf("I"),
"Ljava/lang/String;"
),
),
SubscriberId(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getSubscriberId",
emptyList(),
"Ljava/lang/String;"
)
),
SubscriberIdWithSlot(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getSubscriberId",
listOf("I"),
"Ljava/lang/String;"
)
),
SimSerialNumber(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getSimSerialNumber",
emptyList(),
"Ljava/lang/String;"
)
),
SimSerialNumberWithSlot(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getSimSerialNumber",
listOf("I"),
"Ljava/lang/String;"
)
),
Line1Number(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getLine1Number",
emptyList(),
"Ljava/lang/String;"
)
),
Line1NumberWithSlot(
ImmutableMethodReference(
"Landroid/telephony/TelephonyManager;",
"getLine1Number",
listOf("I"),
"Ljava/lang/String;"
)
)
} }

View file

@ -3,7 +3,7 @@ package app.revanced.patches.all.misc.connectivity.wifi.spoof
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.transformation.IMethodCall import app.revanced.patches.all.misc.transformation.IMethodCall
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch import app.revanced.util.forEachInstructionAsSequence
private const val EXTENSION_CLASS_DESCRIPTOR_PREFIX = private const val EXTENSION_CLASS_DESCRIPTOR_PREFIX =
"Lapp/revanced/extension/all/misc/connectivity/wifi/spoof/SpoofWifiPatch" "Lapp/revanced/extension/all/misc/connectivity/wifi/spoof/SpoofWifiPatch"
@ -19,29 +19,32 @@ val spoofWiFiConnectionPatch = bytecodePatch(
extendWith("extensions/all/misc/connectivity/wifi/spoof/spoof-wifi.rve") extendWith("extensions/all/misc/connectivity/wifi/spoof/spoof-wifi.rve")
dependsOn( dependsOn(
transformInstructionsPatch( bytecodePatch {
filterMap = { classDef, _, instruction, instructionIndex -> apply {
filterMapInstruction35c<MethodCall>( forEachInstructionAsSequence(
EXTENSION_CLASS_DESCRIPTOR_PREFIX, match = { classDef, _, instruction, instructionIndex ->
classDef, filterMapInstruction35c<MethodCall>(
instruction, EXTENSION_CLASS_DESCRIPTOR_PREFIX,
instructionIndex, classDef,
) instruction,
}, instructionIndex,
transform = { method, entry -> )
val (methodType, instruction, instructionIndex) = entry },
methodType.replaceInvokeVirtualWithExtension( transform = { method, entry ->
EXTENSION_CLASS_DESCRIPTOR, val (methodType, instruction, instructionIndex) = entry
method, methodType.replaceInvokeVirtualWithExtension(
instruction, EXTENSION_CLASS_DESCRIPTOR,
instructionIndex, method,
) instruction,
}, instructionIndex,
), )
})
}
},
) )
} }
// Information about method calls we want to replace // Information about method calls we want to replace.
@Suppress("unused") @Suppress("unused")
private enum class MethodCall( private enum class MethodCall(
override val definedClassName: String, override val definedClassName: String,
@ -89,13 +92,13 @@ private enum class MethodCall(
"Landroid/net/NetworkInfo;", "Landroid/net/NetworkInfo;",
"getState", "getState",
arrayOf(), arrayOf(),
"Landroid/net/NetworkInfo\$State;", $$"Landroid/net/NetworkInfo$State;",
), ),
GetDetailedState( GetDetailedState(
"Landroid/net/NetworkInfo;", "Landroid/net/NetworkInfo;",
"getDetailedState", "getDetailedState",
arrayOf(), arrayOf(),
"Landroid/net/NetworkInfo\$DetailedState;", $$"Landroid/net/NetworkInfo$DetailedState;",
), ),
IsActiveNetworkMetered( IsActiveNetworkMetered(
"Landroid/net/ConnectivityManager;", "Landroid/net/ConnectivityManager;",
@ -132,7 +135,7 @@ private enum class MethodCall(
"registerBestMatchingNetworkCallback", "registerBestMatchingNetworkCallback",
arrayOf( arrayOf(
"Landroid/net/NetworkRequest;", "Landroid/net/NetworkRequest;",
"Landroid/net/ConnectivityManager\$NetworkCallback;", $$"Landroid/net/ConnectivityManager$NetworkCallback;",
"Landroid/os/Handler;", "Landroid/os/Handler;",
), ),
"V", "V",
@ -140,19 +143,19 @@ private enum class MethodCall(
RegisterDefaultNetworkCallback1( RegisterDefaultNetworkCallback1(
"Landroid/net/ConnectivityManager;", "Landroid/net/ConnectivityManager;",
"registerDefaultNetworkCallback", "registerDefaultNetworkCallback",
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"), arrayOf($$"Landroid/net/ConnectivityManager$NetworkCallback;"),
"V", "V",
), ),
RegisterDefaultNetworkCallback2( RegisterDefaultNetworkCallback2(
"Landroid/net/ConnectivityManager;", "Landroid/net/ConnectivityManager;",
"registerDefaultNetworkCallback", "registerDefaultNetworkCallback",
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"), arrayOf($$"Landroid/net/ConnectivityManager$NetworkCallback;", "Landroid/os/Handler;"),
"V", "V",
), ),
RegisterNetworkCallback1( RegisterNetworkCallback1(
"Landroid/net/ConnectivityManager;", "Landroid/net/ConnectivityManager;",
"registerNetworkCallback", "registerNetworkCallback",
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"), arrayOf("Landroid/net/NetworkRequest;", $$"Landroid/net/ConnectivityManager$NetworkCallback;"),
"V", "V",
), ),
RegisterNetworkCallback2( RegisterNetworkCallback2(
@ -166,7 +169,7 @@ private enum class MethodCall(
"registerNetworkCallback", "registerNetworkCallback",
arrayOf( arrayOf(
"Landroid/net/NetworkRequest;", "Landroid/net/NetworkRequest;",
"Landroid/net/ConnectivityManager\$NetworkCallback;", $$"Landroid/net/ConnectivityManager$NetworkCallback;",
"Landroid/os/Handler;", "Landroid/os/Handler;",
), ),
"V", "V",
@ -174,13 +177,13 @@ private enum class MethodCall(
RequestNetwork1( RequestNetwork1(
"Landroid/net/ConnectivityManager;", "Landroid/net/ConnectivityManager;",
"requestNetwork", "requestNetwork",
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"), arrayOf("Landroid/net/NetworkRequest;", $$"Landroid/net/ConnectivityManager$NetworkCallback;"),
"V", "V",
), ),
RequestNetwork2( RequestNetwork2(
"Landroid/net/ConnectivityManager;", "Landroid/net/ConnectivityManager;",
"requestNetwork", "requestNetwork",
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "I"), arrayOf("Landroid/net/NetworkRequest;", $$"Landroid/net/ConnectivityManager$NetworkCallback;", "I"),
"V", "V",
), ),
RequestNetwork3( RequestNetwork3(
@ -188,7 +191,7 @@ private enum class MethodCall(
"requestNetwork", "requestNetwork",
arrayOf( arrayOf(
"Landroid/net/NetworkRequest;", "Landroid/net/NetworkRequest;",
"Landroid/net/ConnectivityManager\$NetworkCallback;", $$"Landroid/net/ConnectivityManager$NetworkCallback;",
"Landroid/os/Handler;", "Landroid/os/Handler;",
), ),
"V", "V",
@ -204,7 +207,7 @@ private enum class MethodCall(
"requestNetwork", "requestNetwork",
arrayOf( arrayOf(
"Landroid/net/NetworkRequest;", "Landroid/net/NetworkRequest;",
"Landroid/net/ConnectivityManager\$NetworkCallback;", $$"Landroid/net/ConnectivityManager$NetworkCallback;",
"Landroid/os/Handler;", "Landroid/os/Handler;",
"I", "I",
), ),
@ -213,7 +216,7 @@ private enum class MethodCall(
UnregisterNetworkCallback1( UnregisterNetworkCallback1(
"Landroid/net/ConnectivityManager;", "Landroid/net/ConnectivityManager;",
"unregisterNetworkCallback", "unregisterNetworkCallback",
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"), arrayOf($$"Landroid/net/ConnectivityManager$NetworkCallback;"),
"V", "V",
), ),
UnregisterNetworkCallback2( UnregisterNetworkCallback2(

View file

@ -1,4 +1,4 @@
package app.revanced.patches.all.misc.playintegrity package app.revanced.patches.all.misc.play
import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
@ -9,7 +9,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil import com.android.tools.smali.dexlib2.util.MethodUtil
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/playintegrity/DisablePlayIntegrityPatch;" private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/play/DisablePlayIntegrityPatch;"
private val CONTEXT_BIND_SERVICE_METHOD_REFERENCE = ImmutableMethodReference( private val CONTEXT_BIND_SERVICE_METHOD_REFERENCE = ImmutableMethodReference(
"Landroid/content/Context;", "Landroid/content/Context;",

View file

@ -0,0 +1,138 @@
package app.revanced.patches.all.misc.play
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.intOption
import app.revanced.patcher.patch.option
import app.revanced.util.forEachInstructionAsSequence
import app.revanced.util.getReference
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.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference
@Suppress("unused")
val spoofPlayAgeSignalsPatch = bytecodePatch(
name = "Spoof Play Age Signals",
description = "Spoofs Google Play data about the user's age and verification status.",
use = false,
) {
val lowerAgeBound by intOption(
name = "Lower age bound",
description = "A positive integer.",
default = 18,
validator = { it == null || it > 0 },
)
val upperAgeBound by intOption(
name = "Upper age bound",
description = "A positive integer. Must be greater than the lower age bound.",
default = Int.MAX_VALUE,
validator = { it == null || it > lowerAgeBound!! },
)
val userStatus by intOption(
name = "User status",
description = "An integer representing the user status.",
default = UserStatus.VERIFIED.value,
values = UserStatus.entries.associate { it.name to it.value },
)
apply {
forEachInstructionAsSequence(match = { classDef, _, instruction, instructionIndex ->
// Avoid patching the library itself.
if (classDef.type.startsWith("Lcom/google/android/play/agesignals/")) return@forEachInstructionAsSequence null
// Keep method calls only.
val reference = instruction.getReference<MethodReference>()
?: return@forEachInstructionAsSequence null
val match = MethodCall.entries.firstOrNull {
reference == it.reference
} ?: return@forEachInstructionAsSequence null
val replacement = when (match) {
MethodCall.AgeLower -> lowerAgeBound!!
MethodCall.AgeUpper -> upperAgeBound!!
MethodCall.UserStatus -> userStatus!!
}
replacement.let { instructionIndex to it }
}, transform = { method, entry ->
val (instructionIndex, replacement) = entry
// Get the register which would have contained the return value.
val register = method.getInstruction<OneRegisterInstruction>(instructionIndex + 1).registerA
// Replace the call instructions with the spoofed value.
method.removeInstructions(instructionIndex, 2)
method.addInstructions(
instructionIndex,
"""
const v$register, $replacement
invoke-static { v$register }, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v$register
""".trimIndent(),
)
})
}
}
/**
* See [AgeSignalsResult](https://developer.android.com/google/play/age-signals/reference/com/google/android/play/agesignals/AgeSignalsResult).
*/
private enum class MethodCall(
val reference: MethodReference,
) {
AgeLower(
ImmutableMethodReference(
"Lcom/google/android/play/agesignals/AgeSignalsResult;",
"ageLower",
emptyList(),
"Ljava/lang/Integer;",
),
),
AgeUpper(
ImmutableMethodReference(
"Lcom/google/android/play/agesignals/AgeSignalsResult;",
"ageUpper",
emptyList(),
"Ljava/lang/Integer;",
),
),
UserStatus(
ImmutableMethodReference(
"Lcom/google/android/play/agesignals/AgeSignalsResult;",
"userStatus",
emptyList(),
"Ljava/lang/Integer;",
),
),
}
/**
* All possible user verification statuses.
*
* See [AgeSignalsVerificationStatus](https://developer.android.com/google/play/age-signals/reference/com/google/android/play/agesignals/model/AgeSignalsVerificationStatus).
*/
private enum class UserStatus(val value: Int) {
/** The user provided their age, but it hasn't been verified yet. */
DECLARED(5),
/** The user is 18+. */
VERIFIED(0),
/** The user's guardian has set the age for him. */
SUPERVISED(1),
/** The user's guardian hasn't approved the significant changes yet. */
SUPERVISED_APPROVAL_PENDING(2),
/** The user's guardian has denied approval for one or more pending significant changes. */
SUPERVISED_APPROVAL_DENIED(3),
/** The user is not verified or supervised. */
UNKNOWN(4),
}

View file

@ -0,0 +1,28 @@
package app.revanced.patches.all.misc.spoof
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.forEachInstructionAsSequence
@Suppress("unused")
val spoofKeystoreSecurityLevelPatch = bytecodePatch(
name = "Spoof keystore security level",
description = "Forces apps to see Keymaster and Attestation security levels as 'StrongBox' (Level 2).",
use = false
) {
apply {
forEachInstructionAsSequence(
match = { _, method, _, _ ->
// Match methods by comparing the current method to a reference criteria.
val name = method.name.lowercase()
if (name.contains("securitylevel") && method.returnType == "I") method else null
},
transform = { mutableMethod, _ ->
// Ensure the method has an implementation before replacing.
if (mutableMethod.implementation?.instructions?.iterator()?.hasNext() == true) {
mutableMethod.replaceInstructions(0, "const/4 v0, 0x2\nreturn v0")
}
}
)
}
}

View file

@ -0,0 +1,70 @@
package app.revanced.patches.all.misc.spoof
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.forEachInstructionAsSequence
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
@Suppress("unused")
val spoofRootOfTrustPatch = bytecodePatch(
name = "Spoof root of trust",
description = "Spoofs device integrity states (Locked Bootloader, Verified OS) for apps that perform local certificate attestation.",
use = false
) {
apply {
forEachInstructionAsSequence(
match = { _, method, _, _ ->
MethodCall.entries.firstOrNull { MethodUtil.methodSignaturesMatch(method, it.reference) }
},
transform = { mutableMethod, methodCall ->
if (mutableMethod.implementation?.instructions?.iterator()?.hasNext() == true) {
mutableMethod.replaceInstructions(0, methodCall.replacementInstructions)
}
}
)
}
}
private enum class MethodCall(
val reference: MethodReference,
val replacementInstructions: String,
) {
IsDeviceLockedRootOfTrust(
ImmutableMethodReference(
"LRootOfTrust;",
"isDeviceLocked",
emptyList(),
"Z"
),
"const/4 v0, 0x1\nreturn v0",
),
GetVerifiedBootStateRootOfTrust(
ImmutableMethodReference(
"LRootOfTrust;",
"getVerifiedBootState",
emptyList(),
"I"
),
"const/4 v0, 0x0\nreturn v0",
),
IsDeviceLockedAttestation(
ImmutableMethodReference(
"LAttestation;",
"isDeviceLocked",
emptyList(),
"Z"
),
"const/4 v0, 0x1\nreturn v0",
),
GetVerifiedBootStateAttestation(
ImmutableMethodReference(
"LAttestation;",
"getVerifiedBootState",
emptyList(),
"I"
),
"const/4 v0, 0x0\nreturn v0",
),
}

View file

@ -0,0 +1,20 @@
package app.revanced.patches.instagram.story.locationsticker
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val enableLocationStickerRedesignPatch = bytecodePatch(
name = "Enable location sticker redesign",
description = "Unlocks the redesigned location sticker with additional style options.",
use = false,
) {
compatibleWith("com.instagram.android")
apply {
// The gate method reads a MobileConfig boolean flag and returns it directly.
// Returning early with true bypasses the flag check entirely,
// enabling the redesigned sticker styles regardless of server configuration.
locationStickerRedesignGateMethodMatch.method.returnEarly(true)
}
}

View file

@ -0,0 +1,16 @@
package app.revanced.patches.instagram.story.locationsticker
import app.revanced.patcher.composingFirstMethod
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.patch.BytecodePatchContext
// MobileConfig boolean key that gates the redesigned location sticker styles.
// The method containing this constant reads the flag and returns it directly,
// making it the sole control point for the feature. The key is stable across
// app updates as MobileConfig keys are server-assigned constants.
private const val LOCATION_STICKER_REDESIGN_CONFIG_KEY = 0x8105a100041e0dL
internal val BytecodePatchContext.locationStickerRedesignGateMethodMatch by composingFirstMethod {
instructions(LOCATION_STICKER_REDESIGN_CONFIG_KEY())
}

View file

@ -3,7 +3,6 @@ package app.revanced.patches.shared.layout.branding
import app.revanced.com.android.tools.smali.dexlib2.mutable.MutableMethod import app.revanced.com.android.tools.smali.dexlib2.mutable.MutableMethod
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.firstImmutableClassDef
import app.revanced.patcher.patch.* import app.revanced.patcher.patch.*
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
@ -126,14 +125,14 @@ internal fun baseCustomBrandingPatch(
val getBuilderIndex = if (isYouTubeMusic) { val getBuilderIndex = if (isYouTubeMusic) {
// YT Music the field is not a plain object type. // YT Music the field is not a plain object type.
indexOfFirstInstructionOrThrow { indexOfFirstInstructionOrThrow {
getReference<FieldReference>()?.type == "Landroid/app/Notification\$Builder;" getReference<FieldReference>()?.type == $$"Landroid/app/Notification$Builder;"
} }
} else { } else {
// Find the field name of the notification builder. Field is an Object type. // Find the field name of the notification builder. Field is an Object type.
val builderCastIndex = indexOfFirstInstructionOrThrow { val builderCastIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<TypeReference>() val reference = getReference<TypeReference>()
opcode == Opcode.CHECK_CAST && opcode == Opcode.CHECK_CAST &&
reference?.type == "Landroid/app/Notification\$Builder;" reference?.type == $$"Landroid/app/Notification$Builder;"
} }
indexOfFirstInstructionReversedOrThrow(builderCastIndex) { indexOfFirstInstructionReversedOrThrow(builderCastIndex) {
getReference<FieldReference>()?.type == "Ljava/lang/Object;" getReference<FieldReference>()?.type == "Ljava/lang/Object;"
@ -148,11 +147,11 @@ internal fun baseCustomBrandingPatch(
).forEach { index -> ).forEach { index ->
addInstructionsAtControlFlowLabel( addInstructionsAtControlFlowLabel(
index, index,
""" $$"""
move-object/from16 v0, p0 move-object/from16 v0, p0
iget-object v0, v0, $builderFieldName iget-object v0, v0, $$builderFieldName
check-cast v0, Landroid/app/Notification${'$'}Builder; check-cast v0, Landroid/app/Notification$Builder;
invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->setNotificationIcon(Landroid/app/Notification${'$'}Builder;)V invoke-static { v0 }, $$EXTENSION_CLASS_DESCRIPTOR->setNotificationIcon(Landroid/app/Notification$Builder;)V
""", """,
) )
} }
@ -162,16 +161,37 @@ internal fun baseCustomBrandingPatch(
) )
afterDependents { afterDependents {
val useCustomName = customName != null
val useCustomIcon = customIcon != null
val isRootInstall = setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName
// Can only check if app is root installation by checking if change package name patch is in use. // Can only check if app is root installation by checking if change package name patch is in use.
// and can only do that in the afterDependents block here. // and can only do that in the afterDependents block here.
// The UI preferences cannot be selectively added here, because the settings afterDependents block // The UI preferences cannot be selectively added here, because the settings afterDependents block
// may have already run and the settings are already wrote to file. // may have already run and the settings are already wrote to file.
// Instead, show a warning if any patch option was used (A rooted device launcher ignores the manifest changes), // Instead, show a warning if any patch option was used (A rooted device launcher ignores the manifest changes),
// and the non-functional in-app settings are removed on app startup by extension code. // and the non-functional in-app settings are removed on app startup by extension code.
if (customName != null || customIcon != null) { if (isRootInstall && (useCustomName || useCustomIcon)) {
if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) { Logger.getLogger(this::class.java.name).warning(
Logger.getLogger(this::class.java.name).warning( "Custom branding does not work with root installation. No changes applied."
"Custom branding does not work with root installation. No changes applied.", )
}
if (!isRootInstall || useCustomName) {
document("AndroidManifest.xml").use { document ->
val application = document.getElementsByTagName("application").item(0) as Element
application.setAttribute(
"android:label",
if (useCustomName) {
// Use custom name everywhere.
customName
} else {
// The YT application name can appear in some places alongside the system
// YouTube app, such as the settings app list and in the "open with" file picker.
// Because the YouTube app cannot be completely uninstalled and only disabled,
// use a custom name for this situation to disambiguate which app is which.
"@string/revanced_custom_branding_name_entry_2"
}
) )
} }
} }
@ -312,16 +332,19 @@ internal fun baseCustomBrandingPatch(
activityAliasNameWithIntents, activityAliasNameWithIntents,
).childNodes ).childNodes
// The YT application name can appear in some places alongside the system // If user provides a custom icon, then change the application icon ('static' icon)
// YouTube app, such as the settings app list and in the "open with" file picker. // which shows as the push notification for some devices, in the app settings,
// Because the YouTube app cannot be completely uninstalled and only disabled, // and as the icon for the apk before installing.
// use a custom name for this situation to disambiguate which app is which. // This icon cannot be dynamically selected and this change must only be done if the
application.setAttribute( // user provides an icon otherwise there is no way to restore the original YouTube icon.
"android:label", if (useCustomIcon) {
"@string/revanced_custom_branding_name_entry_2", application.setAttribute(
) "android:icon",
"@mipmap/revanced_launcher_custom"
)
}
val enabledNameIndex = if (useCustomName) numberOfPresetAppNames else 1 // 1 indexing. val enabledNameIndex = if (useCustomName) numberOfPresetAppNames else 2 // 1 indexing.
val enabledIconIndex = if (useCustomIcon) iconStyleNames.size else 0 // 0 indexing. val enabledIconIndex = if (useCustomIcon) iconStyleNames.size else 0 // 0 indexing.
for (appNameIndex in 1..numberOfPresetAppNames) { for (appNameIndex in 1..numberOfPresetAppNames) {
@ -336,7 +359,7 @@ internal fun baseCustomBrandingPatch(
iconMipmapName = originalLauncherIconName, iconMipmapName = originalLauncherIconName,
appNameIndex = appNameIndex, appNameIndex = appNameIndex,
useCustomName = useCustomNameLabel, useCustomName = useCustomNameLabel,
enabled = (appNameIndex == 1), enabled = false,
intentFilters, intentFilters,
), ),
) )

View file

@ -169,13 +169,13 @@ internal fun spoofVideoStreamsPatch(
if-eqz v2, :disabled if-eqz v2, :disabled
# Get streaming data. # Get streaming data.
invoke-static { v2 }, $EXTENSION_CLASS_DESCRIPTOR->getStreamingData(Ljava/lang/String;)Ljava/nio/ByteBuffer; invoke-static { v2 }, $EXTENSION_CLASS_DESCRIPTOR->getStreamingData(Ljava/lang/String;)[B
move-result-object v3 move-result-object v3
if-eqz v3, :disabled if-eqz v3, :disabled
# Parse streaming data. # Parse streaming data.
sget-object v4, $playerProtoClass->a:$playerProtoClass sget-object v4, $playerProtoClass->a:$playerProtoClass
invoke-static { v4, v3 }, $protobufClass->parseFrom(${protobufClass}Ljava/nio/ByteBuffer;)$protobufClass invoke-static { v4, v3 }, $protobufClass->parseFrom(${protobufClass}[B)$protobufClass
move-result-object v5 move-result-object v5
check-cast v5, $playerProtoClass check-cast v5, $playerProtoClass

View file

@ -63,10 +63,10 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
// Requires a key and title but the actual text is chosen at runtime. // Requires a key and title but the actual text is chosen at runtime.
key = "revanced_spoof_video_streams_about", key = "revanced_spoof_video_streams_about",
summaryKey = null, summaryKey = null,
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference", tag = "app.revanced.extension.youtube.settings.preference.SpoofVideoStreamsSideEffectsPreference",
), ),
SwitchPreference("revanced_spoof_video_streams_av1"), SwitchPreference("revanced_spoof_video_streams_av1"),
SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"), SwitchPreference("revanced_spoof_video_streams_stats_for_nerds"),
), ),
), ),
) )

View file

@ -25,6 +25,7 @@ Second \"item\" text"</string>
<string name="revanced_custom_branding_name_entry_5">Vlastní</string> <string name="revanced_custom_branding_name_entry_5">Vlastní</string>
<string name="revanced_custom_branding_icon_title">Ikona aplikace</string> <string name="revanced_custom_branding_icon_title">Ikona aplikace</string>
<string name="revanced_custom_branding_icon_entry_1">Původní</string> <string name="revanced_custom_branding_icon_entry_1">Původní</string>
<string name="revanced_custom_branding_icon_entry_2">ReVanced</string>
<!-- Translation of this should be identical to revanced_header_logo_entry_5 --> <!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimální</string> <string name="revanced_custom_branding_icon_entry_3">ReVanced minimální</string>
<string name="revanced_custom_branding_icon_entry_4">ReVanced škálované</string> <string name="revanced_custom_branding_icon_entry_4">ReVanced škálované</string>
@ -49,6 +50,7 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.settings.settingsResourcePatch"> <patch id="misc.settings.settingsResourcePatch">
<string name="revanced_settings_submenu_title">Nastavení</string> <string name="revanced_settings_submenu_title">Nastavení</string>
<string name="revanced_settings_title">ReVanced</string>
<string name="revanced_settings_confirm_user_dialog_title">Opravdu chcete pokračovat?</string> <string name="revanced_settings_confirm_user_dialog_title">Opravdu chcete pokračovat?</string>
<string name="revanced_settings_save">Uložit</string> <string name="revanced_settings_save">Uložit</string>
<string name="revanced_settings_reset">Výchozí</string> <string name="revanced_settings_reset">Výchozí</string>
@ -131,6 +133,8 @@ Klepněte na tlačítko Pokračovat a povolte změny optimalizace."</string>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">Falšovat video streamy</string> <string name="revanced_spoof_video_streams_screen_title">Falšovat video streamy</string>
<string name="revanced_spoof_video_streams_screen_summary">Falšovat video streamy klienta, aby se předešlo problémům s přehráváním.</string> <string name="revanced_spoof_video_streams_screen_summary">Falšovat video streamy klienta, aby se předešlo problémům s přehráváním.</string>
<string name="revanced_spoof_video_streams_screen_title">Falšovat video streamy</string>
<string name="revanced_spoof_video_streams_screen_summary">Falšovat video streamy klienta, aby se předešlo problémům s přehráváním</string>
<string name="revanced_spoof_video_streams_title">Napodobovat video streamy</string> <string name="revanced_spoof_video_streams_title">Napodobovat video streamy</string>
<string name="revanced_spoof_video_streams_summary_on">"Video streamy jsou maskovány <string name="revanced_spoof_video_streams_summary_on">"Video streamy jsou maskovány
@ -218,9 +222,12 @@ Povolením této možnosti se však budou zaznamenávat i některá uživatelsk
<string name="revanced_settings_screen_03_feed_title">Přísun</string> <string name="revanced_settings_screen_03_feed_title">Přísun</string>
<string name="revanced_settings_screen_04_general_title">Obecné</string> <string name="revanced_settings_screen_04_general_title">Obecné</string>
<string name="revanced_settings_screen_05_player_title">Přehrávač</string> <string name="revanced_settings_screen_05_player_title">Přehrávač</string>
<string name="revanced_settings_screen_06_shorts_title">Shorts</string>
<string name="revanced_settings_screen_07_seekbar_title">Lišta</string> <string name="revanced_settings_screen_07_seekbar_title">Lišta</string>
<string name="revanced_settings_screen_08_swipe_controls_title">Ovládání gesty</string> <string name="revanced_settings_screen_08_swipe_controls_title">Ovládání gesty</string>
<string name="revanced_settings_screen_09_return_youtube_dislike_title">Return YouTube Dislike</string>
<string name="revanced_settings_screen_11_misc_title">Různé</string> <string name="revanced_settings_screen_11_misc_title">Různé</string>
<string name="revanced_settings_screen_12_video_title">Video</string>
<string name="revanced_restore_old_settings_menus_title">Obnovit staré menu nastavení</string> <string name="revanced_restore_old_settings_menus_title">Obnovit staré menu nastavení</string>
<string name="revanced_restore_old_settings_menus_summary_on">Staré menu nastavení se zobrazují</string> <string name="revanced_restore_old_settings_menus_summary_on">Staré menu nastavení se zobrazují</string>
<string name="revanced_restore_old_settings_menus_summary_off">Staré menu nastavení se nezobrazují</string> <string name="revanced_restore_old_settings_menus_summary_off">Staré menu nastavení se nezobrazují</string>
@ -1148,6 +1155,7 @@ Nastavení → Přehrávání → Automatické přehrávání dalšího videa"</
<string name="revanced_ryd_failure_ryd_enabled_while_playing_video_then_user_voted">Načtěte video znovu, abyste hlasovali pomocí Return YouTube Dislike</string> <string name="revanced_ryd_failure_ryd_enabled_while_playing_video_then_user_voted">Načtěte video znovu, abyste hlasovali pomocí Return YouTube Dislike</string>
<!-- Video likes have been set to hidden by the video uploader. --> <!-- Video likes have been set to hidden by the video uploader. -->
<string name="revanced_ryd_video_likes_hidden_by_video_owner">Skryto vlastníkem</string> <string name="revanced_ryd_video_likes_hidden_by_video_owner">Skryto vlastníkem</string>
<string name="revanced_ryd_enabled_title">Return YouTube Dislike</string>
<string name="revanced_ryd_enabled_summary_on">Nelíbí se se zobrazují</string> <string name="revanced_ryd_enabled_summary_on">Nelíbí se se zobrazují</string>
<string name="revanced_ryd_enabled_summary_off">Nelíbí se se nezobrazují</string> <string name="revanced_ryd_enabled_summary_off">Nelíbí se se nezobrazují</string>
<string name="revanced_ryd_shorts_title">Zobrazit nelíbí se v Shorts</string> <string name="revanced_ryd_shorts_title">Zobrazit nelíbí se v Shorts</string>
@ -1168,6 +1176,7 @@ Omezení: Počty „Nelíbí se mi“ se nemusí zobrazit v anonymním režimu"<
<string name="revanced_ryd_toast_on_connection_error_title">Zobrazit toast, pokud API není dostupné</string> <string name="revanced_ryd_toast_on_connection_error_title">Zobrazit toast, pokud API není dostupné</string>
<string name="revanced_ryd_toast_on_connection_error_summary_on">Toast se zobrazí, pokud Return YouTube Dislike není dostupný</string> <string name="revanced_ryd_toast_on_connection_error_summary_on">Toast se zobrazí, pokud Return YouTube Dislike není dostupný</string>
<string name="revanced_ryd_toast_on_connection_error_summary_off">Toast se nezobrazí, pokud Return YouTube Dislike není dostupný</string> <string name="revanced_ryd_toast_on_connection_error_summary_off">Toast se nezobrazí, pokud Return YouTube Dislike není dostupný</string>
<string name="revanced_ryd_attribution_title">ReturnYouTubeDislike.com</string>
<string name="revanced_ryd_attribution_summary">Data jsou poskytována API Return YouTube Dislike. Klepnutím se dozvíte více</string> <string name="revanced_ryd_attribution_summary">Data jsou poskytována API Return YouTube Dislike. Klepnutím se dozvíte více</string>
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. --> <!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
<string name="revanced_ryd_statistics_category_title">Statistiky API ReturnYouTubeDislike tohoto zařízení</string> <string name="revanced_ryd_statistics_category_title">Statistiky API ReturnYouTubeDislike tohoto zařízení</string>
@ -1188,6 +1197,7 @@ Omezení: Počty „Nelíbí se mi“ se nemusí zobrazit v anonymním režimu"<
<string name="revanced_ryd_statistics_millisecond_text">%d milisekund</string> <string name="revanced_ryd_statistics_millisecond_text">%d milisekund</string>
</patch> </patch>
<patch id="layout.sponsorblock.sponsorBlockResourcePatch"> <patch id="layout.sponsorblock.sponsorBlockResourcePatch">
<string name="revanced_settings_screen_10_sponsorblock_title">SponsorBlock</string>
<string name="revanced_sb_enable_sb">Povolit SponsorBlock</string> <string name="revanced_sb_enable_sb">Povolit SponsorBlock</string>
<string name="revanced_sb_enable_sb_sum">SponsorBlock je systém s participací komunity pro přeskakování otravných částí videí na YouTube</string> <string name="revanced_sb_enable_sb_sum">SponsorBlock je systém s participací komunity pro přeskakování otravných částí videí na YouTube</string>
<string name="revanced_sb_appearance_category">Vzhled</string> <string name="revanced_sb_appearance_category">Vzhled</string>
@ -1396,12 +1406,14 @@ Jste připraveni k odeslání?"</string>
<string name="revanced_sb_color_opacity_label">Průhlednost:</string> <string name="revanced_sb_color_opacity_label">Průhlednost:</string>
<string name="revanced_sb_color_dot_label">Barva:</string> <string name="revanced_sb_color_dot_label">Barva:</string>
<string name="revanced_sb_about_title">O aplikaci</string> <string name="revanced_sb_about_title">O aplikaci</string>
<string name="revanced_sb_about_api_title">sponsor.ajay.app</string>
<string name="revanced_sb_about_api_summary">Data poskytuje rozhraní API SponsorBlock. Klepněte zde, abyste se dozvěděli více a zobrazili si soubory ke stažení pro další platformy</string> <string name="revanced_sb_about_api_summary">Data poskytuje rozhraní API SponsorBlock. Klepněte zde, abyste se dozvěděli více a zobrazili si soubory ke stažení pro další platformy</string>
</patch> </patch>
<patch id="layout.formfactor.changeFormFactorPatch"> <patch id="layout.formfactor.changeFormFactorPatch">
<string name="revanced_change_form_factor_title">Rozvržení formuláře</string> <string name="revanced_change_form_factor_title">Rozvržení formuláře</string>
<string name="revanced_change_form_factor_entry_1">Výchozí</string> <string name="revanced_change_form_factor_entry_1">Výchozí</string>
<string name="revanced_change_form_factor_entry_2">Telefon</string> <string name="revanced_change_form_factor_entry_2">Telefon</string>
<string name="revanced_change_form_factor_entry_3">Tablet</string>
<string name="revanced_change_form_factor_entry_4">Automobilový</string> <string name="revanced_change_form_factor_entry_4">Automobilový</string>
<string name="revanced_change_form_factor_user_dialog_message">"Změny zahrnují: <string name="revanced_change_form_factor_user_dialog_message">"Změny zahrnují:
@ -1445,6 +1457,7 @@ Pokud bude později vypnuta, doporučujeme vymazat data aplikace, aby se zabrán
<string name="revanced_change_start_page_entry_playlists">Playlisty</string> <string name="revanced_change_start_page_entry_playlists">Playlisty</string>
<string name="revanced_change_start_page_entry_search">Hledat</string> <string name="revanced_change_start_page_entry_search">Hledat</string>
<string name="revanced_change_start_page_entry_shopping">Nakupování</string> <string name="revanced_change_start_page_entry_shopping">Nakupování</string>
<string name="revanced_change_start_page_entry_shorts">Shorts</string>
<string name="revanced_change_start_page_entry_sports">Sport</string> <string name="revanced_change_start_page_entry_sports">Sport</string>
<string name="revanced_change_start_page_entry_subscriptions">Odběry</string> <string name="revanced_change_start_page_entry_subscriptions">Odběry</string>
<string name="revanced_change_start_page_entry_trending">Trendy</string> <string name="revanced_change_start_page_entry_trending">Trendy</string>
@ -1483,6 +1496,7 @@ Omezení: Použití tlačítka zpět na panelu nástrojů nemusí fungovat"</str
<string name="revanced_miniplayer_type_entry_0">Vypnuto</string> <string name="revanced_miniplayer_type_entry_0">Vypnuto</string>
<string name="revanced_miniplayer_type_entry_1">Výchozí</string> <string name="revanced_miniplayer_type_entry_1">Výchozí</string>
<string name="revanced_miniplayer_type_entry_2">Minimální</string> <string name="revanced_miniplayer_type_entry_2">Minimální</string>
<string name="revanced_miniplayer_type_entry_3">Tablet</string>
<string name="revanced_miniplayer_type_entry_4">Moderní 1</string> <string name="revanced_miniplayer_type_entry_4">Moderní 1</string>
<string name="revanced_miniplayer_type_entry_5">Moderní 2</string> <string name="revanced_miniplayer_type_entry_5">Moderní 2</string>
<string name="revanced_miniplayer_type_entry_6">Moderní 3</string> <string name="revanced_miniplayer_type_entry_6">Moderní 3</string>
@ -1509,6 +1523,11 @@ Omezení: Použití tlačítka zpět na panelu nástrojů nemusí fungovat"</str
<string name="revanced_miniplayer_hide_overlay_buttons_title">Skrýt tlačítka překrytí</string> <string name="revanced_miniplayer_hide_overlay_buttons_title">Skrýt tlačítka překrytí</string>
<string name="revanced_miniplayer_hide_overlay_buttons_summary_on">Tlačítka překrytí jsou skrytá</string> <string name="revanced_miniplayer_hide_overlay_buttons_summary_on">Tlačítka překrytí jsou skrytá</string>
<string name="revanced_miniplayer_hide_overlay_buttons_summary_off">Tlačítka překrytí jsou zobrazena</string> <string name="revanced_miniplayer_hide_overlay_buttons_summary_off">Tlačítka překrytí jsou zobrazena</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_title">Skrýt tlačítka rozbalit a zavřít</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_summary_on">"Tlačítka jsou skrytá
Přejetím roztáhnete nebo zavřete"</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_summary_off">Tlačítka rozbalit a zavřít jsou zobrazena</string>
<string name="revanced_miniplayer_hide_subtext_title">Skrýt podtexty</string> <string name="revanced_miniplayer_hide_subtext_title">Skrýt podtexty</string>
<string name="revanced_miniplayer_hide_subtext_summary_on">Podtexty jsou skryty</string> <string name="revanced_miniplayer_hide_subtext_summary_on">Podtexty jsou skryty</string>
<string name="revanced_miniplayer_hide_subtext_summary_off">Podtexty jsou zobrazeny</string> <string name="revanced_miniplayer_hide_subtext_summary_off">Podtexty jsou zobrazeny</string>
@ -1539,11 +1558,17 @@ Omezení: Použití tlačítka zpět na panelu nástrojů nemusí fungovat"</str
<string name="revanced_seekbar_custom_color_accent_summary">Zvýrazněná barva posuvníku</string> <string name="revanced_seekbar_custom_color_accent_summary">Zvýrazněná barva posuvníku</string>
<string name="revanced_seekbar_custom_color_invalid">Neplatná hodnota barvy posuvníku</string> <string name="revanced_seekbar_custom_color_invalid">Neplatná hodnota barvy posuvníku</string>
</patch> </patch>
<patch id="layout.branding.customBrandingPatch"/> <patch id="layout.branding.customBrandingPatch">
<string name="revanced_custom_branding_name_entry_2">YouTube ReVanced</string>
<string name="revanced_custom_branding_name_entry_3">YT ReVanced</string>
<string name="revanced_custom_branding_name_entry_4">YT</string>
</patch>
<patch id="layout.branding.changeHeaderPatch"> <patch id="layout.branding.changeHeaderPatch">
<string name="revanced_header_logo_title">Logo záhlaví</string> <string name="revanced_header_logo_title">Logo záhlaví</string>
<string name="revanced_header_logo_entry_1">Výchozí</string> <string name="revanced_header_logo_entry_1">Výchozí</string>
<string name="revanced_header_logo_entry_2">Běžné</string> <string name="revanced_header_logo_entry_2">Běžné</string>
<string name="revanced_header_logo_entry_3">Prémium</string>
<string name="revanced_header_logo_entry_4">ReVanced</string>
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 --> <!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
<string name="revanced_header_logo_entry_5">ReVanced minimální</string> <string name="revanced_header_logo_entry_5">ReVanced minimální</string>
<string name="revanced_header_logo_entry_6">Vlastní</string> <string name="revanced_header_logo_entry_6">Vlastní</string>
@ -1568,6 +1593,7 @@ Povolení této funkce může opravit chybějící obrázky, které jsou v někt
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow &amp; Původní náhledy</string> <string name="revanced_alt_thumbnail_options_entry_2">DeArrow &amp; Původní náhledy</string>
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow &amp; Zachycení snímků</string> <string name="revanced_alt_thumbnail_options_entry_3">DeArrow &amp; Zachycení snímků</string>
<string name="revanced_alt_thumbnail_options_entry_4">Zachycení snímků</string> <string name="revanced_alt_thumbnail_options_entry_4">Zachycení snímků</string>
<string name="revanced_alt_thumbnail_dearrow_about_title">DeArrow</string>
<string name="revanced_alt_thumbnail_dearrow_about_summary">"DeArrow poskytuje miniatury videí YouTube z crowdsourcingu. Tyto miniatury jsou často relevantnější než ty, které poskytuje YouTube <string name="revanced_alt_thumbnail_dearrow_about_summary">"DeArrow poskytuje miniatury videí YouTube z crowdsourcingu. Tyto miniatury jsou často relevantnější než ty, které poskytuje YouTube
Pokud je tato funkce povolena, budou adresy URL videí odeslány na server API a nebudou odesílány žádné další údaje. Pokud video nemá miniatury DeArrow, zobrazí se originální nebo statické snímky Pokud je tato funkce povolena, budou adresy URL videí odeslány na server API a nebudou odesílány žádné další údaje. Pokud video nemá miniatury DeArrow, zobrazí se originální nebo statické snímky
@ -1611,7 +1637,11 @@ Klepnutím sem se dozvíte více o DeArrow"</string>
<string name="revanced_loop_video_button_toast_on">Smyčka videa je zapnuta</string> <string name="revanced_loop_video_button_toast_on">Smyčka videa je zapnuta</string>
<string name="revanced_loop_video_button_toast_off">Smyčka videa je vypnuta</string> <string name="revanced_loop_video_button_toast_off">Smyčka videa je vypnuta</string>
</patch> </patch>
<patch id="misc.audiofocus.pauseOnAudioInterruptPatch"/> <patch id="misc.audiofocus.pauseOnAudioInterruptPatch">
<string name="revanced_pause_on_audio_interrupt_title">Pozastavit při přerušení zvuku</string>
<string name="revanced_pause_on_audio_interrupt_summary_on">Přehrávání se pozastaví, když se přehrává jiný zvuk (např. navigace)</string>
<string name="revanced_pause_on_audio_interrupt_summary_off">Sníží hlasitost při přehrávání ostatních zvuků</string>
</patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch"> <patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
<string name="revanced_spoof_device_dimensions_title">Napodobovat rozměry zařízení</string> <string name="revanced_spoof_device_dimensions_title">Napodobovat rozměry zařízení</string>
<string name="revanced_spoof_device_dimensions_summary_on">"Rozměry zařízení jsou zfalšovány <string name="revanced_spoof_device_dimensions_summary_on">"Rozměry zařízení jsou zfalšovány
@ -1766,7 +1796,11 @@ Přehrávání videa s AV1 se může sekat nebo vypadávat snímky."</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">
<patch id="layout.branding.customBrandingPatch"/> <patch id="layout.branding.customBrandingPatch">
<string name="revanced_custom_branding_name_entry_2">YT Music ReVanced</string>
<string name="revanced_custom_branding_name_entry_3">Music ReVanced</string>
<string name="revanced_custom_branding_name_entry_4">Hudba</string>
</patch>
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
<!-- In languages where "About" is ambiguous, translate to "About ReVanced" (i.e., About this app). --> <!-- In languages where "About" is ambiguous, translate to "About ReVanced" (i.e., About this app). -->
<string name="revanced_settings_music_screen_0_about_title">O aplikaci</string> <string name="revanced_settings_music_screen_0_about_title">O aplikaci</string>
@ -1893,6 +1927,7 @@ Přehrávání videa s AV1 se může sekat nebo vypadávat snímky."</string>
<string name="revanced_about_summary">O ReVanced</string> <string name="revanced_about_summary">O ReVanced</string>
<string name="revanced_ads_screen_title">Blokování reklam</string> <string name="revanced_ads_screen_title">Blokování reklam</string>
<string name="revanced_ads_screen_summary">Nastavení blokování reklam</string> <string name="revanced_ads_screen_summary">Nastavení blokování reklam</string>
<string name="revanced_chat_screen_title">Chat</string>
<string name="revanced_chat_screen_summary">Nastavení chatu</string> <string name="revanced_chat_screen_summary">Nastavení chatu</string>
<string name="revanced_misc_screen_title">Různé</string> <string name="revanced_misc_screen_title">Různé</string>
<string name="revanced_misc_screen_summary">Různé nastavení</string> <string name="revanced_misc_screen_summary">Různé nastavení</string>

View file

@ -35,14 +35,14 @@ Second \"item\" text"</string>
<string name="revanced_check_environment_dialog_ignore_button">Ignorieren</string> <string name="revanced_check_environment_dialog_ignore_button">Ignorieren</string>
<string name="revanced_check_environment_failed_message">&lt;h5&gt;Diese App wurde offenbar nicht von Ihnen gepatcht.&lt;/h5&gt;&lt;br&gt;Diese App funktioniert möglicherweise nicht richtig, &lt;b&gt;könnte schädlich oder sogar gefährlich in der Verwendung sein&lt;/b&gt;.&lt; br&gt;&lt;br&gt;Diese Prüfungen deuten darauf hin, dass diese App vorab gepatcht wurde oder von jemandem bezogen wurde:&lt;br&gt;&lt;br&gt;&lt;small&gt;%1$s&lt;/small&gt;&lt;br&gt;Es wird dringend empfohlen, &lt;b&gt;diese App zu deinstallieren und selbst zu patchen&lt;/b&gt; um sicherzustellen, dass Sie eine validierte und sichere App verwenden.&lt;p&gt;&lt;br&gt;Wenn Sie diese Warnung ignorieren, wird sie nur zweimal angezeigt.</string> <string name="revanced_check_environment_failed_message">&lt;h5&gt;Diese App wurde offenbar nicht von Ihnen gepatcht.&lt;/h5&gt;&lt;br&gt;Diese App funktioniert möglicherweise nicht richtig, &lt;b&gt;könnte schädlich oder sogar gefährlich in der Verwendung sein&lt;/b&gt;.&lt; br&gt;&lt;br&gt;Diese Prüfungen deuten darauf hin, dass diese App vorab gepatcht wurde oder von jemandem bezogen wurde:&lt;br&gt;&lt;br&gt;&lt;small&gt;%1$s&lt;/small&gt;&lt;br&gt;Es wird dringend empfohlen, &lt;b&gt;diese App zu deinstallieren und selbst zu patchen&lt;/b&gt; um sicherzustellen, dass Sie eine validierte und sichere App verwenden.&lt;p&gt;&lt;br&gt;Wenn Sie diese Warnung ignorieren, wird sie nur zweimal angezeigt.</string>
<string name="revanced_check_environment_not_same_patching_device">Auf einem anderen Gerät gepatcht</string> <string name="revanced_check_environment_not_same_patching_device">Auf einem anderen Gerät gepatcht</string>
<string name="revanced_check_environment_manager_not_expected_installer">Nicht durch ReVanced Manager installiert</string> <string name="revanced_check_environment_manager_not_expected_installer">Nicht von ReVanced Manager installiert</string>
<string name="revanced_check_environment_not_near_patch_time">Vor mehr als 10 Minuten gepatcht</string> <string name="revanced_check_environment_not_near_patch_time">Vor mehr als 10 Minuten gepatcht</string>
<string name="revanced_check_environment_not_near_patch_time_days">Vor %s Tagen gepatcht</string> <string name="revanced_check_environment_not_near_patch_time_days">Vor %s Tagen gepatcht</string>
<string name="revanced_check_environment_not_near_patch_time_invalid">APK Erstellungsdatum ist beschädigt</string> <string name="revanced_check_environment_not_near_patch_time_invalid">APK Erstellungsdatum ist beschädigt</string>
</patch> </patch>
<patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch"> <patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch">
<string name="revanced_check_watch_history_domain_name_dialog_title">ReVanced Hinweis</string> <string name="revanced_check_watch_history_domain_name_dialog_title">ReVanced Hinweis</string>
<string name="revanced_check_watch_history_domain_name_dialog_message">Ihr Verlauf wird nicht gespeichert.&lt;br&gt;&lt;br&gt;Dies wird höchstwahrscheinlich durch einen DNS-Werbeblocker oder einen Netzwerkproxy verursacht.&lt;br&gt;&lt;br&gt;Um dies zu beheben, setze &lt;b&gt;s.youtube.com&lt;/b&gt; auf die Whitelist oder schalten Sie alle DNS-Blocker und Proxies aus.</string> <string name="revanced_check_watch_history_domain_name_dialog_message">Ihr Verlauf wird nicht gespeichert.&lt;br&gt;&lt;br&gt;Dies wird höchstwahrscheinlich durch einen DNS-Werbeblocker oder einen Netzwerkproxy verursacht.&lt;br&gt;&lt;br&gt;Um dies zu beheben, setze &lt;b&gt;s.youtube.com&lt;/b&gt; auf die Whitelist oder schalten Sie alle DNS-Blocker und Proxys aus.</string>
<string name="revanced_check_watch_history_domain_name_dialog_ignore">Nicht wieder anzeigen</string> <string name="revanced_check_watch_history_domain_name_dialog_ignore">Nicht wieder anzeigen</string>
</patch> </patch>
<patch id="misc.settings.settingsResourcePatch"> <patch id="misc.settings.settingsResourcePatch">
@ -1598,7 +1598,9 @@ Tippen Sie hier, um mehr über DeArrow zu erfahren"</string>
<string name="revanced_loop_video_button_toast_on">Loop-Video ist aktiviert</string> <string name="revanced_loop_video_button_toast_on">Loop-Video ist aktiviert</string>
<string name="revanced_loop_video_button_toast_off">Loop-Video ist deaktiviert</string> <string name="revanced_loop_video_button_toast_off">Loop-Video ist deaktiviert</string>
</patch> </patch>
<patch id="misc.audiofocus.pauseOnAudioInterruptPatch"/> <patch id="misc.audiofocus.pauseOnAudioInterruptPatch">
<string name="revanced_pause_on_audio_interrupt_title">Pause bei Audiounterbrechung</string>
</patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch"> <patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
<string name="revanced_spoof_device_dimensions_title">Spoof-Gerätegröße</string> <string name="revanced_spoof_device_dimensions_title">Spoof-Gerätegröße</string>
<string name="revanced_spoof_device_dimensions_summary_on">"Gerätemessungen gefälscht <string name="revanced_spoof_device_dimensions_summary_on">"Gerätemessungen gefälscht
@ -1753,7 +1755,9 @@ Die Videowiedergabe mit AV1 kann stottern oder Bilder überspringen."</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">
<patch id="layout.branding.customBrandingPatch"/> <patch id="layout.branding.customBrandingPatch">
<string name="revanced_custom_branding_name_entry_4">Musik</string>
</patch>
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
<!-- In languages where "About" is ambiguous, translate to "About ReVanced" (i.e., About this app). --> <!-- In languages where "About" is ambiguous, translate to "About ReVanced" (i.e., About this app). -->
<string name="revanced_settings_music_screen_0_about_title">Über</string> <string name="revanced_settings_music_screen_0_about_title">Über</string>

View file

@ -238,13 +238,9 @@ Second \"item\" text"</string>
<string name="revanced_shorts_disable_background_playback_summary_off">Η αναπαραγωγή παρασκηνίου είναι ενεργοποιημένη για τα Shorts</string> <string name="revanced_shorts_disable_background_playback_summary_off">Η αναπαραγωγή παρασκηνίου είναι ενεργοποιημένη για τα Shorts</string>
</patch> </patch>
<patch id="layout.hide.general.hideLayoutComponentsPatch"> <patch id="layout.hide.general.hideLayoutComponentsPatch">
<string name="revanced_hide_creator_store_shelf_title">Ενότητα καταστήματος δημιουργού</string> <string name="revanced_hide_creator_store_shelf_title">Ενότητα καταστήματος δημιουργού κάτω από την οθόνη αναπαραγωγής</string>
<string name="revanced_hide_creator_store_shelf_summary_on">Κρυμμένη <string name="revanced_hide_creator_store_shelf_summary_on">Κρυμμένη</string>
<string name="revanced_hide_creator_store_shelf_summary_off">Εμφανίζεται</string>
Αφορά την ενότητα καταστήματος δημιουργού κάτω από την οθόνη αναπαραγωγής</string>
<string name="revanced_hide_creator_store_shelf_summary_off">Εμφανίζεται
Αφορά την ενότητα καταστήματος δημιουργού κάτω από την οθόνη αναπαραγωγής</string>
<string name="revanced_hide_album_cards_title">Κάρτες άλμπουμ</string> <string name="revanced_hide_album_cards_title">Κάρτες άλμπουμ</string>
<string name="revanced_hide_album_cards_summary_on">Κρυμμένες</string> <string name="revanced_hide_album_cards_summary_on">Κρυμμένες</string>
<string name="revanced_hide_album_cards_summary_off">Εμφανίζονται</string> <string name="revanced_hide_album_cards_summary_off">Εμφανίζονται</string>
@ -373,13 +369,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_timed_reactions_title">Συγχρονισμένες αντιδράσεις</string> <string name="revanced_hide_timed_reactions_title">Συγχρονισμένες αντιδράσεις</string>
<string name="revanced_hide_timed_reactions_summary_on">Κρυμμένες</string> <string name="revanced_hide_timed_reactions_summary_on">Κρυμμένες</string>
<string name="revanced_hide_timed_reactions_summary_off">Εμφανίζονται</string> <string name="revanced_hide_timed_reactions_summary_off">Εμφανίζονται</string>
<string name="revanced_hide_video_title_title">Τίτλος του βίντεο</string> <string name="revanced_hide_video_title_title">Τίτλος του βίντεο στην πλήρη οθόνη</string>
<string name="revanced_hide_video_title_summary_on">Κρυμμένος <string name="revanced_hide_video_title_summary_on">Κρυμμένος</string>
<string name="revanced_hide_video_title_summary_off">Εμφανίζεται</string>
Αφορά τον τίτλο του βίντεο στη λειτουργία πλήρους οθόνης</string>
<string name="revanced_hide_video_title_summary_off">Εμφανίζεται
Αφορά τον τίτλο του βίντεο στη λειτουργία πλήρους οθόνης</string>
<string name="revanced_hide_ai_generated_video_summary_section_title">Σύνοψη βίντεο που δημιουργήθηκε από AI</string> <string name="revanced_hide_ai_generated_video_summary_section_title">Σύνοψη βίντεο που δημιουργήθηκε από AI</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_on">Κρυμμένη</string> <string name="revanced_hide_ai_generated_video_summary_section_summary_on">Κρυμμένη</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_off">Εμφανίζεται</string> <string name="revanced_hide_ai_generated_video_summary_section_summary_off">Εμφανίζεται</string>
@ -395,13 +387,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_course_progress_section_title">Ενότητα «Πρόοδος μαθήματος»</string> <string name="revanced_hide_course_progress_section_title">Ενότητα «Πρόοδος μαθήματος»</string>
<string name="revanced_hide_course_progress_section_summary_on">Κρυμμένη</string> <string name="revanced_hide_course_progress_section_summary_on">Κρυμμένη</string>
<string name="revanced_hide_course_progress_section_summary_off">Εμφανίζεται</string> <string name="revanced_hide_course_progress_section_summary_off">Εμφανίζεται</string>
<string name="revanced_hide_explore_section_title">Ενότητες «Εξερεύνηση»</string> <string name="revanced_hide_explore_section_title">Ενότητες «Εξερευνήστε...»</string>
<string name="revanced_hide_explore_section_summary_on">Κρυμμένες <string name="revanced_hide_explore_section_summary_on">Κρυμμένες. Αφορά τις ενότητες «Εξερευνήστε αυτή τη σειρά μαθημάτων» και «Εξερευνήστε το podcast»</string>
<string name="revanced_hide_explore_section_summary_off">Εμφανίζονται. Αφορά τις ενότητες «Εξερευνήστε αυτή τη σειρά μαθημάτων» και «Εξερευνήστε το podcast»</string>
Αφορά τις ενότητες «Εξερευνήστε αυτή τη σειρά μαθημάτων» και «Εξερευνήστε το podcast»</string>
<string name="revanced_hide_explore_section_summary_off">Εμφανίζονται
Αφορά τις ενότητες «Εξερευνήστε αυτή τη σειρά μαθημάτων» και «Εξερευνήστε το podcast»</string>
<string name="revanced_hide_explore_course_section_title">Ενότητα «Εξερευνήστε αυτή τη σειρά μαθημάτων»</string> <string name="revanced_hide_explore_course_section_title">Ενότητα «Εξερευνήστε αυτή τη σειρά μαθημάτων»</string>
<string name="revanced_hide_explore_course_section_summary_on">Κρυμμένη</string> <string name="revanced_hide_explore_course_section_summary_on">Κρυμμένη</string>
<string name="revanced_hide_explore_course_section_summary_off">Εμφανίζεται</string> <string name="revanced_hide_explore_course_section_summary_off">Εμφανίζεται</string>
@ -1631,8 +1619,8 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.announcements.announcementsPatch"> <patch id="misc.announcements.announcementsPatch">
<string name="revanced_announcements_title">Εμφάνιση ανακοινώσεων ReVanced</string> <string name="revanced_announcements_title">Εμφάνιση ανακοινώσεων ReVanced</string>
<string name="revanced_announcements_summary_on">Οι ανακοινώσεις κατά την εκκίνηση εμφανίζονται</string> <string name="revanced_announcements_summary_on">Οι ανακοινώσεις εμφανίζονται κατά την εκκίνηση</string>
<string name="revanced_announcements_summary_off">Οι ανακοινώσεις κατά την εκκίνηση δεν εμφανίζονται</string> <string name="revanced_announcements_summary_off">Οι ανακοινώσεις δεν εμφανίζονται κατά την εκκίνηση</string>
<string name="revanced_announcements_enabled_summary">Εμφάνιση ανακοινώσεων κατά την εκκίνηση</string> <string name="revanced_announcements_enabled_summary">Εμφάνιση ανακοινώσεων κατά την εκκίνηση</string>
<string name="revanced_announcements_connection_failed">Αποτυχία σύνδεσης με τον πάροχο ανακοινώσεων</string> <string name="revanced_announcements_connection_failed">Αποτυχία σύνδεσης με τον πάροχο ανακοινώσεων</string>
<string name="revanced_announcements_dialog_dismiss">Παράλειψη</string> <string name="revanced_announcements_dialog_dismiss">Παράλειψη</string>

View file

@ -1514,6 +1514,11 @@ El minireproductor se puede arrastrar fuera de la pantalla hacia la izquierda o
<string name="revanced_miniplayer_hide_overlay_buttons_title">Ocultar botones de superposición</string> <string name="revanced_miniplayer_hide_overlay_buttons_title">Ocultar botones de superposición</string>
<string name="revanced_miniplayer_hide_overlay_buttons_summary_on">Los botones de superposición están ocultos</string> <string name="revanced_miniplayer_hide_overlay_buttons_summary_on">Los botones de superposición están ocultos</string>
<string name="revanced_miniplayer_hide_overlay_buttons_summary_off">Se muestran los botones de superposición</string> <string name="revanced_miniplayer_hide_overlay_buttons_summary_off">Se muestran los botones de superposición</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_title">Ocultar botones de expandir y cerrar</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_summary_on">"Los botones están ocultos
Deslizar para expandir o cerrar"</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_summary_off">Se muestran botones de expandir y cerrar</string>
<string name="revanced_miniplayer_hide_subtext_title">Ocultar subtextos</string> <string name="revanced_miniplayer_hide_subtext_title">Ocultar subtextos</string>
<string name="revanced_miniplayer_hide_subtext_summary_on">Los subtextos están ocultos</string> <string name="revanced_miniplayer_hide_subtext_summary_on">Los subtextos están ocultos</string>
<string name="revanced_miniplayer_hide_subtext_summary_off">Los subtextos se muestran</string> <string name="revanced_miniplayer_hide_subtext_summary_off">Los subtextos se muestran</string>
@ -1622,7 +1627,10 @@ Toca aquí para obtener más información sobre DeArrow"</string>
<string name="revanced_loop_video_button_toast_on">Bucle de vídeo activado</string> <string name="revanced_loop_video_button_toast_on">Bucle de vídeo activado</string>
<string name="revanced_loop_video_button_toast_off">Bucle de vídeo desactivado</string> <string name="revanced_loop_video_button_toast_off">Bucle de vídeo desactivado</string>
</patch> </patch>
<patch id="misc.audiofocus.pauseOnAudioInterruptPatch"/> <patch id="misc.audiofocus.pauseOnAudioInterruptPatch">
<string name="revanced_pause_on_audio_interrupt_title">Pausar cuando se corte el audio</string>
<string name="revanced_pause_on_audio_interrupt_summary_on">La reproducción se detiene cuando se reproduce otro audio (por ejemplo, navegación)</string>
</patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch"> <patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
<string name="revanced_spoof_device_dimensions_title">Dimensiones del dispositivo</string> <string name="revanced_spoof_device_dimensions_title">Dimensiones del dispositivo</string>
<string name="revanced_spoof_device_dimensions_summary_on">"Las dimensiones del dispositivo están falsificadas <string name="revanced_spoof_device_dimensions_summary_on">"Las dimensiones del dispositivo están falsificadas

View file

@ -370,39 +370,39 @@ Mar sin féin, má chumasaíonn tú é seo, logálfar roinnt sonraí úsáideora
<string name="revanced_hide_video_title_title">Folaigh teideal físeáin</string> <string name="revanced_hide_video_title_title">Folaigh teideal físeáin</string>
<string name="revanced_hide_video_title_summary_on">Tá teideal an fhíseáin i bhfolach san fhorleagan seinnteora</string> <string name="revanced_hide_video_title_summary_on">Tá teideal an fhíseáin i bhfolach san fhorleagan seinnteora</string>
<string name="revanced_hide_video_title_summary_off">Taispeántar teideal an fhíseáin i bhforleagan an imreora</string> <string name="revanced_hide_video_title_summary_off">Taispeántar teideal an fhíseáin i bhforleagan an imreora</string>
<string name="revanced_hide_ai_generated_video_summary_section_title">Folaigh \'Achoimre físeáin arna giniúint ag AI\'</string> <string name="revanced_hide_ai_generated_video_summary_section_title">Folaigh \'Achoimre físe a ghintear le hintleacht shaorga\'</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_on">Tá an chuid achoimre físe IS-ghinte i bhfolach</string> <string name="revanced_hide_ai_generated_video_summary_section_summary_on">Tá an chuid achoimre físe IS-ghinte i bhfolach</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_off">Taispeántar an chuid achoimre físe a ghintear ag AI</string> <string name="revanced_hide_ai_generated_video_summary_section_summary_off">Taispeántar an chuid achoimre físe a ghintear ag Intleacht Shaorga</string>
<string name="revanced_hide_ask_section_title">Folaigh Iarr</string> <string name="revanced_hide_ask_section_title">Folaigh Iarr</string>
<string name="revanced_hide_ask_section_summary_on">Tá an rannán Iarratas i bhfolach</string> <string name="revanced_hide_ask_section_summary_on">Tá an rannán Iarratas i bhfolach</string>
<string name="revanced_hide_ask_section_summary_off">Taispeántar an rannán Iarratas</string> <string name="revanced_hide_ask_section_summary_off">Taispeántar an rannán Iarratas</string>
<string name="revanced_hide_attributes_section_title">Folaigh Tréithe</string> <string name="revanced_hide_attributes_section_title">Folaigh Tréithe</string>
<string name="revanced_hide_attributes_section_summary_on">ailt d\'áiteanna sonracha, Cluichí, Ceol agus Daoine a luaitear i bhfolach</string> <string name="revanced_hide_attributes_section_summary_on">na rannóga \'Áiteanna Réadmhaoine\', \'Cluichí\', \'Ceol\' agus \'Daoine\' i bhfolach</string>
<string name="revanced_hide_attributes_section_summary_off">Taispeántar ailt d\'áiteanna sonracha, Cluichí, Ceol agus Daoine a luaitear</string> <string name="revanced_hide_attributes_section_summary_off">Taispeántar ailt d\'áiteanna sonracha, Cluichí, Ceol agus Daoine a luaitear</string>
<string name="revanced_hide_chapters_section_title">Folaigh Caibidlí</string> <string name="revanced_hide_chapters_section_title">Folaigh Caibidlí</string>
<string name="revanced_hide_chapters_section_summary_on">Tá an chuid Caibidil i bhfolach</string> <string name="revanced_hide_chapters_section_summary_on">Tá an chuid Caibidil i bhfolach</string>
<string name="revanced_hide_chapters_section_summary_off">Taispeántar alt na gcaibidlí</string> <string name="revanced_hide_chapters_section_summary_off">Taispeántar alt na gcaibidlí</string>
<string name="revanced_hide_course_progress_section_title">Folaigh Dul chun cinn cúrsa</string> <string name="revanced_hide_course_progress_section_title">Folaigh \'Dul chun cinn an chúrsa\'</string>
<string name="revanced_hide_course_progress_section_summary_on">Tá rannóg an dul chun cinn cúrsa i bhfolach</string> <string name="revanced_hide_course_progress_section_summary_on">Tá rannóg an dul chun cinn cúrsa i bhfolach</string>
<string name="revanced_hide_course_progress_section_summary_off">Taispeántar rannóg an dul chun cinn cúrsa</string> <string name="revanced_hide_course_progress_section_summary_off">Taispeántar rannóg an dul chun cinn cúrsa</string>
<string name="revanced_hide_explore_section_title">Folaigh Iniúchadh</string> <string name="revanced_hide_explore_section_title">Folaigh Iniúchadh</string>
<string name="revanced_hide_explore_section_summary_on">Tá rannóga Iniúchadh ar an gcúrsa seo agus Déan iniúchadh ar an bpodchraoladh i bhfolach</string> <string name="revanced_hide_explore_section_summary_on">Tá rannóga Iniúchadh ar an gcúrsa seo agus Déan iniúchadh ar an bpodchraoladh i bhfolach</string>
<string name="revanced_hide_explore_section_summary_off">Taispeántar rannóga Iniúchadh ar an gcúrsa seo agus Déan iniúchadh ar an bpodchraoladh</string> <string name="revanced_hide_explore_section_summary_off">Taispeántar na rannóga Iniúchadh an chúrsa seo agus Iniúchadh na podchraoltaí</string>
<string name="revanced_hide_explore_course_section_title">Folaigh Déan iniúchadh ar an gcúrsa seo</string> <string name="revanced_hide_explore_course_section_title">Folaigh Déan iniúchadh ar an gcúrsa seo</string>
<string name="revanced_hide_explore_course_section_summary_on">Tá rannóg Déan iniúchadh ar an gcúrsa seo i bhfolach</string> <string name="revanced_hide_explore_course_section_summary_on">Tá rannóg Déan iniúchadh ar an gcúrsa seo i bhfolach</string>
<string name="revanced_hide_explore_course_section_summary_off">Taispeántar rannóg Déan iniúchadh ar an gcúrsa seo</string> <string name="revanced_hide_explore_course_section_summary_off">Taispeántar an chuid seo den chúrsa a iniúchadh</string>
<string name="revanced_hide_explore_podcast_section_title">Folaigh \'Déan iniúchadh ar an bpodchraoladh\'</string> <string name="revanced_hide_explore_podcast_section_title">Folaigh \'Déan iniúchadh ar an bpodchraoladh\'</string>
<string name="revanced_hide_explore_podcast_section_summary_on">Tá an chuid Déan iniúchadh ar an bpodchraoladh i bhfolach</string> <string name="revanced_hide_explore_podcast_section_summary_on">Tá an chuid Déan iniúchadh ar an bpodchraoladh i bhfolach</string>
<string name="revanced_hide_explore_podcast_section_summary_off">Taispeántar an chuid Déan iniúchadh ar an bpodchraoladh</string> <string name="revanced_hide_explore_podcast_section_summary_off">Taispeántar an rannóg podchraoltaí a iniúchadh</string>
<string name="revanced_hide_podcast_section_title">Folaigh \'Déan iniúchadh ar an bpodchraoladh\'</string> <string name="revanced_hide_podcast_section_title">Folaigh \'Iniúchadh a dhéanamh ar an bpodchraoladh\'</string>
<string name="revanced_hide_podcast_section_summary_on">Tá an chuid Déan iniúchadh ar an bpodchraoladh i bhfolach</string> <string name="revanced_hide_podcast_section_summary_on">Tá an rannán podchraoltaí a iniúchadh i bhfolach</string>
<string name="revanced_hide_podcast_section_summary_off">Taispeántar an chuid Déan iniúchadh ar an bpodchraoladh</string> <string name="revanced_hide_podcast_section_summary_off">Taispeántar an rannóg podchraoltaí a iniúchadh</string>
<string name="revanced_hide_featured_links_section_title">Folaigh naisc le feiceáil</string> <string name="revanced_hide_featured_links_section_title">Folaigh naisc le feiceáil</string>
<string name="revanced_hide_featured_links_section_summary_on">Tá an chuid nasc le feiceáil i bhfolach</string> <string name="revanced_hide_featured_links_section_summary_on">Tá an chuid nasc le feiceáil i bhfolach</string>
<string name="revanced_hide_featured_links_section_summary_off">Taispeántar an chuid nasc le feiceáil</string> <string name="revanced_hide_featured_links_section_summary_off">Taispeántar an chuid nasc le feiceáil</string>
<string name="revanced_hide_featured_places_section_title">Folaigh Áiteanna faoi Thrácht</string> <string name="revanced_hide_featured_places_section_title">Folaigh Áiteanna faoi Thrácht</string>
<string name="revanced_hide_featured_places_section_summary_on">Tá rannóg na n-áiteanna faoi Thrácht i bhfolach</string> <string name="revanced_hide_featured_places_section_summary_on">Tá rannóg na n-áiteanna faoi Thrácht i bhfolach</string>
<string name="revanced_hide_featured_places_section_summary_off">Taispeántar rannóg na n-áiteanna faoi Thrácht</string> <string name="revanced_hide_featured_places_section_summary_off">Taispeántar an chuid áiteanna feiceálacha</string>
<string name="revanced_hide_featured_videos_section_title">Folaigh físeáin le feiceáil</string> <string name="revanced_hide_featured_videos_section_title">Folaigh físeáin le feiceáil</string>
<string name="revanced_hide_featured_videos_section_summary_on">Tá an chuid físeán le feiceáil i bhfolach</string> <string name="revanced_hide_featured_videos_section_summary_on">Tá an chuid físeán le feiceáil i bhfolach</string>
<string name="revanced_hide_featured_videos_section_summary_off">Taispeántar an chuid físeán le feiceáil</string> <string name="revanced_hide_featured_videos_section_summary_off">Taispeántar an chuid físeán le feiceáil</string>
@ -1847,7 +1847,7 @@ Dfhéadfadh sé go mbeadh stad nó go gcaillfí frámaí ag athsheinm físe l
<string name="revanced_music_navigation_bar_screen_summary">Folaigh nó athraigh cnaipí an bharra nascleanúna</string> <string name="revanced_music_navigation_bar_screen_summary">Folaigh nó athraigh cnaipí an bharra nascleanúna</string>
<!-- 'Home' should be translated using the same localized wording YouTube Music displays for the tab. --> <!-- 'Home' should be translated using the same localized wording YouTube Music displays for the tab. -->
<string name="revanced_music_hide_navigation_bar_home_button_title">Folaigh Baile</string> <string name="revanced_music_hide_navigation_bar_home_button_title">Folaigh Baile</string>
<string name="revanced_music_hide_navigation_bar_home_button_summary_on">cnaipe Baile folaithe</string> <string name="revanced_music_hide_navigation_bar_home_button_summary_on">an cnaipe baile i bhfolach</string>
<string name="revanced_music_hide_navigation_bar_home_button_summary_off">Taispeántar an cnaipe baile</string> <string name="revanced_music_hide_navigation_bar_home_button_summary_off">Taispeántar an cnaipe baile</string>
<!-- 'Samples' should be translated using the same localized wording YouTube Music displays for the tab. --> <!-- 'Samples' should be translated using the same localized wording YouTube Music displays for the tab. -->
<string name="revanced_music_hide_navigation_bar_samples_button_title">Folaigh Samplaí</string> <string name="revanced_music_hide_navigation_bar_samples_button_title">Folaigh Samplaí</string>
@ -1875,7 +1875,7 @@ Dfhéadfadh sé go mbeadh stad nó go gcaillfí frámaí ag athsheinm físe l
<patch id="layout.premium.hideGetPremiumPatch"> <patch id="layout.premium.hideGetPremiumPatch">
<string name="revanced_music_hide_get_premium_label_title">Folaigh an lipéad \'Faigh Music Premium\'</string> <string name="revanced_music_hide_get_premium_label_title">Folaigh an lipéad \'Faigh Music Premium\'</string>
<string name="revanced_music_hide_get_premium_label_summary_on">Tá an lipéad i bhfolach</string> <string name="revanced_music_hide_get_premium_label_summary_on">Tá an lipéad i bhfolach</string>
<string name="revanced_music_hide_get_premium_label_summary_off">Taispeántar an lipéad</string> <string name="revanced_music_hide_get_premium_label_summary_off">Taispeántar lipéad</string>
</patch> </patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch"> <patch id="layout.upgradebutton.hideUpgradeButtonPatch">
<string name="revanced_music_hide_upgrade_button_title">Folaigh an cnaipe uasghrádaithe</string> <string name="revanced_music_hide_upgrade_button_title">Folaigh an cnaipe uasghrádaithe</string>
@ -1885,28 +1885,28 @@ Dfhéadfadh sé go mbeadh stad nó go gcaillfí frámaí ag athsheinm físe l
</app> </app>
<app id="twitch"> <app id="twitch">
<patch id="ad.audio.audioAdsPatch"> <patch id="ad.audio.audioAdsPatch">
<string name="revanced_block_audio_ads_title">Cuir bac ar fógraí fuaime</string> <string name="revanced_block_audio_ads_title">Blocáil fógraí fuaime</string>
<string name="revanced_block_audio_ads_summary_on">Cuirtear bac ar fhógraí fuaime</string> <string name="revanced_block_audio_ads_summary_on">Tá fógraí fuaime blocáilte</string>
<string name="revanced_block_audio_ads_summary_off">Tá fógraí fuaime díbhlocáilte</string> <string name="revanced_block_audio_ads_summary_off">Tá fógraí fuaime díbhlocáilte</string>
</patch> </patch>
<patch id="ad.embedded.embeddedAdsPatch"> <patch id="ad.embedded.embeddedAdsPatch">
<string name="revanced_embedded_ads_service_unavailable">%s neamh-infheidhme, d\'fhéadfadh go dtaispeánfadh fógraí. Bain triail as seirbhís blocála fógraí a athrú sna socruithe.</string> <string name="revanced_embedded_ads_service_unavailable">%s neamh-infheidhme, d\'fhéadfadh go dtaispeánfadh fógraí. Bain triail as seirbhís blocála fógraí a athrú sna socruithe.</string>
<string name="revanced_embedded_ads_service_failed">Tháinig earráid ar %s, d\'fhéadfadh go dtaispeánfadh fógraí. Bain triail as seirbhís blocála fógraí a athrú sna socruithe.</string> <string name="revanced_embedded_ads_service_failed">Thug %s earráid ar ais, dfhéadfadh fógraí a bheith le feiceáil. Bain triail as an tseirbhís blocála fógraí a athrú sna socruithe.</string>
<string name="revanced_block_embedded_ads_title">Bloc ar fhógraí físe leabaithe</string> <string name="revanced_block_embedded_ads_title">Bloc ar fhógraí físe leabaithe</string>
<string name="revanced_block_embedded_ads_entry_1">Díchumasaithe</string> <string name="revanced_block_embedded_ads_entry_1">Díchumasaithe</string>
<string name="revanced_block_embedded_ads_entry_2">Proxy lonrúil</string> <string name="revanced_block_embedded_ads_entry_2">Seachfhreastalaí lonrúil</string>
<string name="revanced_block_embedded_ads_entry_3">Seachfhreastalaí PurpleAdBlock</string> <string name="revanced_block_embedded_ads_entry_3">Seachfhreastalaí PurpleAdBlock</string>
</patch> </patch>
<patch id="ad.video.videoAdsPatch"> <patch id="ad.video.videoAdsPatch">
<string name="revanced_block_video_ads_title">Bloc ar fhógraí físe</string> <string name="revanced_block_video_ads_title">Bloc ar fhógraí físe</string>
<string name="revanced_block_video_ads_summary_on">Cuirtear bac ar fhógraí físe</string> <string name="revanced_block_video_ads_summary_on"> bac ar fhógraí físe</string>
<string name="revanced_block_video_ads_summary_off">Déantar fógraí físe a dhíbhlocáil</string> <string name="revanced_block_video_ads_summary_off">Tá fógraí físe díbhlocáilte</string>
</patch> </patch>
<patch id="chat.antidelete.showDeletedMessagesPatch"> <patch id="chat.antidelete.showDeletedMessagesPatch">
<string name="revanced_deleted_msg">Teachtaireacht scriosta</string> <string name="revanced_deleted_msg">Teachtaireacht scriosta</string>
<string name="revanced_show_deleted_messages_title">Taispeáin teachtaireachtaí scriosta</string> <string name="revanced_show_deleted_messages_title">Taispeáin teachtaireachtaí scriosta</string>
<string name="revanced_show_deleted_messages_entry_1">Ná taispeáin teachtaireachtaí scriosta</string> <string name="revanced_show_deleted_messages_entry_1">Ná taispeáin teachtaireachtaí scriosta</string>
<string name="revanced_show_deleted_messages_entry_2">Folaigh teachtaireachtaí scriosta taobh thiar a fhalsúa</string> <string name="revanced_show_deleted_messages_entry_2">Folaigh teachtaireachtaí scriosta taobh thiar a mhilleann</string>
<string name="revanced_show_deleted_messages_entry_3">Taispeáin teachtaireachtaí scriosta mar théacs trasnaithe amach</string> <string name="revanced_show_deleted_messages_entry_3">Taispeáin teachtaireachtaí scriosta mar théacs trasnaithe amach</string>
</patch> </patch>
<patch id="chat.autoclaim.autoClaimChannelPointsPatch"> <patch id="chat.autoclaim.autoClaimChannelPointsPatch">

View file

@ -29,7 +29,7 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch"/> <patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch"/>
<patch id="misc.settings.settingsResourcePatch"> <patch id="misc.settings.settingsResourcePatch">
<string name="revanced_settings_save">Sačuvaj</string> <string name="revanced_settings_save">Spremi</string>
<string name="revanced_settings_disable_bold_icons_title">Onemogući podebljane ikone</string> <string name="revanced_settings_disable_bold_icons_title">Onemogući podebljane ikone</string>
<string name="revanced_settings_disable_bold_icons_summary_on">Ikone nisu podebljane</string> <string name="revanced_settings_disable_bold_icons_summary_on">Ikone nisu podebljane</string>
<string name="revanced_settings_disable_bold_icons_summary_off">Ikone su podebljane</string> <string name="revanced_settings_disable_bold_icons_summary_off">Ikone su podebljane</string>
@ -41,7 +41,7 @@ Second \"item\" text"</string>
<string name="revanced_gms_core_screen_title">GmsCore</string> <string name="revanced_gms_core_screen_title">GmsCore</string>
<string name="revanced_gms_core_screen_summary">Postavke povezane s GmsCoreom</string> <string name="revanced_gms_core_screen_summary">Postavke povezane s GmsCoreom</string>
<string name="revanced_gms_core_check_updates_title">Provjeri ažuriranja za GmsCore</string> <string name="revanced_gms_core_check_updates_title">Provjeri ažuriranja za GmsCore</string>
<string name="revanced_gms_core_check_updates_summary_on">Provjera ažuriranja omogućena je</string> <string name="revanced_gms_core_check_updates_summary_on">Provjera ažuriranja je omogućena</string>
<string name="revanced_gms_core_check_updates_summary_off">Provjera ažuriranja je onemogućena</string> <string name="revanced_gms_core_check_updates_summary_off">Provjera ažuriranja je onemogućena</string>
<string name="revanced_gms_core_settings_title">Otvori postavke za GmsCore</string> <string name="revanced_gms_core_settings_title">Otvori postavke za GmsCore</string>
<string name="revanced_gms_core_settings_summary">Postavke za GmsCore</string> <string name="revanced_gms_core_settings_summary">Postavke za GmsCore</string>
@ -49,7 +49,7 @@ Second \"item\" text"</string>
<string name="revanced_gms_core_toast_not_installed_message">MicroG GmsCore nije instaliran. Instalirajte ga.</string> <string name="revanced_gms_core_toast_not_installed_message">MicroG GmsCore nije instaliran. Instalirajte ga.</string>
<string name="revanced_gms_core_dialog_title">Potrebna je radnja</string> <string name="revanced_gms_core_dialog_title">Potrebna je radnja</string>
<string name="revanced_gms_core_toast_update_check_failed_message">Nije uspjela provjera ažuriranja za MicroG GmsCore</string> <string name="revanced_gms_core_toast_update_check_failed_message">Nije uspjela provjera ažuriranja za MicroG GmsCore</string>
<string name="revanced_gms_core_update_available_message">Dostupna je nova verzija (%1$s) MicroG GmsCore. Trenutno koristite verziju %2$s.</string> <string name="revanced_gms_core_update_available_message">Dostupna je nova verzija (%1$s) MicroG GmsCorea. Trenutno koristite verziju %2$s.</string>
<string name="revanced_gms_core_dialog_not_whitelisted_not_allowed_in_background_message">"MicroG GmsCore nema dopuštenje za rad u pozadini.\n\nSlijedite vodič \"Ne ubijaj moju aplikaciju\" za svoj telefon i primijenite upute na svoju MicroG instalaciju.\n\nOvo je potrebno da bi aplikacija radila."</string> <string name="revanced_gms_core_dialog_not_whitelisted_not_allowed_in_background_message">"MicroG GmsCore nema dopuštenje za rad u pozadini.\n\nSlijedite vodič \"Ne ubijaj moju aplikaciju\" za svoj telefon i primijenite upute na svoju MicroG instalaciju.\n\nOvo je potrebno da bi aplikacija radila."</string>
<string name="revanced_gms_core_dialog_open_website_text">Otvori web-stranicu</string> <string name="revanced_gms_core_dialog_open_website_text">Otvori web-stranicu</string>
<string name="revanced_gms_core_dialog_cancel_text">Odustani</string> <string name="revanced_gms_core_dialog_cancel_text">Odustani</string>
@ -438,8 +438,8 @@ Već postoji"</string>
<patch id="video.quality.advancedVideoQualityMenuPatch"/> <patch id="video.quality.advancedVideoQualityMenuPatch"/>
<patch id="video.quality.hidePremiumVideoQualityPatch"> <patch id="video.quality.hidePremiumVideoQualityPatch">
<string name="revanced_hide_premium_video_quality_title">Sakrij opcije premium kvalitete</string> <string name="revanced_hide_premium_video_quality_title">Sakrij opcije premium kvalitete</string>
<string name="revanced_hide_premium_video_quality_summary_on">Opcije premium kvalitete su sakrivene</string> <string name="revanced_hide_premium_video_quality_summary_on">Premium opcije kvalitete su skrivene</string>
<string name="revanced_hide_premium_video_quality_summary_off">Opcije premium kvalitete su prikazane</string> <string name="revanced_hide_premium_video_quality_summary_off">Premium opcije kvalitete su prikazane</string>
</patch> </patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch"/> <patch id="interaction.seekbar.enableSlideToSeekPatch"/>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">

View file

@ -188,7 +188,7 @@ Anda tidak akan diberi tahu tentang kejadian yang tidak terduga."</string>
<string name="revanced_debug_protocolbuffer_title">Catatan protokol buffer</string> <string name="revanced_debug_protocolbuffer_title">Catatan protokol buffer</string>
<string name="revanced_debug_protocolbuffer_summary_on">Pencatatan debug termasuk buffer proto</string> <string name="revanced_debug_protocolbuffer_summary_on">Pencatatan debug termasuk buffer proto</string>
<string name="revanced_debug_protocolbuffer_summary_off">Pencatatan debug tidak menyertakan buffer proto</string> <string name="revanced_debug_protocolbuffer_summary_off">Pencatatan debug tidak menyertakan buffer proto</string>
<string name="revanced_debug_protocolbuffer_user_dialog_message">"Mengaktifkan setelan ini akan mencatat data tata letak tambahan, termasuk teks pada layar untuk beberapa komponen UI. <string name="revanced_debug_protocolbuffer_user_dialog_message">"Mengaktifkan pengaturan ini akan mencatat data tata letak tambahan, termasuk teks pada layar untuk beberapa komponen UI.
Ini dapat membantu mengidentifikasi komponen saat membuat penyaring khusus. Ini dapat membantu mengidentifikasi komponen saat membuat penyaring khusus.

View file

@ -1693,13 +1693,13 @@ Automotive レイアウト
<string name="revanced_remember_video_quality_last_selected_toast_summary_on">デフォルトの画質が変更された場合にトースト通知が表示されます</string> <string name="revanced_remember_video_quality_last_selected_toast_summary_on">デフォルトの画質が変更された場合にトースト通知が表示されます</string>
<string name="revanced_remember_video_quality_last_selected_toast_summary_off">デフォルトの画質が変更された場合にトースト通知は表示されません</string> <string name="revanced_remember_video_quality_last_selected_toast_summary_off">デフォルトの画質が変更された場合にトースト通知は表示されません</string>
<string name="revanced_video_quality_default_wifi_title">デフォルトの画質 (Wi-Fi)</string> <string name="revanced_video_quality_default_wifi_title">デフォルトの画質 (Wi-Fi)</string>
<string name="revanced_video_quality_default_mobile_title">デフォルトの画質 (携帯回線)</string> <string name="revanced_video_quality_default_mobile_title">デフォルトの画質 (モバイル)</string>
<string name="revanced_remember_shorts_quality_last_selected_title">ショートの画質の変更を保存</string> <string name="revanced_remember_shorts_quality_last_selected_title">ショートの画質の変更を保存</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_on">画質の変更はすべてのショート動画に適用されます</string> <string name="revanced_remember_shorts_quality_last_selected_summary_on">画質の変更はすべてのショート動画に適用されます</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_off">画質の変更は現在のショート動画にのみ適用されます</string> <string name="revanced_remember_shorts_quality_last_selected_summary_off">画質の変更は現在のショート動画にのみ適用されます</string>
<string name="revanced_shorts_quality_default_wifi_title">デフォルトのショートの画質 (Wi-Fi)</string> <string name="revanced_shorts_quality_default_wifi_title">デフォルトのショートの画質 (Wi-Fi)</string>
<string name="revanced_shorts_quality_default_mobile_title">デフォルトのショートの画質 (携帯回線)</string> <string name="revanced_shorts_quality_default_mobile_title">デフォルトのショートの画質 (モバイル)</string>
<string name="revanced_remember_video_quality_mobile">携帯回線</string> <string name="revanced_remember_video_quality_mobile">モバイル</string>
<string name="revanced_remember_video_quality_wifi">Wi-Fi</string> <string name="revanced_remember_video_quality_wifi">Wi-Fi</string>
<string name="revanced_remember_video_quality_toast">デフォルトの画質の変更 (%1$s): %2$s</string> <string name="revanced_remember_video_quality_toast">デフォルトの画質の変更 (%1$s): %2$s</string>
<string name="revanced_remember_video_quality_toast_shorts">ショートの画質の変更 (%1$s): %2$s</string> <string name="revanced_remember_video_quality_toast_shorts">ショートの画質の変更 (%1$s): %2$s</string>

View file

@ -649,7 +649,7 @@ YouTube Premium 사용자라면 이 설정은 필요하지 않을 수 있습니
<string name="revanced_external_downloader_other_item_hint">앱 패키지명을 입력하세요</string> <string name="revanced_external_downloader_other_item_hint">앱 패키지명을 입력하세요</string>
<string name="revanced_external_downloader_other_item">기타</string> <string name="revanced_external_downloader_other_item">기타</string>
<string name="revanced_external_downloader_not_found_title">앱이 설치되지 않습니다</string> <string name="revanced_external_downloader_not_found_title">앱이 설치되지 않습니다</string>
<string name="revanced_external_downloader_not_installed_warning">%s 는 설치되어 있지 않습니다. 설치하세요</string> <string name="revanced_external_downloader_not_installed_warning">%s 는 설치되어 있지 않습니다. 설치하세요.</string>
<string name="revanced_external_downloader_package_not_found_warning">"패키지 이름이 '%s'인 설치된 앱을 찾을 수 없습니다 <string name="revanced_external_downloader_package_not_found_warning">"패키지 이름이 '%s'인 설치된 앱을 찾을 수 없습니다
패키지 이름이 올바르고 앱이 설치되어 있는지 확인하세요"</string> 패키지 이름이 올바르고 앱이 설치되어 있는지 확인하세요"</string>

View file

@ -57,7 +57,7 @@ Second \"item\" text"</string>
<string name="revanced_settings_restart_title">Nepieciešama restartēšana</string> <string name="revanced_settings_restart_title">Nepieciešama restartēšana</string>
<string name="revanced_settings_restart_dialog_message">Lai šīs izmaiņas stātos spēkā, restartējiet lietotni.</string> <string name="revanced_settings_restart_dialog_message">Lai šīs izmaiņas stātos spēkā, restartējiet lietotni.</string>
<string name="revanced_settings_restart">Restartēt</string> <string name="revanced_settings_restart">Restartēt</string>
<string name="revanced_settings_import">Importēt</string> <string name="revanced_settings_import">Ievietot</string>
<string name="revanced_settings_import_copy">Kopēt</string> <string name="revanced_settings_import_copy">Kopēt</string>
<string name="revanced_settings_import_reset">ReVanced iestatījumi atiestatīti uz noklusējuma vērtībām</string> <string name="revanced_settings_import_reset">ReVanced iestatījumi atiestatīti uz noklusējuma vērtībām</string>
<string name="revanced_settings_import_success">Importēti %d iestatījumi</string> <string name="revanced_settings_import_success">Importēti %d iestatījumi</string>
@ -641,8 +641,8 @@ Ierobežojumi:
<string name="revanced_external_downloader_name_summary">Jūsu instalētās ārējās lejupielādētāja lietotnes pakotnes nosaukums</string> <string name="revanced_external_downloader_name_summary">Jūsu instalētās ārējās lejupielādētāja lietotnes pakotnes nosaukums</string>
<string name="revanced_external_downloader_other_item_hint">Ievadiet pakotnes nosaukumu</string> <string name="revanced_external_downloader_other_item_hint">Ievadiet pakotnes nosaukumu</string>
<string name="revanced_external_downloader_other_item">Cits</string> <string name="revanced_external_downloader_other_item">Cits</string>
<string name="revanced_external_downloader_not_found_title">Lietotne nav instalēta</string> <string name="revanced_external_downloader_not_found_title">Lietotne nav uzstādīta</string>
<string name="revanced_external_downloader_not_installed_warning">%s nav instalēts. Lūdzu, instalējiet to.</string> <string name="revanced_external_downloader_not_installed_warning">%s nav uzstādīta. Lūdzu, uzstādiet to.</string>
<string name="revanced_external_downloader_package_not_found_warning">"Nevarēja atrast instalēto lietotni ar pakotnes nosaukumu: %s <string name="revanced_external_downloader_package_not_found_warning">"Nevarēja atrast instalēto lietotni ar pakotnes nosaukumu: %s
Pārbaudiet, vai pakotnes nosaukums ir pareizs un lietotne ir instalēta"</string> Pārbaudiet, vai pakotnes nosaukums ir pareizs un lietotne ir instalēta"</string>

View file

@ -25,7 +25,7 @@ Second \"item\" text"</string>
<string name="revanced_custom_branding_name_entry_5">Aangepast</string> <string name="revanced_custom_branding_name_entry_5">Aangepast</string>
<string name="revanced_custom_branding_icon_title">App-pictogram</string> <string name="revanced_custom_branding_icon_title">App-pictogram</string>
<string name="revanced_custom_branding_icon_entry_1">Origineel</string> <string name="revanced_custom_branding_icon_entry_1">Origineel</string>
<string name="revanced_custom_branding_icon_entry_2">shared.layout.branding.baseCustomBrandingPatch.revanced_custom_branding_icon_entry_2</string> <string name="revanced_custom_branding_icon_entry_2">ReVanced</string>
<!-- Translation of this should be identical to revanced_header_logo_entry_5 --> <!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimaal</string> <string name="revanced_custom_branding_icon_entry_3">ReVanced minimaal</string>
<string name="revanced_custom_branding_icon_entry_4">ReVanced geschaald</string> <string name="revanced_custom_branding_icon_entry_4">ReVanced geschaald</string>
@ -33,7 +33,7 @@ Second \"item\" text"</string>
<string name="revanced_custom_branding_icon_entry_5">Aangepast</string> <string name="revanced_custom_branding_icon_entry_5">Aangepast</string>
</patch> </patch>
<patch id="misc.checks.checkEnvironmentPatch"> <patch id="misc.checks.checkEnvironmentPatch">
<string name="revanced_check_environment_failed_title">Controle mislukt</string> <string name="revanced_check_environment_failed_title">Controles mislukt</string>
<string name="revanced_check_environment_dialog_open_official_source_button">Open officiële website</string> <string name="revanced_check_environment_dialog_open_official_source_button">Open officiële website</string>
<string name="revanced_check_environment_dialog_ignore_button">Negeren</string> <string name="revanced_check_environment_dialog_ignore_button">Negeren</string>
<string name="revanced_check_environment_failed_message">&lt;h5&gt;Deze app lijkt niet door u te zijn gepatcht.&lt;/h5&gt;&lt;br&gt;Deze app werkt mogelijk niet goed, is **mogelijk schadelijk of zelfs gevaarlijk om te gebruiken**.&lt;br&gt;&lt;br&gt;Deze checks geven aan dat deze app is gepatcht of van iemand anders is verkregen:&lt;br&gt;&lt;br&gt;&lt;small&gt;%1$s&lt;/small&gt;&lt;br&gt;Het is sterk aan te raden om **deze app te verwijderen en zelf te patchen** om er zeker van te zijn dat u een gevalideerde en veilige app gebruikt.&lt;p&gt;&lt;br&gt;Indien genegeerd, zal deze waarschuwing nog slechts twee keer worden getoond.</string> <string name="revanced_check_environment_failed_message">&lt;h5&gt;Deze app lijkt niet door u te zijn gepatcht.&lt;/h5&gt;&lt;br&gt;Deze app werkt mogelijk niet goed, is **mogelijk schadelijk of zelfs gevaarlijk om te gebruiken**.&lt;br&gt;&lt;br&gt;Deze checks geven aan dat deze app is gepatcht of van iemand anders is verkregen:&lt;br&gt;&lt;br&gt;&lt;small&gt;%1$s&lt;/small&gt;&lt;br&gt;Het is sterk aan te raden om **deze app te verwijderen en zelf te patchen** om er zeker van te zijn dat u een gevalideerde en veilige app gebruikt.&lt;p&gt;&lt;br&gt;Indien genegeerd, zal deze waarschuwing nog slechts twee keer worden getoond.</string>
@ -1592,6 +1592,7 @@ Het inschakelen hiervan kan ontbrekende afbeeldingen oplossen die in sommige reg
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow &amp; Oorspronkelijke miniaturen</string> <string name="revanced_alt_thumbnail_options_entry_2">DeArrow &amp; Oorspronkelijke miniaturen</string>
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow &amp; Stilstaande opnames</string> <string name="revanced_alt_thumbnail_options_entry_3">DeArrow &amp; Stilstaande opnames</string>
<string name="revanced_alt_thumbnail_options_entry_4">Stilstaande opnames</string> <string name="revanced_alt_thumbnail_options_entry_4">Stilstaande opnames</string>
<string name="revanced_alt_thumbnail_dearrow_about_title">DeArrow</string>
<string name="revanced_alt_thumbnail_dearrow_about_summary">"DeArrow biedt door de menigte gecrowdsourcede miniaturen voor YouTube-video's. Deze miniaturen zijn vaak relevanter dan die van YouTube. <string name="revanced_alt_thumbnail_dearrow_about_summary">"DeArrow biedt door de menigte gecrowdsourcede miniaturen voor YouTube-video's. Deze miniaturen zijn vaak relevanter dan die van YouTube.
Als dit is ingeschakeld, worden video-URL's naar de API-server verzonden en worden geen andere gegevens verzonden. Als een video geen DeArrow-miniaturen heeft, worden de originele of stilstaande opnames weergegeven. Als dit is ingeschakeld, worden video-URL's naar de API-server verzonden en worden geen andere gegevens verzonden. Als een video geen DeArrow-miniaturen heeft, worden de originele of stilstaande opnames weergegeven.
@ -1635,7 +1636,11 @@ Tik hier om meer te weten te komen over DeArrow"</string>
<string name="revanced_loop_video_button_toast_on">Loopvideo is ingeschakeld</string> <string name="revanced_loop_video_button_toast_on">Loopvideo is ingeschakeld</string>
<string name="revanced_loop_video_button_toast_off">Loopvideo is uitgeschakeld</string> <string name="revanced_loop_video_button_toast_off">Loopvideo is uitgeschakeld</string>
</patch> </patch>
<patch id="misc.audiofocus.pauseOnAudioInterruptPatch"/> <patch id="misc.audiofocus.pauseOnAudioInterruptPatch">
<string name="revanced_pause_on_audio_interrupt_title">Pauzeren bij audio-onderbreking</string>
<string name="revanced_pause_on_audio_interrupt_summary_on">Afspelen wordt gepauzeerd wanneer andere audio wordt afgespeeld (bijv. navigatie)</string>
<string name="revanced_pause_on_audio_interrupt_summary_off">Volume wordt zachter wanneer andere audio wordt afgespeeld</string>
</patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch"> <patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
<string name="revanced_spoof_device_dimensions_title">Spoof apparaatdimensies</string> <string name="revanced_spoof_device_dimensions_title">Spoof apparaatdimensies</string>
<string name="revanced_spoof_device_dimensions_summary_on">"Apparaatdimensies gespoofed <string name="revanced_spoof_device_dimensions_summary_on">"Apparaatdimensies gespoofed
@ -1695,6 +1700,7 @@ Het inschakelen hiervan kan hogere videokwaliteiten ontgrendelen"</string>
<string name="revanced_shorts_quality_default_wifi_title">Standaardkwaliteit voor Shorts op wifi-netwerk</string> <string name="revanced_shorts_quality_default_wifi_title">Standaardkwaliteit voor Shorts op wifi-netwerk</string>
<string name="revanced_shorts_quality_default_mobile_title">Standaardkwaliteit voor Shorts op mobiel netwerk</string> <string name="revanced_shorts_quality_default_mobile_title">Standaardkwaliteit voor Shorts op mobiel netwerk</string>
<string name="revanced_remember_video_quality_mobile">mobiel</string> <string name="revanced_remember_video_quality_mobile">mobiel</string>
<string name="revanced_remember_video_quality_wifi">wifi</string>
<string name="revanced_remember_video_quality_toast">Standaard %1$s-kwaliteit gewijzigd naar: %2$s</string> <string name="revanced_remember_video_quality_toast">Standaard %1$s-kwaliteit gewijzigd naar: %2$s</string>
<string name="revanced_remember_video_quality_toast_shorts">De kwaliteit van Shorts %1$s is gewijzigd in: %2$s</string> <string name="revanced_remember_video_quality_toast_shorts">De kwaliteit van Shorts %1$s is gewijzigd in: %2$s</string>
</patch> </patch>
@ -1789,7 +1795,11 @@ Het afspelen van video met AV1 kan haperen of frames overslaan."</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">
<patch id="layout.branding.customBrandingPatch"/> <patch id="layout.branding.customBrandingPatch">
<string name="revanced_custom_branding_name_entry_2">YT Music ReVanced</string>
<string name="revanced_custom_branding_name_entry_3">Music ReVanced</string>
<string name="revanced_custom_branding_name_entry_4">Music</string>
</patch>
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
<!-- In languages where "About" is ambiguous, translate to "About ReVanced" (i.e., About this app). --> <!-- In languages where "About" is ambiguous, translate to "About ReVanced" (i.e., About this app). -->
<string name="revanced_settings_music_screen_0_about_title">Over</string> <string name="revanced_settings_music_screen_0_about_title">Over</string>
@ -1916,6 +1926,7 @@ Het afspelen van video met AV1 kan haperen of frames overslaan."</string>
<string name="revanced_about_summary">Over ReVanced</string> <string name="revanced_about_summary">Over ReVanced</string>
<string name="revanced_ads_screen_title">Advertentieblokkering</string> <string name="revanced_ads_screen_title">Advertentieblokkering</string>
<string name="revanced_ads_screen_summary">Instellingen advertentieblokkering</string> <string name="revanced_ads_screen_summary">Instellingen advertentieblokkering</string>
<string name="revanced_chat_screen_title">Chat</string>
<string name="revanced_chat_screen_summary">Chat-instellingen</string> <string name="revanced_chat_screen_summary">Chat-instellingen</string>
<string name="revanced_misc_screen_title">Overige</string> <string name="revanced_misc_screen_title">Overige</string>
<string name="revanced_misc_screen_summary">Diverse instellingen</string> <string name="revanced_misc_screen_summary">Diverse instellingen</string>

View file

@ -91,7 +91,7 @@ Second \"item\" text"</string>
<string name="revanced_language_title">ReVanced 語言</string> <string name="revanced_language_title">ReVanced 語言</string>
<string name="revanced_language_user_dialog_message">"部分語言的翻譯可能缺少或不完整。 <string name="revanced_language_user_dialog_message">"部分語言的翻譯可能缺少或不完整。
要翻譯新的語言或改善現有翻譯,請前往 translate.revanced.app"</string> 要翻譯新的語言或改善現有翻譯,請前往 translate.revanced.app"</string>
<string name="revanced_language_DEFAULT">應用程式語言</string> <string name="revanced_language_DEFAULT">應用程式語言</string>
<string name="revanced_pref_import_export_title">匯入/匯出</string> <string name="revanced_pref_import_export_title">匯入/匯出</string>
<string name="revanced_pref_import_export_summary">匯入/匯出 ReVanced 設定</string> <string name="revanced_pref_import_export_summary">匯入/匯出 ReVanced 設定</string>
@ -312,8 +312,8 @@ Second \"item\" text"</string>
<string name="revanced_hide_ticket_shelf_summary_off">票券架已顯示</string> <string name="revanced_hide_ticket_shelf_summary_off">票券架已顯示</string>
<!-- 'People also watched' and 'You might also like' should be translated using the same localized wording YouTube displays. --> <!-- 'People also watched' and 'You might also like' should be translated using the same localized wording YouTube displays. -->
<string name="revanced_hide_video_recommendation_labels_title">隱藏影片推薦標籤</string> <string name="revanced_hide_video_recommendation_labels_title">隱藏影片推薦標籤</string>
<string name="revanced_hide_video_recommendation_labels_summary_on">搜尋結果中的「其他人也觀看」與「您可能也喜歡」標籤已隱藏</string> <string name="revanced_hide_video_recommendation_labels_summary_on">已隱藏搜尋結果中的「其他人也觀看」與「你可能也喜歡」標籤</string>
<string name="revanced_hide_video_recommendation_labels_summary_off">搜尋結果中的「其他人也觀看」與「您可能也喜歡」標籤已顯示</string> <string name="revanced_hide_video_recommendation_labels_summary_off">已顯示搜尋結果中的「其他人也觀看」與「你可能也喜歡」標籤</string>
<string name="revanced_hide_visual_spacer_title">隱藏視覺間隔</string> <string name="revanced_hide_visual_spacer_title">隱藏視覺間隔</string>
<string name="revanced_hide_visual_spacer_summary_on">視覺間隔已隱藏</string> <string name="revanced_hide_visual_spacer_summary_on">視覺間隔已隱藏</string>
<string name="revanced_hide_visual_spacer_summary_off">視覺間隔已顯示</string> <string name="revanced_hide_visual_spacer_summary_off">視覺間隔已顯示</string>
@ -907,9 +907,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_player_flyout_video_quality_title">隱藏影片畫質選單</string> <string name="revanced_hide_player_flyout_video_quality_title">隱藏影片畫質選單</string>
<string name="revanced_hide_player_flyout_video_quality_summary_on">影片畫質選單已隱藏</string> <string name="revanced_hide_player_flyout_video_quality_summary_on">影片畫質選單已隱藏</string>
<string name="revanced_hide_player_flyout_video_quality_summary_off">影片畫質選單已顯示</string> <string name="revanced_hide_player_flyout_video_quality_summary_off">影片畫質選單已顯示</string>
<string name="revanced_hide_player_flyout_video_quality_footer_title">隱藏影片畫質選單頁尾</string> <string name="revanced_hide_player_flyout_video_quality_footer_title">隱藏影片畫質選單頁尾</string>
<string name="revanced_hide_player_flyout_video_quality_footer_summary_on">已隱藏影片畫質選單頁尾</string> <string name="revanced_hide_player_flyout_video_quality_footer_summary_on">已隱藏影片畫質選單頁尾</string>
<string name="revanced_hide_player_flyout_video_quality_footer_summary_off">已顯示影片畫質選單頁尾</string> <string name="revanced_hide_player_flyout_video_quality_footer_summary_off">已顯示影片畫質選單頁尾</string>
</patch> </patch>
<patch id="layout.buttons.overlay.hidePlayerOverlayButtonsPatch"> <patch id="layout.buttons.overlay.hidePlayerOverlayButtonsPatch">
<string name="revanced_hide_autoplay_button_title">隱藏「自動播放」按鈕</string> <string name="revanced_hide_autoplay_button_title">隱藏「自動播放」按鈕</string>
@ -1670,8 +1670,8 @@ Second \"item\" text"</string>
<string name="revanced_disable_haptic_feedback_seek_undo_summary_on">拖曳還原觸覺回饋已停用</string> <string name="revanced_disable_haptic_feedback_seek_undo_summary_on">拖曳還原觸覺回饋已停用</string>
<string name="revanced_disable_haptic_feedback_seek_undo_summary_off">拖曳還原觸覺回饋已啟用</string> <string name="revanced_disable_haptic_feedback_seek_undo_summary_off">拖曳還原觸覺回饋已啟用</string>
<string name="revanced_disable_haptic_feedback_tap_and_hold_title">停用輕觸並按住觸覺回饋</string> <string name="revanced_disable_haptic_feedback_tap_and_hold_title">停用輕觸並按住觸覺回饋</string>
<string name="revanced_disable_haptic_feedback_tap_and_hold_summary_on">輕觸並按住觸覺回饋已停用</string> <string name="revanced_disable_haptic_feedback_tap_and_hold_summary_on">已停用輕觸並按住觸覺回饋</string>
<string name="revanced_disable_haptic_feedback_tap_and_hold_summary_off">輕觸並按住觸覺回饋已啟用</string> <string name="revanced_disable_haptic_feedback_tap_and_hold_summary_off">已啟用輕觸並按住觸覺回饋</string>
<string name="revanced_disable_haptic_feedback_zoom_title">停用縮放震動</string> <string name="revanced_disable_haptic_feedback_zoom_title">停用縮放震動</string>
<string name="revanced_disable_haptic_feedback_zoom_summary_on">縮放觸覺回饋已停用</string> <string name="revanced_disable_haptic_feedback_zoom_summary_on">縮放觸覺回饋已停用</string>
<string name="revanced_disable_haptic_feedback_zoom_summary_off">縮放觸覺回饋已啟用</string> <string name="revanced_disable_haptic_feedback_zoom_summary_off">縮放觸覺回饋已啟用</string>
@ -1712,12 +1712,12 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="video.speed.button.playbackSpeedButtonPatch"> <patch id="video.speed.button.playbackSpeedButtonPatch">
<string name="revanced_playback_speed_dialog_button_title">顯示速度對話方塊按鈕</string> <string name="revanced_playback_speed_dialog_button_title">顯示速度對話方塊按鈕</string>
<string name="revanced_playback_speed_dialog_button_summary_on">速度對話框按鈕已顯示。長按可將播放速度重設為預設值</string> <string name="revanced_playback_speed_dialog_button_summary_on">已顯示速度對話框按鈕。長按可將播放速度重設為預設值</string>
<string name="revanced_playback_speed_dialog_button_summary_off">速度對話框按鈕未顯示</string> <string name="revanced_playback_speed_dialog_button_summary_off">速度對話框按鈕未顯示</string>
</patch> </patch>
<patch id="video.quality.button.videoQualityDialogButtonPatch"> <patch id="video.quality.button.videoQualityDialogButtonPatch">
<string name="revanced_video_quality_dialog_button_title">顯示畫質切換按鈕</string> <string name="revanced_video_quality_dialog_button_title">顯示畫質切換按鈕</string>
<string name="revanced_video_quality_dialog_button_summary_on">影片畫質按鈕已顯示。長按可重設為預設畫質</string> <string name="revanced_video_quality_dialog_button_summary_on">已顯示影片畫質按鈕。長按可重設為預設畫質</string>
<string name="revanced_video_quality_dialog_button_summary_off">影片畫質按鈕未顯示</string> <string name="revanced_video_quality_dialog_button_summary_off">影片畫質按鈕未顯示</string>
</patch> </patch>
<patch id="video.speed.custom.customPlaybackSpeedPatch"> <patch id="video.speed.custom.customPlaybackSpeedPatch">
@ -1791,7 +1791,7 @@ AV1 視訊播放可能會卡頓或丟格。"</string>
<string name="revanced_spoof_video_streams_about_playback_failure">• 影片可能會在 1:00 停止,或在某些地區無法播放</string> <string name="revanced_spoof_video_streams_about_playback_failure">• 影片可能會在 1:00 停止,或在某些地區無法播放</string>
<string name="revanced_spoof_video_streams_about_no_audio_tracks">• 音軌選單遺失</string> <string name="revanced_spoof_video_streams_about_no_audio_tracks">• 音軌選單遺失</string>
<string name="revanced_spoof_video_streams_about_no_av1">• 沒有 AV1 影片解碼器</string> <string name="revanced_spoof_video_streams_about_no_av1">• 沒有 AV1 影片解碼器</string>
<string name="revanced_spoof_video_streams_about_no_stable_volume">穩定音量無法使用</string> <string name="revanced_spoof_video_streams_about_no_stable_volume">• 無法使用平衡音量</string>
<string name="revanced_spoof_video_streams_about_kids_videos">• 在登出或無痕模式下,兒童影片可能無法播放</string> <string name="revanced_spoof_video_streams_about_kids_videos">• 在登出或無痕模式下,兒童影片可能無法播放</string>
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_about_no_force_original_audio">• 強制原始音訊不可用</string> <string name="revanced_spoof_video_streams_about_no_force_original_audio">• 強制原始音訊不可用</string>

View file

@ -220,14 +220,14 @@
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string-array name="revanced_spoof_video_streams_client_type_entries"> <string-array name="revanced_spoof_video_streams_client_type_entries">
<item>Android Reel</item>
<item>Android VR</item> <item>Android VR</item>
<item>visionOS</item> <item>visionOS</item>
<item>Android No SDK</item>
</string-array> </string-array>
<string-array name="revanced_spoof_video_streams_client_type_entry_values"> <string-array name="revanced_spoof_video_streams_client_type_entry_values">
<item>ANDROID_REEL</item>
<item>ANDROID_VR_1_43_32</item> <item>ANDROID_VR_1_43_32</item>
<item>VISIONOS</item> <item>VISIONOS</item>
<item>ANDROID_NO_SDK</item>
</string-array> </string-array>
</patch> </patch>
</app> </app>
@ -264,18 +264,16 @@
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string-array name="revanced_spoof_video_streams_client_type_entries"> <string-array name="revanced_spoof_video_streams_client_type_entries">
<item>Android Reel</item>
<item>Android VR</item> <item>Android VR</item>
<item>Android Studio</item> <item>Android Studio</item>
<item>Android No SDK</item>
<item>visionOS</item> <item>visionOS</item>
<item>iPadOS</item>
</string-array> </string-array>
<string-array name="revanced_spoof_video_streams_client_type_entry_values"> <string-array name="revanced_spoof_video_streams_client_type_entry_values">
<item>ANDROID_REEL</item>
<item>ANDROID_VR_1_43_32</item> <item>ANDROID_VR_1_43_32</item>
<item>ANDROID_CREATOR</item> <item>ANDROID_CREATOR</item>
<item>ANDROID_NO_SDK</item>
<item>VISIONOS</item> <item>VISIONOS</item>
<item>IPADOS</item>
</string-array> </string-array>
</patch> </patch>
<patch id="interaction.swipecontrols.swipeControlsResourcePatch"> <patch id="interaction.swipecontrols.swipeControlsResourcePatch">
@ -663,8 +661,7 @@
<item>cross-out</item> <item>cross-out</item>
</string-array> </string-array>
</patch> </patch>
<patch id="chat.autoclaim.autoClaimChannelPointsPatch"> <patch id="chat.autoclaim.autoClaimChannelPointsPatch"></patch>
</patch>
<patch id="ad.embedded.embeddedAdsPatch"> <patch id="ad.embedded.embeddedAdsPatch">
<string-array name="revanced_block_embedded_ads_entries"> <string-array name="revanced_block_embedded_ads_entries">
<item>@string/revanced_block_embedded_ads_entry_1</item> <item>@string/revanced_block_embedded_ads_entry_1</item>

View file

@ -144,6 +144,16 @@ If you are a YouTube Premium user, this setting may not be required"</string>
Playback may not work"</string> Playback may not work"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">Turning off this setting may cause playback issues.</string> <string name="revanced_spoof_video_streams_user_dialog_message">Turning off this setting may cause playback issues.</string>
<string name="revanced_spoof_video_streams_client_type_title">Default client</string> <string name="revanced_spoof_video_streams_client_type_title">Default client</string>
<string name="revanced_spoof_video_streams_about_experimental">• Experimental client and may stop working anytime</string>
<string name="revanced_spoof_video_streams_about_playback_failure">• Video may stop at 1:00, or may not be available in some regions</string>
<string name="revanced_spoof_video_streams_about_no_audio_tracks">• Audio track menu is missing</string>
<string name="revanced_spoof_video_streams_about_no_av1">• No AV1 video codec</string>
<string name="revanced_spoof_video_streams_about_no_immersive_mode">• 360° VR immersive mode is not available</string>
<string name="revanced_spoof_video_streams_about_no_stable_volume">• Stable volume is not available</string>
<string name="revanced_spoof_video_streams_about_title">Spoofing side effects</string>
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_about_no_force_original_audio">• Force original audio is not available</string>
</patch> </patch>
<patch id="misc.audio.forceOriginalAudioPatch"> <patch id="misc.audio.forceOriginalAudioPatch">
<string name="revanced_force_original_audio_title">Force original audio language</string> <string name="revanced_force_original_audio_title">Force original audio language</string>
@ -900,10 +910,10 @@ Adjust volume by swiping vertically on the right side of the screen"</string>
<string name="revanced_hide_player_flyout_audio_track_summary_on">Audio track menu is hidden</string> <string name="revanced_hide_player_flyout_audio_track_summary_on">Audio track menu is hidden</string>
<string name="revanced_hide_player_flyout_audio_track_summary_off">Audio track menu is shown</string> <string name="revanced_hide_player_flyout_audio_track_summary_off">Audio track menu is shown</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'.
'Android No SDK' must be kept untranslated. --> 'Android Reel' must be kept untranslated. -->
<string name="revanced_hide_player_flyout_audio_track_not_available">"Audio track menu is hidden <string name="revanced_hide_player_flyout_audio_track_not_available">"Audio track menu is hidden
To show the Audio track menu, change \'Spoof video streams\' to \'Android No SDK\'"</string> To show the Audio track menu, change \'Spoof video streams\' to \'Android >Reel\'"</string>
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. --> <!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
<string name="revanced_hide_player_flyout_watch_in_vr_title">Hide Watch in VR</string> <string name="revanced_hide_player_flyout_watch_in_vr_title">Hide Watch in VR</string>
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">Watch in VR menu is hidden</string> <string name="revanced_hide_player_flyout_watch_in_vr_summary_on">Watch in VR menu is hidden</string>
@ -1786,18 +1796,9 @@ Playback may stutter or drop frames"</string>
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Enabling this setting may use software AV1 decoding. <string name="revanced_spoof_video_streams_av1_user_dialog_message">"Enabling this setting may use software AV1 decoding.
Video playback with AV1 may stutter or drop frames."</string> Video playback with AV1 may stutter or drop frames."</string>
<string name="revanced_spoof_video_streams_about_title">Spoofing side effects</string> <string name="revanced_spoof_video_streams_stats_for_nerds_title">Show in Stats for nerds</string>
<string name="revanced_spoof_video_streams_about_experimental">• Experimental client and may stop working anytime</string> <string name="revanced_spoof_video_streams_stats_for_nerds_summary_on">Client type is shown in Stats for nerds</string>
<string name="revanced_spoof_video_streams_about_playback_failure">• Video may stop at 1:00, or may not be available in some regions</string> <string name="revanced_spoof_video_streams_stats_for_nerds_summary_off">Client is hidden in Stats for nerds</string>
<string name="revanced_spoof_video_streams_about_no_audio_tracks">• Audio track menu is missing</string>
<string name="revanced_spoof_video_streams_about_no_av1">• No AV1 video codec</string>
<string name="revanced_spoof_video_streams_about_no_stable_volume">• Stable volume is not available</string>
<string name="revanced_spoof_video_streams_about_kids_videos">• Kids videos may not play when logged out or in incognito mode</string>
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_about_no_force_original_audio">• Force original audio is not available</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Show in Stats for nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Client type is shown in Stats for nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Client is hidden in Stats for nerds</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View file

@ -2,7 +2,6 @@ rootProject.name = "revanced-patches"
pluginManagement { pluginManagement {
repositories { repositories {
mavenLocal()
gradlePluginPortal() gradlePluginPortal()
google() google()
maven { maven {
@ -10,12 +9,16 @@ pluginManagement {
url = uri("https://maven.pkg.github.com/revanced/revanced-patches-gradle-plugin") url = uri("https://maven.pkg.github.com/revanced/revanced-patches-gradle-plugin")
credentials(PasswordCredentials::class) credentials(PasswordCredentials::class)
} }
// TODO: Remove once https://github.com/google/protobuf-gradle-plugin/pull/797 is merged.
maven { url = uri("https://jitpack.io") }
} }
} // TODO: Remove once https://github.com/google/protobuf-gradle-plugin/pull/797 is merged.
resolutionStrategy {
dependencyResolutionManagement { eachPlugin {
repositories { if (requested.id.id == "com.google.protobuf") {
mavenLocal() useModule("com.github.ReVanced:protobuf-gradle-plugin:${requested.version}")
}
}
} }
} }
@ -33,4 +36,4 @@ settings {
} }
} }
include(":patches:stub") include(":patches:stub")