mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-07 18:03:55 +01:00
Compare commits
61 Commits
v5.2.0-dev
...
v5.3.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f02f583be | ||
|
|
6462fb8cba | ||
|
|
f9dcce927e | ||
|
|
69f9ab8345 | ||
|
|
dd400ac2a0 | ||
|
|
538ed6d876 | ||
|
|
5ff94dc34a | ||
|
|
b04a11a885 | ||
|
|
4983e021f9 | ||
|
|
bee917f4ed | ||
|
|
c94376bc4c | ||
|
|
87fe83aacf | ||
|
|
92d282e963 | ||
|
|
4a88f650c2 | ||
|
|
8b67716506 | ||
|
|
95d56b1529 | ||
|
|
b1f3b12fa1 | ||
|
|
cf4456c2ba | ||
|
|
d509a3f397 | ||
|
|
d1ae1f1da7 | ||
|
|
9c1c90864c | ||
|
|
5ae76f4df8 | ||
|
|
87eaf61ef1 | ||
|
|
35594d0a20 | ||
|
|
e3c54d8a64 | ||
|
|
06202c8807 | ||
|
|
53efe10222 | ||
|
|
decd3fcb47 | ||
|
|
c7692d7561 | ||
|
|
73c7c8c93a | ||
|
|
3a4a124f0b | ||
|
|
3015993f55 | ||
|
|
e04c681424 | ||
|
|
de492de77d | ||
|
|
fc5dcbd13c | ||
|
|
91a5c95f9a | ||
|
|
a7aa8de6a8 | ||
|
|
4ee70e3869 | ||
|
|
c912a662ab | ||
|
|
d3b3262a31 | ||
|
|
78390a8bca | ||
|
|
85bfa4ca91 | ||
|
|
9bcde94724 | ||
|
|
0cfd8e6760 | ||
|
|
3265372035 | ||
|
|
57a8e47041 | ||
|
|
cd476c1227 | ||
|
|
064be93ee2 | ||
|
|
f74fd7113f | ||
|
|
628afc22bc | ||
|
|
8686bd9f20 | ||
|
|
534996f251 | ||
|
|
ca4a16dbd8 | ||
|
|
e33082f765 | ||
|
|
18360464a9 | ||
|
|
968e6e9b69 | ||
|
|
02732ab432 | ||
|
|
77aea074a9 | ||
|
|
fe15213cf9 | ||
|
|
046bd3ec88 | ||
|
|
d6bc998365 |
200
CHANGELOG.md
200
CHANGELOG.md
@@ -1,3 +1,203 @@
|
||||
# [5.3.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.3.0-dev.6...v5.3.0-dev.7) (2024-12-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Add missing preferred language preference to the settings ([630633c](https://github.com/ReVanced/revanced-patches/commit/630633cf57c65c65e5578046413e17670ae336e8))
|
||||
|
||||
# [5.3.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.3.0-dev.5...v5.3.0-dev.6) (2024-12-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Spoof video streams:** Allow picking a default audio language track ([#4050](https://github.com/ReVanced/revanced-patches/issues/4050)) ([ede666b](https://github.com/ReVanced/revanced-patches/commit/ede666b5cb64fcbaa1334ad8bef79e2634ced113))
|
||||
|
||||
# [5.3.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.3.0-dev.4...v5.3.0-dev.5) (2024-12-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Change package name:** Prevent applying the patch to known incompatible apps ([#3943](https://github.com/ReVanced/revanced-patches/issues/3943)) ([44936e7](https://github.com/ReVanced/revanced-patches/commit/44936e71e846f72f7279950232a5dba37765ceb3))
|
||||
* **YouTube Music - Permanent shuffle:** Remove obsolete and non functional patch ([#4073](https://github.com/ReVanced/revanced-patches/issues/4073)) ([fbc6ab6](https://github.com/ReVanced/revanced-patches/commit/fbc6ab6a357b351f02d4d486ddc2072cf53199c3))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube:** Add `Open videos fullscreen` patch ([#4069](https://github.com/ReVanced/revanced-patches/issues/4069)) ([296d63b](https://github.com/ReVanced/revanced-patches/commit/296d63bd42c338a01efbcb2df702e5822d05a5f1))
|
||||
|
||||
# [5.3.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.3.0-dev.3...v5.3.0-dev.4) (2024-12-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Nyx:** Remove broken `Unlock pro` patch ([1fe8b16](https://github.com/ReVanced/revanced-patches/commit/1fe8b164eab0c4fa80ab2da2581977f5111a2858))
|
||||
|
||||
# [5.3.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.3.0-dev.2...v5.3.0-dev.3) (2024-12-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Update `Force AVC` client data ([#4064](https://github.com/ReVanced/revanced-patches/issues/4064)) ([7d537dd](https://github.com/ReVanced/revanced-patches/commit/7d537ddff4bb5421fa320741275131a66ef5c7bb))
|
||||
|
||||
# [5.3.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.3.0-dev.1...v5.3.0-dev.2) (2024-12-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Reddit:** Fix patches by using correct extension class ([70bdc68](https://github.com/ReVanced/revanced-patches/commit/70bdc6840d465399625aa1ae0259f49e72711955))
|
||||
|
||||
# [5.3.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.2.4-dev.3...v5.3.0-dev.1) (2024-12-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube Music:** Add `Spoof video streams` patch to fix playback ([#4065](https://github.com/ReVanced/revanced-patches/issues/4065)) ([cf3116a](https://github.com/ReVanced/revanced-patches/commit/cf3116a7583d09c25c798a85687a056f143656f0))
|
||||
|
||||
## [5.2.4-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.2.4-dev.2...v5.2.4-dev.3) (2024-12-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Enable opus codec by updating iOS client version ([#4063](https://github.com/ReVanced/revanced-patches/issues/4063)) ([0af156f](https://github.com/ReVanced/revanced-patches/commit/0af156f18972c5f089af4bb69824968d2a47d18f))
|
||||
|
||||
## [5.2.4-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.2.4-dev.1...v5.2.4-dev.2) (2024-12-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Sync for Reddit:** Fix patches by using correct extension name ([030093e](https://github.com/ReVanced/revanced-patches/commit/030093e913aab3fab43935eedbaeba0f6c0491bb))
|
||||
|
||||
## [5.2.4-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.2.3...v5.2.4-dev.1) (2024-12-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Twitter:** Merge correct extension by depending on correct extension patch ([8281cf6](https://github.com/ReVanced/revanced-patches/commit/8281cf6a3eead8cc25a277371e0b0ab2be982497))
|
||||
|
||||
## [5.2.3](https://github.com/ReVanced/revanced-patches/compare/v5.2.2...v5.2.3) (2024-12-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music - GmsCore support:** Resolve patching errors ([#4056](https://github.com/ReVanced/revanced-patches/issues/4056)) ([38a4bad](https://github.com/ReVanced/revanced-patches/commit/38a4bad5b890e3906d77d22efeabd8f38653508b))
|
||||
|
||||
## [5.2.3-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.2.2...v5.2.3-dev.1) (2024-12-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music - GmsCore support:** Resolve patching errors ([#4056](https://github.com/ReVanced/revanced-patches/issues/4056)) ([38a4bad](https://github.com/ReVanced/revanced-patches/commit/38a4bad5b890e3906d77d22efeabd8f38653508b))
|
||||
|
||||
## [5.2.2](https://github.com/ReVanced/revanced-patches/compare/v5.2.1...v5.2.2) (2024-12-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Use system language as default iOS audio stream ([#4042](https://github.com/ReVanced/revanced-patches/issues/4042)) ([4017185](https://github.com/ReVanced/revanced-patches/commit/4017185e760c0569e6644b94bbe66a84fa245b4b))
|
||||
|
||||
## [5.2.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.2.1...v5.2.2-dev.1) (2024-12-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Use system language as default iOS audio stream ([#4042](https://github.com/ReVanced/revanced-patches/issues/4042)) ([4017185](https://github.com/ReVanced/revanced-patches/commit/4017185e760c0569e6644b94bbe66a84fa245b4b))
|
||||
|
||||
## [5.2.1](https://github.com/ReVanced/revanced-patches/compare/v5.2.0...v5.2.1) (2024-12-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Twitch:** Resolve setting menu crashes ([#4025](https://github.com/ReVanced/revanced-patches/issues/4025)) ([62df596](https://github.com/ReVanced/revanced-patches/commit/62df5965d7331e47b3143425d169a79a19eac447))
|
||||
* **YouTube - Spoof app version:** Update spoof target to resolve library tab crashes ([#4014](https://github.com/ReVanced/revanced-patches/issues/4014)) ([c8eced5](https://github.com/ReVanced/revanced-patches/commit/c8eced54704017df4e91e536dbef1e9514306f67))
|
||||
* **YouTube - Spoof app version:** Update spoof target to resolve library tab crashes ([#4019](https://github.com/ReVanced/revanced-patches/issues/4019)) ([d89ad65](https://github.com/ReVanced/revanced-patches/commit/d89ad6501a7cdb3c074c6204dac7960ca3e252f1))
|
||||
* **YouTube Music - Hide category bar:** Add support for latest release ([#3968](https://github.com/ReVanced/revanced-patches/issues/3968)) ([b63fdeb](https://github.com/ReVanced/revanced-patches/commit/b63fdeb10b504468307a77bd5de69407906848bf))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* Move variables to local scope ([43c0421](https://github.com/ReVanced/revanced-patches/commit/43c04216c6e647eaf6ad7e813eb5f0df0c108b77))
|
||||
|
||||
## [5.2.1-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.2.1-dev.4...v5.2.1-dev.5) (2024-12-01)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* Move variables to local scope ([43c0421](https://github.com/ReVanced/revanced-patches/commit/43c04216c6e647eaf6ad7e813eb5f0df0c108b77))
|
||||
|
||||
## [5.2.1-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.2.1-dev.3...v5.2.1-dev.4) (2024-11-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Twitch:** Resolve setting menu crashes ([#4025](https://github.com/ReVanced/revanced-patches/issues/4025)) ([62df596](https://github.com/ReVanced/revanced-patches/commit/62df5965d7331e47b3143425d169a79a19eac447))
|
||||
|
||||
## [5.2.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.2.1-dev.2...v5.2.1-dev.3) (2024-11-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music - Hide category bar:** Add support for latest release ([#3968](https://github.com/ReVanced/revanced-patches/issues/3968)) ([b63fdeb](https://github.com/ReVanced/revanced-patches/commit/b63fdeb10b504468307a77bd5de69407906848bf))
|
||||
|
||||
## [5.2.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.2.1-dev.1...v5.2.1-dev.2) (2024-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof app version:** Update spoof target to resolve library tab crashes ([#4019](https://github.com/ReVanced/revanced-patches/issues/4019)) ([d89ad65](https://github.com/ReVanced/revanced-patches/commit/d89ad6501a7cdb3c074c6204dac7960ca3e252f1))
|
||||
|
||||
## [5.2.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.2.0...v5.2.1-dev.1) (2024-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof app version:** Update spoof target to resolve library tab crashes ([#4014](https://github.com/ReVanced/revanced-patches/issues/4014)) ([c8eced5](https://github.com/ReVanced/revanced-patches/commit/c8eced54704017df4e91e536dbef1e9514306f67))
|
||||
|
||||
# [5.2.0](https://github.com/ReVanced/revanced-patches/compare/v5.1.0...v5.2.0) (2024-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **My Expenses - Unlock pro:** Constrain compatible version to working version ([#3974](https://github.com/ReVanced/revanced-patches/issues/3974)) ([ba3bf69](https://github.com/ReVanced/revanced-patches/commit/ba3bf69df07ec8dab46868c3940ebd56db0cd137))
|
||||
* **YouTube - Hide Shorts components:** Add missing options to patch ([65f62fc](https://github.com/ReVanced/revanced-patches/commit/65f62fcd5ac340616a96542c64faf2af2a60df28))
|
||||
* **YouTube - Playback speed:** Allow long press 2x speed when using custom playback speeds ([#3990](https://github.com/ReVanced/revanced-patches/issues/3990)) ([79a543a](https://github.com/ReVanced/revanced-patches/commit/79a543a57470638f983862c61270e046f3ac5cb7))
|
||||
* **YouTube - Settings:** Do not clip settings menus when using an Android 15 device ([#3999](https://github.com/ReVanced/revanced-patches/issues/3999)) ([7382a02](https://github.com/ReVanced/revanced-patches/commit/7382a020b8322a7abc016a4569bc15f9caf05546))
|
||||
* **YouTube - Settings:** Show navigation back button in setting sub menus ([#3991](https://github.com/ReVanced/revanced-patches/issues/3991)) ([e61686c](https://github.com/ReVanced/revanced-patches/commit/e61686c1039ae29e443273e4da4ec63956216841))
|
||||
* **YouTube - Spoof video streams:** Log out the iOS client to restore kids videos playback ([#4000](https://github.com/ReVanced/revanced-patches/issues/4000)) ([cc2ac4e](https://github.com/ReVanced/revanced-patches/commit/cc2ac4e4cd15ca2a23d60abd160d915bc98f99b4))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **TikTok:** Add ReVanced settings about screen ([#4009](https://github.com/ReVanced/revanced-patches/issues/4009)) ([12ea26b](https://github.com/ReVanced/revanced-patches/commit/12ea26b10ddea5ad39da1d35e2b8fd0b48c15d88))
|
||||
* **VSCO:** Remove non functional `Unlock pro` patch ([4fddb19](https://github.com/ReVanced/revanced-patches/commit/4fddb1930bc7adeee3b60ae9cd346b143e88bd42))
|
||||
* **YouTube - Theme:** Apply custom seekbar color to splash screen animation ([#3978](https://github.com/ReVanced/revanced-patches/issues/3978)) ([98d57e2](https://github.com/ReVanced/revanced-patches/commit/98d57e28af7206099867474b7aa3760cd4fe333f))
|
||||
* **YouTube:** Support version `19.46.42` ([#4010](https://github.com/ReVanced/revanced-patches/issues/4010)) ([122aac6](https://github.com/ReVanced/revanced-patches/commit/122aac6aee8ef0737f18564f11bbc2a6addf4a6b))
|
||||
|
||||
# [5.2.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.6...v5.2.0-dev.7) (2024-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Settings:** Do not clip settings menus when using an Android 15 device ([#3999](https://github.com/ReVanced/revanced-patches/issues/3999)) ([7382a02](https://github.com/ReVanced/revanced-patches/commit/7382a020b8322a7abc016a4569bc15f9caf05546))
|
||||
|
||||
# [5.2.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.5...v5.2.0-dev.6) (2024-11-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube:** Support version `19.46.42` ([#4010](https://github.com/ReVanced/revanced-patches/issues/4010)) ([122aac6](https://github.com/ReVanced/revanced-patches/commit/122aac6aee8ef0737f18564f11bbc2a6addf4a6b))
|
||||
|
||||
# [5.2.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.4...v5.2.0-dev.5) (2024-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof video streams:** Log out the iOS client to restore kids videos playback ([#4000](https://github.com/ReVanced/revanced-patches/issues/4000)) ([cc2ac4e](https://github.com/ReVanced/revanced-patches/commit/cc2ac4e4cd15ca2a23d60abd160d915bc98f99b4))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **TikTok:** Add ReVanced settings about screen ([#4009](https://github.com/ReVanced/revanced-patches/issues/4009)) ([12ea26b](https://github.com/ReVanced/revanced-patches/commit/12ea26b10ddea5ad39da1d35e2b8fd0b48c15d88))
|
||||
|
||||
# [5.2.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.3...v5.2.0-dev.4) (2024-11-26)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
android.namespace = "app.revanced.extension"
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
</manifest>
|
||||
@@ -0,0 +1,5 @@
|
||||
android.namespace = "app.revanced.extension"
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
android.namespace = "app.revanced.extension"
|
||||
4
extensions/boostforreddit/build.gradle.kts
Normal file
4
extensions/boostforreddit/build.gradle.kts
Normal file
@@ -0,0 +1,4 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:shared:library"))
|
||||
compileOnly(project(":extensions:boostforreddit:stub"))
|
||||
}
|
||||
1
extensions/boostforreddit/src/main/AndroidManifest.xml
Normal file
1
extensions/boostforreddit/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -4,7 +4,9 @@ import com.rubenmayayo.reddit.ui.activities.WebViewActivity;
|
||||
|
||||
import app.revanced.extension.shared.fixes.slink.BaseFixSLinksPatch;
|
||||
|
||||
/** @noinspection unused*/
|
||||
/**
|
||||
* @noinspection unused
|
||||
*/
|
||||
public class FixSLinksPatch extends BaseFixSLinksPatch {
|
||||
static {
|
||||
INSTANCE = new FixSLinksPatch();
|
||||
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
3
extensions/reddit/build.gradle.kts
Normal file
3
extensions/reddit/build.gradle.kts
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:reddit:stub"))
|
||||
}
|
||||
1
extensions/reddit/src/main/AndroidManifest.xml
Normal file
1
extensions/reddit/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -5,8 +5,12 @@ import com.reddit.domain.model.ILink;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class FilterPromotedLinksPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*
|
||||
* Filters list from promoted links.
|
||||
**/
|
||||
public static List<?> filterChildren(final Iterable<?> links) {
|
||||
17
extensions/reddit/stub/build.gradle.kts
Normal file
17
extensions/reddit/stub/build.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
id(libs.plugins.android.library.get().pluginId)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
compileSdk = 33
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
1
extensions/reddit/stub/src/main/AndroidManifest.xml
Normal file
1
extensions/reddit/stub/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -1,11 +0,0 @@
|
||||
extension {
|
||||
name = "extensions/all/screencapture/remove-screen-capture-restriction.rve"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
extension {
|
||||
name = "extensions/all/screenshot/remove-screenshot-restriction.rve"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
}
|
||||
@@ -1,22 +1,3 @@
|
||||
extension {
|
||||
name = "extensions/shared.rve"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.appcompat)
|
||||
compileOnly(libs.annotation)
|
||||
compileOnly(libs.okhttp)
|
||||
compileOnly(libs.retrofit)
|
||||
|
||||
compileOnly(project(":extensions:shared:stub"))
|
||||
implementation(project(":extensions:shared:library"))
|
||||
}
|
||||
|
||||
21
extensions/shared/library/build.gradle.kts
Normal file
21
extensions/shared/library/build.gradle.kts
Normal file
@@ -0,0 +1,21 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import java.util.Collection;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
|
||||
abstract class Check {
|
||||
private static final int NUMBER_OF_TIMES_TO_IGNORE_WARNING_BEFORE_DISABLING = 2;
|
||||
@@ -46,11 +46,11 @@ abstract class Check {
|
||||
/**
|
||||
* For debugging and development only.
|
||||
* Forces all checks to be performed and the check failed dialog to be shown.
|
||||
* Can be enabled by importing settings text with {@link Settings#CHECK_ENVIRONMENT_WARNINGS_ISSUED}
|
||||
* Can be enabled by importing settings text with {@link BaseSettings#CHECK_ENVIRONMENT_WARNINGS_ISSUED}
|
||||
* set to -1.
|
||||
*/
|
||||
static boolean debugAlwaysShowWarning() {
|
||||
final boolean alwaysShowWarning = Settings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.get() < 0;
|
||||
final boolean alwaysShowWarning = BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.get() < 0;
|
||||
if (alwaysShowWarning) {
|
||||
Logger.printInfo(() -> "Debug forcing environment check warning to show");
|
||||
}
|
||||
@@ -59,14 +59,14 @@ abstract class Check {
|
||||
}
|
||||
|
||||
static boolean shouldRun() {
|
||||
return Settings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.get()
|
||||
return BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.get()
|
||||
< NUMBER_OF_TIMES_TO_IGNORE_WARNING_BEFORE_DISABLING;
|
||||
}
|
||||
|
||||
static void disableForever() {
|
||||
Logger.printInfo(() -> "Environment checks disabled forever");
|
||||
|
||||
Settings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.save(Integer.MAX_VALUE);
|
||||
BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.save(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@@ -107,8 +107,8 @@ abstract class Check {
|
||||
" ",
|
||||
(dialog, which) -> {
|
||||
// Cleanup data if the user incorrectly imported a huge negative number.
|
||||
final int current = Math.max(0, Settings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.get());
|
||||
Settings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.save(current + 1);
|
||||
final int current = Math.max(0, BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.get());
|
||||
BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.save(current + 1);
|
||||
|
||||
dialog.dismiss();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.extension.youtube.requests;
|
||||
package app.revanced.extension.shared.requests;
|
||||
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import org.json.JSONArray;
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.extension.youtube.requests;
|
||||
package app.revanced.extension.shared.requests;
|
||||
|
||||
public class Route {
|
||||
private final String route;
|
||||
@@ -0,0 +1,30 @@
|
||||
package app.revanced.extension.shared.settings;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.ForceiOSAVCAvailability;
|
||||
|
||||
import app.revanced.extension.shared.spoof.AudioStreamLanguage;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
|
||||
/**
|
||||
* Settings shared across multiple apps.
|
||||
* <p>
|
||||
* To ensure this class is loaded when the UI is created, app specific setting bundles should extend
|
||||
* or reference this class.
|
||||
*/
|
||||
public class BaseSettings {
|
||||
public static final BooleanSetting DEBUG = new BooleanSetting("revanced_debug", FALSE);
|
||||
public static final BooleanSetting DEBUG_STACKTRACE = new BooleanSetting("revanced_debug_stacktrace", FALSE, parent(DEBUG));
|
||||
public static final BooleanSetting DEBUG_TOAST_ON_ERROR = new BooleanSetting("revanced_debug_toast_on_error", TRUE, "revanced_debug_toast_on_error_user_dialog_message");
|
||||
|
||||
public static final IntegerSetting CHECK_ENVIRONMENT_WARNINGS_ISSUED = new IntegerSetting("revanced_check_environment_warnings_issued", 0, true, false);
|
||||
|
||||
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message");
|
||||
public static final EnumSetting<AudioStreamLanguage> SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AudioStreamLanguage.DEFAULT, parent(SPOOF_VIDEO_STREAMS));
|
||||
public static final BooleanSetting SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_video_streams_ios_force_avc", FALSE, true,
|
||||
"revanced_spoof_video_streams_ios_force_avc_user_dialog_message", new ForceiOSAVCAvailability());
|
||||
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client", ClientType.ANDROID_VR, true, parent(SPOOF_VIDEO_STREAMS));
|
||||
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.StringRef;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.preference.SharedPrefCategory;
|
||||
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -62,6 +61,30 @@ public abstract class Setting<T> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for importing/exporting settings.
|
||||
*/
|
||||
public interface ImportExportCallback {
|
||||
/**
|
||||
* Called after all settings have been imported.
|
||||
*/
|
||||
void settingsImported(@Nullable Context context);
|
||||
|
||||
/**
|
||||
* Called after all settings have been exported.
|
||||
*/
|
||||
void settingsExported(@Nullable Context context);
|
||||
}
|
||||
|
||||
private static final List<ImportExportCallback> importExportCallbacks = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Adds a callback for {@link #importFromJSON(Context, String)} and {@link #exportToJson(Context)}.
|
||||
*/
|
||||
public static void addImportExportCallback(@NonNull ImportExportCallback callback) {
|
||||
importExportCallbacks.add(Objects.requireNonNull(callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* All settings that were instantiated.
|
||||
* When a new setting is created, it is automatically added to this list.
|
||||
@@ -365,7 +388,10 @@ public abstract class Setting<T> {
|
||||
setting.writeToJSON(json, importExportKey);
|
||||
}
|
||||
}
|
||||
SponsorBlockSettings.showExportWarningIfNeeded(alertDialogContext);
|
||||
|
||||
for (ImportExportCallback callback : importExportCallbacks) {
|
||||
callback.settingsExported(alertDialogContext);
|
||||
}
|
||||
|
||||
if (json.length() == 0) {
|
||||
return "";
|
||||
@@ -385,7 +411,7 @@ public abstract class Setting<T> {
|
||||
/**
|
||||
* @return if any settings that require a reboot were changed.
|
||||
*/
|
||||
public static boolean importFromJSON(@NonNull String settingsJsonString) {
|
||||
public static boolean importFromJSON(@NonNull Context alertDialogContext, @NonNull String settingsJsonString) {
|
||||
try {
|
||||
if (!settingsJsonString.matches("[\\s\\S]*\\{")) {
|
||||
settingsJsonString = '{' + settingsJsonString + '}'; // Restore outer JSON braces
|
||||
@@ -411,12 +437,9 @@ public abstract class Setting<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// SB Enum categories are saved using StringSettings.
|
||||
// Which means they need to reload again if changed by other code (such as here).
|
||||
// This call could be removed by creating a custom Setting class that manages the
|
||||
// "String <-> Enum" logic or by adding an event hook of when settings are imported.
|
||||
// But for now this is simple and works.
|
||||
SponsorBlockSettings.updateFromImportedSettings();
|
||||
for (ImportExportCallback callback : importExportCallbacks) {
|
||||
callback.settingsImported(alertDialogContext);
|
||||
}
|
||||
|
||||
Utils.showToastLong(numberOfSettingsImported == 0
|
||||
? str("revanced_settings_import_reset")
|
||||
@@ -1,21 +1,13 @@
|
||||
package app.revanced.extension.shared.settings.preference;
|
||||
|
||||
import static app.revanced.extension.shared.StringRef.str;
|
||||
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.*;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -27,7 +19,6 @@ import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.settings.BooleanSetting;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.youtube.ThemeHelper;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
||||
@@ -83,14 +74,6 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
public static Drawable getBackButtonDrawable() {
|
||||
final int backButtonResource = getResourceIdentifier(ThemeHelper.isDarkTheme()
|
||||
? "yt_outline_arrow_left_white_24"
|
||||
: "yt_outline_arrow_left_black_24",
|
||||
"drawable");
|
||||
return Utils.getContext().getResources().getDrawable(backButtonResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this instance, and do any custom behavior.
|
||||
@@ -282,7 +265,6 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
||||
// causes a callback to the listener even though nothing changed.
|
||||
initialize();
|
||||
updateUIToSettingValues();
|
||||
setPreferenceScreenToolbar(getPreferenceScreen());
|
||||
|
||||
preferenceManager.getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
|
||||
} catch (Exception ex) {
|
||||
@@ -295,44 +277,4 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
||||
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
|
||||
for (int i = 0, preferenceCount = parentScreen.getPreferenceCount(); i < preferenceCount; i++) {
|
||||
Preference childPreference = parentScreen.getPreference(i);
|
||||
if (childPreference instanceof PreferenceScreen) {
|
||||
// Recursively set sub preferences.
|
||||
setPreferenceScreenToolbar((PreferenceScreen) childPreference);
|
||||
|
||||
childPreference.setOnPreferenceClickListener(
|
||||
childScreen -> {
|
||||
Dialog preferenceScreenDialog = ((PreferenceScreen) childScreen).getDialog();
|
||||
ViewGroup rootView = (ViewGroup) preferenceScreenDialog
|
||||
.findViewById(android.R.id.content)
|
||||
.getParent();
|
||||
|
||||
Toolbar toolbar = new Toolbar(childScreen.getContext());
|
||||
toolbar.setTitle(childScreen.getTitle());
|
||||
toolbar.setNavigationIcon(getBackButtonDrawable());
|
||||
toolbar.setNavigationOnClickListener(view -> preferenceScreenDialog.dismiss());
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
final int margin = (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()
|
||||
);
|
||||
toolbar.setTitleMargin(margin, 0, margin, 0);
|
||||
}
|
||||
|
||||
TextView toolbarTextView = Utils.getChildView(toolbar,
|
||||
true, TextView.class::isInstance);
|
||||
if (toolbarTextView != null) {
|
||||
toolbarTextView.setTextColor(ThemeHelper.getForegroundColor());
|
||||
}
|
||||
|
||||
rootView.addView(toolbar, 0);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,20 +72,21 @@ public class ImportExportPreference extends EditTextPreference implements Prefer
|
||||
builder.setNeutralButton(str("revanced_settings_import_copy"), (dialog, which) -> {
|
||||
Utils.setClipboard(getEditText().getText().toString());
|
||||
}).setPositiveButton(str("revanced_settings_import"), (dialog, which) -> {
|
||||
importSettings(getEditText().getText().toString());
|
||||
importSettings(builder.getContext(), getEditText().getText().toString());
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "onPrepareDialogBuilder failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void importSettings(String replacementSettings) {
|
||||
private void importSettings(Context context, String replacementSettings) {
|
||||
try {
|
||||
if (replacementSettings.equals(existingSettings)) {
|
||||
return;
|
||||
}
|
||||
AbstractPreferenceFragment.settingImportInProgress = true;
|
||||
final boolean rebootNeeded = Setting.importFromJSON(replacementSettings);
|
||||
|
||||
final boolean rebootNeeded = Setting.importFromJSON(context, replacementSettings);
|
||||
if (rebootNeeded) {
|
||||
AbstractPreferenceFragment.showRestartDialog(getContext());
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
package app.revanced.extension.shared.settings.preference;
|
||||
|
||||
import static app.revanced.extension.shared.StringRef.sf;
|
||||
import static app.revanced.extension.shared.StringRef.str;
|
||||
import static app.revanced.extension.youtube.requests.Route.Method.GET;
|
||||
import static app.revanced.extension.shared.requests.Route.Method.GET;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
@@ -13,6 +12,8 @@ import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.preference.Preference;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Window;
|
||||
@@ -33,11 +34,11 @@ import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.youtube.requests.Requester;
|
||||
import app.revanced.extension.youtube.requests.Route;
|
||||
import app.revanced.extension.shared.requests.Requester;
|
||||
import app.revanced.extension.shared.requests.Route;
|
||||
|
||||
/**
|
||||
* Opens a dialog showing the links from {@link SocialLinksRoutes}.
|
||||
* Opens a dialog showing official links.
|
||||
*/
|
||||
@SuppressWarnings({"unused", "deprecation"})
|
||||
public class ReVancedAboutPreference extends Preference {
|
||||
@@ -72,7 +73,16 @@ public class ReVancedAboutPreference extends Preference {
|
||||
return Color.BLACK;
|
||||
}
|
||||
|
||||
private String createDialogHtml(WebLink[] socialLinks) {
|
||||
/**
|
||||
* Apps that do not support bundling resources must override this.
|
||||
*
|
||||
* @return A localized string to display for the key.
|
||||
*/
|
||||
protected String getString(String key, Object ... args) {
|
||||
return str(key, args);
|
||||
}
|
||||
|
||||
private String createDialogHtml(WebLink[] aboutLinks) {
|
||||
final boolean isNetworkConnected = Utils.isNetworkConnected();
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@@ -91,7 +101,7 @@ public class ReVancedAboutPreference extends Preference {
|
||||
builder.append("<img style=\"width: 100px; height: 100px;\" "
|
||||
// Hide the image if it does not load.
|
||||
+ "onerror=\"this.style.display='none';\" "
|
||||
+ "src=\"https://revanced.app/favicon.ico\" />");
|
||||
+ "src=\"").append(AboutLinksRoutes.aboutLogoUrl).append("\" />");
|
||||
}
|
||||
|
||||
String patchesVersion = Utils.getPatchesReleaseVersion();
|
||||
@@ -103,29 +113,29 @@ public class ReVancedAboutPreference extends Preference {
|
||||
|
||||
builder.append("<p>")
|
||||
// Replace hyphens with non breaking dashes so the version number does not break lines.
|
||||
.append(useNonBreakingHyphens(str("revanced_settings_about_links_body", patchesVersion)))
|
||||
.append(useNonBreakingHyphens(getString("revanced_settings_about_links_body", patchesVersion)))
|
||||
.append("</p>");
|
||||
|
||||
// Add a disclaimer if using a dev release.
|
||||
if (patchesVersion.contains("dev")) {
|
||||
builder.append("<h3>")
|
||||
// English text 'Pre-release' can break lines.
|
||||
.append(useNonBreakingHyphens(str("revanced_settings_about_links_dev_header")))
|
||||
.append(useNonBreakingHyphens(getString("revanced_settings_about_links_dev_header")))
|
||||
.append("</h3>");
|
||||
|
||||
builder.append("<p>")
|
||||
.append(str("revanced_settings_about_links_dev_body"))
|
||||
.append(getString("revanced_settings_about_links_dev_body"))
|
||||
.append("</p>");
|
||||
}
|
||||
|
||||
builder.append("<h2 style=\"margin-top: 30px;\">")
|
||||
.append(str("revanced_settings_about_links_header"))
|
||||
.append(getString("revanced_settings_about_links_header"))
|
||||
.append("</h2>");
|
||||
|
||||
builder.append("<div>");
|
||||
for (WebLink social : socialLinks) {
|
||||
for (WebLink link : aboutLinks) {
|
||||
builder.append("<div style=\"margin-bottom: 20px;\">");
|
||||
builder.append(String.format("<a href=\"%s\">%s</a>", social.url, social.name));
|
||||
builder.append(String.format("<a href=\"%s\">%s</a>", link.url, link.name));
|
||||
builder.append("</div>");
|
||||
}
|
||||
builder.append("</div>");
|
||||
@@ -137,25 +147,44 @@ public class ReVancedAboutPreference extends Preference {
|
||||
{
|
||||
setOnPreferenceClickListener(pref -> {
|
||||
// Show a progress spinner if the social links are not fetched yet.
|
||||
if (!SocialLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
|
||||
if (!AboutLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
|
||||
// Show a progress spinner, but only if the api fetch takes more than a half a second.
|
||||
final long delayToShowProgressSpinner = 500;
|
||||
ProgressDialog progress = new ProgressDialog(getContext());
|
||||
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
progress.show();
|
||||
Utils.runOnBackgroundThread(() -> fetchLinksAndShowDialog(progress));
|
||||
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
Runnable showDialogRunnable = progress::show;
|
||||
handler.postDelayed(showDialogRunnable, delayToShowProgressSpinner);
|
||||
|
||||
Utils.runOnBackgroundThread(() ->
|
||||
fetchLinksAndShowDialog(handler, showDialogRunnable, progress));
|
||||
} else {
|
||||
// No network call required and can run now.
|
||||
fetchLinksAndShowDialog(null);
|
||||
fetchLinksAndShowDialog(null, null, null);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void fetchLinksAndShowDialog(@Nullable ProgressDialog progress) {
|
||||
WebLink[] socialLinks = SocialLinksRoutes.fetchSocialLinks();
|
||||
String htmlDialog = createDialogHtml(socialLinks);
|
||||
private void fetchLinksAndShowDialog(@Nullable Handler handler,
|
||||
Runnable showDialogRunnable,
|
||||
@Nullable ProgressDialog progress) {
|
||||
WebLink[] links = AboutLinksRoutes.fetchAboutLinks();
|
||||
String htmlDialog = createDialogHtml(links);
|
||||
|
||||
// Enable to randomly force a delay to debug the spinner logic.
|
||||
final boolean debugSpinnerDelayLogic = false;
|
||||
//noinspection ConstantConditions
|
||||
if (debugSpinnerDelayLogic && handler != null && Math.random() < 0.5f) {
|
||||
Utils.doNothingForDuration((long) (Math.random() * 4000));
|
||||
}
|
||||
|
||||
Utils.runOnMainThreadNowOrLater(() -> {
|
||||
if (handler != null) {
|
||||
handler.removeCallbacks(showDialogRunnable);
|
||||
}
|
||||
if (progress != null) {
|
||||
progress.dismiss();
|
||||
}
|
||||
@@ -224,7 +253,7 @@ class WebViewDialog extends Dialog {
|
||||
|
||||
class WebLink {
|
||||
final boolean preferred;
|
||||
final String name;
|
||||
String name;
|
||||
final String url;
|
||||
|
||||
WebLink(JSONObject json) throws JSONException {
|
||||
@@ -243,7 +272,7 @@ class WebLink {
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ReVancedSocialLink{" +
|
||||
return "WebLink{" +
|
||||
"preferred=" + preferred +
|
||||
", name='" + name + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
@@ -251,25 +280,21 @@ class WebLink {
|
||||
}
|
||||
}
|
||||
|
||||
class SocialLinksRoutes {
|
||||
class AboutLinksRoutes {
|
||||
/**
|
||||
* Simple link to the website donate page,
|
||||
* rather than fetching and parsing the donation links using the API.
|
||||
* Backup icon url if the API call fails.
|
||||
*/
|
||||
public static final WebLink DONATE_LINK = new WebLink(true,
|
||||
sf("revanced_settings_about_links_donate").toString(),
|
||||
"https://revanced.app/donate");
|
||||
public static volatile String aboutLogoUrl = "https://revanced.app/favicon.ico";
|
||||
|
||||
/**
|
||||
* Links to use if fetch links api call fails.
|
||||
*/
|
||||
private static final WebLink[] NO_CONNECTION_STATIC_LINKS = {
|
||||
new WebLink(true, "ReVanced.app", "https://revanced.app"),
|
||||
DONATE_LINK,
|
||||
new WebLink(true, "ReVanced.app", "https://revanced.app")
|
||||
};
|
||||
|
||||
private static final String SOCIAL_LINKS_PROVIDER = "https://api.revanced.app/v2";
|
||||
private static final Route.CompiledRoute GET_SOCIAL = new Route(GET, "/socials").compile();
|
||||
private static final String SOCIAL_LINKS_PROVIDER = "https://api.revanced.app/v4";
|
||||
private static final Route.CompiledRoute GET_SOCIAL = new Route(GET, "/about").compile();
|
||||
|
||||
@Nullable
|
||||
private static volatile WebLink[] fetchedLinks;
|
||||
@@ -278,7 +303,7 @@ class SocialLinksRoutes {
|
||||
return fetchedLinks != null;
|
||||
}
|
||||
|
||||
static WebLink[] fetchSocialLinks() {
|
||||
static WebLink[] fetchAboutLinks() {
|
||||
try {
|
||||
if (hasFetchedLinks()) return fetchedLinks;
|
||||
|
||||
@@ -298,11 +323,22 @@ class SocialLinksRoutes {
|
||||
}
|
||||
|
||||
JSONObject json = Requester.parseJSONObjectAndDisconnect(connection);
|
||||
JSONArray socials = json.getJSONArray("socials");
|
||||
aboutLogoUrl = json.getJSONObject("branding").getString("logo");
|
||||
|
||||
List<WebLink> links = new ArrayList<>();
|
||||
|
||||
links.add(DONATE_LINK); // Show donate link first.
|
||||
JSONArray donations = json.getJSONObject("donations").getJSONArray("links");
|
||||
for (int i = 0, length = donations.length(); i < length; i++) {
|
||||
WebLink link = new WebLink(donations.getJSONObject(i));
|
||||
if (link.preferred) {
|
||||
// This could be localized, but TikTok does not support localized resources.
|
||||
// All link names returned by the api are also non localized.
|
||||
link.name = "Donate";
|
||||
links.add(link);
|
||||
}
|
||||
}
|
||||
|
||||
JSONArray socials = json.getJSONArray("socials");
|
||||
for (int i = 0, length = socials.length(); i < length; i++) {
|
||||
WebLink link = new WebLink(socials.getJSONObject(i));
|
||||
links.add(link);
|
||||
@@ -0,0 +1,102 @@
|
||||
package app.revanced.extension.shared.spoof;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public enum AudioStreamLanguage {
|
||||
DEFAULT,
|
||||
|
||||
// Language codes found in locale_config.xml
|
||||
// Region specific variants of Chinese/English/Spanish/French have been removed.
|
||||
AF,
|
||||
AM,
|
||||
AR,
|
||||
AS,
|
||||
AZ,
|
||||
BE,
|
||||
BG,
|
||||
BN,
|
||||
BS,
|
||||
CA,
|
||||
CS,
|
||||
DA,
|
||||
DE,
|
||||
EL,
|
||||
EN,
|
||||
ES,
|
||||
ET,
|
||||
EU,
|
||||
FA,
|
||||
FI,
|
||||
FR,
|
||||
GL,
|
||||
GU,
|
||||
HI,
|
||||
HE, // App uses obsolete 'IW' and 'HE' is modern ISO code.
|
||||
HR,
|
||||
HU,
|
||||
HY,
|
||||
ID,
|
||||
IS,
|
||||
IT,
|
||||
JA,
|
||||
KA,
|
||||
KK,
|
||||
KM,
|
||||
KN,
|
||||
KO,
|
||||
KY,
|
||||
LO,
|
||||
LT,
|
||||
LV,
|
||||
MK,
|
||||
ML,
|
||||
MN,
|
||||
MR,
|
||||
MS,
|
||||
MY,
|
||||
NE,
|
||||
NL,
|
||||
NB,
|
||||
OR,
|
||||
PA,
|
||||
PL,
|
||||
PT_BR,
|
||||
PT_PT,
|
||||
RO,
|
||||
RU,
|
||||
SI,
|
||||
SK,
|
||||
SL,
|
||||
SQ,
|
||||
SR,
|
||||
SV,
|
||||
SW,
|
||||
TA,
|
||||
TE,
|
||||
TH,
|
||||
TL,
|
||||
TR,
|
||||
UK,
|
||||
UR,
|
||||
UZ,
|
||||
VI,
|
||||
ZH,
|
||||
ZU;
|
||||
|
||||
private final String iso639_1;
|
||||
|
||||
AudioStreamLanguage() {
|
||||
iso639_1 = name().replace('_', '-');
|
||||
}
|
||||
|
||||
public String getIso639_1() {
|
||||
// Changing the app language does not force the app to completely restart,
|
||||
// so the default needs to be the current language and not a static field.
|
||||
if (this == DEFAULT) {
|
||||
// Android VR requires uppercase language code.
|
||||
return Locale.getDefault().toLanguageTag().toUpperCase(Locale.US);
|
||||
}
|
||||
|
||||
return iso639_1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package app.revanced.extension.shared.spoof;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
|
||||
public enum ClientType {
|
||||
// Specific purpose for age restricted, or private videos, because the iOS client is not logged in.
|
||||
// https://dumps.tadiphone.dev/dumps/oculus/eureka
|
||||
ANDROID_VR(28,
|
||||
"Quest 3",
|
||||
"12",
|
||||
"com.google.android.apps.youtube.vr.oculus/1.56.21 (Linux; U; Android 12; GB) gzip",
|
||||
"32", // Android 12.1
|
||||
"1.56.21",
|
||||
true
|
||||
),
|
||||
// Specific for kids videos.
|
||||
IOS(5,
|
||||
forceAVC()
|
||||
? "iPhone12,5" // 11 Pro Max (last device with iOS 13)
|
||||
: "iPhone16,2", // 15 Pro Max
|
||||
// iOS 13 and earlier uses only AVC. 14+ adds VP9 and AV1.
|
||||
forceAVC()
|
||||
? "13.7.17H35" // Last release of iOS 13.
|
||||
: "17.5.1.21F90",
|
||||
forceAVC()
|
||||
? "com.google.ios.youtube/17.40.5 (iPhone; U; CPU iOS 13_7 like Mac OS X)"
|
||||
: "com.google.ios.youtube/19.47.7 (iPhone; U; CPU iOS 17_5_1 like Mac OS X)",
|
||||
null,
|
||||
// Version number should be a valid iOS release.
|
||||
// https://www.ipa4fun.com/history/185230
|
||||
forceAVC()
|
||||
// Some newer versions can also force AVC,
|
||||
// but 17.40 is the last version that supports iOS 13.
|
||||
? "17.40.5"
|
||||
: "19.47.7",
|
||||
false
|
||||
);
|
||||
|
||||
private static boolean forceAVC() {
|
||||
return BaseSettings.SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* YouTube
|
||||
* <a href="https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients">client type</a>
|
||||
*/
|
||||
public final int id;
|
||||
|
||||
/**
|
||||
* Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model)
|
||||
*/
|
||||
public final String deviceModel;
|
||||
|
||||
/**
|
||||
* Device OS version.
|
||||
*/
|
||||
public final String osVersion;
|
||||
|
||||
/**
|
||||
* Player user-agent.
|
||||
*/
|
||||
public final String userAgent;
|
||||
|
||||
/**
|
||||
* Android SDK version, equivalent to {@link Build.VERSION#SDK} (System property: ro.build.version.sdk)
|
||||
* Field is null if not applicable.
|
||||
*/
|
||||
@Nullable
|
||||
public final String androidSdkVersion;
|
||||
|
||||
/**
|
||||
* App version.
|
||||
*/
|
||||
public final String clientVersion;
|
||||
|
||||
/**
|
||||
* If the client can access the API logged in.
|
||||
*/
|
||||
public final boolean canLogin;
|
||||
|
||||
ClientType(int id,
|
||||
String deviceModel,
|
||||
String osVersion,
|
||||
String userAgent,
|
||||
@Nullable String androidSdkVersion,
|
||||
String clientVersion,
|
||||
boolean canLogin
|
||||
) {
|
||||
this.id = id;
|
||||
this.deviceModel = deviceModel;
|
||||
this.osVersion = osVersion;
|
||||
this.userAgent = userAgent;
|
||||
this.androidSdkVersion = androidSdkVersion;
|
||||
this.clientVersion = clientVersion;
|
||||
this.canLogin = canLogin;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.extension.youtube.patches.spoof;
|
||||
package app.revanced.extension.shared.spoof;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
@@ -12,20 +12,11 @@ import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.youtube.patches.spoof.requests.StreamingDataRequest;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofVideoStreamsPatch {
|
||||
public static final class ForceiOSAVCAvailability implements Setting.Availability {
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return Settings.SPOOF_VIDEO_STREAMS.get() && Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS;
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean SPOOF_STREAMING_DATA = Settings.SPOOF_VIDEO_STREAMS.get();
|
||||
|
||||
private static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_VIDEO_STREAMS.get();
|
||||
/**
|
||||
* Any unreachable ip address. Used to intentionally fail requests.
|
||||
*/
|
||||
@@ -165,4 +156,11 @@ public class SpoofVideoStreamsPatch {
|
||||
|
||||
return postData;
|
||||
}
|
||||
|
||||
public static final class ForceiOSAVCAvailability implements Setting.Availability {
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.extension.youtube.patches.spoof.requests;
|
||||
package app.revanced.extension.shared.spoof.requests;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -7,20 +7,19 @@ import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.youtube.patches.spoof.ClientType;
|
||||
import app.revanced.extension.youtube.requests.Requester;
|
||||
import app.revanced.extension.youtube.requests.Route;
|
||||
import app.revanced.extension.shared.requests.Requester;
|
||||
import app.revanced.extension.shared.requests.Route;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
|
||||
final class PlayerRoutes {
|
||||
private static final String YT_API_URL = "https://youtubei.googleapis.com/youtubei/v1/";
|
||||
|
||||
static final Route.CompiledRoute GET_STREAMING_DATA = new Route(
|
||||
Route.Method.POST,
|
||||
"player" +
|
||||
"?fields=streamingData" +
|
||||
"&alt=proto"
|
||||
).compile();
|
||||
|
||||
private static final String YT_API_URL = "https://youtubei.googleapis.com/youtubei/v1/";
|
||||
/**
|
||||
* TCP connection and HTTP read timeout
|
||||
*/
|
||||
@@ -30,20 +29,20 @@ final class PlayerRoutes {
|
||||
}
|
||||
|
||||
static String createInnertubeBody(ClientType clientType) {
|
||||
JSONObject innerTubeBody = new JSONObject();
|
||||
JSONObject innerTubeBody = new JSONObject();
|
||||
|
||||
try {
|
||||
JSONObject context = new JSONObject();
|
||||
|
||||
JSONObject client = new JSONObject();
|
||||
client.put("hl", BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get().getIso639_1());
|
||||
client.put("clientName", clientType.name());
|
||||
client.put("clientVersion", clientType.appVersion);
|
||||
client.put("deviceModel", clientType.model);
|
||||
client.put("clientVersion", clientType.clientVersion);
|
||||
client.put("deviceModel", clientType.deviceModel);
|
||||
client.put("osVersion", clientType.osVersion);
|
||||
if (clientType.androidSdkVersion != null) {
|
||||
client.put("androidSdkVersion", clientType.androidSdkVersion);
|
||||
}
|
||||
|
||||
context.put("client", client);
|
||||
|
||||
innerTubeBody.put("context", context);
|
||||
@@ -57,7 +56,9 @@ final class PlayerRoutes {
|
||||
return innerTubeBody.toString();
|
||||
}
|
||||
|
||||
/** @noinspection SameParameterValue*/
|
||||
/**
|
||||
* @noinspection SameParameterValue
|
||||
*/
|
||||
static HttpURLConnection getPlayerResponseConnectionFromRoute(Route.CompiledRoute route, ClientType clientType) throws IOException {
|
||||
var connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package app.revanced.extension.youtube.patches.spoof.requests;
|
||||
package app.revanced.extension.shared.spoof.requests;
|
||||
|
||||
import static app.revanced.extension.youtube.patches.spoof.requests.PlayerRoutes.GET_STREAMING_DATA;
|
||||
import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_STREAMING_DATA;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -22,13 +22,12 @@ import java.util.concurrent.TimeoutException;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.youtube.patches.spoof.ClientType;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
|
||||
/**
|
||||
* Video streaming data. Fetching is tied to the behavior YT uses,
|
||||
* where this class fetches the streams only when YT fetches.
|
||||
*
|
||||
* <p>
|
||||
* Effectively the cache expiration of these fetches is the same as the stock app,
|
||||
* since the stock app would not use expired streams and therefor
|
||||
* the extension replace stream hook is called only if YT
|
||||
@@ -37,38 +36,20 @@ import app.revanced.extension.youtube.settings.Settings;
|
||||
public class StreamingDataRequest {
|
||||
|
||||
private static final ClientType[] CLIENT_ORDER_TO_USE;
|
||||
|
||||
static {
|
||||
ClientType[] allClientTypes = ClientType.values();
|
||||
ClientType preferredClient = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
||||
|
||||
CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length];
|
||||
CLIENT_ORDER_TO_USE[0] = preferredClient;
|
||||
|
||||
int i = 1;
|
||||
for (ClientType c : allClientTypes) {
|
||||
if (c != preferredClient) {
|
||||
CLIENT_ORDER_TO_USE[i++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
private static final String[] REQUEST_HEADER_KEYS = {
|
||||
"Authorization", // Available only to logged in users.
|
||||
AUTHORIZATION_HEADER, // Available only to logged-in users.
|
||||
"X-GOOG-API-FORMAT-VERSION",
|
||||
"X-Goog-Visitor-Id"
|
||||
};
|
||||
|
||||
/**
|
||||
* TCP connection and HTTP read timeout.
|
||||
*/
|
||||
private static final int HTTP_TIMEOUT_MILLISECONDS = 10 * 1000;
|
||||
|
||||
/**
|
||||
* Any arbitrarily large value, but must be at least twice {@link #HTTP_TIMEOUT_MILLISECONDS}
|
||||
*/
|
||||
private static final int MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000;
|
||||
|
||||
private static final Map<String, StreamingDataRequest> cache = Collections.synchronizedMap(
|
||||
new LinkedHashMap<>(100) {
|
||||
/**
|
||||
@@ -86,8 +67,32 @@ public class StreamingDataRequest {
|
||||
}
|
||||
});
|
||||
|
||||
static {
|
||||
ClientType[] allClientTypes = ClientType.values();
|
||||
ClientType preferredClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
||||
|
||||
CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length];
|
||||
CLIENT_ORDER_TO_USE[0] = preferredClient;
|
||||
|
||||
int i = 1;
|
||||
for (ClientType c : allClientTypes) {
|
||||
if (c != preferredClient) {
|
||||
CLIENT_ORDER_TO_USE[i++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final String videoId;
|
||||
private final Future<ByteBuffer> future;
|
||||
|
||||
private StreamingDataRequest(String videoId, Map<String, String> playerHeaders) {
|
||||
Objects.requireNonNull(playerHeaders);
|
||||
this.videoId = videoId;
|
||||
this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId, playerHeaders));
|
||||
}
|
||||
|
||||
public static void fetchRequest(String videoId, Map<String, String> fetchHeaders) {
|
||||
// Always fetch, even if there is a existing request for the same video.
|
||||
// Always fetch, even if there is an existing request for the same video.
|
||||
cache.put(videoId, new StreamingDataRequest(videoId, fetchHeaders));
|
||||
}
|
||||
|
||||
@@ -119,6 +124,10 @@ public class StreamingDataRequest {
|
||||
connection.setReadTimeout(HTTP_TIMEOUT_MILLISECONDS);
|
||||
|
||||
for (String key : REQUEST_HEADER_KEYS) {
|
||||
if (!clientType.canLogin && key.equals(AUTHORIZATION_HEADER)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = playerHeaders.get(key);
|
||||
if (value != null) {
|
||||
connection.setRequestProperty(key, value);
|
||||
@@ -186,15 +195,6 @@ public class StreamingDataRequest {
|
||||
return null;
|
||||
}
|
||||
|
||||
private final String videoId;
|
||||
private final Future<ByteBuffer> future;
|
||||
|
||||
private StreamingDataRequest(String videoId, Map<String, String> playerHeaders) {
|
||||
Objects.requireNonNull(playerHeaders);
|
||||
this.videoId = videoId;
|
||||
this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId, playerHeaders));
|
||||
}
|
||||
|
||||
public boolean fetchCompleted() {
|
||||
return future.isDone();
|
||||
}
|
||||
@@ -1,4 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
</manifest>
|
||||
<manifest/>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package app.revanced.extension.shared.settings;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||
|
||||
/**
|
||||
* Settings shared across multiple apps.
|
||||
*
|
||||
* To ensure this class is loaded when the UI is created, app specific setting bundles should extend
|
||||
* or reference this class.
|
||||
*/
|
||||
public class BaseSettings {
|
||||
public static final BooleanSetting DEBUG = new BooleanSetting("revanced_debug", FALSE);
|
||||
public static final BooleanSetting DEBUG_STACKTRACE = new BooleanSetting("revanced_debug_stacktrace", FALSE, parent(DEBUG));
|
||||
public static final BooleanSetting DEBUG_TOAST_ON_ERROR = new BooleanSetting("revanced_debug_toast_on_error", TRUE, "revanced_debug_toast_on_error_user_dialog_message");
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package app.revanced.extension.youtube.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class FullscreenPanelsRemoverPatch {
|
||||
public static int getFullscreenPanelsVisibility() {
|
||||
return Settings.HIDE_FULLSCREEN_PANELS.get() ? View.GONE : View.VISIBLE;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package app.revanced.extension.youtube.patches.spoof;
|
||||
|
||||
import static app.revanced.extension.youtube.patches.spoof.DeviceHardwareSupport.allowAV1;
|
||||
import static app.revanced.extension.youtube.patches.spoof.DeviceHardwareSupport.allowVP9;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public enum ClientType {
|
||||
// https://dumps.tadiphone.dev/dumps/oculus/eureka
|
||||
IOS(5,
|
||||
// iPhone 15 supports AV1 hardware decoding.
|
||||
// Only use if this Android device also has hardware decoding.
|
||||
allowAV1()
|
||||
? "iPhone16,2" // 15 Pro Max
|
||||
: "iPhone11,4", // XS Max
|
||||
// iOS 14+ forces VP9.
|
||||
allowVP9()
|
||||
? "17.5.1.21F90"
|
||||
: "13.7.17H35",
|
||||
allowVP9()
|
||||
? "com.google.ios.youtube/19.10.7 (iPhone; U; CPU iOS 17_5_1 like Mac OS X)"
|
||||
: "com.google.ios.youtube/19.10.7 (iPhone; U; CPU iOS 13_7 like Mac OS X)",
|
||||
null,
|
||||
// Version number should be a valid iOS release.
|
||||
// https://www.ipa4fun.com/history/185230
|
||||
"19.10.7"
|
||||
),
|
||||
ANDROID_VR(28,
|
||||
"Quest 3",
|
||||
"12",
|
||||
"com.google.android.apps.youtube.vr.oculus/1.56.21 (Linux; U; Android 12; GB) gzip",
|
||||
"32", // Android 12.1
|
||||
"1.56.21"
|
||||
);
|
||||
|
||||
/**
|
||||
* YouTube
|
||||
* <a href="https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients">client type</a>
|
||||
*/
|
||||
public final int id;
|
||||
|
||||
/**
|
||||
* Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model)
|
||||
*/
|
||||
public final String model;
|
||||
|
||||
/**
|
||||
* Device OS version.
|
||||
*/
|
||||
public final String osVersion;
|
||||
|
||||
/**
|
||||
* Player user-agent.
|
||||
*/
|
||||
public final String userAgent;
|
||||
|
||||
/**
|
||||
* Android SDK version, equivalent to {@link Build.VERSION#SDK} (System property: ro.build.version.sdk)
|
||||
* Field is null if not applicable.
|
||||
*/
|
||||
@Nullable
|
||||
public final String androidSdkVersion;
|
||||
|
||||
/**
|
||||
* App version.
|
||||
*/
|
||||
public final String appVersion;
|
||||
|
||||
ClientType(int id, String model, String osVersion, String userAgent, @Nullable String androidSdkVersion, String appVersion) {
|
||||
this.id = id;
|
||||
this.model = model;
|
||||
this.osVersion = osVersion;
|
||||
this.userAgent = userAgent;
|
||||
this.androidSdkVersion = androidSdkVersion;
|
||||
this.appVersion = appVersion;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package app.revanced.extension.youtube.patches.spoof;
|
||||
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaCodecList;
|
||||
import android.os.Build;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
public class DeviceHardwareSupport {
|
||||
public static final boolean DEVICE_HAS_HARDWARE_DECODING_VP9;
|
||||
public static final boolean DEVICE_HAS_HARDWARE_DECODING_AV1;
|
||||
|
||||
static {
|
||||
boolean vp9found = false;
|
||||
boolean av1found = false;
|
||||
MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
|
||||
final boolean deviceIsAndroidTenOrLater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
|
||||
|
||||
for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {
|
||||
final boolean isHardwareAccelerated = deviceIsAndroidTenOrLater
|
||||
? codecInfo.isHardwareAccelerated()
|
||||
: !codecInfo.getName().startsWith("OMX.google"); // Software decoder.
|
||||
if (isHardwareAccelerated && !codecInfo.isEncoder()) {
|
||||
for (String type : codecInfo.getSupportedTypes()) {
|
||||
if (type.equalsIgnoreCase("video/x-vnd.on2.vp9")) {
|
||||
vp9found = true;
|
||||
} else if (type.equalsIgnoreCase("video/av01")) {
|
||||
av1found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEVICE_HAS_HARDWARE_DECODING_VP9 = vp9found;
|
||||
DEVICE_HAS_HARDWARE_DECODING_AV1 = av1found;
|
||||
|
||||
Logger.printDebug(() -> DEVICE_HAS_HARDWARE_DECODING_AV1
|
||||
? "Device supports AV1 hardware decoding\n"
|
||||
: "Device does not support AV1 hardware decoding\n"
|
||||
+ (DEVICE_HAS_HARDWARE_DECODING_VP9
|
||||
? "Device supports VP9 hardware decoding"
|
||||
: "Device does not support VP9 hardware decoding"));
|
||||
}
|
||||
|
||||
public static boolean allowVP9() {
|
||||
return DEVICE_HAS_HARDWARE_DECODING_VP9 && !Settings.SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC.get();
|
||||
}
|
||||
|
||||
public static boolean allowAV1() {
|
||||
return allowVP9() && DEVICE_HAS_HARDWARE_DECODING_AV1;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package app.revanced.extension.youtube.settings.preference;
|
||||
|
||||
import static app.revanced.extension.shared.StringRef.str;
|
||||
import static app.revanced.extension.youtube.patches.spoof.DeviceHardwareSupport.DEVICE_HAS_HARDWARE_DECODING_VP9;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.SwitchPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
@SuppressWarnings({"unused", "deprecation"})
|
||||
public class ForceAVCSpoofingPreference extends SwitchPreference {
|
||||
{
|
||||
if (!DEVICE_HAS_HARDWARE_DECODING_VP9) {
|
||||
setSummaryOn(str("revanced_spoof_video_streams_ios_force_avc_no_hardware_vp9_summary_on"));
|
||||
}
|
||||
}
|
||||
|
||||
public ForceAVCSpoofingPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
public ForceAVCSpoofingPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
public ForceAVCSpoofingPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
public ForceAVCSpoofingPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
if (DEVICE_HAS_HARDWARE_DECODING_VP9) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Temporarily remove the preference key to allow changing this preference without
|
||||
// causing the settings UI listeners from showing reboot dialogs by the changes made here.
|
||||
String key = getKey();
|
||||
setKey(null);
|
||||
|
||||
// This setting cannot be changed by the user.
|
||||
super.setEnabled(false);
|
||||
super.setChecked(true);
|
||||
|
||||
setKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
|
||||
updateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) {
|
||||
super.setChecked(checked);
|
||||
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package app.revanced.extension.youtube.settings.preference;
|
||||
|
||||
import android.os.Build;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment;
|
||||
import app.revanced.extension.youtube.patches.playback.speed.CustomPlaybackSpeedPatch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
/**
|
||||
* Preference fragment for ReVanced settings.
|
||||
*
|
||||
* @noinspection deprecation
|
||||
*/
|
||||
public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@Override
|
||||
protected void initialize() {
|
||||
super.initialize();
|
||||
|
||||
try {
|
||||
// If the preference was included, then initialize it based on the available playback speed.
|
||||
Preference defaultSpeedPreference = findPreference(Settings.PLAYBACK_SPEED_DEFAULT.key);
|
||||
if (defaultSpeedPreference instanceof ListPreference) {
|
||||
CustomPlaybackSpeedPatch.initializeListPreference((ListPreference) defaultSpeedPreference);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "initialize failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
||||
@@ -1,11 +0,0 @@
|
||||
extension {
|
||||
name = "extensions/all/connectivity/wifi/spoof/spoof-wifi.rve"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
5
extensions/syncforreddit/build.gradle.kts
Normal file
5
extensions/syncforreddit/build.gradle.kts
Normal file
@@ -0,0 +1,5 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:shared:library"))
|
||||
compileOnly(project(":extensions:syncforreddit:stub"))
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
1
extensions/syncforreddit/src/main/AndroidManifest.xml
Normal file
1
extensions/syncforreddit/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
17
extensions/syncforreddit/stub/build.gradle.kts
Normal file
17
extensions/syncforreddit/stub/build.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
id(libs.plugins.android.library.get().pluginId)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
compileSdk = 33
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
5
extensions/tiktok/build.gradle.kts
Normal file
5
extensions/tiktok/build.gradle.kts
Normal file
@@ -0,0 +1,5 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:shared:library"))
|
||||
compileOnly(project(":extensions:tiktok:stub"))
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
1
extensions/tiktok/src/main/AndroidManifest.xml
Normal file
1
extensions/tiktok/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -0,0 +1,55 @@
|
||||
package app.revanced.extension.tiktok.settings.preference;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.settings.preference.ReVancedAboutPreference;
|
||||
|
||||
public class ReVancedTikTokAboutPreference extends ReVancedAboutPreference {
|
||||
|
||||
/**
|
||||
* Because resources cannot be added to TikTok,
|
||||
* these strings are copied from the shared strings.xml file.
|
||||
*
|
||||
* Changes here must also be made in strings.xml
|
||||
*/
|
||||
private final Map<String, String> aboutStrings = Map.of(
|
||||
"revanced_settings_about_links_body", "You are using ReVanced Patches version <i>%s</i>",
|
||||
"revanced_settings_about_links_dev_header", "Note",
|
||||
"revanced_settings_about_links_dev_body", "This version is a pre-release and you may experience unexpected issues",
|
||||
"revanced_settings_about_links_header", "Official links"
|
||||
);
|
||||
|
||||
{
|
||||
//noinspection deprecation
|
||||
setTitle("About");
|
||||
}
|
||||
|
||||
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
public ReVancedTikTokAboutPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getString(String key, Object ... args) {
|
||||
String format = aboutStrings.get(key);
|
||||
|
||||
if (format == null) {
|
||||
Logger.printException(() -> "Unknown key: " + key);
|
||||
return "";
|
||||
}
|
||||
|
||||
return String.format(format, args);
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,14 @@ import android.content.Context;
|
||||
import android.preference.PreferenceScreen;
|
||||
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.tiktok.settings.preference.ReVancedTikTokAboutPreference;
|
||||
import app.revanced.extension.tiktok.settings.preference.TogglePreference;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
||||
public ExtensionPreferenceCategory(Context context, PreferenceScreen screen) {
|
||||
super(context, screen);
|
||||
setTitle("Extension");
|
||||
setTitle("Miscellaneous");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -20,6 +21,8 @@ public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
||||
|
||||
@Override
|
||||
public void addPreferences(Context context) {
|
||||
addPreference(new ReVancedTikTokAboutPreference(context));
|
||||
|
||||
addPreference(new TogglePreference(context,
|
||||
"Enable debug log",
|
||||
"Show extension debug log.",
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user