Compare commits

...

34 Commits

Author SHA1 Message Date
semantic-release-bot
113a3d9f19 chore: Release v5.29.0-dev.7 [skip ci]
# [5.29.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.6...v5.29.0-dev.7) (2025-06-24)

### Bug Fixes

* **YouTube - Hide layout components:** Fix "Hide video description attributes" ([#5250](https://github.com/ReVanced/revanced-patches/issues/5250)) ([978c244](978c24458b))
* **YouTube - Hide Shorts components:** Fix "Hide Use this template button" ([#5249](https://github.com/ReVanced/revanced-patches/issues/5249)) ([957bece](957bece3e9))
2025-06-24 18:50:18 +00:00
ILoveOpenSourceApplications
978c24458b fix(YouTube - Hide layout components): Fix "Hide video description attributes" (#5250) 2025-06-24 22:47:46 +04:00
ILoveOpenSourceApplications
957bece3e9 fix(YouTube - Hide Shorts components): Fix "Hide Use this template button" (#5249) 2025-06-24 22:47:05 +04:00
github-actions[bot]
d32c3ac51d chore: Sync translations (#5251) 2025-06-24 22:46:50 +04:00
LisoUseInAIKyrios
26102a70a2 chore: Fix compile warning 2025-06-24 22:43:25 +04:00
semantic-release-bot
2b44bf4c23 chore: Release v5.29.0-dev.6 [skip ci]
# [5.29.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.5...v5.29.0-dev.6) (2025-06-24)

### Features

* **YouTube - Hide video action buttons:** Add `Hide Stop ads` ([#5245](https://github.com/ReVanced/revanced-patches/issues/5245)) ([0e63f49](0e63f49e13))
2025-06-24 11:14:05 +00:00
ILoveOpenSourceApplications
0e63f49e13 feat(YouTube - Hide video action buttons): Add Hide Stop ads (#5245) 2025-06-24 15:10:23 +04:00
semantic-release-bot
674a5b8d29 chore: Release v5.29.0-dev.5 [skip ci]
# [5.29.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.4...v5.29.0-dev.5) (2025-06-23)

### Bug Fixes

* **Google Photos:** Resolve startup crash for Android 5.0 devices ([7be3741](7be374100b))
2025-06-23 12:28:49 +00:00
LisoUseInAIKyrios
7be374100b fix(Google Photos): Resolve startup crash for Android 5.0 devices 2025-06-23 16:24:42 +04:00
semantic-release-bot
e48c152b95 chore: Release v5.29.0-dev.4 [skip ci]
# [5.29.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.3...v5.29.0-dev.4) (2025-06-23)

### Bug Fixes

* **YouTube - Hide Shorts components:** Fix "Hide Use this sound button" ([#5233](https://github.com/ReVanced/revanced-patches/issues/5233)) ([a678f17](a678f178e1))
2025-06-23 09:33:13 +00:00
ILoveOpenSourceApplications
a678f178e1 fix(YouTube - Hide Shorts components): Fix "Hide Use this sound button" (#5233) 2025-06-23 13:29:53 +04:00
semantic-release-bot
2d8f5641f9 chore: Release v5.29.0-dev.3 [skip ci]
# [5.29.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.2...v5.29.0-dev.3) (2025-06-23)

### Bug Fixes

* **YouTube:** Fix refactoring app startup exception ([0dbd058](0dbd058099))
2025-06-23 09:18:27 +00:00
LisoUseInAIKyrios
0dbd058099 fix(YouTube): Fix refactoring app startup exception 2025-06-23 13:15:43 +04:00
semantic-release-bot
c1a8fd0766 chore: Release v5.29.0-dev.2 [skip ci]
# [5.29.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.1...v5.29.0-dev.2) (2025-06-23)

### Features

* **Crunchyroll:** Add `Hide ads` patch ([#5201](https://github.com/ReVanced/revanced-patches/issues/5201)) ([d338989](d338989cb4))
2025-06-23 08:47:04 +00:00
hoodles
d338989cb4 feat(Crunchyroll): Add Hide ads patch (#5201) 2025-06-23 12:44:07 +04:00
github-actions[bot]
b94daacf01 chore: Sync translations (#5236) 2025-06-23 12:43:45 +04:00
semantic-release-bot
c764c4f197 chore: Release v5.29.0-dev.1 [skip ci]
# [5.29.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.28.1-dev.2...v5.29.0-dev.1) (2025-06-23)

### Bug Fixes

* **YouTube:** Always use single threaded layout to resolve layout bugs in unpatched YouTube ([#5226](https://github.com/ReVanced/revanced-patches/issues/5226)) ([ccd1691](ccd169121a))

### Features

* **YouTube:** Add an option to disable toasts when changing default playback speed or quality ([#5230](https://github.com/ReVanced/revanced-patches/issues/5230)) ([6b719df](6b719dfcd7))
2025-06-23 08:24:13 +00:00
MarcaD
6b719dfcd7 feat(YouTube): Add an option to disable toasts when changing default playback speed or quality (#5230) 2025-06-23 12:20:37 +04:00
LisoUseInAIKyrios
ccd169121a fix(YouTube): Always use single threaded layout to resolve layout bugs in unpatched YouTube (#5226) 2025-06-23 12:19:07 +04:00
semantic-release-bot
dcfbd8bf93 chore: Release v5.28.1-dev.2 [skip ci]
## [5.28.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.28.1-dev.1...v5.28.1-dev.2) (2025-06-23)

### Bug Fixes

* **YouTube - Hide ads:** Hide new type of product ad in video description ([#5225](https://github.com/ReVanced/revanced-patches/issues/5225)) ([b656976](b65697603d))
2025-06-23 07:19:38 +00:00
ILoveOpenSourceApplications
b65697603d fix(YouTube - Hide ads): Hide new type of product ad in video description (#5225) 2025-06-23 11:17:08 +04:00
semantic-release-bot
25da5cca8b chore: Release v5.28.1-dev.1 [skip ci]
## [5.28.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.28.0...v5.28.1-dev.1) (2025-06-22)

### Bug Fixes

* Add scrollable content to modern style settings dialogs ([#5211](https://github.com/ReVanced/revanced-patches/issues/5211)) ([2b62fc2](2b62fc2224))
2025-06-22 11:23:52 +00:00
MarcaD
2b62fc2224 fix: Add scrollable content to modern style settings dialogs (#5211) 2025-06-22 15:21:00 +04:00
semantic-release-bot
a9e9456b6b chore: Release v5.28.0 [skip ci]
# [5.28.0](https://github.com/ReVanced/revanced-patches/compare/v5.27.0...v5.28.0) (2025-06-20)

### Bug Fixes

* **Google Photos:** Resolve startup crash if MicroG GmsCore does not already have granted permissions ([1cea6bf](1cea6bfdff))
* **Messenger - Remove Meta AI:** Improve patch logic ([#5153](https://github.com/ReVanced/revanced-patches/issues/5153)) ([a8d2a1e](a8d2a1e028))
* **Pandora - Disable ads:** Support latest app target ([#5185](https://github.com/ReVanced/revanced-patches/issues/5185)) ([90868ff](90868ff025))
* **Spotify:** Fix `Hide Create button` and `Sanitize sharing links` for older but supported app targets ([#5159](https://github.com/ReVanced/revanced-patches/issues/5159)) ([5540136](55401368b8))
* **Threads - Hide ads:** Constrain patch to the last working app target ([#5189](https://github.com/ReVanced/revanced-patches/issues/5189)) ([e138501](e138501657))
* **YouTube:** Remove old app targets that are no longer supported by YouTube ([#5192](https://github.com/ReVanced/revanced-patches/issues/5192)) ([e790cfb](e790cfbf59))

### Features

* **Spotify:** Add `Change lyrics provider` patch ([#4937](https://github.com/ReVanced/revanced-patches/issues/4937)) ([7bbaca7](7bbaca77ad))
* Use modern style settings dialogs ([#5109](https://github.com/ReVanced/revanced-patches/issues/5109)) ([a426e2a](a426e2af50))
2025-06-20 08:17:57 +00:00
LisoUseInAIKyrios
b01523e97d chore: Merge branch dev to main (#5160) 2025-06-20 12:14:29 +04:00
github-actions[bot]
b8afb4e821 chore: Sync translations (#5210) 2025-06-20 12:13:39 +04:00
github-actions[bot]
0d2198faed chore: Sync translations (#5207) 2025-06-20 01:33:20 +04:00
semantic-release-bot
5c7c407b82 chore: Release v5.28.0-dev.8 [skip ci]
# [5.28.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.7...v5.28.0-dev.8) (2025-06-19)

### Bug Fixes

* **Messenger - Remove Meta AI:** Improve patch logic ([#5153](https://github.com/ReVanced/revanced-patches/issues/5153)) ([a8d2a1e](a8d2a1e028))
2025-06-19 06:10:06 +00:00
Dawid Krajcarz
a8d2a1e028 fix(Messenger - Remove Meta AI): Improve patch logic (#5153) 2025-06-19 10:06:46 +04:00
semantic-release-bot
d31624cae8 chore: Release v5.28.0-dev.7 [skip ci]
# [5.28.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.6...v5.28.0-dev.7) (2025-06-18)

### Bug Fixes

* **YouTube:** Remove old app targets that are no longer supported by YouTube ([#5192](https://github.com/ReVanced/revanced-patches/issues/5192)) ([e790cfb](e790cfbf59))
2025-06-18 10:38:43 +00:00
LisoUseInAIKyrios
e790cfbf59 fix(YouTube): Remove old app targets that are no longer supported by YouTube (#5192) 2025-06-18 12:35:43 +02:00
LisoUseInAIKyrios
a54d408d3e chore: Fix string typos, fix missing long/wide returnEarly/returnLate 2025-06-18 11:06:48 +02:00
semantic-release-bot
5d3769e921 chore: Release v5.28.0-dev.6 [skip ci]
# [5.28.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.5...v5.28.0-dev.6) (2025-06-17)

### Bug Fixes

* **Threads - Hide ads:** Constrain patch to the last working app target ([#5189](https://github.com/ReVanced/revanced-patches/issues/5189)) ([e138501](e138501657))
2025-06-17 21:07:00 +00:00
LisoUseInAIKyrios
e138501657 fix(Threads - Hide ads): Constrain patch to the last working app target (#5189) 2025-06-17 23:03:35 +02:00
175 changed files with 1784 additions and 2545 deletions

View File

@@ -1,3 +1,111 @@
# [5.29.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.6...v5.29.0-dev.7) (2025-06-24)
### Bug Fixes
* **YouTube - Hide layout components:** Fix "Hide video description attributes" ([#5250](https://github.com/ReVanced/revanced-patches/issues/5250)) ([2f22d45](https://github.com/ReVanced/revanced-patches/commit/2f22d45eb80745ac64fbea44c8055ebe7925a586))
* **YouTube - Hide Shorts components:** Fix "Hide Use this template button" ([#5249](https://github.com/ReVanced/revanced-patches/issues/5249)) ([b399ecb](https://github.com/ReVanced/revanced-patches/commit/b399ecbb6a222d82dd5e4b3417c9f7eff4324adb))
# [5.29.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.5...v5.29.0-dev.6) (2025-06-24)
### Features
* **YouTube - Hide video action buttons:** Add `Hide Stop ads` ([#5245](https://github.com/ReVanced/revanced-patches/issues/5245)) ([274dcc6](https://github.com/ReVanced/revanced-patches/commit/274dcc676e009be63eb6970de33abacd34dc6560))
# [5.29.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.4...v5.29.0-dev.5) (2025-06-23)
### Bug Fixes
* **Google Photos:** Resolve startup crash for Android 5.0 devices ([0294533](https://github.com/ReVanced/revanced-patches/commit/0294533c4d9a321aea086eedb4e46385ae9a026e))
# [5.29.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.3...v5.29.0-dev.4) (2025-06-23)
### Bug Fixes
* **YouTube - Hide Shorts components:** Fix "Hide Use this sound button" ([#5233](https://github.com/ReVanced/revanced-patches/issues/5233)) ([5d6ec9e](https://github.com/ReVanced/revanced-patches/commit/5d6ec9e94a6221a0f32762d5bede893e9e7457fc))
# [5.29.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.2...v5.29.0-dev.3) (2025-06-23)
### Bug Fixes
* **YouTube:** Fix refactoring app startup exception ([1b00c90](https://github.com/ReVanced/revanced-patches/commit/1b00c907f4b90f4659afb4a54ba61ac2835b460d))
# [5.29.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.1...v5.29.0-dev.2) (2025-06-23)
### Features
* **Crunchyroll:** Add `Hide ads` patch ([#5201](https://github.com/ReVanced/revanced-patches/issues/5201)) ([46b4398](https://github.com/ReVanced/revanced-patches/commit/46b4398fd6ca223391ed8f497a8347c2313421b7))
# [5.29.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.28.1-dev.2...v5.29.0-dev.1) (2025-06-23)
### Bug Fixes
* **YouTube:** Always use single threaded layout to resolve layout bugs in unpatched YouTube ([#5226](https://github.com/ReVanced/revanced-patches/issues/5226)) ([1f539b1](https://github.com/ReVanced/revanced-patches/commit/1f539b1396526b2c767d77a804bd0308ee4a42ec))
### Features
* **YouTube:** Add an option to disable toasts when changing default playback speed or quality ([#5230](https://github.com/ReVanced/revanced-patches/issues/5230)) ([c68cde3](https://github.com/ReVanced/revanced-patches/commit/c68cde3a896450874cc571be5c4723387db96032))
## [5.28.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.28.1-dev.1...v5.28.1-dev.2) (2025-06-23)
### Bug Fixes
* **YouTube - Hide ads:** Hide new type of product ad in video description ([#5225](https://github.com/ReVanced/revanced-patches/issues/5225)) ([1e2efad](https://github.com/ReVanced/revanced-patches/commit/1e2efad7b2714c395ed6b0a77cbbf8a2265df520))
## [5.28.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.28.0...v5.28.1-dev.1) (2025-06-22)
### Bug Fixes
* Add scrollable content to modern style settings dialogs ([#5211](https://github.com/ReVanced/revanced-patches/issues/5211)) ([e6876d5](https://github.com/ReVanced/revanced-patches/commit/e6876d510d28f6a3a41ec1722a033b3e30a22c65))
# [5.28.0](https://github.com/ReVanced/revanced-patches/compare/v5.27.0...v5.28.0) (2025-06-20)
### Bug Fixes
* **Google Photos:** Resolve startup crash if MicroG GmsCore does not already have granted permissions ([a93d74d](https://github.com/ReVanced/revanced-patches/commit/a93d74d26e7ef87a3745df2b9fe82722d65a0e59))
* **Messenger - Remove Meta AI:** Improve patch logic ([#5153](https://github.com/ReVanced/revanced-patches/issues/5153)) ([4ad4887](https://github.com/ReVanced/revanced-patches/commit/4ad488744d87543c31e453dc7b6d8182b3a7f440))
* **Pandora - Disable ads:** Support latest app target ([#5185](https://github.com/ReVanced/revanced-patches/issues/5185)) ([ca83047](https://github.com/ReVanced/revanced-patches/commit/ca83047f5c4acbb267d5b98db80ad111999086e0))
* **Spotify:** Fix `Hide Create button` and `Sanitize sharing links` for older but supported app targets ([#5159](https://github.com/ReVanced/revanced-patches/issues/5159)) ([e7dd061](https://github.com/ReVanced/revanced-patches/commit/e7dd061c513af90861c0ab0d7adc6ee43be57ce2))
* **Threads - Hide ads:** Constrain patch to the last working app target ([#5189](https://github.com/ReVanced/revanced-patches/issues/5189)) ([3558c44](https://github.com/ReVanced/revanced-patches/commit/3558c44a05c13f19fefdbbf14b364181a79f17c0))
* **YouTube:** Remove old app targets that are no longer supported by YouTube ([#5192](https://github.com/ReVanced/revanced-patches/issues/5192)) ([c9e54e1](https://github.com/ReVanced/revanced-patches/commit/c9e54e1d36243945ac1ec3108fe38edf0e15d772))
### Features
* **Spotify:** Add `Change lyrics provider` patch ([#4937](https://github.com/ReVanced/revanced-patches/issues/4937)) ([8736b6a](https://github.com/ReVanced/revanced-patches/commit/8736b6a80b48cb1f4562c9f9919804006ddb18bd))
* Use modern style settings dialogs ([#5109](https://github.com/ReVanced/revanced-patches/issues/5109)) ([312b6dc](https://github.com/ReVanced/revanced-patches/commit/312b6dc04e01c2758cd304ca8606306027aa2f01))
# [5.28.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.7...v5.28.0-dev.8) (2025-06-19)
### Bug Fixes
* **Messenger - Remove Meta AI:** Improve patch logic ([#5153](https://github.com/ReVanced/revanced-patches/issues/5153)) ([4ad4887](https://github.com/ReVanced/revanced-patches/commit/4ad488744d87543c31e453dc7b6d8182b3a7f440))
# [5.28.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.6...v5.28.0-dev.7) (2025-06-18)
### Bug Fixes
* **YouTube:** Remove old app targets that are no longer supported by YouTube ([#5192](https://github.com/ReVanced/revanced-patches/issues/5192)) ([c9e54e1](https://github.com/ReVanced/revanced-patches/commit/c9e54e1d36243945ac1ec3108fe38edf0e15d772))
# [5.28.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.5...v5.28.0-dev.6) (2025-06-17)
### Bug Fixes
* **Threads - Hide ads:** Constrain patch to the last working app target ([#5189](https://github.com/ReVanced/revanced-patches/issues/5189)) ([3558c44](https://github.com/ReVanced/revanced-patches/commit/3558c44a05c13f19fefdbbf14b364181a79f17c0))
# [5.28.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.4...v5.28.0-dev.5) (2025-06-17) # [5.28.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.4...v5.28.0-dev.5) (2025-06-17)

View File

@@ -1,15 +1,23 @@
package app.revanced.extension.messenger.metaai; package app.revanced.extension.messenger.metaai;
import java.util.*;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class RemoveMetaAIPatch { public class RemoveMetaAIPatch {
private static final Set<Long> loggedIDs = Collections.synchronizedSet(new HashSet<>());
public static boolean overrideBooleanFlag(long id, boolean value) { public static boolean overrideBooleanFlag(long id, boolean value) {
// This catches all flag IDs related to Meta AI. try {
// The IDs change slightly with every update, if (Long.toString(id).startsWith("REPLACED_BY_PATCH")) {
// so to work around this, IDs from different versions were compared if (loggedIDs.add(id))
// to find what they have in common, which turned out to be those first bits. Logger.printInfo(() -> "Overriding " + id + " from " + value + " to false");
// TODO: Find the specific flags that we care about and patch the code they control instead.
if ((id & 0x7FFFFFC000000000L) == 0x810A8000000000L) { return false;
return false; }
} catch (Exception ex) {
Logger.printException(() -> "overrideBooleanFlag failure", ex);
} }
return value; return value;

View File

@@ -19,7 +19,6 @@ import android.util.Pair;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
@@ -28,7 +27,6 @@ import java.util.Locale;
import app.revanced.extension.shared.requests.Requester; import app.revanced.extension.shared.requests.Requester;
import app.revanced.extension.shared.requests.Route; import app.revanced.extension.shared.requests.Route;
import app.revanced.extension.shared.Utils;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class GmsCoreSupport { public class GmsCoreSupport {
@@ -109,7 +107,6 @@ public class GmsCoreSupport {
/** /**
* Injection point. * Injection point.
*/ */
@RequiresApi(api = Build.VERSION_CODES.N)
public static void checkGmsCore(Activity context) { public static void checkGmsCore(Activity context) {
try { try {
// Verify the user has not included GmsCore for a root installation. // Verify the user has not included GmsCore for a root installation.
@@ -157,7 +154,9 @@ public class GmsCoreSupport {
} }
// Check if GmsCore is currently running in the background. // Check if GmsCore is currently running in the background.
try (var client = context.getContentResolver().acquireContentProviderClient(GMS_CORE_PROVIDER)) { var client = context.getContentResolver().acquireContentProviderClient(GMS_CORE_PROVIDER);
//noinspection TryFinallyCanBeTryWithResources
try {
if (client == null) { if (client == null) {
Logger.printInfo(() -> "GmsCore is not running in the background"); Logger.printInfo(() -> "GmsCore is not running in the background");
checkIfDontKillMyAppSupportsManufacturer(); checkIfDontKillMyAppSupportsManufacturer();
@@ -167,6 +166,8 @@ public class GmsCoreSupport {
"gms_core_dialog_open_website_text", "gms_core_dialog_open_website_text",
(dialog, id) -> openDontKillMyApp()); (dialog, id) -> openDontKillMyApp());
} }
} finally {
if (client != null) client.close();
} }
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "checkGmsCore failure", ex); Logger.printException(() -> "checkGmsCore failure", ex);
@@ -226,6 +227,11 @@ public class GmsCoreSupport {
* @return If GmsCore is not whitelisted from battery optimizations. * @return If GmsCore is not whitelisted from battery optimizations.
*/ */
private static boolean batteryOptimizationsEnabled(Context context) { private static boolean batteryOptimizationsEnabled(Context context) {
//noinspection ObsoleteSdkInt
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Android 5.0 does not have battery optimization settings.
return false;
}
var powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); var powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
return !powerManager.isIgnoringBatteryOptimizations(GMS_CORE_PACKAGE_NAME); return !powerManager.isIgnoringBatteryOptimizations(GMS_CORE_PACKAGE_NAME);
} }

View File

@@ -42,6 +42,7 @@ import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import android.widget.Toolbar; import android.widget.Toolbar;
@@ -773,16 +774,15 @@ public class Utils {
Dialog dialog = new Dialog(context); Dialog dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // Remove default title bar. dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // Remove default title bar.
// Create main layout.
LinearLayout mainLayout = new LinearLayout(context);
mainLayout.setOrientation(LinearLayout.VERTICAL);
// Preset size constants. // Preset size constants.
final int dip4 = dipToPixels(4); final int dip4 = dipToPixels(4);
final int dip8 = dipToPixels(8); final int dip8 = dipToPixels(8);
final int dip16 = dipToPixels(16); final int dip16 = dipToPixels(16);
final int dip24 = dipToPixels(24); final int dip24 = dipToPixels(24);
// Create main layout.
LinearLayout mainLayout = new LinearLayout(context);
mainLayout.setOrientation(LinearLayout.VERTICAL);
mainLayout.setPadding(dip24, dip16, dip24, dip24); mainLayout.setPadding(dip24, dip16, dip24, dip24);
// Set rounded rectangle background. // Set rounded rectangle background.
ShapeDrawable mainBackground = new ShapeDrawable(new RoundRectShape( ShapeDrawable mainBackground = new ShapeDrawable(new RoundRectShape(
@@ -802,55 +802,71 @@ public class Utils {
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
layoutParams.setMargins(0, 0, 0, dip8); layoutParams.setMargins(0, 0, 0, dip16);
titleView.setLayoutParams(layoutParams); titleView.setLayoutParams(layoutParams);
mainLayout.addView(titleView); mainLayout.addView(titleView);
} }
// Message (if not replaced by EditText). // Create content container (message/EditText) inside a ScrollView only if message or editText is provided.
if (editText == null && message != null) { ScrollView contentScrollView = null;
TextView messageView = new TextView(context); LinearLayout contentContainer = null;
messageView.setText(message); // Supports Spanned (HTML). if (message != null || editText != null) {
messageView.setTextSize(16); contentScrollView = new ScrollView(context);
messageView.setTextColor(getAppForegroundColor()); contentScrollView.setVerticalScrollBarEnabled(false); // Disable the vertical scrollbar.
// Enable HTML link clicking if the message contains links. contentScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
if (message instanceof Spanned) { if (editText != null) {
messageView.setMovementMethod(LinkMovementMethod.getInstance()); ShapeDrawable scrollViewBackground = new ShapeDrawable(new RoundRectShape(
createCornerRadii(10), null, null));
scrollViewBackground.getPaint().setColor(getEditTextBackground());
contentScrollView.setPadding(dip8, dip8, dip8, dip8);
contentScrollView.setBackground(scrollViewBackground);
contentScrollView.setClipToOutline(true);
} }
LinearLayout.LayoutParams messageParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams contentParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT 0,
1.0f // Weight to take available space.
); );
messageParams.setMargins(0, dip8, 0, dip16); contentScrollView.setLayoutParams(contentParams);
messageView.setLayoutParams(messageParams); contentContainer = new LinearLayout(context);
mainLayout.addView(messageView); contentContainer.setOrientation(LinearLayout.VERTICAL);
} contentScrollView.addView(contentContainer);
// EditText (if provided). // Message (if not replaced by EditText).
if (editText != null) { if (editText == null && message != null) {
// Remove EditText from its current parent, if any. TextView messageView = new TextView(context);
ViewGroup parent = (ViewGroup) editText.getParent(); messageView.setText(message); // Supports Spanned (HTML).
if (parent != null) { messageView.setTextSize(16);
parent.removeView(editText); messageView.setTextColor(getAppForegroundColor());
// Enable HTML link clicking if the message contains links.
if (message instanceof Spanned) {
messageView.setMovementMethod(LinkMovementMethod.getInstance());
}
LinearLayout.LayoutParams messageParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
messageView.setLayoutParams(messageParams);
contentContainer.addView(messageView);
} }
// Style the EditText to match the dialog theme.
editText.setTextColor(getAppForegroundColor());
editText.setBackgroundColor(isDarkModeEnabled() ? Color.BLACK : Color.WHITE);
editText.setPadding(dip8, dip8, dip8, dip8);
ShapeDrawable editTextBackground = new ShapeDrawable(new RoundRectShape(
createCornerRadii(10), null, null));
editTextBackground.getPaint().setColor(getEditTextBackground()); // Background color for EditText.
editText.setBackground(editTextBackground);
LinearLayout.LayoutParams editTextParams = new LinearLayout.LayoutParams( // EditText (if provided).
LinearLayout.LayoutParams.MATCH_PARENT, if (editText != null) {
LinearLayout.LayoutParams.WRAP_CONTENT // Remove EditText from its current parent, if any.
); ViewGroup parent = (ViewGroup) editText.getParent();
editTextParams.setMargins(0, dip8, 0, dip16); if (parent != null) {
// Prevent buttons from moving off the screen by fixing the height of the EditText. parent.removeView(editText);
final int maxHeight = (int) (context.getResources().getDisplayMetrics().heightPixels * 0.6); }
editText.setMaxHeight(maxHeight); // Style the EditText to match the dialog theme.
mainLayout.addView(editText, 1, editTextParams); editText.setTextColor(getAppForegroundColor());
editText.setBackgroundColor(Color.TRANSPARENT);
editText.setPadding(0, 0, 0, 0);
LinearLayout.LayoutParams editTextParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
contentContainer.addView(editText, editTextParams);
}
} }
// Button container. // Button container.
@@ -861,7 +877,7 @@ public class Utils {
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT LinearLayout.LayoutParams.WRAP_CONTENT
); );
buttonContainerParams.setMargins(0, dip8, 0, 0); buttonContainerParams.setMargins(0, dip16, 0, 0);
buttonContainer.setLayoutParams(buttonContainerParams); buttonContainer.setLayoutParams(buttonContainerParams);
// Lists to track buttons. // Lists to track buttons.
@@ -1036,25 +1052,29 @@ public class Utils {
} }
} }
// Add ScrollView to main layout only if content exist.
if (contentScrollView != null) {
mainLayout.addView(contentScrollView);
}
mainLayout.addView(buttonContainer); mainLayout.addView(buttonContainer);
dialog.setContentView(mainLayout); dialog.setContentView(mainLayout);
// Set dialog window attributes. // Set dialog window attributes.
Window window = dialog.getWindow(); Window window = dialog.getWindow();
if (window != null) { if (window != null) {
setDialogWindowParameters(context, window); setDialogWindowParameters(window);
} }
return new Pair<>(dialog, mainLayout); return new Pair<>(dialog, mainLayout);
} }
public static void setDialogWindowParameters(Context context, Window window) { public static void setDialogWindowParameters(Window window) {
WindowManager.LayoutParams params = window.getAttributes(); WindowManager.LayoutParams params = window.getAttributes();
Resources resources = context.getResources(); DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
int portraitWidth = (int) (displayMetrics.widthPixels * 0.9); int portraitWidth = (int) (displayMetrics.widthPixels * 0.9);
if (resources.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
if (Resources.getSystem().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
portraitWidth = (int) Math.min(portraitWidth, displayMetrics.heightPixels * 0.9); portraitWidth = (int) Math.min(portraitWidth, displayMetrics.heightPixels * 0.9);
} }
params.width = portraitWidth; params.width = portraitWidth;
@@ -1199,7 +1219,7 @@ public class Utils {
return darkColor == Color.BLACK return darkColor == Color.BLACK
// Lighten the background a little if using AMOLED dark theme // Lighten the background a little if using AMOLED dark theme
// as the dialogs are almost invisible. // as the dialogs are almost invisible.
? 0xFF0D0D0D ? 0xFF080808 // 3%
: darkColor; : darkColor;
} }
return getThemeLightColor(); return getThemeLightColor();

View File

@@ -129,8 +129,7 @@ abstract class Check {
ImageView iconView = new ImageView(activity); ImageView iconView = new ImageView(activity);
iconView.setImageResource(Utils.getResourceIdentifier("revanced_ic_dialog_alert", "drawable")); iconView.setImageResource(Utils.getResourceIdentifier("revanced_ic_dialog_alert", "drawable"));
iconView.setColorFilter(Utils.getAppForegroundColor(), PorterDuff.Mode.SRC_IN); iconView.setColorFilter(Utils.getAppForegroundColor(), PorterDuff.Mode.SRC_IN);
final int dip8 = dipToPixels(8); iconView.setPadding(0, 0, 0, 0);
iconView.setPadding(0, dip8, 0, dip8);
LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT LinearLayout.LayoutParams.WRAP_CONTENT

View File

@@ -24,10 +24,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewParent; import android.view.ViewParent;
import android.widget.Button; import android.widget.*;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
@@ -298,7 +295,6 @@ public class ColorPickerPreference extends EditTextPreference {
// Horizontal layout for preview and EditText. // Horizontal layout for preview and EditText.
LinearLayout inputLayout = new LinearLayout(context); LinearLayout inputLayout = new LinearLayout(context);
inputLayout.setOrientation(LinearLayout.HORIZONTAL); inputLayout.setOrientation(LinearLayout.HORIZONTAL);
inputLayout.setPadding(0, 0, 0, dipToPixels(10));
dialogColorPreview = new TextView(context); dialogColorPreview = new TextView(context);
LinearLayout.LayoutParams previewParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams previewParams = new LinearLayout.LayoutParams(
@@ -338,11 +334,23 @@ public class ColorPickerPreference extends EditTextPreference {
paddingView.setLayoutParams(params); paddingView.setLayoutParams(params);
inputLayout.addView(paddingView); inputLayout.addView(paddingView);
// Create main container for color picker and input layout. // Create content container for color picker and input layout.
LinearLayout container = new LinearLayout(context); LinearLayout contentContainer = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL); contentContainer.setOrientation(LinearLayout.VERTICAL);
container.addView(colorPicker); contentContainer.addView(colorPicker);
container.addView(inputLayout); contentContainer.addView(inputLayout);
// Create ScrollView to wrap the content container.
ScrollView contentScrollView = new ScrollView(context);
contentScrollView.setVerticalScrollBarEnabled(false); // Disable vertical scrollbar.
contentScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER); // Disable overscroll effect.
LinearLayout.LayoutParams scrollViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
0,
1.0f
);
contentScrollView.setLayoutParams(scrollViewParams);
contentScrollView.addView(contentContainer);
// Create custom dialog. // Create custom dialog.
final int originalColor = currentColor & 0x00FFFFFF; final int originalColor = currentColor & 0x00FFFFFF;
@@ -391,9 +399,9 @@ public class ColorPickerPreference extends EditTextPreference {
false // Do not dismiss dialog when onNeutralClick. false // Do not dismiss dialog when onNeutralClick.
); );
// Add the custom container to the dialog's main layout. // Add the ScrollView to the dialog's main layout.
LinearLayout dialogMainLayout = dialogPair.second; LinearLayout dialogMainLayout = dialogPair.second;
dialogMainLayout.addView(container, 1); dialogMainLayout.addView(contentScrollView, dialogMainLayout.getChildCount() - 1);
// Set up color picker listener with debouncing. // Set up color picker listener with debouncing.
// Add listener last to prevent callbacks from set calls above. // Add listener last to prevent callbacks from set calls above.

View File

@@ -11,11 +11,7 @@ import android.util.Pair;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.*;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -107,14 +103,16 @@ public class CustomDialogListPreference extends ListPreference {
@Override @Override
protected void showDialog(Bundle state) { protected void showDialog(Bundle state) {
Context context = getContext();
// Create ListView. // Create ListView.
ListView listView = new ListView(getContext()); ListView listView = new ListView(context);
listView.setId(android.R.id.list); listView.setId(android.R.id.list);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Create custom adapter for the ListView. // Create custom adapter for the ListView.
ListPreferenceArrayAdapter adapter = new ListPreferenceArrayAdapter( ListPreferenceArrayAdapter adapter = new ListPreferenceArrayAdapter(
getContext(), context,
Utils.getResourceIdentifier("revanced_custom_list_item_checked", "layout"), Utils.getResourceIdentifier("revanced_custom_list_item_checked", "layout"),
getEntries(), getEntries(),
getEntryValues(), getEntryValues(),
@@ -137,7 +135,7 @@ public class CustomDialogListPreference extends ListPreference {
// Create the custom dialog without OK button. // Create the custom dialog without OK button.
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog( Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
getContext(), context,
getTitle() != null ? getTitle().toString() : "", getTitle() != null ? getTitle().toString() : "",
null, null,
null, null,
@@ -149,35 +147,13 @@ public class CustomDialogListPreference extends ListPreference {
true true
); );
Dialog dialog = dialogPair.first; // Add the ListView to the main layout.
LinearLayout mainLayout = dialogPair.second; LinearLayout mainLayout = dialogPair.second;
// Measure content height before adding ListView to layout.
// Otherwise, the ListView will push the buttons off the screen.
int totalHeight = 0;
int widthSpec = View.MeasureSpec.makeMeasureSpec(
getContext().getResources().getDisplayMetrics().widthPixels,
View.MeasureSpec.AT_MOST
);
int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
for (int i = 0; i < adapter.getCount(); i++) {
View listItem = adapter.getView(i, null, listView);
listItem.measure(widthSpec, heightSpec);
totalHeight += listItem.getMeasuredHeight();
}
// Cap the height at maxHeight.
int maxHeight = (int) (getContext().getResources().getDisplayMetrics().heightPixels * 0.6);
int finalHeight = Math.min(totalHeight, maxHeight);
// Add ListView to the main layout with calculated height.
LinearLayout.LayoutParams listViewParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams listViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT,
finalHeight // Use calculated height directly. 0,
1.0f
); );
final int marginHorizontal = dipToPixels(8);
listViewParams.setMargins(0, marginHorizontal, 0, marginHorizontal);
mainLayout.addView(listView, mainLayout.getChildCount() - 1, listViewParams); mainLayout.addView(listView, mainLayout.getChildCount() - 1, listViewParams);
// Handle item click to select value and dismiss dialog. // Handle item click to select value and dismiss dialog.
@@ -188,10 +164,10 @@ public class CustomDialogListPreference extends ListPreference {
adapter.setSelectedValue(selectedValue); adapter.setSelectedValue(selectedValue);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
} }
dialog.dismiss(); dialogPair.first.dismiss();
}); });
// Show the dialog. // Show the dialog.
dialog.show(); dialogPair.first.show();
} }
} }

View File

@@ -17,6 +17,7 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.preference.Preference; import android.preference.Preference;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View;
import android.view.Window; import android.view.Window;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
@@ -216,6 +217,8 @@ class WebViewDialog extends Dialog {
// Create WebView. // Create WebView.
WebView webView = new WebView(getContext()); WebView webView = new WebView(getContext());
webView.setVerticalScrollBarEnabled(false); // Disable the vertical scrollbar.
webView.setOverScrollMode(View.OVER_SCROLL_NEVER);
webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new OpenLinksExternallyWebClient()); webView.setWebViewClient(new OpenLinksExternallyWebClient());
webView.loadDataWithBaseURL(null, htmlContent, "text/html", "utf-8", null); webView.loadDataWithBaseURL(null, htmlContent, "text/html", "utf-8", null);
@@ -228,7 +231,7 @@ class WebViewDialog extends Dialog {
// Set dialog window attributes // Set dialog window attributes
Window window = getWindow(); Window window = getWindow();
if (window != null) { if (window != null) {
Utils.setDialogWindowParameters(getContext(), window); Utils.setDialogWindowParameters(window);
} }
} }

View File

@@ -7,11 +7,17 @@ public class VersionCheckPatch {
return Utils.getAppVersionName().compareTo(version) >= 0; return Utils.getAppVersionName().compareTo(version) >= 0;
} }
@Deprecated
public static final boolean IS_19_17_OR_GREATER = isVersionOrGreater("19.17.00"); public static final boolean IS_19_17_OR_GREATER = isVersionOrGreater("19.17.00");
@Deprecated
public static final boolean IS_19_20_OR_GREATER = isVersionOrGreater("19.20.00"); public static final boolean IS_19_20_OR_GREATER = isVersionOrGreater("19.20.00");
@Deprecated
public static final boolean IS_19_21_OR_GREATER = isVersionOrGreater("19.21.00"); public static final boolean IS_19_21_OR_GREATER = isVersionOrGreater("19.21.00");
@Deprecated
public static final boolean IS_19_26_OR_GREATER = isVersionOrGreater("19.26.00"); public static final boolean IS_19_26_OR_GREATER = isVersionOrGreater("19.26.00");
@Deprecated
public static final boolean IS_19_29_OR_GREATER = isVersionOrGreater("19.29.00"); public static final boolean IS_19_29_OR_GREATER = isVersionOrGreater("19.29.00");
@Deprecated
public static final boolean IS_19_34_OR_GREATER = isVersionOrGreater("19.34.00"); public static final boolean IS_19_34_OR_GREATER = isVersionOrGreater("19.34.00");
public static final boolean IS_19_46_OR_GREATER = isVersionOrGreater("19.46.00"); public static final boolean IS_19_46_OR_GREATER = isVersionOrGreater("19.46.00");
} }

View File

@@ -121,12 +121,14 @@ public final class AdsFilter extends Filter {
playerShoppingShelf = new StringFilterGroup( playerShoppingShelf = new StringFilterGroup(
Settings.HIDE_PLAYER_STORE_SHELF, Settings.HIDE_PLAYER_STORE_SHELF,
"expandable_list.eml",
"horizontal_shelf.eml" "horizontal_shelf.eml"
); );
playerShoppingShelfBuffer = new ByteArrayFilterGroup( playerShoppingShelfBuffer = new ByteArrayFilterGroup(
null, null,
"shopping_item_card_list.eml" "shopping_link_item",
"shopping_item_card_list"
); );
channelProfile = new StringFilterGroup( channelProfile = new StringFilterGroup(

View File

@@ -46,7 +46,7 @@ final class ButtonsFilter extends Filter {
"|download_button.eml" "|download_button.eml"
), ),
new StringFilterGroup( new StringFilterGroup(
Settings.HIDE_PLAYLIST_BUTTON, Settings.HIDE_SAVE_BUTTON,
"|save_to_playlist_button" "|save_to_playlist_button"
), ),
new StringFilterGroup( new StringFilterGroup(
@@ -76,6 +76,10 @@ final class ButtonsFilter extends Filter {
Settings.HIDE_ASK_BUTTON, Settings.HIDE_ASK_BUTTON,
"yt_fill_spark" "yt_fill_spark"
), ),
new ByteArrayFilterGroup(
Settings.HIDE_STOP_ADS_BUTTON,
"yt_outline_slash_circle_left"
),
// Check for clip button both here and using a path filter, // Check for clip button both here and using a path filter,
// as there's a chance the path is a generic action button and won't contain 'clip_button' // as there's a chance the path is a generic action button and won't contain 'clip_button'
new ByteArrayFilterGroup( new ByteArrayFilterGroup(

View File

@@ -14,6 +14,9 @@ final class DescriptionComponentsFilter extends Filter {
private final StringFilterGroup macroMarkersCarousel; private final StringFilterGroup macroMarkersCarousel;
private final StringFilterGroup horizontalShelf;
private final ByteArrayFilterGroup cellVideoAttribute;
public DescriptionComponentsFilter() { public DescriptionComponentsFilter() {
exceptions.addPatterns( exceptions.addPatterns(
"compact_channel", "compact_channel",
@@ -35,8 +38,7 @@ final class DescriptionComponentsFilter extends Filter {
final StringFilterGroup attributesSection = new StringFilterGroup( final StringFilterGroup attributesSection = new StringFilterGroup(
Settings.HIDE_ATTRIBUTES_SECTION, Settings.HIDE_ATTRIBUTES_SECTION,
"gaming_section", // "gaming_section", "music_section"
"music_section",
"video_attributes_section" "video_attributes_section"
); );
@@ -76,15 +78,26 @@ final class DescriptionComponentsFilter extends Filter {
) )
); );
horizontalShelf = new StringFilterGroup(
Settings.HIDE_ATTRIBUTES_SECTION,
"horizontal_shelf.eml"
);
cellVideoAttribute = new ByteArrayFilterGroup(
null,
"cell_video_attribute"
);
addPathCallbacks( addPathCallbacks(
aiGeneratedVideoSummarySection, aiGeneratedVideoSummarySection,
askSection, askSection,
attributesSection, attributesSection,
infoCardsSection, infoCardsSection,
horizontalShelf,
howThisWasMadeSection, howThisWasMadeSection,
macroMarkersCarousel,
podcastSection, podcastSection,
transcriptSection, transcriptSection
macroMarkersCarousel
); );
} }
@@ -97,6 +110,10 @@ final class DescriptionComponentsFilter extends Filter {
return contentIndex == 0 && macroMarkersCarouselGroupList.check(protobufBufferArray).isFiltered(); return contentIndex == 0 && macroMarkersCarouselGroupList.check(protobufBufferArray).isFiltered();
} }
if (matchedGroup == horizontalShelf) {
return cellVideoAttribute.check(protobufBufferArray).isFiltered();
}
return true; return true;
} }
} }

View File

@@ -74,6 +74,27 @@ public final class LithoFilterPatch {
} }
} }
/**
* Litho layout fixed thread pool size override.
* <p>
* Unpatched YouTube uses a layout fixed thread pool between 1 and 3 threads:
* <pre>
* 1 thread - > Device has less than 6 cores
* 2 threads -> Device has over 6 cores and less than 6GB of memory
* 3 threads -> Device has over 6 cores and more than 6GB of memory
* </pre>
*
* Using more than 1 thread causes layout issues such as the You tab watch/playlist shelf
* that is sometimes incorrectly hidden (ReVanced is not hiding it), and seems to
* fix a race issue if using the active navigation tab status with litho filtering.
*/
private static final int LITHO_LAYOUT_THREAD_POOL_SIZE = 1;
/**
* Placeholder for actual filters.
*/
private static final class DummyFilter extends Filter { }
private static final Filter[] filters = new Filter[] { private static final Filter[] filters = new Filter[] {
new DummyFilter() // Replaced by patch. new DummyFilter() // Replaced by patch.
}; };
@@ -213,9 +234,28 @@ public final class LithoFilterPatch {
return false; return false;
} }
}
/** /**
* Placeholder for actual filters. * Injection point.
*/ */
final class DummyFilter extends Filter { } public static int getExecutorCorePoolSize(int originalCorePoolSize) {
if (originalCorePoolSize != LITHO_LAYOUT_THREAD_POOL_SIZE) {
Logger.printDebug(() -> "Overriding core thread pool size from: " + originalCorePoolSize
+ " to: " + LITHO_LAYOUT_THREAD_POOL_SIZE);
}
return LITHO_LAYOUT_THREAD_POOL_SIZE;
}
/**
* Injection point.
*/
public static int getExecutorMaxThreads(int originalMaxThreads) {
if (originalMaxThreads != LITHO_LAYOUT_THREAD_POOL_SIZE) {
Logger.printDebug(() -> "Overriding max thread pool size from: " + originalMaxThreads
+ " to: " + LITHO_LAYOUT_THREAD_POOL_SIZE);
}
return LITHO_LAYOUT_THREAD_POOL_SIZE;
}
}

View File

@@ -40,8 +40,10 @@ public final class ShortsFilter extends Filter {
private static WeakReference<PivotBar> pivotBarRef = new WeakReference<>(null); private static WeakReference<PivotBar> pivotBarRef = new WeakReference<>(null);
private final StringFilterGroup shortsCompactFeedVideoPath; private final StringFilterGroup shortsCompactFeedVideo;
private final ByteArrayFilterGroup shortsCompactFeedVideoBuffer; private final ByteArrayFilterGroup shortsCompactFeedVideoBuffer;
private final StringFilterGroup useSoundButton;
private final ByteArrayFilterGroup useSoundButtonBuffer;
private final StringFilterGroup subscribeButton; private final StringFilterGroup subscribeButton;
private final StringFilterGroup joinButton; private final StringFilterGroup joinButton;
@@ -49,11 +51,11 @@ public final class ShortsFilter extends Filter {
private final StringFilterGroup shelfHeader; private final StringFilterGroup shelfHeader;
private final StringFilterGroup suggestedAction; private final StringFilterGroup suggestedAction;
private final ByteArrayFilterGroupList suggestedActionsGroupList = new ByteArrayFilterGroupList(); private final ByteArrayFilterGroupList suggestedActionsBuffer = new ByteArrayFilterGroupList();
private final StringFilterGroup shortsActionBar; private final StringFilterGroup shortsActionBar;
private final StringFilterGroup actionButton; private final StringFilterGroup videoActionButton;
private final ByteArrayFilterGroupList videoActionButtonGroupList = new ByteArrayFilterGroupList(); private final ByteArrayFilterGroupList videoActionButtonBuffer = new ByteArrayFilterGroupList();
public ShortsFilter() { public ShortsFilter() {
// //
@@ -82,7 +84,7 @@ public final class ShortsFilter extends Filter {
// Path components. // Path components.
// //
shortsCompactFeedVideoPath = new StringFilterGroup(null, shortsCompactFeedVideo = new StringFilterGroup(null,
// Shorts that appear in the feed/search when the device is using tablet layout. // Shorts that appear in the feed/search when the device is using tablet layout.
"compact_video.eml", "compact_video.eml",
// 'video_lockup_with_attachment.eml' is shown instead of 'compact_video.eml' for some users // 'video_lockup_with_attachment.eml' is shown instead of 'compact_video.eml' for some users
@@ -174,7 +176,18 @@ public final class ShortsFilter extends Filter {
"reel_action_bar.eml" "reel_action_bar.eml"
); );
actionButton = new StringFilterGroup( useSoundButton = new StringFilterGroup(
Settings.HIDE_SHORTS_USE_SOUND_BUTTON,
"floating_action_button.eml",
REEL_METAPANEL_PATH
);
useSoundButtonBuffer = new ByteArrayFilterGroup(
null,
"yt_outline_camera_"
);
videoActionButton = new StringFilterGroup(
null, null,
// Can be simply 'button.eml', 'shorts_video_action_button.eml' or 'reel_action_button.eml' // Can be simply 'button.eml', 'shorts_video_action_button.eml' or 'reel_action_button.eml'
"button.eml" "button.eml"
@@ -182,20 +195,21 @@ public final class ShortsFilter extends Filter {
suggestedAction = new StringFilterGroup( suggestedAction = new StringFilterGroup(
null, null,
"suggested_action.eml" "suggested_action.eml",
REEL_METAPANEL_PATH
); );
addPathCallbacks( addPathCallbacks(
shortsCompactFeedVideoPath, joinButton, subscribeButton, paidPromotionButton, shortsCompactFeedVideo, joinButton, subscribeButton, paidPromotionButton,
shortsActionBar, suggestedAction, pausedOverlayButtons, channelBar, shortsActionBar, suggestedAction, pausedOverlayButtons, channelBar,
fullVideoLinkLabel, videoTitle, reelSoundMetadata, soundButton, infoPanel, fullVideoLinkLabel, videoTitle, useSoundButton, reelSoundMetadata, soundButton, infoPanel,
stickers, likeFountain, likeButton, dislikeButton stickers, likeFountain, likeButton, dislikeButton
); );
// //
// All other action buttons. // All other action buttons.
// //
videoActionButtonGroupList.addAll( videoActionButtonBuffer.addAll(
new ByteArrayFilterGroup( new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_COMMENTS_BUTTON, Settings.HIDE_SHORTS_COMMENTS_BUTTON,
"reel_comment_button", "reel_comment_button",
@@ -216,7 +230,7 @@ public final class ShortsFilter extends Filter {
// //
// Suggested actions. // Suggested actions.
// //
suggestedActionsGroupList.addAll( suggestedActionsBuffer.addAll(
new ByteArrayFilterGroup( new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_PREVIEW_COMMENT, Settings.HIDE_SHORTS_PREVIEW_COMMENT,
// Preview comment that can popup while a Short is playing. // Preview comment that can popup while a Short is playing.
@@ -242,10 +256,7 @@ public final class ShortsFilter extends Filter {
"yt_outline_bookmark_", "yt_outline_bookmark_",
// 'Save sound' button. It seems this has been removed and only 'Save music' is used. // 'Save sound' button. It seems this has been removed and only 'Save music' is used.
// Still hide this in case it's still present. // Still hide this in case it's still present.
"yt_outline_list_add_", "yt_outline_list_add_"
// 'Use this sound' button. It seems this has been removed and only 'Save music' is used.
// Still hide this in case it's still present.
"yt_outline_camera_"
), ),
new ByteArrayFilterGroup( new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_SEARCH_SUGGESTIONS, Settings.HIDE_SHORTS_SEARCH_SUGGESTIONS,
@@ -279,7 +290,7 @@ public final class ShortsFilter extends Filter {
} }
private boolean isEverySuggestedActionFilterEnabled() { private boolean isEverySuggestedActionFilterEnabled() {
for (ByteArrayFilterGroup group : suggestedActionsGroupList) { for (ByteArrayFilterGroup group : suggestedActionsBuffer) {
if (!group.isEnabled()) { if (!group.isEnabled()) {
return false; return false;
} }
@@ -297,15 +308,19 @@ public final class ShortsFilter extends Filter {
return path.startsWith(REEL_CHANNEL_BAR_PATH) || path.startsWith(REEL_METAPANEL_PATH); return path.startsWith(REEL_CHANNEL_BAR_PATH) || path.startsWith(REEL_METAPANEL_PATH);
} }
if (matchedGroup == shortsCompactFeedVideoPath) { if (matchedGroup == useSoundButton) {
return useSoundButtonBuffer.check(protobufBufferArray).isFiltered();
}
if (matchedGroup == shortsCompactFeedVideo) {
return shouldHideShortsFeedItems() && shortsCompactFeedVideoBuffer.check(protobufBufferArray).isFiltered(); return shouldHideShortsFeedItems() && shortsCompactFeedVideoBuffer.check(protobufBufferArray).isFiltered();
} }
// Video action buttons (comment, share, remix) have the same path. // Video action buttons (comment, share, remix) have the same path.
// Like and dislike are separate path filters and don't require buffer searching. // Like and dislike are separate path filters and don't require buffer searching.
if (matchedGroup == shortsActionBar) { if (matchedGroup == shortsActionBar) {
return actionButton.check(path).isFiltered() return videoActionButton.check(path).isFiltered()
&& videoActionButtonGroupList.check(protobufBufferArray).isFiltered(); && videoActionButtonBuffer.check(protobufBufferArray).isFiltered();
} }
if (matchedGroup == suggestedAction) { if (matchedGroup == suggestedAction) {
@@ -316,7 +331,7 @@ public final class ShortsFilter extends Filter {
return true; return true;
} }
return suggestedActionsGroupList.check(protobufBufferArray).isFiltered(); return suggestedActionsBuffer.check(protobufBufferArray).isFiltered();
} }
return true; return true;

View File

@@ -64,10 +64,11 @@ public class RememberVideoQualityPatch {
else videoQualityWifi.save(defaultQuality); else videoQualityWifi.save(defaultQuality);
networkTypeMessage = str("revanced_remember_video_quality_wifi"); networkTypeMessage = str("revanced_remember_video_quality_wifi");
} }
Utils.showToastShort(str( if (Settings.REMEMBER_VIDEO_QUALITY_LAST_SELECTED_TOAST.get())
useShortsPreference ? "revanced_remember_video_quality_toast_shorts" : "revanced_remember_video_quality_toast", Utils.showToastShort(str(
networkTypeMessage, (defaultQuality + "p") useShortsPreference ? "revanced_remember_video_quality_toast_shorts" : "revanced_remember_video_quality_toast",
)); networkTypeMessage, (defaultQuality + "p")
));
} }
/** /**

View File

@@ -617,9 +617,9 @@ public class CustomPlaybackSpeedPatch {
* @return The rounded speed, constrained to the specified bounds. * @return The rounded speed, constrained to the specified bounds.
*/ */
private static float roundSpeedToNearestIncrement(float speed) { private static float roundSpeedToNearestIncrement(float speed) {
// Round to nearest 0.05 speed. // Round to nearest 0.05 speed. Must use double precision otherwise rounding error can occur.
final float roundedSpeed = Math.round(speed / 0.05f) * 0.05f; final double roundedSpeed = Math.round(speed / 0.05) * 0.05;
return Utils.clamp(roundedSpeed, 0.05f, PLAYBACK_SPEED_MAXIMUM); return Utils.clamp((float) roundedSpeed, 0.05f, PLAYBACK_SPEED_MAXIMUM);
} }
/** /**

View File

@@ -57,7 +57,8 @@ public final class RememberPlaybackSpeedPatch {
} }
Settings.PLAYBACK_SPEED_DEFAULT.save(finalPlaybackSpeed); Settings.PLAYBACK_SPEED_DEFAULT.save(finalPlaybackSpeed);
Utils.showToastShort(str("revanced_remember_playback_speed_toast", (finalPlaybackSpeed + "x"))); if (Settings.REMEMBER_PLAYBACK_SPEED_LAST_SELECTED_TOAST.get())
Utils.showToastShort(str("revanced_remember_playback_speed_toast", (finalPlaybackSpeed + "x")));
}, TOAST_DELAY_MILLISECONDS); }, TOAST_DELAY_MILLISECONDS);
} }
} catch (Exception ex) { } catch (Exception ex) {

View File

@@ -19,6 +19,7 @@ import android.widget.SearchView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toolbar; import android.widget.Toolbar;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import java.util.ArrayList; import java.util.ArrayList;
@@ -58,11 +59,7 @@ public class SearchViewController {
GradientDrawable background = new GradientDrawable(); GradientDrawable background = new GradientDrawable();
background.setShape(GradientDrawable.RECTANGLE); background.setShape(GradientDrawable.RECTANGLE);
background.setCornerRadius(28 * context.getResources().getDisplayMetrics().density); // 28dp corner radius. background.setCornerRadius(28 * context.getResources().getDisplayMetrics().density); // 28dp corner radius.
int baseColor = Utils.getAppBackgroundColor(); background.setColor(getSearchViewBackground());
int adjustedColor = Utils.isDarkModeEnabled()
? Utils.adjustColorBrightness(baseColor, 1.11f) // Lighten for dark theme.
: Utils.adjustColorBrightness(baseColor, 0.95f); // Darken for light theme.
background.setColor(adjustedColor);
return background; return background;
} }
@@ -72,10 +69,17 @@ public class SearchViewController {
private static GradientDrawable createSuggestionBackgroundDrawable(Context context) { private static GradientDrawable createSuggestionBackgroundDrawable(Context context) {
GradientDrawable background = new GradientDrawable(); GradientDrawable background = new GradientDrawable();
background.setShape(GradientDrawable.RECTANGLE); background.setShape(GradientDrawable.RECTANGLE);
background.setCornerRadius(8 * context.getResources().getDisplayMetrics().density); // 8dp corner radius. background.setColor(getSearchViewBackground());
return background; return background;
} }
@ColorInt
public static int getSearchViewBackground() {
return Utils.isDarkModeEnabled()
? Utils.adjustColorBrightness(Utils.getDialogBackgroundColor(), 1.11f)
: Utils.adjustColorBrightness(Utils.getThemeLightColor(), 0.95f);
}
/** /**
* Adds search view components to the activity. * Adds search view components to the activity.
*/ */

View File

@@ -52,6 +52,8 @@ public class Settings extends BaseSettings {
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE); public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED_TOAST = new BooleanSetting("revanced_remember_video_quality_last_selected_toast", TRUE, false,
parent(REMEMBER_VIDEO_QUALITY_LAST_SELECTED));
public static final IntegerSetting SHORTS_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_shorts_quality_default_wifi", -2, true); public static final IntegerSetting SHORTS_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_shorts_quality_default_wifi", -2, true);
public static final IntegerSetting SHORTS_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_shorts_quality_default_mobile", -2, true); public static final IntegerSetting SHORTS_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_shorts_quality_default_mobile", -2, true);
public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE); public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE);
@@ -60,6 +62,8 @@ public class Settings extends BaseSettings {
// Speed // Speed
public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true); public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true);
public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE); public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE);
public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED_TOAST = new BooleanSetting("revanced_remember_playback_speed_last_selected_toast", TRUE, false,
parent(REMEMBER_PLAYBACK_SPEED_LAST_SELECTED));
public static final BooleanSetting CUSTOM_SPEED_MENU = new BooleanSetting("revanced_custom_speed_menu", TRUE); public static final BooleanSetting CUSTOM_SPEED_MENU = new BooleanSetting("revanced_custom_speed_menu", TRUE);
public static final FloatSetting PLAYBACK_SPEED_DEFAULT = new FloatSetting("revanced_playback_speed_default", -2.0f); public static final FloatSetting PLAYBACK_SPEED_DEFAULT = new FloatSetting("revanced_playback_speed_default", -2.0f);
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds", public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
@@ -196,15 +200,16 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_TRANSCRIPT_SECTION = new BooleanSetting("revanced_hide_transcript_section", TRUE); public static final BooleanSetting HIDE_TRANSCRIPT_SECTION = new BooleanSetting("revanced_hide_transcript_section", TRUE);
// Action buttons // Action buttons
public static final BooleanSetting DISABLE_LIKE_SUBSCRIBE_GLOW = new BooleanSetting("revanced_disable_like_subscribe_glow", FALSE); public static final BooleanSetting DISABLE_LIKE_SUBSCRIBE_GLOW = new BooleanSetting("revanced_disable_like_subscribe_glow", FALSE);
public static final BooleanSetting HIDE_ASK_BUTTON = new BooleanSetting("revanced_hide_ask_button", FALSE);
public static final BooleanSetting HIDE_CLIP_BUTTON = new BooleanSetting("revanced_hide_clip_button", TRUE); public static final BooleanSetting HIDE_CLIP_BUTTON = new BooleanSetting("revanced_hide_clip_button", TRUE);
public static final BooleanSetting HIDE_DOWNLOAD_BUTTON = new BooleanSetting("revanced_hide_download_button", FALSE); public static final BooleanSetting HIDE_DOWNLOAD_BUTTON = new BooleanSetting("revanced_hide_download_button", FALSE);
public static final BooleanSetting HIDE_LIKE_DISLIKE_BUTTON = new BooleanSetting("revanced_hide_like_dislike_button", FALSE); public static final BooleanSetting HIDE_LIKE_DISLIKE_BUTTON = new BooleanSetting("revanced_hide_like_dislike_button", FALSE);
public static final BooleanSetting HIDE_PLAYLIST_BUTTON = new BooleanSetting("revanced_hide_playlist_button", FALSE);
public static final BooleanSetting HIDE_REMIX_BUTTON = new BooleanSetting("revanced_hide_remix_button", TRUE); public static final BooleanSetting HIDE_REMIX_BUTTON = new BooleanSetting("revanced_hide_remix_button", TRUE);
public static final BooleanSetting HIDE_REPORT_BUTTON = new BooleanSetting("revanced_hide_report_button", FALSE); public static final BooleanSetting HIDE_REPORT_BUTTON = new BooleanSetting("revanced_hide_report_button", FALSE);
public static final BooleanSetting HIDE_SAVE_BUTTON = new BooleanSetting("revanced_hide_save_button", FALSE);
public static final BooleanSetting HIDE_SHARE_BUTTON = new BooleanSetting("revanced_hide_share_button", FALSE); public static final BooleanSetting HIDE_SHARE_BUTTON = new BooleanSetting("revanced_hide_share_button", FALSE);
public static final BooleanSetting HIDE_STOP_ADS_BUTTON = new BooleanSetting("revanced_hide_stop_ads_button", TRUE);
public static final BooleanSetting HIDE_THANKS_BUTTON = new BooleanSetting("revanced_hide_thanks_button", TRUE); public static final BooleanSetting HIDE_THANKS_BUTTON = new BooleanSetting("revanced_hide_thanks_button", TRUE);
public static final BooleanSetting HIDE_ASK_BUTTON = new BooleanSetting("revanced_hide_ask_button", FALSE);
// Player flyout menu items // Player flyout menu items
public static final BooleanSetting HIDE_PLAYER_FLYOUT_ADDITIONAL_SETTINGS = new BooleanSetting("revanced_hide_player_flyout_additional_settings", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_ADDITIONAL_SETTINGS = new BooleanSetting("revanced_hide_player_flyout_additional_settings", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_AMBIENT_MODE = new BooleanSetting("revanced_hide_player_flyout_ambient_mode", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_AMBIENT_MODE = new BooleanSetting("revanced_hide_player_flyout_ambient_mode", FALSE);
@@ -289,6 +294,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_SHORTS_SUPER_THANKS_BUTTON = new BooleanSetting("revanced_hide_shorts_super_thanks_button", TRUE); public static final BooleanSetting HIDE_SHORTS_SUPER_THANKS_BUTTON = new BooleanSetting("revanced_hide_shorts_super_thanks_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_TAGGED_PRODUCTS = new BooleanSetting("revanced_hide_shorts_tagged_products", TRUE); public static final BooleanSetting HIDE_SHORTS_TAGGED_PRODUCTS = new BooleanSetting("revanced_hide_shorts_tagged_products", TRUE);
public static final BooleanSetting HIDE_SHORTS_UPCOMING_BUTTON = new BooleanSetting("revanced_hide_shorts_upcoming_button", TRUE); public static final BooleanSetting HIDE_SHORTS_UPCOMING_BUTTON = new BooleanSetting("revanced_hide_shorts_upcoming_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_USE_SOUND_BUTTON = new BooleanSetting("revanced_hide_shorts_use_sound_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_USE_TEMPLATE_BUTTON = new BooleanSetting("revanced_hide_shorts_use_template_button", TRUE); public static final BooleanSetting HIDE_SHORTS_USE_TEMPLATE_BUTTON = new BooleanSetting("revanced_hide_shorts_use_template_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_VIDEO_TITLE = new BooleanSetting("revanced_hide_shorts_video_title", FALSE); public static final BooleanSetting HIDE_SHORTS_VIDEO_TITLE = new BooleanSetting("revanced_hide_shorts_video_title", FALSE);
public static final BooleanSetting SHORTS_AUTOPLAY = new BooleanSetting("revanced_shorts_autoplay", FALSE); public static final BooleanSetting SHORTS_AUTOPLAY = new BooleanSetting("revanced_shorts_autoplay", FALSE);

View File

@@ -18,12 +18,7 @@ import android.text.TextWatcher;
import android.util.Pair; import android.util.Pair;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.*;
import android.widget.GridLayout;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
@@ -88,8 +83,6 @@ public class SegmentCategoryListPreference extends ListPreference {
// Create the main layout for the dialog content. // Create the main layout for the dialog content.
LinearLayout contentLayout = new LinearLayout(context); LinearLayout contentLayout = new LinearLayout(context);
contentLayout.setOrientation(LinearLayout.VERTICAL); contentLayout.setOrientation(LinearLayout.VERTICAL);
final int dip10 = dipToPixels(10);
contentLayout.setPadding(0, 0, 0, dip10);
// Add behavior selection radio buttons. // Add behavior selection radio buttons.
RadioGroup radioGroup = new RadioGroup(context); RadioGroup radioGroup = new RadioGroup(context);
@@ -103,7 +96,7 @@ public class SegmentCategoryListPreference extends ListPreference {
radioGroup.addView(radioButton); radioGroup.addView(radioButton);
} }
radioGroup.setOnCheckedChangeListener((group, checkedId) -> selectedDialogEntryIndex = checkedId); radioGroup.setOnCheckedChangeListener((group, checkedId) -> selectedDialogEntryIndex = checkedId);
radioGroup.setPadding(dip10, 0, 0, 0); radioGroup.setPadding(dipToPixels(10), 0, 0, 0);
contentLayout.addView(radioGroup); contentLayout.addView(radioGroup);
// Inflate the color picker view. // Inflate the color picker view.
@@ -131,7 +124,7 @@ public class SegmentCategoryListPreference extends ListPreference {
gridParams = new GridLayout.LayoutParams(); gridParams = new GridLayout.LayoutParams();
gridParams.rowSpec = GridLayout.spec(0); // First row. gridParams.rowSpec = GridLayout.spec(0); // First row.
gridParams.columnSpec = GridLayout.spec(1); // Second column. gridParams.columnSpec = GridLayout.spec(1); // Second column.
gridParams.setMargins(0, 0, dip10, 0); gridParams.setMargins(0, 0, dipToPixels(10), 0);
dialogColorDotView = new TextView(context); dialogColorDotView = new TextView(context);
dialogColorDotView.setLayoutParams(gridParams); dialogColorDotView.setLayoutParams(gridParams);
gridLayout.addView(dialogColorDotView); gridLayout.addView(dialogColorDotView);
@@ -250,20 +243,17 @@ public class SegmentCategoryListPreference extends ListPreference {
contentLayout.addView(gridLayout); contentLayout.addView(gridLayout);
// Set up color picker listener. // Create ScrollView to wrap the content layout.
// Do last to prevent listener callbacks while setting up view. ScrollView contentScrollView = new ScrollView(context);
dialogColorPickerView.setOnColorChangedListener(color -> { contentScrollView.setVerticalScrollBarEnabled(false); // Disable vertical scrollbar.
if (categoryColor == color) { contentScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER); // Disable overscroll effect.
return; LinearLayout.LayoutParams scrollViewParams = new LinearLayout.LayoutParams(
} LinearLayout.LayoutParams.MATCH_PARENT,
categoryColor = color; 0,
String hexColor = getColorString(color); 1.0f
Logger.printDebug(() -> "onColorChanged: " + hexColor); );
contentScrollView.setLayoutParams(scrollViewParams);
updateCategoryColorDot(); contentScrollView.addView(contentLayout);
dialogColorEditText.setText(hexColor);
dialogColorEditText.setSelection(hexColor.length());
});
// Create the custom dialog. // Create the custom dialog.
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog( Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
@@ -309,13 +299,27 @@ public class SegmentCategoryListPreference extends ListPreference {
false // Do not dismiss dialog on Neutral button click. false // Do not dismiss dialog on Neutral button click.
); );
dialog = dialogPair.first; // Add the ScrollView to the dialog's main layout.
LinearLayout dialogMainLayout = dialogPair.second; LinearLayout dialogMainLayout = dialogPair.second;
dialogMainLayout.addView(contentScrollView, dialogMainLayout.getChildCount() - 1);
// Add the custom content to the dialog's main layout. // Set up color picker listener.
dialogMainLayout.addView(contentLayout, 1); // Add after title, before buttons. // Do last to prevent listener callbacks while setting up view.
dialogColorPickerView.setOnColorChangedListener(color -> {
if (categoryColor == color) {
return;
}
categoryColor = color;
String hexColor = getColorString(color);
Logger.printDebug(() -> "onColorChanged: " + hexColor);
updateCategoryColorDot();
dialogColorEditText.setText(hexColor);
dialogColorEditText.setSelection(hexColor.length());
});
// Show the dialog. // Show the dialog.
dialog = dialogPair.first;
dialog.show(); dialog.show();
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "showDialog failure", ex); Logger.printException(() -> "showDialog failure", ex);

View File

@@ -42,7 +42,6 @@ public class PlaybackSpeedDialogButton {
: Settings.PLAYBACK_SPEED_DEFAULT.get(); : Settings.PLAYBACK_SPEED_DEFAULT.get();
VideoInformation.overridePlaybackSpeed(speed); VideoInformation.overridePlaybackSpeed(speed);
showToastShort(str("revanced_custom_playback_speeds_reset_toast", (speed + "x")));
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "speed button reset failure", ex); Logger.printException(() -> "speed button reset failure", ex);
} }

View File

@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
org.gradle.parallel = true org.gradle.parallel = true
android.useAndroidX = true android.useAndroidX = true
kotlin.code.style = official kotlin.code.style = official
version = 5.28.0-dev.5 version = 5.29.0-dev.7

View File

@@ -160,6 +160,10 @@ public final class app/revanced/patches/cieid/restrictions/root/BypassRootChecks
public static final fun getBypassRootChecksPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getBypassRootChecksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/crunchyroll/ads/HideAdsPatchKt {
public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/duolingo/ad/DisableAdsPatchKt { public final class app/revanced/patches/duolingo/ad/DisableAdsPatchKt {
public static final fun getDisableAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getDisableAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -958,6 +962,10 @@ public final class app/revanced/patches/swissid/integritycheck/RemoveGooglePlayI
public static final fun getRemoveGooglePlayIntegrityCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getRemoveGooglePlayIntegrityCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/threads/HideAdsPatchKt {
public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/ticktick/misc/themeunlock/UnlockThemePatchKt { public final class app/revanced/patches/ticktick/misc/themeunlock/UnlockThemePatchKt {
public static final fun getUnlockProPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getUnlockProPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }

View File

@@ -0,0 +1,7 @@
package app.revanced.patches.crunchyroll.ads
import app.revanced.patcher.fingerprint
internal val videoUrlReadyToStringFingerprint = fingerprint {
strings("VideoUrlReady(url=", ", enableAds=")
}

View File

@@ -0,0 +1,46 @@
package app.revanced.patches.crunchyroll.ads
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.instructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.removeFlags
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Suppress("unused")
val hideAdsPatch = bytecodePatch(
name = "Hide Ads"
) {
compatibleWith("com.crunchyroll.crunchyroid")
execute {
// Get obfuscated "enableAds" field from toString method.
val enableAdsField = videoUrlReadyToStringFingerprint.let {
val strIndex = videoUrlReadyToStringFingerprint.stringMatches!!.last().index
val fieldIndex = it.method.indexOfFirstInstruction(strIndex, Opcode.IGET_BOOLEAN)
it.method.getInstruction<ReferenceInstruction>(fieldIndex).getReference<FieldReference>()!!
}
// Remove final access flag on field.
videoUrlReadyToStringFingerprint.classDef.fields
.first { it.name == enableAdsField.name }
.removeFlags(AccessFlags.FINAL)
// Override enableAds field in non-default constructor.
val constructor = videoUrlReadyToStringFingerprint.classDef.methods.first {
AccessFlags.CONSTRUCTOR.isSet(it.accessFlags) && it.parameters.isNotEmpty()
}
constructor.addInstructions(
constructor.instructions.count() - 1,
"""
move-object/from16 v0, p0
const/4 v1, 0x0
iput-boolean v1, v0, $enableAdsField
""")
}
}

View File

@@ -1,9 +1,16 @@
package app.revanced.patches.instagram.ads package app.revanced.patches.instagram.ads
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.meta.ads.adInjectorFingerprint
import app.revanced.util.returnEarly
@Deprecated("Patch was moved to different package: app.revanced.patches.meta.ads.hideAdsPatch")
@Suppress("unused") @Suppress("unused")
val hideAdsPatch = bytecodePatch { val hideAdsPatch = bytecodePatch(
dependsOn(app.revanced.patches.meta.ads.hideAdsPatch) name = "Hide ads",
) {
compatibleWith("com.instagram.android")
execute {
adInjectorFingerprint.method.returnEarly(false)
}
} }

View File

@@ -11,3 +11,15 @@ internal val getMobileConfigBoolFingerprint = fingerprint {
classDef.interfaces.contains("Lcom/facebook/mobileconfig/factory/MobileConfigUnsafeContext;") classDef.interfaces.contains("Lcom/facebook/mobileconfig/factory/MobileConfigUnsafeContext;")
} }
} }
internal val metaAIKillSwitchCheckFingerprint = fingerprint {
strings("SearchAiagentImplementationsKillSwitch")
opcodes(Opcode.CONST_WIDE)
}
internal val extensionMethodFingerprint = fingerprint {
strings("REPLACED_BY_PATCH")
custom { method, classDef ->
method.name == EXTENSION_METHOD_NAME && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}

View File

@@ -2,11 +2,14 @@ package app.revanced.patches.messenger.metaai
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.messenger.misc.extension.sharedExtensionPatch import app.revanced.patches.messenger.misc.extension.sharedExtensionPatch
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.WideLiteralInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/messenger/metaai/RemoveMetaAIPatch;" internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/messenger/metaai/RemoveMetaAIPatch;"
internal const val EXTENSION_METHOD_NAME = "overrideBooleanFlag"
@Suppress("unused") @Suppress("unused")
val removeMetaAIPatch = bytecodePatch( val removeMetaAIPatch = bytecodePatch(
@@ -25,10 +28,25 @@ val removeMetaAIPatch = bytecodePatch(
addInstructions( addInstructions(
returnIndex, returnIndex,
""" """
invoke-static { p1, p2, v$returnRegister }, $EXTENSION_CLASS_DESCRIPTOR->overrideBooleanFlag(JZ)Z invoke-static { p1, p2, v$returnRegister }, $EXTENSION_CLASS_DESCRIPTOR->$EXTENSION_METHOD_NAME(JZ)Z
move-result v$returnRegister move-result v$returnRegister
""" """
) )
} }
// Extract the common starting digits of Meta AI flag IDs from a flag found in code.
val relevantDigits = with(metaAIKillSwitchCheckFingerprint) {
method.getInstruction<WideLiteralInstruction>(patternMatch!!.startIndex).wideLiteral
}.toString().substring(0, 7)
// Replace placeholder in the extension method.
with(extensionMethodFingerprint) {
method.replaceInstruction(
stringMatches!!.first().index,
"""
const-string v1, "$relevantDigits"
"""
)
}
} }
} }

View File

@@ -2,4 +2,4 @@ package app.revanced.patches.messenger.misc.extension
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
val sharedExtensionPatch = sharedExtensionPatch("messenger", mainActivityOnCreateHook) val sharedExtensionPatch = sharedExtensionPatch("messenger", messengerApplicationOnCreateHook)

View File

@@ -2,6 +2,8 @@ package app.revanced.patches.messenger.misc.extension
import app.revanced.patches.shared.misc.extension.extensionHook import app.revanced.patches.shared.misc.extension.extensionHook
internal val mainActivityOnCreateHook = extensionHook { internal val messengerApplicationOnCreateHook = extensionHook {
strings("MainActivity_onCreate_begin") custom { method, classDef ->
method.name == "onCreate" && classDef.endsWith("/MessengerApplication;")
}
} }

View File

@@ -3,18 +3,9 @@ package app.revanced.patches.meta.ads
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
@Deprecated("Instead use the Instagram or Threads specific hide ads patch")
@Suppress("unused") @Suppress("unused")
val hideAdsPatch = bytecodePatch( val hideAdsPatch = bytecodePatch {
name = "Hide ads",
) {
/**
* Patch is identical for both Instagram and Threads app.
*/
compatibleWith(
"com.instagram.android",
"com.instagram.barcelona",
)
execute { execute {
adInjectorFingerprint.method.returnEarly(false) adInjectorFingerprint.method.returnEarly(false)
} }

View File

@@ -0,0 +1,16 @@
package app.revanced.patches.threads
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.meta.ads.adInjectorFingerprint
import app.revanced.util.returnEarly
@Suppress("unused")
val hideAdsPatch = bytecodePatch(
name = "Hide ads",
) {
compatibleWith("com.instagram.barcelona"("382.0.0.51.85"))
execute {
adInjectorFingerprint.method.returnEarly(false)
}
}

View File

@@ -77,8 +77,6 @@ val hideAdsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -25,8 +25,6 @@ val hideGetPremiumPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -23,8 +23,6 @@ val videoAdsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -53,8 +53,6 @@ val copyVideoUrlPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -24,8 +24,6 @@ val removeViewerDiscretionDialogPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -72,8 +72,6 @@ val downloadsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -20,8 +20,6 @@ val seekbarPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -18,8 +18,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;" "Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;"
val seekbarThumbnailsPatch = bytecodePatch( val seekbarThumbnailsPatch = bytecodePatch(
description = "Adds an option to use high quality fullscreen seekbar thumbnails. " + description = "Adds an option to use high quality fullscreen seekbar thumbnails."
"Patching 19.16.39 adds an option to restore old seekbar thumbnails.",
) { ) {
dependsOn( dependsOn(
sharedExtensionPatch, sharedExtensionPatch,

View File

@@ -88,8 +88,6 @@ val swipeControlsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -24,8 +24,6 @@ val autoCaptionsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -43,8 +43,6 @@ val customBrandingPatch = resourcePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -41,8 +41,6 @@ val changeHeaderPatch = resourcePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -22,8 +22,6 @@ val hideButtonsPatch = resourcePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
@@ -40,15 +38,16 @@ val hideButtonsPatch = resourcePatch(
"revanced_hide_buttons_screen", "revanced_hide_buttons_screen",
preferences = setOf( preferences = setOf(
SwitchPreference("revanced_disable_like_subscribe_glow"), SwitchPreference("revanced_disable_like_subscribe_glow"),
SwitchPreference("revanced_hide_like_dislike_button"),
SwitchPreference("revanced_hide_share_button"),
SwitchPreference("revanced_hide_report_button"),
SwitchPreference("revanced_hide_remix_button"),
SwitchPreference("revanced_hide_download_button"),
SwitchPreference("revanced_hide_thanks_button"),
SwitchPreference("revanced_hide_ask_button"), SwitchPreference("revanced_hide_ask_button"),
SwitchPreference("revanced_hide_clip_button"), SwitchPreference("revanced_hide_clip_button"),
SwitchPreference("revanced_hide_playlist_button"), SwitchPreference("revanced_hide_download_button"),
SwitchPreference("revanced_hide_like_dislike_button"),
SwitchPreference("revanced_hide_remix_button"),
SwitchPreference("revanced_hide_report_button"),
SwitchPreference("revanced_hide_save_button"),
SwitchPreference("revanced_hide_share_button"),
SwitchPreference("revanced_hide_stop_ads_button"),
SwitchPreference("revanced_hide_thanks_button"),
) )
) )
) )

View File

@@ -40,8 +40,6 @@ val navigationButtonsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -58,8 +58,6 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -33,8 +33,6 @@ val changeFormFactorPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -59,8 +59,6 @@ val hideEndscreenCardsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -31,8 +31,6 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -29,8 +29,6 @@ val disableFullscreenAmbientModePatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -125,8 +125,6 @@ val hideLayoutComponentsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -57,8 +57,6 @@ val hideInfoCardsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -24,8 +24,6 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -48,8 +48,6 @@ val hideRelatedVideoOverlayPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -29,8 +29,6 @@ val disableRollingNumberAnimationPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -94,6 +94,7 @@ private val hideShortsComponentsResourcePatch = resourcePatch {
// Suggested actions. // Suggested actions.
SwitchPreference("revanced_hide_shorts_preview_comment"), SwitchPreference("revanced_hide_shorts_preview_comment"),
SwitchPreference("revanced_hide_shorts_save_sound_button"), SwitchPreference("revanced_hide_shorts_save_sound_button"),
SwitchPreference("revanced_hide_shorts_use_sound_button"),
SwitchPreference("revanced_hide_shorts_use_template_button"), SwitchPreference("revanced_hide_shorts_use_template_button"),
SwitchPreference("revanced_hide_shorts_upcoming_button"), SwitchPreference("revanced_hide_shorts_upcoming_button"),
SwitchPreference("revanced_hide_shorts_green_screen_button"), SwitchPreference("revanced_hide_shorts_green_screen_button"),
@@ -170,8 +171,6 @@ val hideShortsComponentsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -21,8 +21,6 @@ val hideTimestampPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -153,22 +153,6 @@ val miniplayerPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39", // First with modern miniplayers.
// 19.17.41 // Works without issues, but no reason to recommend over 19.16.
// 19.18.41 // Works without issues, but no reason to recommend over 19.16.
// 19.19.39 // Last bug free version with smaller Modern 1 miniplayer, but no reason to recommend over 19.16.
// 19.20.35 // Cannot swipe to expand.
// 19.21.40 // Cannot swipe to expand.
// 19.22.43 // Cannot swipe to expand.
// 19.23.40 // First with Modern 1 drag and drop, Cannot swipe to expand.
// 19.24.45 // First with larger Modern 1, Cannot swipe to expand.
"19.25.37", // First with double tap, last with skip forward/back buttons, last with swipe to expand/close, and last before double tap to expand seems to be required.
// 19.26.42 // Modern 1 Pause/play button are always hidden. Unusable.
// 19.28.42 // First with custom miniplayer size, screen flickers when swiping to maximize Modern 1. Swipe to close miniplayer is broken.
// 19.29.42 // All modern players are broken and ignore tapping the miniplayer video.
// 19.30.39 // Modern 3 is less broken when double tap expand is enabled, but cannot swipe to expand when double tap is off.
// 19.31.36 // All Modern 1 buttons are missing. Unusable.
// 19.32.36 // 19.32+ and beyond all work without issues.
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -21,8 +21,6 @@ val playerPopupPanelsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -21,8 +21,6 @@ internal val exitFullscreenPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -52,8 +52,6 @@ val customPlayerOverlayOpacityPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -61,8 +61,6 @@ val returnYouTubeDislikePatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -66,8 +66,6 @@ val wideSearchbarPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -44,8 +44,6 @@ val shortsAutoplayPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -64,8 +64,6 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -126,8 +126,6 @@ val sponsorBlockPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -58,8 +58,6 @@ val spoofAppVersionPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -32,8 +32,6 @@ val changeStartPagePatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -34,8 +34,6 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -204,8 +204,6 @@ val themePatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -33,8 +33,6 @@ val alternativeThumbnailsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -27,8 +27,6 @@ val bypassImageRegionRestrictionsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -23,8 +23,6 @@ val announcementsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -24,8 +24,6 @@ val autoRepeatPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -51,8 +51,6 @@ val backgroundPlaybackPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -35,8 +35,6 @@ val enableDebuggingPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -24,8 +24,6 @@ val spoofDeviceDimensionsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -21,8 +21,6 @@ val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -35,8 +35,6 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
compatibleWith( compatibleWith(
YOUTUBE_PACKAGE_NAME( YOUTUBE_PACKAGE_NAME(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -26,8 +26,6 @@ val disableHapticFeedbackPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -32,8 +32,6 @@ val bypassURLRedirectsPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -41,8 +41,6 @@ val openLinksExternallyPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.misc.litho.filter package app.revanced.patches.youtube.misc.litho.filter
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.literal import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@@ -52,6 +53,15 @@ internal val emptyComponentFingerprint = fingerprint {
} }
} }
internal val lithoThreadExecutorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("I", "I", "I")
custom { method, classDef ->
classDef.superclass == "Ljava/util/concurrent/ThreadPoolExecutor;" &&
method.containsLiteralInstruction(1L) // 1L = default thread timeout.
}
}
internal val lithoComponentNameUpbFeatureFlagFingerprint = fingerprint { internal val lithoComponentNameUpbFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z") returns("Z")

View File

@@ -209,6 +209,22 @@ val lithoFilterPatch = bytecodePatch(
// endregion // endregion
// region Change Litho thread executor to 1 thread to fix layout issue in unpatched YouTube.
lithoThreadExecutorFingerprint.method.addInstructions(
0,
"""
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getExecutorCorePoolSize(I)I
move-result p1
invoke-static { p2 }, $EXTENSION_CLASS_DESCRIPTOR->getExecutorMaxThreads(I)I
move-result p2
"""
)
// endregion
// region A/B test of new Litho native code. // region A/B test of new Litho native code.
// Turn off native code that handles litho component names. If this feature is on then nearly // Turn off native code that handles litho component names. If this feature is on then nearly

View File

@@ -5,29 +5,37 @@ package app.revanced.patches.youtube.misc.playservice
import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.resourcePatch
import app.revanced.util.findElementByAttributeValueOrThrow import app.revanced.util.findElementByAttributeValueOrThrow
@Deprecated("19.16.39 is the lowest supported version") @Deprecated("19.34.42 is the lowest supported version")
var is_19_03_or_greater = false var is_19_03_or_greater = false
private set private set
@Deprecated("19.16.39 is the lowest supported version") @Deprecated("19.34.42 is the lowest supported version")
var is_19_04_or_greater = false var is_19_04_or_greater = false
private set private set
@Deprecated("19.16.39 is the lowest supported version") @Deprecated("19.34.42 is the lowest supported version")
var is_19_16_or_greater = false var is_19_16_or_greater = false
private set private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_17_or_greater = false var is_19_17_or_greater = false
private set private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_18_or_greater = false var is_19_18_or_greater = false
private set private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_23_or_greater = false var is_19_23_or_greater = false
private set private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_25_or_greater = false var is_19_25_or_greater = false
private set private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_26_or_greater = false var is_19_26_or_greater = false
private set private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_29_or_greater = false var is_19_29_or_greater = false
private set private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_32_or_greater = false var is_19_32_or_greater = false
private set private set
@Deprecated("19.34.42 is the lowest supported version")
var is_19_33_or_greater = false var is_19_33_or_greater = false
private set private set
var is_19_34_or_greater = false var is_19_34_or_greater = false

View File

@@ -30,8 +30,6 @@ val removeTrackingQueryParameterPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -17,8 +17,6 @@ import app.revanced.patches.youtube.misc.settings.settingsPatch
val spoofVideoStreamsPatch = spoofVideoStreamsPatch({ val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -41,8 +41,6 @@ val forceOriginalAudioPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -28,8 +28,6 @@ val disableHdrPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -57,7 +57,8 @@ val rememberVideoQualityPatch = bytecodePatch {
entriesKey = "revanced_shorts_quality_default_entries", entriesKey = "revanced_shorts_quality_default_entries",
entryValuesKey = "revanced_shorts_quality_default_entry_values" entryValuesKey = "revanced_shorts_quality_default_entry_values"
), ),
SwitchPreference("revanced_remember_shorts_quality_last_selected") SwitchPreference("revanced_remember_shorts_quality_last_selected"),
SwitchPreference("revanced_remember_video_quality_last_selected_toast")
)) ))
/* /*

View File

@@ -23,8 +23,6 @@ val videoQualityPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -28,8 +28,6 @@ val playbackSpeedPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",

View File

@@ -39,7 +39,8 @@ internal val rememberPlaybackSpeedPatch = bytecodePatch {
entryValuesKey = null, entryValuesKey = null,
tag = "app.revanced.extension.youtube.settings.preference.CustomVideoSpeedListPreference" tag = "app.revanced.extension.youtube.settings.preference.CustomVideoSpeedListPreference"
), ),
SwitchPreference("revanced_remember_playback_speed_last_selected") SwitchPreference("revanced_remember_playback_speed_last_selected"),
SwitchPreference("revanced_remember_playback_speed_last_selected_toast")
) )
) )

View File

@@ -10,6 +10,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableField
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
@@ -1011,8 +1012,8 @@ private fun MutableMethod.overrideReturnValue(value: String, returnLate: Boolean
} }
if (returnLate) { if (returnLate) {
findInstructionIndicesReversed { findInstructionIndicesReversedOrThrow {
opcode == RETURN || opcode == RETURN_OBJECT opcode == RETURN || opcode == RETURN_WIDE || opcode == RETURN_OBJECT
}.forEach { index -> }.forEach { index ->
addInstructionsAtControlFlowLabel(index, instructions) addInstructionsAtControlFlowLabel(index, instructions)
} }
@@ -1021,6 +1022,14 @@ private fun MutableMethod.overrideReturnValue(value: String, returnLate: Boolean
} }
} }
/**
* Remove the given AccessFlags from the field.
*/
internal fun MutableField.removeFlags(vararg flags: AccessFlags) {
val bitField = flags.map { it.value }.reduce { acc, flag -> acc and flag }
this.accessFlags = this.accessFlags and bitField.inv()
}
internal fun BytecodePatchContext.addStaticFieldToExtension( internal fun BytecodePatchContext.addStaticFieldToExtension(
className: String, className: String,
methodName: String, methodName: String,

View File

@@ -79,6 +79,7 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="layout.buttons.action.hideButtonsPatch"> <patch id="layout.buttons.action.hideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. --> <!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Stop ads' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays. <!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. --> This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. --> <!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->

View File

@@ -79,6 +79,7 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="layout.buttons.action.hideButtonsPatch"> <patch id="layout.buttons.action.hideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. --> <!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Stop ads' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays. <!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. --> This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. --> <!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->

View File

@@ -35,7 +35,7 @@ Second \"item\" text"</string>
<string name="revanced_settings_submenu_title">الإعدادات</string> <string name="revanced_settings_submenu_title">الإعدادات</string>
<string name="revanced_settings_confirm_user_dialog_title">هل أنت متأكد أنك تريد المتابعة؟</string> <string name="revanced_settings_confirm_user_dialog_title">هل أنت متأكد أنك تريد المتابعة؟</string>
<string name="revanced_settings_reset">إعادة التعيين</string> <string name="revanced_settings_reset">إعادة التعيين</string>
<string name="revanced_settings_reset_color">Reset color</string> <string name="revanced_settings_reset_color">إعادة تعيين اللون</string>
<string name="revanced_settings_color_invalid">لون غير صالح</string> <string name="revanced_settings_color_invalid">لون غير صالح</string>
<string name="revanced_settings_restart_title">إعادة التشغيل مطلوبة</string> <string name="revanced_settings_restart_title">إعادة التشغيل مطلوبة</string>
<string name="revanced_settings_restart_dialog_message">أعد تشغيل التطبيق لكي يسري هذا التغيير.</string> <string name="revanced_settings_restart_dialog_message">أعد تشغيل التطبيق لكي يسري هذا التغيير.</string>
@@ -533,6 +533,10 @@ Second \"item\" text"</string>
<string name="revanced_hide_share_button_title">إخفاء المشاركة</string> <string name="revanced_hide_share_button_title">إخفاء المشاركة</string>
<string name="revanced_hide_share_button_summary_on">تم إخفاء زر مشاركة</string> <string name="revanced_hide_share_button_summary_on">تم إخفاء زر مشاركة</string>
<string name="revanced_hide_share_button_summary_off">يتم عرض زر مشاركة</string> <string name="revanced_hide_share_button_summary_off">يتم عرض زر مشاركة</string>
<!-- 'Stop ads' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_stop_ads_button_title">إخفاء إيقاف الإعلانات</string>
<string name="revanced_hide_stop_ads_button_summary_on">زر إيقاف الإعلانات مخفي</string>
<string name="revanced_hide_stop_ads_button_summary_off">زر إيقاف الإعلانات معروض</string>
<!-- 'Report' should be translated with the same localized wording that YouTube displays. <!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. --> This button usually appears only on live streams. -->
<string name="revanced_hide_report_button_title">إخفاء الإبلاغ</string> <string name="revanced_hide_report_button_title">إخفاء الإبلاغ</string>
@@ -560,9 +564,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_clip_button_summary_on">تم إخفاء زر إنشاء مقطع</string> <string name="revanced_hide_clip_button_summary_on">تم إخفاء زر إنشاء مقطع</string>
<string name="revanced_hide_clip_button_summary_off">يتم عرض زر إنشاء مقطع</string> <string name="revanced_hide_clip_button_summary_off">يتم عرض زر إنشاء مقطع</string>
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_playlist_button_title">إخفاء الحفظ في قائمة التشغيل</string> <string name="revanced_hide_save_button_title">إخفاء حفظ</string>
<string name="revanced_hide_playlist_button_summary_on">تم إخفاء زر الحفظ في قائمة التشغيل</string> <string name="revanced_hide_save_button_summary_on">زر الحفظ مخفي</string>
<string name="revanced_hide_playlist_button_summary_off">يتم عرض زر الحفظ في قائمة التشغيل</string> <string name="revanced_hide_save_button_summary_off">زر الحفظ معروض</string>
</patch> </patch>
<patch id="layout.buttons.navigation.navigationButtonsPatch"> <patch id="layout.buttons.navigation.navigationButtonsPatch">
<string name="revanced_navigation_buttons_screen_title">أزرار التنقل</string> <string name="revanced_navigation_buttons_screen_title">أزرار التنقل</string>
@@ -760,9 +764,12 @@ Second \"item\" text"</string>
<string name="revanced_hide_shorts_save_sound_button_title">إخفاء زر حفظ الموسيقى</string> <string name="revanced_hide_shorts_save_sound_button_title">إخفاء زر حفظ الموسيقى</string>
<string name="revanced_hide_shorts_save_sound_button_summary_on">تم إخفاء زر حفظ الموسيقى</string> <string name="revanced_hide_shorts_save_sound_button_summary_on">تم إخفاء زر حفظ الموسيقى</string>
<string name="revanced_hide_shorts_save_sound_button_summary_off">يتم عرض زر حفظ الموسيقى</string> <string name="revanced_hide_shorts_save_sound_button_summary_off">يتم عرض زر حفظ الموسيقى</string>
<string name="revanced_hide_shorts_use_template_button_title">إخفاء زر استخدام القالب</string> <string name="revanced_hide_shorts_use_sound_button_title">إخفاء زر استخدام هذا الصوت</string>
<string name="revanced_hide_shorts_use_template_button_summary_on">تم إخفاء زر استخدام القالب</string> <string name="revanced_hide_shorts_use_sound_button_summary_on">زر استخدام هذا الصوت مخفي</string>
<string name="revanced_hide_shorts_use_template_button_summary_off">يتم عرض زر استخدام القالب</string> <string name="revanced_hide_shorts_use_sound_button_summary_off">زر استخدام هذا الصوت معروض</string>
<string name="revanced_hide_shorts_use_template_button_title">إخفاء زر استخدام هذا القالب</string>
<string name="revanced_hide_shorts_use_template_button_summary_on">زر استخدام هذا القالب مخفي</string>
<string name="revanced_hide_shorts_use_template_button_summary_off">زر استخدام هذا القالب ظاهر</string>
<string name="revanced_hide_shorts_upcoming_button_title">إخفاء زر القادم</string> <string name="revanced_hide_shorts_upcoming_button_title">إخفاء زر القادم</string>
<string name="revanced_hide_shorts_upcoming_button_summary_on">تم إخفاء زر القادم</string> <string name="revanced_hide_shorts_upcoming_button_summary_on">تم إخفاء زر القادم</string>
<string name="revanced_hide_shorts_upcoming_button_summary_off">يتم عرض زر القادم</string> <string name="revanced_hide_shorts_upcoming_button_summary_off">يتم عرض زر القادم</string>
@@ -921,8 +928,6 @@ Second \"item\" text"</string>
<string name="revanced_seekbar_thumbnails_high_quality_title">تمكين المصغرات عالية الجودة</string> <string name="revanced_seekbar_thumbnails_high_quality_title">تمكين المصغرات عالية الجودة</string>
<string name="revanced_seekbar_thumbnails_high_quality_summary_on">مصغرات شريط التقدم عالية الجودة</string> <string name="revanced_seekbar_thumbnails_high_quality_summary_on">مصغرات شريط التقدم عالية الجودة</string>
<string name="revanced_seekbar_thumbnails_high_quality_summary_off">مصغرات شريط التقدم متوسطة الجودة</string> <string name="revanced_seekbar_thumbnails_high_quality_summary_off">مصغرات شريط التقدم متوسطة الجودة</string>
<string name="revanced_seekbar_thumbnails_high_quality_legacy_summary_on">مصغرات شريط التقدم بملء الشاشة عالية الجودة</string>
<string name="revanced_seekbar_thumbnails_high_quality_legacy_summary_off">مصغرات شريط التقدم بملء الشاشة متوسطة الجودة</string>
<string name="revanced_seekbar_thumbnails_high_quality_dialog_message">"سيؤدي هذا أيضا إلى استعادة المصغرات على البث المباشر الذي لا يحتوي على مصغرات شريط التقدم. <string name="revanced_seekbar_thumbnails_high_quality_dialog_message">"سيؤدي هذا أيضا إلى استعادة المصغرات على البث المباشر الذي لا يحتوي على مصغرات شريط التقدم.
مصغرات شريط التقدم سوف تستخدم نفس جودة الفيديو الحالي. مصغرات شريط التقدم سوف تستخدم نفس جودة الفيديو الحالي.
@@ -1009,7 +1014,7 @@ Second \"item\" text"</string>
<string name="revanced_sb_segments_highlight_sum">الجزء من الفيديو الذي يبحث عنه معظم الناس</string> <string name="revanced_sb_segments_highlight_sum">الجزء من الفيديو الذي يبحث عنه معظم الناس</string>
<string name="revanced_sb_segments_intro">المقدمة/فاصل</string> <string name="revanced_sb_segments_intro">المقدمة/فاصل</string>
<string name="revanced_sb_segments_intro_sum">فاصل زمني بدون محتوى فعلي. قد يكون توقفًا مؤقتًا، أو إطارًا ثابتًا، أو رسومًا متحركة متكررة. لا يتضمن انتقالات تحتوي على معلومات</string> <string name="revanced_sb_segments_intro_sum">فاصل زمني بدون محتوى فعلي. قد يكون توقفًا مؤقتًا، أو إطارًا ثابتًا، أو رسومًا متحركة متكررة. لا يتضمن انتقالات تحتوي على معلومات</string>
<string name="revanced_sb_segments_outro">الخاتمة/تترات النهاية</string> <string name="revanced_sb_segments_outro">الخاتمة / تترات النهاية</string>
<string name="revanced_sb_segments_outro_sum">تتر النهاية أو عندما تظهر بطاقات نهاية YouTube، نهايات غير منطوقة. ليس للاستنتاجات مع المعلومات</string> <string name="revanced_sb_segments_outro_sum">تتر النهاية أو عندما تظهر بطاقات نهاية YouTube، نهايات غير منطوقة. ليس للاستنتاجات مع المعلومات</string>
<string name="revanced_sb_segments_preview">معاينة/موجز/ربط</string> <string name="revanced_sb_segments_preview">معاينة/موجز/ربط</string>
<string name="revanced_sb_segments_preview_sum">مجموعة من المقاطع التي توضح ما هو قادم أو ما حدث في الفيديو أو في مقاطع فيديو أخرى من السلسلة، حيث تتكرر جميع المعلومات في مكان آخر</string> <string name="revanced_sb_segments_preview_sum">مجموعة من المقاطع التي توضح ما هو قادم أو ما حدث في الفيديو أو في مقاطع فيديو أخرى من السلسلة، حيث تتكرر جميع المعلومات في مكان آخر</string>
@@ -1131,7 +1136,6 @@ Second \"item\" text"</string>
<string name="revanced_change_form_factor_entry_1">الافتراضي</string> <string name="revanced_change_form_factor_entry_1">الافتراضي</string>
<string name="revanced_change_form_factor_entry_2">الجوّال</string> <string name="revanced_change_form_factor_entry_2">الجوّال</string>
<string name="revanced_change_form_factor_entry_3">الجهاز اللوحي</string> <string name="revanced_change_form_factor_entry_3">الجهاز اللوحي</string>
<string name="revanced_change_form_factor_entry_4">Automotive</string>
<string name="revanced_change_form_factor_user_dialog_message">"التغييرات تشمل: <string name="revanced_change_form_factor_user_dialog_message">"التغييرات تشمل:
تصميم الجهاز اللوحي تصميم الجهاز اللوحي
@@ -1241,11 +1245,6 @@ Second \"item\" text"</string>
<string name="revanced_miniplayer_hide_overlay_buttons_title">إخفاء أزرار الواجهة</string> <string name="revanced_miniplayer_hide_overlay_buttons_title">إخفاء أزرار الواجهة</string>
<string name="revanced_miniplayer_hide_overlay_buttons_summary_on">تم إخفاء أزرار الواجهة</string> <string name="revanced_miniplayer_hide_overlay_buttons_summary_on">تم إخفاء أزرار الواجهة</string>
<string name="revanced_miniplayer_hide_overlay_buttons_summary_off">يتم عرض أزرار الواجهة</string> <string name="revanced_miniplayer_hide_overlay_buttons_summary_off">يتم عرض أزرار الواجهة</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_title">إخفاء زري التوسيع والإغلاق</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_summary_on">"تم إخفاء الأزرار
اسحب للتوسيع أو الإغلاق"</string>
<string name="revanced_miniplayer_hide_overlay_buttons_legacy_summary_off">يتم عرض زري التوسيع والإغلاق</string>
<string name="revanced_miniplayer_hide_subtext_title">إخفاء النصوص الفرعية</string> <string name="revanced_miniplayer_hide_subtext_title">إخفاء النصوص الفرعية</string>
<string name="revanced_miniplayer_hide_subtext_summary_on">تم إخفاء النصوص الفرعية</string> <string name="revanced_miniplayer_hide_subtext_summary_on">تم إخفاء النصوص الفرعية</string>
<string name="revanced_miniplayer_hide_subtext_summary_off">يتم عرض النصوص الفرعية</string> <string name="revanced_miniplayer_hide_subtext_summary_off">يتم عرض النصوص الفرعية</string>
@@ -1303,8 +1302,8 @@ Second \"item\" text"</string>
<string name="revanced_alt_thumbnail_dearrow_connection_toast_title">عرض ملاحظة إذا كان API غير متاح</string> <string name="revanced_alt_thumbnail_dearrow_connection_toast_title">عرض ملاحظة إذا كان API غير متاح</string>
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_on">يتم عرض ملاحظة إذا كان DeArrow غير متوفر</string> <string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_on">يتم عرض ملاحظة إذا كان DeArrow غير متوفر</string>
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_off">لا يتم عرض ملاحظة إذا كان DeArrow غير متوفر</string> <string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_off">لا يتم عرض ملاحظة إذا كان DeArrow غير متوفر</string>
<string name="revanced_alt_thumbnail_dearrow_api_url_title">DeArrow API endpoint</string> <string name="revanced_alt_thumbnail_dearrow_api_url_title">نقطة نهاية واجهة برمجة تطبيقات DeArrow</string>
<string name="revanced_alt_thumbnail_dearrow_api_url_summary">The URL of the DeArrow thumbnail cache endpoint</string> <string name="revanced_alt_thumbnail_dearrow_api_url_summary">عنوان URL لنقطة نهاية ذاكرة التخزين المؤقت للصور المصغرة لـ DeArrow</string>
<string name="revanced_alt_thumbnail_stills_about_title">لقطات الفيديو الثابتة</string> <string name="revanced_alt_thumbnail_stills_about_title">لقطات الفيديو الثابتة</string>
<string name="revanced_alt_thumbnail_stills_about_summary">يتم التقاط اللقطات الثابتة من بداية/وسط/نهاية كل فيديو. هذه الصور مدمجة في YouTube ولا يتم استخدام أي واجهة برمجة تطبيقات خارجية</string> <string name="revanced_alt_thumbnail_stills_about_summary">يتم التقاط اللقطات الثابتة من بداية/وسط/نهاية كل فيديو. هذه الصور مدمجة في YouTube ولا يتم استخدام أي واجهة برمجة تطبيقات خارجية</string>
<string name="revanced_alt_thumbnail_stills_fast_title">استخدم اللقطات الثابتة السريعة</string> <string name="revanced_alt_thumbnail_stills_fast_title">استخدم اللقطات الثابتة السريعة</string>
@@ -1397,6 +1396,9 @@ Second \"item\" text"</string>
<string name="revanced_remember_video_quality_last_selected_title">تذكر تغييرات جودة الفيديو</string> <string name="revanced_remember_video_quality_last_selected_title">تذكر تغييرات جودة الفيديو</string>
<string name="revanced_remember_video_quality_last_selected_summary_on">تنطبق تغييرات الجودة على جميع الفيديوهات</string> <string name="revanced_remember_video_quality_last_selected_summary_on">تنطبق تغييرات الجودة على جميع الفيديوهات</string>
<string name="revanced_remember_video_quality_last_selected_summary_off">تنطبق تغييرات الجودة على الفيديو الحالي فقط</string> <string name="revanced_remember_video_quality_last_selected_summary_off">تنطبق تغييرات الجودة على الفيديو الحالي فقط</string>
<string name="revanced_remember_video_quality_last_selected_toast_title">إظهار إشعار عند تغيير جودة الفيديو</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_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">تذكر تغييرات جودة Shorts</string> <string name="revanced_remember_shorts_quality_last_selected_title">تذكر تغييرات جودة Shorts</string>
@@ -1423,7 +1425,6 @@ Second \"item\" text"</string>
<string name="revanced_custom_playback_speeds_invalid">يجب أن تكون سرعات التشغيل المخصصة أقل من %s</string> <string name="revanced_custom_playback_speeds_invalid">يجب أن تكون سرعات التشغيل المخصصة أقل من %s</string>
<string name="revanced_custom_playback_speeds_parse_exception">سرعة التشغيل المخصصة غير صالحة</string> <string name="revanced_custom_playback_speeds_parse_exception">سرعة التشغيل المخصصة غير صالحة</string>
<string name="revanced_custom_playback_speeds_auto">تلقائي</string> <string name="revanced_custom_playback_speeds_auto">تلقائي</string>
<string name="revanced_custom_playback_speeds_reset_toast">تمت إعادة ضبط سرعة التشغيل إلى: %s</string>
<string name="revanced_speed_tap_and_hold_title">سرعة النقر مع الاستمرار المخصصة</string> <string name="revanced_speed_tap_and_hold_title">سرعة النقر مع الاستمرار المخصصة</string>
<string name="revanced_speed_tap_and_hold_summary">سرعة التشغيل بين 0-8</string> <string name="revanced_speed_tap_and_hold_summary">سرعة التشغيل بين 0-8</string>
</patch> </patch>
@@ -1431,6 +1432,9 @@ Second \"item\" text"</string>
<string name="revanced_remember_playback_speed_last_selected_title">تذكر التغيرات في سرعة التشغيل</string> <string name="revanced_remember_playback_speed_last_selected_title">تذكر التغيرات في سرعة التشغيل</string>
<string name="revanced_remember_playback_speed_last_selected_summary_on">تطبيق تغييرات سرعة التشغيل على جميع الفيديوهات</string> <string name="revanced_remember_playback_speed_last_selected_summary_on">تطبيق تغييرات سرعة التشغيل على جميع الفيديوهات</string>
<string name="revanced_remember_playback_speed_last_selected_summary_off">تطبيق تغييرات سرعة التشغيل فقط على الفيديو الحالي</string> <string name="revanced_remember_playback_speed_last_selected_summary_off">تطبيق تغييرات سرعة التشغيل فقط على الفيديو الحالي</string>
<string name="revanced_remember_playback_speed_last_selected_toast_title">إظهار إشعار عند تغيير سرعة التشغيل</string>
<string name="revanced_remember_playback_speed_last_selected_toast_summary_on">يتم إظهار إشعار عند تغيير سرعة التشغيل الافتراضية</string>
<string name="revanced_remember_playback_speed_last_selected_toast_summary_off">لا يتم عرض إشعار عند تغيير سرعة التشغيل الافتراضية.</string>
<string name="revanced_playback_speed_default_title">سرعة التشغيل الافتراضية</string> <string name="revanced_playback_speed_default_title">سرعة التشغيل الافتراضية</string>
<string name="revanced_remember_playback_speed_toast">تغيير السرعة الافتراضية إلى: %s</string> <string name="revanced_remember_playback_speed_toast">تغيير السرعة الافتراضية إلى: %s</string>
</patch> </patch>

View File

@@ -79,6 +79,7 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="layout.buttons.action.hideButtonsPatch"> <patch id="layout.buttons.action.hideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. --> <!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Stop ads' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays. <!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. --> This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. --> <!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->

Some files were not shown because too many files have changed in this diff Show More