You've already forked revanced-integrations
mirror of
https://github.com/revanced/revanced-integrations
synced 2025-11-19 03:23:27 +01:00
Compare commits
59 Commits
v0.111.1-d
...
v0.115.0-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2a8c33109 | ||
|
|
d3f523f9dd | ||
|
|
1c2976526e | ||
|
|
18f29004b8 | ||
|
|
0207496926 | ||
|
|
b2085aeebf | ||
|
|
ac8de0a3b7 | ||
|
|
d4bc6cff68 | ||
|
|
e906c6d3a2 | ||
|
|
fdc56bf68e | ||
|
|
ea7bc57375 | ||
|
|
8ef81235d7 | ||
|
|
c7d2a9b310 | ||
|
|
d7fc06a647 | ||
|
|
67cf3e2eb4 | ||
|
|
dcd97f3143 | ||
|
|
e1011e42df | ||
|
|
e2f25cd5ae | ||
|
|
2a784a47d1 | ||
|
|
dc591ac7ed | ||
|
|
8c61561d63 | ||
|
|
8920e1dfe8 | ||
|
|
59f7733f99 | ||
|
|
6104e263ce | ||
|
|
a0f831ac3f | ||
|
|
2f39f32a52 | ||
|
|
821a32ee40 | ||
|
|
d3533824f4 | ||
|
|
7a28c2fa13 | ||
|
|
5056adbc3c | ||
|
|
9f21c7268e | ||
|
|
42750409b7 | ||
|
|
630776fd35 | ||
|
|
0e18f209dc | ||
|
|
a2b1630df8 | ||
|
|
e78ef6df9c | ||
|
|
f69492819e | ||
|
|
59850b2c04 | ||
|
|
cfc7081971 | ||
|
|
6f0248cc1a | ||
|
|
789e0c8bcb | ||
|
|
e783142741 | ||
|
|
dec7348203 | ||
|
|
7b61cc8567 | ||
|
|
b8b9edad64 | ||
|
|
be3955fee4 | ||
|
|
3da3ce9e9a | ||
|
|
ea7ee56276 | ||
|
|
8b01ca0c0e | ||
|
|
170685b920 | ||
|
|
f46cbaa3fe | ||
|
|
e9947fd66a | ||
|
|
d947de2e03 | ||
|
|
e9f797824e | ||
|
|
8afe82c0e0 | ||
|
|
bb9120ebae | ||
|
|
bc91b35994 | ||
|
|
f3f8026c1e | ||
|
|
12f3f97552 |
9
.gitattributes
vendored
Normal file
9
.gitattributes
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# Linux start script should use lf
|
||||
/gradlew text eol=lf
|
||||
|
||||
# These are Windows script files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -30,7 +30,6 @@ jobs:
|
||||
${{ runner.home }}/.gradle/caches
|
||||
${{ runner.home }}/.gradle/wrapper
|
||||
.gradle
|
||||
build
|
||||
node_modules
|
||||
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
|
||||
- name: Setup Java
|
||||
@@ -38,7 +37,7 @@ jobs:
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew clean --no-daemon
|
||||
run: ./gradlew build clean
|
||||
- name: Setup semantic-release
|
||||
run: npm install
|
||||
- name: Release
|
||||
|
||||
218
CHANGELOG.md
218
CHANGELOG.md
@@ -1,3 +1,221 @@
|
||||
# [0.115.0-dev.6](https://github.com/ReVanced/revanced-integrations/compare/v0.115.0-dev.5...v0.115.0-dev.6) (2023-08-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube:** fix potential litho filter thread race ([d3f523f](https://github.com/ReVanced/revanced-integrations/commit/d3f523f9dd5c3638cf9e2ba849b91e446daa99fa))
|
||||
|
||||
# [0.115.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v0.115.0-dev.4...v0.115.0-dev.5) (2023-08-01)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **YouTube:** Filter litho components using prefix tree ([#447](https://github.com/ReVanced/revanced-integrations/issues/447)) ([18f2900](https://github.com/ReVanced/revanced-integrations/commit/18f29004b8d570915a0228e292f1256785ac2cab))
|
||||
|
||||
# [0.115.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v0.115.0-dev.3...v0.115.0-dev.4) (2023-07-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube:** add `Player Flyout Menu` patch ([#416](https://github.com/ReVanced/revanced-integrations/issues/416)) ([b2085ae](https://github.com/ReVanced/revanced-integrations/commit/b2085aeebf4cfc21d69c0abfe545b382e2c82abe))
|
||||
|
||||
# [0.115.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.115.0-dev.2...v0.115.0-dev.3) (2023-07-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof App Version:** Remove 17.30.35 target ([e906c6d](https://github.com/ReVanced/revanced-integrations/commit/e906c6d3a2195c94c926f9903f1e4e66c3714e3e))
|
||||
|
||||
# [0.115.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.115.0-dev.1...v0.115.0-dev.2) (2023-07-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - SponsorBlock:** Fix skip highlight button showing when set to 'show in seekbar' ([ea7bc57](https://github.com/ReVanced/revanced-integrations/commit/ea7bc5737584ce967becd5b9e5d0d57f5d2fbc49))
|
||||
|
||||
# [0.115.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.114.0...v0.115.0-dev.1) (2023-07-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide layout components:** Hide `chips shelf` ([#448](https://github.com/ReVanced/revanced-integrations/issues/448)) ([c7d2a9b](https://github.com/ReVanced/revanced-integrations/commit/c7d2a9b3101439b241218c45d0c4b64012adab65))
|
||||
|
||||
# [0.114.0](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0...v0.114.0) (2023-07-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tiktok - Settings:** check for null when opening ads settings ([#443](https://github.com/ReVanced/revanced-integrations/issues/443)) ([8c61561](https://github.com/ReVanced/revanced-integrations/commit/8c61561d6375cfad3571cea98013b549ed6ecd6b))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **youtube/theme:** add a switch to enable/disable custom seekbar color ([#442](https://github.com/ReVanced/revanced-integrations/issues/442)) ([2a784a4](https://github.com/ReVanced/revanced-integrations/commit/2a784a47d18da90ce23fcd527eef1f6e2d8e166d))
|
||||
|
||||
# [0.114.0-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.113.1-dev.1...v0.114.0-dev.1) (2023-07-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **youtube/theme:** add a switch to enable/disable custom seekbar color ([#442](https://github.com/ReVanced/revanced-integrations/issues/442)) ([2a784a4](https://github.com/ReVanced/revanced-integrations/commit/2a784a47d18da90ce23fcd527eef1f6e2d8e166d))
|
||||
|
||||
## [0.113.1-dev.1](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0...v0.113.1-dev.1) (2023-07-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tiktok - Settings:** check for null when opening ads settings ([#443](https://github.com/ReVanced/revanced-integrations/issues/443)) ([8c61561](https://github.com/ReVanced/revanced-integrations/commit/8c61561d6375cfad3571cea98013b549ed6ecd6b))
|
||||
|
||||
# [0.113.0](https://github.com/ReVanced/revanced-integrations/compare/v0.112.0...v0.113.0) (2023-07-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tiktok - Settings:** bump compatibility ([#440](https://github.com/ReVanced/revanced-integrations/issues/440)) ([821a32e](https://github.com/ReVanced/revanced-integrations/commit/821a32ee40d7795cabedc40f24356c1c1069ddec))
|
||||
* **YouTube - Hide Shorts Components:** hide sound button ([a2b1630](https://github.com/ReVanced/revanced-integrations/commit/a2b1630df8d330f3c0cbf77e9ea46b9d1c51adde))
|
||||
* **YouTube - Spoof client:** show video time and chapters while using seekbar ([#435](https://github.com/ReVanced/revanced-integrations/issues/435)) ([a0f831a](https://github.com/ReVanced/revanced-integrations/commit/a0f831ac3f3773a0b47a0fb532d0bf58f6aa96d7))
|
||||
* **youtube/return-youtube-dislike:** fix dislikes not showing in some situations ([#439](https://github.com/ReVanced/revanced-integrations/issues/439)) ([7a28c2f](https://github.com/ReVanced/revanced-integrations/commit/7a28c2fa13438947931b8c41ef73b128a32530eb))
|
||||
* **youtube/sponsorblock:** fix some segments skipping slightly too late ([#436](https://github.com/ReVanced/revanced-integrations/issues/436)) ([f694928](https://github.com/ReVanced/revanced-integrations/commit/f69492819e52e0fd99c4e10390fd39f26c3a9c48))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide ads:** hide new type of buttoned ad ([9f21c72](https://github.com/ReVanced/revanced-integrations/commit/9f21c7268e5a08f542f5b090316486aadf4a5acd))
|
||||
* **youtube:** rename `video-speed` to `playback-speed` ([#438](https://github.com/ReVanced/revanced-integrations/issues/438)) ([630776f](https://github.com/ReVanced/revanced-integrations/commit/630776fd3514435dd83ef1c765a4f5b007e8e2f2))
|
||||
|
||||
# [0.113.0-dev.5](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0-dev.4...v0.113.0-dev.5) (2023-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof client:** show video time and chapters while using seekbar ([#435](https://github.com/ReVanced/revanced-integrations/issues/435)) ([a0f831a](https://github.com/ReVanced/revanced-integrations/commit/a0f831ac3f3773a0b47a0fb532d0bf58f6aa96d7))
|
||||
|
||||
# [0.113.0-dev.4](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0-dev.3...v0.113.0-dev.4) (2023-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tiktok - Settings:** bump compatibility ([#440](https://github.com/ReVanced/revanced-integrations/issues/440)) ([821a32e](https://github.com/ReVanced/revanced-integrations/commit/821a32ee40d7795cabedc40f24356c1c1069ddec))
|
||||
|
||||
# [0.113.0-dev.3](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0-dev.2...v0.113.0-dev.3) (2023-07-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/return-youtube-dislike:** fix dislikes not showing in some situations ([#439](https://github.com/ReVanced/revanced-integrations/issues/439)) ([7a28c2f](https://github.com/ReVanced/revanced-integrations/commit/7a28c2fa13438947931b8c41ef73b128a32530eb))
|
||||
|
||||
# [0.113.0-dev.2](https://github.com/ReVanced/revanced-integrations/compare/v0.113.0-dev.1...v0.113.0-dev.2) (2023-07-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide ads:** hide new type of buttoned ad ([9f21c72](https://github.com/ReVanced/revanced-integrations/commit/9f21c7268e5a08f542f5b090316486aadf4a5acd))
|
||||
|
||||
# [0.113.0-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.112.1-dev.2...v0.113.0-dev.1) (2023-07-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **youtube:** rename `video-speed` to `playback-speed` ([#438](https://github.com/revanced/revanced-integrations/issues/438)) ([630776f](https://github.com/revanced/revanced-integrations/commit/630776fd3514435dd83ef1c765a4f5b007e8e2f2))
|
||||
|
||||
## [0.112.1-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.112.1-dev.1...v0.112.1-dev.2) (2023-07-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide Shorts Components:** hide sound button ([a2b1630](https://github.com/revanced/revanced-integrations/commit/a2b1630df8d330f3c0cbf77e9ea46b9d1c51adde))
|
||||
|
||||
## [0.112.1-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.112.0...v0.112.1-dev.1) (2023-07-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/sponsorblock:** fix some segments skipping slightly too late ([#436](https://github.com/revanced/revanced-integrations/issues/436)) ([f694928](https://github.com/revanced/revanced-integrations/commit/f69492819e52e0fd99c4e10390fd39f26c3a9c48))
|
||||
|
||||
# [0.112.0](https://github.com/revanced/revanced-integrations/compare/v0.111.2...v0.112.0) (2023-07-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/hide-ads:** remove duplicate filter ([#432](https://github.com/revanced/revanced-integrations/issues/432)) ([ea7ee56](https://github.com/revanced/revanced-integrations/commit/ea7ee56276a4a88f156a06c8f614360561231908))
|
||||
* **youtube/hide-layout-components:** hide mix playlists ([789e0c8](https://github.com/revanced/revanced-integrations/commit/789e0c8bcb1c2e964abcc496144d2f614c36fc0e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* remove unnecessary notice ([be3955f](https://github.com/revanced/revanced-integrations/commit/be3955fee45d22966006156a5475ef91b6f2b981))
|
||||
* **youtube:** support version `18.23.35` ([#433](https://github.com/revanced/revanced-integrations/issues/433)) ([dec7348](https://github.com/revanced/revanced-integrations/commit/dec73482038b3cc8b2031fd876643f89d937d142))
|
||||
|
||||
# [0.112.0-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.112.0-dev.2...v0.112.0-dev.3) (2023-07-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/hide-layout-components:** hide mix playlists ([789e0c8](https://github.com/revanced/revanced-integrations/commit/789e0c8bcb1c2e964abcc496144d2f614c36fc0e))
|
||||
|
||||
# [0.112.0-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.112.0-dev.1...v0.112.0-dev.2) (2023-07-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **youtube:** support version `18.23.35` ([#433](https://github.com/revanced/revanced-integrations/issues/433)) ([dec7348](https://github.com/revanced/revanced-integrations/commit/dec73482038b3cc8b2031fd876643f89d937d142))
|
||||
|
||||
# [0.112.0-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.111.3-dev.1...v0.112.0-dev.1) (2023-07-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* remove unnecessary notice ([be3955f](https://github.com/revanced/revanced-integrations/commit/be3955fee45d22966006156a5475ef91b6f2b981))
|
||||
|
||||
## [0.111.3-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.111.2...v0.111.3-dev.1) (2023-07-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/hide-ads:** remove duplicate filter ([#432](https://github.com/revanced/revanced-integrations/issues/432)) ([ea7ee56](https://github.com/revanced/revanced-integrations/commit/ea7ee56276a4a88f156a06c8f614360561231908))
|
||||
|
||||
## [0.111.2](https://github.com/revanced/revanced-integrations/compare/v0.111.1...v0.111.2) (2023-07-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reddit/sanitize-sharing-links:** update patch to support latest app version ([#430](https://github.com/revanced/revanced-integrations/issues/430)) ([d947de2](https://github.com/revanced/revanced-integrations/commit/d947de2e03683889f11fc461dc53e08fee735ca8))
|
||||
* **youtube/spoof-signature-verification:** remove auto re-enable functionality ([#428](https://github.com/revanced/revanced-integrations/issues/428)) ([8afe82c](https://github.com/revanced/revanced-integrations/commit/8afe82c0e078880d58e3adef23618a6feaf52e7e))
|
||||
|
||||
## [0.111.2-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.111.2-dev.1...v0.111.2-dev.2) (2023-07-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reddit/sanitize-sharing-links:** update patch to support latest app version ([#430](https://github.com/revanced/revanced-integrations/issues/430)) ([d947de2](https://github.com/revanced/revanced-integrations/commit/d947de2e03683889f11fc461dc53e08fee735ca8))
|
||||
|
||||
## [0.111.2-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.111.1...v0.111.2-dev.1) (2023-07-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/spoof-signature-verification:** remove auto re-enable functionality ([#428](https://github.com/revanced/revanced-integrations/issues/428)) ([8afe82c](https://github.com/revanced/revanced-integrations/commit/8afe82c0e078880d58e3adef23618a6feaf52e7e))
|
||||
|
||||
## [0.111.1](https://github.com/revanced/revanced-integrations/compare/v0.111.0...v0.111.1) (2023-07-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/client-spoof:** update settings text for known side effects of spoof signature ([#424](https://github.com/revanced/revanced-integrations/issues/424)) ([d7a3973](https://github.com/revanced/revanced-integrations/commit/d7a3973ef1e6c4443fc4d89f063bc6bf3446bec3))
|
||||
* **youtube/disable-fullscreen-panels:** prompt to restart after turning on/off ([#426](https://github.com/revanced/revanced-integrations/issues/426)) ([328ecff](https://github.com/revanced/revanced-integrations/commit/328ecff18bf301ec8993bba49356f9813de1d901))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* return earlier when possible ([#427](https://github.com/revanced/revanced-integrations/issues/427)) ([12f3f97](https://github.com/revanced/revanced-integrations/commit/12f3f975525863e593216ecf36ca817d162474e1))
|
||||
|
||||
## [0.111.1-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.111.1-dev.2...v0.111.1-dev.3) (2023-06-27)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* return earlier when possible ([#427](https://github.com/revanced/revanced-integrations/issues/427)) ([12f3f97](https://github.com/revanced/revanced-integrations/commit/12f3f975525863e593216ecf36ca817d162474e1))
|
||||
|
||||
## [0.111.1-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.111.1-dev.1...v0.111.1-dev.2) (2023-06-25)
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideWatchInVRPatch {
|
||||
public static boolean hideWatchInVR() {
|
||||
return SettingsEnum.HIDE_WATCH_IN_VR.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -202,7 +202,13 @@ public class ReturnYouTubeDislikePatch {
|
||||
*/
|
||||
public static boolean setShortsDislikes(@NonNull View likeDislikeView) {
|
||||
try {
|
||||
if (!SettingsEnum.RYD_ENABLED.getBoolean() || !SettingsEnum.RYD_SHORTS.getBoolean()) {
|
||||
if (!SettingsEnum.RYD_ENABLED.getBoolean()) {
|
||||
return false;
|
||||
}
|
||||
if (!SettingsEnum.RYD_SHORTS.getBoolean()) {
|
||||
// Must clear the data here, in case a new video was loaded while PlayerType
|
||||
// suggested the video was not a short (can happen when spoofing to an old app version).
|
||||
ReturnYouTubeDislike.setCurrentVideoId(null);
|
||||
return false;
|
||||
}
|
||||
LogHelper.printDebug(() -> "setShortsDislikes");
|
||||
@@ -302,7 +308,7 @@ public class ReturnYouTubeDislikePatch {
|
||||
if (!videoId.equals(currentVideoId)) {
|
||||
currentVideoId = videoId;
|
||||
|
||||
final boolean noneHiddenOrMinimized = PlayerType.getCurrent().isNoneHiddenOrMinimized();
|
||||
final boolean noneHiddenOrMinimized = PlayerType.getCurrent().isNoneOrHidden();
|
||||
if (noneHiddenOrMinimized && !SettingsEnum.RYD_SHORTS.getBoolean()) {
|
||||
ReturnYouTubeDislike.setCurrentVideoId(null);
|
||||
return;
|
||||
|
||||
@@ -2,10 +2,13 @@ package app.revanced.integrations.patches;
|
||||
|
||||
import static app.revanced.integrations.utils.ReVancedUtils.containsAny;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.shared.PlayerType;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
|
||||
public class SpoofSignatureVerificationPatch {
|
||||
/**
|
||||
@@ -68,32 +71,24 @@ public class SpoofSignatureVerificationPatch {
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static boolean getSeekbarThumbnailOverrideValue() {
|
||||
return SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point. Runs off the main thread.
|
||||
* <p>
|
||||
* Used to check the response code of video playback requests made by YouTube.
|
||||
* Response code of interest is 403 that indicate a signature verification failure for the current request
|
||||
* Injection point.
|
||||
*
|
||||
* @param responseCode HTTP status code of the completed YouTube connection
|
||||
* @param view seekbar thumbnail view. Includes both shorts and regular videos.
|
||||
*/
|
||||
public static void onResponse(int responseCode) {
|
||||
try {
|
||||
if (responseCode < 400 || responseCode >= 500) {
|
||||
return; // everything normal
|
||||
}
|
||||
LogHelper.printDebug(() -> "YouTube HTTP status code: " + responseCode);
|
||||
|
||||
if (SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean()) {
|
||||
return; // already enabled
|
||||
}
|
||||
|
||||
SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.saveValue(true);
|
||||
ReVancedUtils.showToastLong("Spoofing app signature to prevent playback issues");
|
||||
// it would be great if the video could be forcefully reloaded, but currently there is no code to do this
|
||||
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(() -> "onResponse failure", ex);
|
||||
public static void seekbarImageViewCreated(ImageView view) {
|
||||
if (SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean()) {
|
||||
view.setVisibility(View.GONE);
|
||||
// Also hide the border around the thumbnail (otherwise a 1 pixel wide bordered frame is visible).
|
||||
ViewGroup parentLayout = (ViewGroup) view.getParent();
|
||||
parentLayout.setPadding(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public final class VideoInformation {
|
||||
@NonNull
|
||||
private static String videoId = "";
|
||||
private static long videoLength = 0;
|
||||
private static volatile long videoTime = -1; // must be volatile. Value is set off main thread from high precision patch hook
|
||||
private static long videoTime = -1;
|
||||
/**
|
||||
* The current playback speed
|
||||
*/
|
||||
@@ -98,17 +98,17 @@ public final class VideoInformation {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* Called off the main thread approximately every 50ms to 100ms
|
||||
* Called on the main thread every 1000ms.
|
||||
*
|
||||
* @param currentPlaybackTime The current playback time of the video in milliseconds.
|
||||
*/
|
||||
public static void setVideoTimeHighPrecision(final long currentPlaybackTime) {
|
||||
public static void setVideoTime(final long currentPlaybackTime) {
|
||||
videoTime = currentPlaybackTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek on the current video.
|
||||
* Does not function for playback of Shorts or Stories.
|
||||
* Does not function for playback of Shorts.
|
||||
*
|
||||
* Caution: If called from a videoTimeHook() callback,
|
||||
* this will cause a recursive call into the same videoTimeHook() callback.
|
||||
@@ -118,11 +118,6 @@ public final class VideoInformation {
|
||||
*/
|
||||
public static boolean seekTo(final long millisecond) {
|
||||
ReVancedUtils.verifyOnMainThread();
|
||||
if (seekMethod == null) {
|
||||
LogHelper.printException(() -> "seekMethod was null");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
LogHelper.printDebug(() -> "Seeking to " + millisecond);
|
||||
return (Boolean) seekMethod.invoke(playerControllerRef.get(), millisecond);
|
||||
@@ -137,7 +132,7 @@ public final class VideoInformation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Id of the current video playing. Includes Shorts and YouTube Stories.
|
||||
* Id of the current video playing. Includes Shorts.
|
||||
*
|
||||
* @return The id of the video. Empty string if not set yet.
|
||||
*/
|
||||
@@ -154,7 +149,7 @@ public final class VideoInformation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of the current video playing. Includes Shorts and YouTube Stories.
|
||||
* Length of the current video playing. Includes Shorts.
|
||||
*
|
||||
* @return The length of the video in milliseconds.
|
||||
* If the video is not yet loaded, or if the video is playing in the background with no video visible,
|
||||
@@ -165,14 +160,14 @@ public final class VideoInformation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Playback time of the current video playing.
|
||||
* Value can lag up to approximately 100ms behind the actual current video playback time.
|
||||
* Playback time of the current video playing. Includes Shorts.
|
||||
*
|
||||
* Note: Code inside a videoTimeHook patch callback
|
||||
* should use the callback video time and avoid using this method
|
||||
* (in situations of recursive hook callbacks, the value returned here may be outdated).
|
||||
* Value will lag behind the actual playback time by a variable amount based on the playback speed.
|
||||
*
|
||||
* Includes Shorts and YouTube Stories.
|
||||
* If playback speed is 2.0x, this value may be up to 2000ms behind the actual playback time.
|
||||
* If playback speed is 1.0x, this value may be up to 1000ms behind the actual playback time.
|
||||
* If playback speed is 0.5x, this value may be up to 500ms behind the actual playback time.
|
||||
* Etc.
|
||||
*
|
||||
* @return The time of the video in milliseconds. -1 if not set yet.
|
||||
*/
|
||||
@@ -192,7 +187,7 @@ public final class VideoInformation {
|
||||
* @see VideoState
|
||||
*/
|
||||
public static boolean isAtEndOfVideo() {
|
||||
return videoTime > 0 && videoLength > 0 && videoTime >= videoLength;
|
||||
return videoTime >= videoLength && videoLength > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,27 +2,32 @@ package app.revanced.integrations.patches.components;
|
||||
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
import app.revanced.integrations.utils.StringTrieSearch;
|
||||
|
||||
|
||||
public final class AdsFilter extends Filter {
|
||||
private final String[] exceptions;
|
||||
private final StringTrieSearch exceptions = new StringTrieSearch();
|
||||
|
||||
public AdsFilter() {
|
||||
exceptions = new String[]{
|
||||
exceptions.addPatterns(
|
||||
"home_video_with_context", // Don't filter anything in the home page video component.
|
||||
"related_video_with_context", // Don't filter anything in the related video component.
|
||||
"comment_thread", // Don't filter anything in the comments.
|
||||
"|comment.", // Don't filter anything in the comments replies.
|
||||
"library_recent_shelf",
|
||||
};
|
||||
"library_recent_shelf"
|
||||
);
|
||||
|
||||
final var buttonedAd = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_BUTTONED_ADS,
|
||||
"_buttoned_layout",
|
||||
"full_width_square_image_layout",
|
||||
"_ad_with",
|
||||
"text_image_button_group_layout",
|
||||
"video_display_button_group_layout",
|
||||
"landscape_image_wide_button_layout"
|
||||
);
|
||||
@@ -94,11 +99,12 @@ public final class AdsFilter extends Filter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFiltered(final String path, final String identifier, final byte[] _protobufBufferArray) {
|
||||
if (ReVancedUtils.containsAny(path, exceptions))
|
||||
public boolean isFiltered(String path, @Nullable String identifier, byte[] protobufBufferArray,
|
||||
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
|
||||
if (exceptions.matches(path))
|
||||
return false;
|
||||
|
||||
return super.isFiltered(path, identifier, _protobufBufferArray);
|
||||
return super.isFiltered(path, identifier, protobufBufferArray, matchedList, matchedGroup, matchedIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package app.revanced.integrations.patches.components;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
final class ButtonsFilter extends Filter {
|
||||
@@ -33,7 +35,8 @@ final class ButtonsFilter extends Filter {
|
||||
SettingsEnum.HIDE_ACTION_BUTTONS,
|
||||
"ContainerType|video_action_button",
|
||||
"|CellType|CollectionType|CellType|ContainerType|button.eml|"
|
||||
)
|
||||
),
|
||||
actionBarRule
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,10 +48,12 @@ final class ButtonsFilter extends Filter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFiltered(final String path, final String identifier, final byte[] _protobufBufferArray) {
|
||||
if (isEveryFilterGroupEnabled())
|
||||
if (actionBarRule.check(identifier).isFiltered()) return true;
|
||||
public boolean isFiltered(String path, @Nullable String identifier, byte[] protobufBufferArray,
|
||||
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
|
||||
if (matchedGroup == actionBarRule) {
|
||||
return isEveryFilterGroupEnabled();
|
||||
}
|
||||
|
||||
return super.isFiltered(path, identifier, _protobufBufferArray);
|
||||
return super.isFiltered(path, identifier, protobufBufferArray, matchedList, matchedGroup, matchedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,32 +2,32 @@ package app.revanced.integrations.patches.components;
|
||||
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
|
||||
import app.revanced.integrations.utils.StringTrieSearch;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public final class LayoutComponentsFilter extends Filter {
|
||||
private final String[] exceptions;
|
||||
|
||||
private final StringTrieSearch exceptions = new StringTrieSearch();
|
||||
private final CustomFilterGroup custom;
|
||||
|
||||
// region Mix playlists
|
||||
private final ByteArrayAsStringFilterGroup mixPlaylists;
|
||||
private final ByteArrayAsStringFilterGroup imageHosting;
|
||||
|
||||
// endregion
|
||||
private static final ByteArrayAsStringFilterGroup mixPlaylists = new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_MIX_PLAYLISTS,
|
||||
"&list="
|
||||
);
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public LayoutComponentsFilter() {
|
||||
exceptions = new String[]{
|
||||
exceptions.addPatterns(
|
||||
"home_video_with_context",
|
||||
"related_video_with_context",
|
||||
"comment_thread", // skip filtering anything in the comments
|
||||
"|comment.", // skip filtering anything in the comments replies
|
||||
"library_recent_shelf",
|
||||
};
|
||||
"library_recent_shelf"
|
||||
);
|
||||
|
||||
custom = new CustomFilterGroup(
|
||||
SettingsEnum.CUSTOM_FILTER,
|
||||
@@ -137,21 +137,11 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
"cell_divider" // layout residue (gray line above the buttoned ad),
|
||||
);
|
||||
|
||||
// region Mix playlists
|
||||
|
||||
mixPlaylists = new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_MIX_PLAYLISTS,
|
||||
"&list=",
|
||||
"YouTube Music"
|
||||
final var chipsShelf = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_CHIPS_SHELF,
|
||||
"chips_shelf"
|
||||
);
|
||||
|
||||
imageHosting = new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_MIX_PLAYLISTS, // Unused
|
||||
"ggpht.com"
|
||||
);
|
||||
|
||||
// endregion
|
||||
|
||||
this.pathFilterGroups.addAll(
|
||||
channelBar,
|
||||
communityPosts,
|
||||
@@ -171,52 +161,32 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
artistCard,
|
||||
imageShelf,
|
||||
subscribersCommunityGuidelines,
|
||||
channelMemberShelf
|
||||
);
|
||||
|
||||
final var carouselAd = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_GENERAL_ADS,
|
||||
"carousel_ad"
|
||||
channelMemberShelf,
|
||||
custom
|
||||
);
|
||||
|
||||
this.identifierFilterGroups.addAll(
|
||||
graySeparator,
|
||||
carouselAd
|
||||
chipsShelf
|
||||
);
|
||||
}
|
||||
|
||||
private boolean isMixPlaylistFiltered(final byte[] _protobufBufferArray) {
|
||||
if (!mixPlaylists.isEnabled()) return false;
|
||||
|
||||
// Two checks are required to prevent false positives.
|
||||
|
||||
// First check if the current buffer potentially contains a mix playlist.
|
||||
if (!mixPlaylists.check(_protobufBufferArray).isFiltered()) return false;
|
||||
|
||||
// Ensure that the buffer actually contains a mix playlist.
|
||||
return imageHosting.check(_protobufBufferArray).isFiltered();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFiltered(final String path, final String identifier, final byte[] _protobufBufferArray) {
|
||||
if (custom.isEnabled() && custom.check(path).isFiltered())
|
||||
return true;
|
||||
|
||||
if (ReVancedUtils.containsAny(path, exceptions))
|
||||
public boolean isFiltered(String path, @Nullable String identifier, byte[] protobufBufferArray,
|
||||
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
|
||||
if (matchedGroup != custom && exceptions.matches(path))
|
||||
return false; // Exceptions are not filtered.
|
||||
|
||||
if (super.isFiltered(path, identifier, _protobufBufferArray))
|
||||
return true;
|
||||
|
||||
return isMixPlaylistFiltered(_protobufBufferArray);
|
||||
return super.isFiltered(path, identifier, protobufBufferArray, matchedList, matchedGroup, matchedIndex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hide the view, which shows ads in the homepage.
|
||||
* Injection point.
|
||||
*
|
||||
* @param view The view, which shows ads.
|
||||
* Called from a different place then the other filters.
|
||||
*/
|
||||
public static void hideAdAttributionView(View view) {
|
||||
ReVancedUtils.hideViewBy1dpUnderCondition(SettingsEnum.HIDE_GENERAL_ADS, view);
|
||||
public static boolean filterMixPlaylists(final byte[] bytes) {
|
||||
return mixPlaylists.check(bytes).isFiltered();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
package app.revanced.integrations.patches.components;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
// Abuse LithoFilter for CustomPlaybackSpeedPatch.
|
||||
public final class PlaybackSpeedMenuFilterPatch extends Filter {
|
||||
// Must be volatile or synchronized, as litho filtering runs off main thread and this field is then access from the main thread.
|
||||
public static volatile boolean isPlaybackSpeedMenuVisible;
|
||||
|
||||
public PlaybackSpeedMenuFilterPatch() {
|
||||
pathFilterGroups.addAll(new StringFilterGroup(
|
||||
null,
|
||||
"playback_speed_sheet_content.eml-js"
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isFiltered(String path, @Nullable String identifier, byte[] protobufBufferArray,
|
||||
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
|
||||
isPlaybackSpeedMenuVisible = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package app.revanced.integrations.patches.components;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class PlayerFlyoutMenuItemsFilter extends Filter {
|
||||
|
||||
// Search the buffer only if the flyout menu identifier is found.
|
||||
// Handle the searching in this class instead of adding to the global filter group (which searches all the time)
|
||||
private final ByteArrayFilterGroupList flyoutFilterGroupList = new ByteArrayFilterGroupList();
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public PlayerFlyoutMenuItemsFilter() {
|
||||
identifierFilterGroups.addAll(new StringFilterGroup(null, "overflow_menu_item.eml|"));
|
||||
|
||||
flyoutFilterGroupList.addAll(
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_QUALITY_MENU,
|
||||
"yt_outline_gear"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_CAPTIONS_MENU,
|
||||
"closed_caption"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_LOOP_VIDEO_MENU,
|
||||
"yt_outline_arrow_repeat_1_"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_AMBIENT_MODE_MENU,
|
||||
"yt_outline_screen_light"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_REPORT_MENU,
|
||||
"yt_outline_flag"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_HELP_MENU,
|
||||
"yt_outline_question_circle"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_MORE_INFO_MENU,
|
||||
"yt_outline_info_circle"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_SPEED_MENU,
|
||||
"yt_outline_play_arrow_half_circle"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_AUDIO_TRACK_MENU,
|
||||
"yt_outline_person_radar"
|
||||
),
|
||||
new ByteArrayAsStringFilterGroup(
|
||||
SettingsEnum.HIDE_WATCH_IN_VR_MENU,
|
||||
"yt_outline_vr"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isFiltered(String path, @Nullable String identifier, byte[] protobufBufferArray,
|
||||
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
|
||||
// Only 1 group is added to the parent class, so the matched group must be the overflow menu.
|
||||
if (matchedIndex == 0 && flyoutFilterGroupList.check(protobufBufferArray).isFiltered()) {
|
||||
// Super class handles logging.
|
||||
return super.isFiltered(path, identifier, protobufBufferArray, matchedList, matchedGroup, matchedIndex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3,30 +3,37 @@ package app.revanced.integrations.patches.components;
|
||||
import static app.revanced.integrations.utils.ReVancedUtils.hideViewBy1dpUnderCondition;
|
||||
import static app.revanced.integrations.utils.ReVancedUtils.hideViewUnderCondition;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public final class ShortsFilter extends Filter {
|
||||
public static PivotBar pivotBar;
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar";
|
||||
public static PivotBar pivotBar; // Set by patch.
|
||||
|
||||
private final StringFilterGroup reelChannelBar = new StringFilterGroup(
|
||||
null,
|
||||
"reel_channel_bar"
|
||||
);
|
||||
|
||||
private final StringFilterGroup infoPanel = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_SHORTS_INFO_PANEL,
|
||||
"shorts_info_panel_overview"
|
||||
);
|
||||
private final StringFilterGroup channelBar;
|
||||
private final StringFilterGroup soundButton;
|
||||
private final StringFilterGroup infoPanel;
|
||||
|
||||
public ShortsFilter() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
|
||||
channelBar = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_SHORTS_CHANNEL_BAR,
|
||||
REEL_CHANNEL_BAR_PATH
|
||||
);
|
||||
|
||||
soundButton = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_SHORTS_SOUND_BUTTON,
|
||||
"reel_pivot_button"
|
||||
);
|
||||
|
||||
infoPanel = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_SHORTS_INFO_PANEL,
|
||||
"shorts_info_panel_overview"
|
||||
);
|
||||
|
||||
final var thanksButton = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_SHORTS_THANKS_BUTTON,
|
||||
@@ -43,16 +50,6 @@ public final class ShortsFilter extends Filter {
|
||||
"sponsor_button"
|
||||
);
|
||||
|
||||
final var soundButton = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_SHORTS_SOUND_BUTTON,
|
||||
"reel_pivot_button"
|
||||
);
|
||||
|
||||
final var channelBar = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_SHORTS_CHANNEL_BAR,
|
||||
"reel_channel_bar"
|
||||
);
|
||||
|
||||
final var shorts = new StringFilterGroup(
|
||||
SettingsEnum.HIDE_SHORTS,
|
||||
"shorts_shelf",
|
||||
@@ -61,21 +58,21 @@ public final class ShortsFilter extends Filter {
|
||||
"shorts_video_cell"
|
||||
);
|
||||
|
||||
this.pathFilterGroups.addAll(joinButton, subscribeButton, soundButton, channelBar);
|
||||
this.identifierFilterGroups.addAll(shorts, thanksButton);
|
||||
pathFilterGroups.addAll(joinButton, subscribeButton, channelBar, soundButton, infoPanel);
|
||||
identifierFilterGroups.addAll(shorts, thanksButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isFiltered(final String path, final String identifier,
|
||||
final byte[] protobufBufferArray) {
|
||||
boolean isFiltered(String path, @Nullable String identifier, byte[] protobufBufferArray,
|
||||
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
|
||||
if (matchedGroup == soundButton || matchedGroup == infoPanel || matchedGroup == channelBar) return true;
|
||||
|
||||
// Filter the path only when reelChannelBar is visible.
|
||||
if (reelChannelBar.check(path).isFiltered())
|
||||
if (this.pathFilterGroups.contains(path)) return true;
|
||||
if (pathFilterGroups == matchedList) {
|
||||
return path.contains(REEL_CHANNEL_BAR_PATH);
|
||||
}
|
||||
|
||||
// Shorts info panel path appears outside of reelChannelBar path.
|
||||
if (infoPanel.isEnabled() && infoPanel.check(path).isFiltered()) return true;
|
||||
|
||||
return this.identifierFilterGroups.contains(identifier);
|
||||
return identifierFilterGroups == matchedList;
|
||||
}
|
||||
|
||||
public static void hideShortsShelf(final View shortsShelfView) {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package app.revanced.integrations.patches.components;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
// Abuse LithoFilter for OldVideoQualityMenuPatch.
|
||||
public final class VideoQualityMenuFilterPatch extends Filter {
|
||||
// Must be volatile or synchronized, as litho filtering runs off main thread and this field is then access from the main thread.
|
||||
public static volatile boolean isVideoQualityMenuVisible;
|
||||
|
||||
public VideoQualityMenuFilterPatch() {
|
||||
pathFilterGroups.addAll(new StringFilterGroup(
|
||||
SettingsEnum.SHOW_OLD_VIDEO_QUALITY_MENU,
|
||||
"quick_quality_sheet_content.eml-js"
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isFiltered(String path, @Nullable String identifier, byte[] protobufBufferArray,
|
||||
FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) {
|
||||
isVideoQualityMenuVisible = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package app.revanced.integrations.patches.playback.quality;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
public class OldQualityLayoutPatch {
|
||||
public static void showOldQualityMenu(ListView listView)
|
||||
{
|
||||
if (!SettingsEnum.SHOW_OLD_VIDEO_MENU.getBoolean()) return;
|
||||
|
||||
listView.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
|
||||
@Override
|
||||
public void onChildViewAdded(View parent, View child) {
|
||||
LogHelper.printDebug(() -> "Added: " + child);
|
||||
|
||||
parent.setVisibility(View.GONE);
|
||||
|
||||
final var indexOfAdvancedQualityMenuItem = 4;
|
||||
if (listView.indexOfChild(child) != indexOfAdvancedQualityMenuItem) return;
|
||||
|
||||
LogHelper.printDebug(() -> "Found advanced menu: " + child);
|
||||
|
||||
final var qualityItemMenuPosition = 4;
|
||||
listView.performItemClick(null, qualityItemMenuPosition, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildViewRemoved(View parent, View child) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package app.revanced.integrations.patches.playback.quality;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import app.revanced.integrations.patches.components.VideoQualityMenuFilterPatch;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
import com.facebook.litho.ComponentHost;
|
||||
import kotlin.Deprecated;
|
||||
|
||||
// This patch contains the logic to show the old video quality menu.
|
||||
// Two methods are required, because the quality menu is a RecyclerView in the new YouTube version
|
||||
// and a ListView in the old one.
|
||||
public final class OldVideoQualityMenuPatch {
|
||||
|
||||
public static void onFlyoutMenuCreate(final LinearLayout linearLayout) {
|
||||
if (!SettingsEnum.SHOW_OLD_VIDEO_QUALITY_MENU.getBoolean()) return;
|
||||
|
||||
// The quality menu is a RecyclerView with 3 children. The third child is the "Advanced" quality menu.
|
||||
addRecyclerListener(linearLayout, 3, 2, recyclerView -> {
|
||||
// Check if the current view is the quality menu.
|
||||
if (VideoQualityMenuFilterPatch.isVideoQualityMenuVisible) {
|
||||
VideoQualityMenuFilterPatch.isVideoQualityMenuVisible = false;
|
||||
linearLayout.setVisibility(View.GONE);
|
||||
|
||||
// Click the "Advanced" quality menu to show the "old" quality menu.
|
||||
((ComponentHost) recyclerView.getChildAt(0)).getChildAt(3).performClick();
|
||||
LogHelper.printDebug(() -> "Advanced quality menu in new type of quality menu clicked");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void addRecyclerListener(@NonNull LinearLayout linearLayout,
|
||||
int expectedLayoutChildCount, int recyclerViewIndex,
|
||||
@NonNull RecyclerViewGlobalLayoutListener listener) {
|
||||
if (linearLayout.getChildCount() != expectedLayoutChildCount) return;
|
||||
|
||||
var layoutChild = linearLayout.getChildAt(recyclerViewIndex);
|
||||
if (!(layoutChild instanceof RecyclerView)) return;
|
||||
final var recyclerView = (RecyclerView) layoutChild;
|
||||
|
||||
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
try {
|
||||
listener.recyclerOnGlobalLayout(recyclerView);
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(() -> "addRecyclerListener failure", ex);
|
||||
} finally {
|
||||
// Remove the listener because it will be added again.
|
||||
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public interface RecyclerViewGlobalLayoutListener {
|
||||
void recyclerOnGlobalLayout(@NonNull RecyclerView recyclerView);
|
||||
}
|
||||
|
||||
@Deprecated(message = "This patch is deprecated because the quality menu is not a ListView anymore")
|
||||
public static void showOldVideoQualityMenu(final ListView listView) {
|
||||
if (!SettingsEnum.SHOW_OLD_VIDEO_QUALITY_MENU.getBoolean()) return;
|
||||
|
||||
listView.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
|
||||
@Override
|
||||
public void onChildViewAdded(View parent, View child) {
|
||||
LogHelper.printDebug(() -> "Added listener to old type of quality menu");
|
||||
|
||||
parent.setVisibility(View.GONE);
|
||||
|
||||
final var indexOfAdvancedQualityMenuItem = 4;
|
||||
if (listView.indexOfChild(child) != indexOfAdvancedQualityMenuItem) return;
|
||||
|
||||
LogHelper.printDebug(() -> "Found advanced menu item in old type of quality menu");
|
||||
|
||||
final var qualityItemMenuPosition = 4;
|
||||
listView.performItemClick(null, qualityItemMenuPosition, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildViewRemoved(View parent, View child) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -38,13 +38,8 @@ public class RememberVideoQualityPatch {
|
||||
private static List<Integer> videoQualities;
|
||||
|
||||
private static void changeDefaultQuality(int defaultQuality) {
|
||||
NetworkType networkType = ReVancedUtils.getNetworkType();
|
||||
if (networkType == NetworkType.NONE) {
|
||||
ReVancedUtils.showToastShort("No internet connection");
|
||||
return;
|
||||
}
|
||||
String networkTypeMessage;
|
||||
if (networkType == NetworkType.MOBILE) {
|
||||
if (ReVancedUtils.getNetworkType() == NetworkType.MOBILE) {
|
||||
mobileQualitySetting.saveValue(defaultQuality);
|
||||
networkTypeMessage = "mobile";
|
||||
} else {
|
||||
@@ -139,15 +134,24 @@ public class RememberVideoQualityPatch {
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* Injection point. Old quality menu.
|
||||
*/
|
||||
public static void userChangedQuality(int selectedQuality) {
|
||||
public static void userChangedQuality(int selectedQualityIndex) {
|
||||
if (!SettingsEnum.REMEMBER_VIDEO_QUALITY_LAST_SELECTED.getBoolean()) return;
|
||||
|
||||
userSelectedQualityIndex = selectedQuality;
|
||||
userSelectedQualityIndex = selectedQualityIndex;
|
||||
userChangedDefaultQuality = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point. New quality menu.
|
||||
*/
|
||||
public static void userChangedQualityInNewFlyout(int selectedQuality) {
|
||||
if (!SettingsEnum.REMEMBER_VIDEO_QUALITY_LAST_SELECTED.getBoolean()) return;
|
||||
|
||||
changeDefaultQuality(selectedQuality); // Quality is human readable resolution (ie: 1080).
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
package app.revanced.integrations.patches.playback.speed;
|
||||
|
||||
import android.preference.ListPreference;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import app.revanced.integrations.patches.components.PlaybackSpeedMenuFilterPatch;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
import com.facebook.litho.ComponentHost;
|
||||
|
||||
public class CustomVideoSpeedPatch {
|
||||
import java.util.Arrays;
|
||||
|
||||
import static app.revanced.integrations.patches.playback.quality.OldVideoQualityMenuPatch.addRecyclerListener;
|
||||
|
||||
public class CustomPlaybackSpeedPatch {
|
||||
/**
|
||||
* Maximum playback speed, exclusive value. Custom speeds must be less than this value.
|
||||
*/
|
||||
@@ -19,17 +24,17 @@ public class CustomVideoSpeedPatch {
|
||||
/**
|
||||
* Custom playback speeds.
|
||||
*/
|
||||
public static float[] customVideoSpeeds;
|
||||
public static float[] customPlaybackSpeeds;
|
||||
|
||||
/**
|
||||
* Minimum value of {@link #customVideoSpeeds}
|
||||
* Minimum value of {@link #customPlaybackSpeeds}
|
||||
*/
|
||||
public static float minVideoSpeed;
|
||||
public static float minPlaybackSpeed;
|
||||
|
||||
/**
|
||||
* Maxium value of {@link #customVideoSpeeds}
|
||||
* Maxium value of {@link #customPlaybackSpeeds}
|
||||
*/
|
||||
public static float maxVideoSpeed;
|
||||
public static float maxPlaybackSpeed;
|
||||
|
||||
/**
|
||||
* PreferenceList entries and values, of all available playback speeds.
|
||||
@@ -37,7 +42,7 @@ public class CustomVideoSpeedPatch {
|
||||
private static String[] preferenceListEntries, preferenceListEntryValues;
|
||||
|
||||
static {
|
||||
loadSpeeds();
|
||||
loadCustomSpeeds();
|
||||
}
|
||||
|
||||
private static void resetCustomSpeeds(@NonNull String toastMessage) {
|
||||
@@ -45,33 +50,33 @@ public class CustomVideoSpeedPatch {
|
||||
SettingsEnum.CUSTOM_PLAYBACK_SPEEDS.saveValue(SettingsEnum.CUSTOM_PLAYBACK_SPEEDS.defaultValue);
|
||||
}
|
||||
|
||||
private static void loadSpeeds() {
|
||||
private static void loadCustomSpeeds() {
|
||||
try {
|
||||
String[] speedStrings = SettingsEnum.CUSTOM_PLAYBACK_SPEEDS.getString().split("\\s+");
|
||||
Arrays.sort(speedStrings);
|
||||
if (speedStrings.length == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
customVideoSpeeds = new float[speedStrings.length];
|
||||
customPlaybackSpeeds = new float[speedStrings.length];
|
||||
for (int i = 0, length = speedStrings.length; i < length; i++) {
|
||||
final float speed = Float.parseFloat(speedStrings[i]);
|
||||
if (speed <= 0 || arrayContains(customVideoSpeeds, speed)) {
|
||||
if (speed <= 0 || arrayContains(customPlaybackSpeeds, speed)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (speed >= MAXIMUM_PLAYBACK_SPEED) {
|
||||
resetCustomSpeeds("Custom speeds must be less than " + MAXIMUM_PLAYBACK_SPEED
|
||||
+ ". Using default values.");
|
||||
loadSpeeds();
|
||||
loadCustomSpeeds();
|
||||
return;
|
||||
}
|
||||
minVideoSpeed = Math.min(minVideoSpeed, speed);
|
||||
maxVideoSpeed = Math.max(maxVideoSpeed, speed);
|
||||
customVideoSpeeds[i] = speed;
|
||||
minPlaybackSpeed = Math.min(minPlaybackSpeed, speed);
|
||||
maxPlaybackSpeed = Math.max(maxPlaybackSpeed, speed);
|
||||
customPlaybackSpeeds[i] = speed;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printInfo(() -> "parse error", ex);
|
||||
resetCustomSpeeds("Invalid custom video speeds. Using default values.");
|
||||
loadSpeeds();
|
||||
resetCustomSpeeds("Invalid custom playback speeds. Using default values.");
|
||||
loadCustomSpeeds();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +92,10 @@ public class CustomVideoSpeedPatch {
|
||||
*/
|
||||
public static void initializeListPreference(ListPreference preference) {
|
||||
if (preferenceListEntries == null) {
|
||||
preferenceListEntries = new String[customVideoSpeeds.length];
|
||||
preferenceListEntryValues = new String[customVideoSpeeds.length];
|
||||
preferenceListEntries = new String[customPlaybackSpeeds.length];
|
||||
preferenceListEntryValues = new String[customPlaybackSpeeds.length];
|
||||
int i = 0;
|
||||
for (float speed : customVideoSpeeds) {
|
||||
for (float speed : customPlaybackSpeeds) {
|
||||
String speedString = String.valueOf(speed);
|
||||
preferenceListEntries[i] = speedString + "x";
|
||||
preferenceListEntryValues[i] = speedString;
|
||||
@@ -100,4 +105,33 @@ public class CustomVideoSpeedPatch {
|
||||
preference.setEntries(preferenceListEntries);
|
||||
preference.setEntryValues(preferenceListEntryValues);
|
||||
}
|
||||
|
||||
/*
|
||||
* To reduce copy and paste between two similar code paths.
|
||||
*/
|
||||
public static void onFlyoutMenuCreate(final LinearLayout linearLayout) {
|
||||
// The playback rate menu is a RecyclerView with 2 children. The third child is the "Advanced" quality menu.
|
||||
addRecyclerListener(linearLayout, 2, 1, recyclerView -> {
|
||||
if (PlaybackSpeedMenuFilterPatch.isPlaybackSpeedMenuVisible) {
|
||||
PlaybackSpeedMenuFilterPatch.isPlaybackSpeedMenuVisible = false;
|
||||
|
||||
if (recyclerView.getChildCount() == 1 && recyclerView.getChildAt(0) instanceof ComponentHost) {
|
||||
linearLayout.setVisibility(View.GONE);
|
||||
|
||||
// Close the new Playback speed menu and instead show the old one.
|
||||
showOldPlaybackSpeedMenu();
|
||||
|
||||
// DismissView [R.id.touch_outside] is the 1st ChildView of the 3rd ParentView.
|
||||
((ViewGroup) linearLayout.getParent().getParent().getParent())
|
||||
.getChildAt(0).performClick();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void showOldPlaybackSpeedMenu() {
|
||||
LogHelper.printDebug(() -> "Old video quality menu shown");
|
||||
|
||||
// Rest of the implementation added by patch.
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import app.revanced.integrations.settings.SettingsEnum;
|
||||
*/
|
||||
public class ProgressBarDrawable extends Drawable {
|
||||
|
||||
|
||||
private final Paint paint = new Paint();
|
||||
|
||||
@Override
|
||||
@@ -25,7 +26,7 @@ public class ProgressBarDrawable extends Drawable {
|
||||
if (SettingsEnum.HIDE_SEEKBAR_THUMBNAIL.getBoolean()) {
|
||||
return;
|
||||
}
|
||||
paint.setColor(SeekbarColorPatch.getCustomSeekbarColor());
|
||||
paint.setColor(SeekbarColorPatch.getSeekbarColor());
|
||||
canvas.drawRect(getBounds(), paint);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,10 @@ import app.revanced.integrations.utils.ReVancedUtils;
|
||||
|
||||
public final class SeekbarColorPatch {
|
||||
|
||||
private static final boolean USE_SEEKBAR_CUSTOM_COLOR = SettingsEnum.SEEKBAR_CUSTOM_COLOR.getBoolean();
|
||||
|
||||
/**
|
||||
* Default color of seekbar.
|
||||
* Default color of the seekbar.
|
||||
*/
|
||||
private static final int ORIGINAL_SEEKBAR_COLOR = 0xFFFF0000;
|
||||
|
||||
@@ -19,9 +21,11 @@ public final class SeekbarColorPatch {
|
||||
private static final float ORIGINAL_SEEKBAR_COLOR_BRIGHTNESS;
|
||||
|
||||
/**
|
||||
* Color value of {@link SettingsEnum#SEEKBAR_COLOR}
|
||||
* If {@link SettingsEnum#SEEKBAR_CUSTOM_COLOR} is enabled,
|
||||
* this is the color value of {@link SettingsEnum#SEEKBAR_CUSTOM_COLOR_VALUE}.
|
||||
* Otherwise this is {@link #ORIGINAL_SEEKBAR_COLOR}.
|
||||
*/
|
||||
private static int customSeekbarColor;
|
||||
private static int seekbarColor = ORIGINAL_SEEKBAR_COLOR;
|
||||
|
||||
/**
|
||||
* Custom seekbar hue, saturation, and brightness values.
|
||||
@@ -33,22 +37,24 @@ public final class SeekbarColorPatch {
|
||||
Color.colorToHSV(ORIGINAL_SEEKBAR_COLOR, hsv);
|
||||
ORIGINAL_SEEKBAR_COLOR_BRIGHTNESS = hsv[2];
|
||||
|
||||
loadCustomSeekbarColorHSV();
|
||||
}
|
||||
|
||||
private static void loadCustomSeekbarColorHSV() {
|
||||
try {
|
||||
customSeekbarColor = Color.parseColor(SettingsEnum.SEEKBAR_COLOR.getString());
|
||||
Color.colorToHSV(customSeekbarColor, customSeekbarColorHSV);
|
||||
} catch (Exception ex) {
|
||||
ReVancedUtils.showToastShort("Invalid seekbar color value. Using default value.");
|
||||
SettingsEnum.SEEKBAR_COLOR.saveValue(SettingsEnum.SEEKBAR_COLOR.defaultValue);
|
||||
loadCustomSeekbarColorHSV();
|
||||
if (USE_SEEKBAR_CUSTOM_COLOR) {
|
||||
loadCustomSeekbarColor();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getCustomSeekbarColor() {
|
||||
return customSeekbarColor;
|
||||
private static void loadCustomSeekbarColor() {
|
||||
try {
|
||||
seekbarColor = Color.parseColor(SettingsEnum.SEEKBAR_CUSTOM_COLOR_VALUE.getString());
|
||||
Color.colorToHSV(seekbarColor, customSeekbarColorHSV);
|
||||
} catch (Exception ex) {
|
||||
ReVancedUtils.showToastShort("Invalid seekbar color value. Using default value.");
|
||||
SettingsEnum.SEEKBAR_CUSTOM_COLOR_VALUE.saveValue(SettingsEnum.SEEKBAR_CUSTOM_COLOR_VALUE.defaultValue);
|
||||
loadCustomSeekbarColor();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getSeekbarColor() {
|
||||
return seekbarColor;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +102,7 @@ public final class SeekbarColorPatch {
|
||||
*/
|
||||
private static int getSeekbarColorValue(int originalColor) {
|
||||
try {
|
||||
if (customSeekbarColor == ORIGINAL_SEEKBAR_COLOR) {
|
||||
if (!USE_SEEKBAR_CUSTOM_COLOR || originalColor == seekbarColor) {
|
||||
return originalColor; // nothing to do
|
||||
}
|
||||
final int alphaDifference = Color.alpha(originalColor) - Color.alpha(ORIGINAL_SEEKBAR_COLOR);
|
||||
@@ -111,7 +117,7 @@ public final class SeekbarColorPatch {
|
||||
hsv[1] = customSeekbarColorHSV[1];
|
||||
hsv[2] = clamp(customSeekbarColorHSV[2] + brightnessDifference, 0, 1);
|
||||
|
||||
final int replacementAlpha = clamp(Color.alpha(customSeekbarColor) + alphaDifference, 0, 255);
|
||||
final int replacementAlpha = clamp(Color.alpha(seekbarColor) + alphaDifference, 0, 255);
|
||||
final int replacementColor = Color.HSVToColor(replacementAlpha, hsv);
|
||||
LogHelper.printDebug(() -> String.format("Original color: #%08X replacement color: #%08X",
|
||||
originalColor, replacementColor));
|
||||
|
||||
@@ -255,7 +255,7 @@ public class ReturnYouTubeDislike {
|
||||
// If a Short is opened while a regular video is on screen, this will incorrectly set this as false.
|
||||
// But this check is needed to fix unusual situations of opening/closing the app
|
||||
// while both a regular video and a short are on screen.
|
||||
dislikeDataIsShort = currentPlayerType.isNoneHiddenOrMinimized();
|
||||
dislikeDataIsShort = currentPlayerType.isNoneOrHidden();
|
||||
|
||||
RYDCachedFetch entry = futureCache.get(videoId);
|
||||
if (entry != null && entry.futureInProgressOrFinishedSuccessfully()) {
|
||||
@@ -371,7 +371,7 @@ public class ReturnYouTubeDislike {
|
||||
// Must make a local copy of videoId, since it may change between now and when the vote thread runs.
|
||||
String videoIdToVoteFor = getCurrentVideoId();
|
||||
if (videoIdToVoteFor == null ||
|
||||
(SettingsEnum.RYD_SHORTS.getBoolean() && dislikeDataIsShort != PlayerType.getCurrent().isNoneHiddenOrMinimized())) {
|
||||
(SettingsEnum.RYD_SHORTS.getBoolean() && dislikeDataIsShort != PlayerType.getCurrent().isNoneOrHidden())) {
|
||||
// User enabled RYD after starting playback of a video.
|
||||
// Or shorts was loaded with regular video present, then shorts was closed,
|
||||
// and then user voted on the now visible original video.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.apps.youtube.app.application.Shell_HomeActivity;
|
||||
|
||||
import app.revanced.integrations.patches.playback.speed.CustomVideoSpeedPatch;
|
||||
import app.revanced.integrations.patches.playback.speed.CustomPlaybackSpeedPatch;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.settings.SharedPrefCategory;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
@@ -135,7 +135,7 @@ public class ReVancedSettingsFragment extends PreferenceFragment {
|
||||
// if the preference was included, then initialize it based on the available playback speed
|
||||
Preference defaultSpeedPreference = findPreference(SettingsEnum.PLAYBACK_SPEED_DEFAULT.path);
|
||||
if (defaultSpeedPreference instanceof ListPreference) {
|
||||
CustomVideoSpeedPatch.initializeListPreference((ListPreference) defaultSpeedPreference);
|
||||
CustomPlaybackSpeedPatch.initializeListPreference((ListPreference) defaultSpeedPreference);
|
||||
}
|
||||
|
||||
// Set current value from SettingsEnum
|
||||
@@ -180,6 +180,11 @@ public class ReVancedSettingsFragment extends PreferenceFragment {
|
||||
if (entryIndex >= 0) {
|
||||
listPreference.setSummary(listPreference.getEntries()[entryIndex]);
|
||||
listPreference.setValue(objectStringValue);
|
||||
} else {
|
||||
// Value is not an available option.
|
||||
// User manually edited import data, or options changed and current selection is no longer available.
|
||||
// Still show the value in the summary so it's clear that something is selected.
|
||||
listPreference.setSummary(objectStringValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -427,16 +427,6 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
Preference preference = new Preference(context);
|
||||
category.addPreference(preference);
|
||||
preference.setSummary(str("sb_about_made_by"));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
preference.setSingleLineTitle(false);
|
||||
}
|
||||
preference.setSelectable(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void openGuidelines() {
|
||||
|
||||
@@ -8,16 +8,17 @@ import app.revanced.integrations.utils.LogHelper
|
||||
*/
|
||||
enum class PlayerType {
|
||||
/**
|
||||
* Includes Shorts and Stories playback.
|
||||
* Either no video, or a Short is playing.
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* A Shorts or Stories, if a regular video is minimized and a Short/Story is then opened.
|
||||
* A Short is playing. Occurs if a regular video is first opened
|
||||
* and then a Short is opened (without first closing the regular video).
|
||||
*/
|
||||
HIDDEN,
|
||||
/**
|
||||
* When spoofing to an old version of YouTube, and watching a short with a regular video in the background,
|
||||
* the type will be this (and not [HIDDEN]).
|
||||
* When spoofing to 16.x YouTube and watching a short with a regular video in the background,
|
||||
* the type can be this (and not [HIDDEN]).
|
||||
*/
|
||||
WATCH_WHILE_MINIMIZED,
|
||||
WATCH_WHILE_MAXIMIZED,
|
||||
@@ -76,7 +77,7 @@ enum class PlayerType {
|
||||
* Useful to check if a short is currently playing.
|
||||
*
|
||||
* Does not include the first moment after a short is opened when a regular video is minimized on screen,
|
||||
* or while watching a short with a regular video present on a spoofed old version of YouTube.
|
||||
* or while watching a short with a regular video present on a spoofed 16.x version of YouTube.
|
||||
* To include those situations instead use [isNoneHiddenOrMinimized].
|
||||
*/
|
||||
fun isNoneOrHidden(): Boolean {
|
||||
@@ -84,12 +85,13 @@ enum class PlayerType {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current player type is [NONE], [HIDDEN], [WATCH_WHILE_MINIMIZED], [WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED].
|
||||
* Check if the current player type is
|
||||
* [NONE], [HIDDEN], [WATCH_WHILE_MINIMIZED], [WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED].
|
||||
*
|
||||
* Useful to check if a Short is being played,
|
||||
* although can return false positive if the player is minimized.
|
||||
* although will return false positive if a regular video is opened and minimized (and no short is playing).
|
||||
*
|
||||
* @return If nothing, a Short, a Story,
|
||||
* @return If nothing, a Short,
|
||||
* or a regular video is minimized video or sliding off screen to a dismissed or hidden state.
|
||||
*/
|
||||
fun isNoneHiddenOrMinimized(): Boolean {
|
||||
|
||||
@@ -50,7 +50,7 @@ public class SegmentPlaybackController {
|
||||
private static SponsorSegment[] segments;
|
||||
|
||||
/**
|
||||
* Highlight segment, if one exists.
|
||||
* Highlight segment, if one exists and the skip behavior is not set to {@link CategoryBehaviour#SHOW_IN_SEEKBAR}.
|
||||
*/
|
||||
@Nullable
|
||||
private static SponsorSegment highlightSegment;
|
||||
@@ -58,6 +58,7 @@ public class SegmentPlaybackController {
|
||||
/**
|
||||
* Because loading can take time, show the skip to highlight for a few seconds after the segments load.
|
||||
* This is the system time (in milliseconds) to no longer show the initial display skip to highlight.
|
||||
* Value will be zero if no highlight segment exists, or if the system time to show the highlight has passed.
|
||||
*/
|
||||
private static long highlightSegmentInitialShowEndTime;
|
||||
|
||||
@@ -111,10 +112,13 @@ public class SegmentPlaybackController {
|
||||
segments = videoSegments;
|
||||
calculateTimeWithoutSegments();
|
||||
|
||||
for (SponsorSegment segment : videoSegments) {
|
||||
if (segment.category == SegmentCategory.HIGHLIGHT) {
|
||||
highlightSegment = segment;
|
||||
return;
|
||||
if (SegmentCategory.HIGHLIGHT.behaviour == CategoryBehaviour.SKIP_AUTOMATICALLY
|
||||
|| SegmentCategory.HIGHLIGHT.behaviour == CategoryBehaviour.MANUAL_SKIP) {
|
||||
for (SponsorSegment segment : videoSegments) {
|
||||
if (segment.category == SegmentCategory.HIGHLIGHT) {
|
||||
highlightSegment = segment;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
highlightSegment = null;
|
||||
@@ -198,7 +202,7 @@ public class SegmentPlaybackController {
|
||||
return;
|
||||
}
|
||||
if (PlayerType.getCurrent().isNoneOrHidden()) {
|
||||
LogHelper.printDebug(() -> "ignoring short or story");
|
||||
LogHelper.printDebug(() -> "ignoring Short");
|
||||
return;
|
||||
}
|
||||
if (!ReVancedUtils.isNetworkConnected()) {
|
||||
@@ -238,14 +242,20 @@ public class SegmentPlaybackController {
|
||||
setSegments(segments);
|
||||
|
||||
final long videoTime = VideoInformation.getVideoTime();
|
||||
// if the current video time is before the highlight
|
||||
if (highlightSegment != null && videoTime < highlightSegment.end) {
|
||||
if (highlightSegment.shouldAutoSkip()) {
|
||||
skipSegment(highlightSegment, false);
|
||||
return;
|
||||
if (highlightSegment != null) {
|
||||
// If the current video time is before the highlight.
|
||||
final long timeUntilHighlight = highlightSegment.start - videoTime;
|
||||
if (timeUntilHighlight > 0) {
|
||||
if (highlightSegment.shouldAutoSkip()) {
|
||||
skipSegment(highlightSegment, false);
|
||||
return;
|
||||
}
|
||||
highlightSegmentInitialShowEndTime = System.currentTimeMillis() + Math.min(
|
||||
(long) (timeUntilHighlight / VideoInformation.getPlaybackSpeed()),
|
||||
DURATION_TO_SHOW_SKIP_BUTTON);
|
||||
}
|
||||
highlightSegmentInitialShowEndTime = System.currentTimeMillis() + DURATION_TO_SHOW_SKIP_BUTTON;
|
||||
}
|
||||
|
||||
// check for any skips now, instead of waiting for the next update to setVideoTime()
|
||||
setVideoTime(videoTime);
|
||||
});
|
||||
@@ -262,7 +272,7 @@ public class SegmentPlaybackController {
|
||||
public static void setVideoTime(long millis) {
|
||||
try {
|
||||
if (!SettingsEnum.SB_ENABLED.getBoolean()
|
||||
|| PlayerType.getCurrent().isNoneOrHidden() // shorts playback
|
||||
|| PlayerType.getCurrent().isNoneOrHidden() // Shorts playback.
|
||||
|| segments == null || segments.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -270,11 +280,17 @@ public class SegmentPlaybackController {
|
||||
|
||||
updateHiddenSegments(millis);
|
||||
|
||||
// to debug the timing logic, set this to a very large value (5000 or more)
|
||||
// then try manually seeking just playback reaches a skip/hide of different segments
|
||||
final long lookAheadMilliseconds = 1500; // must be larger than the average time between calls to this method
|
||||
final float playbackSpeed = VideoInformation.getPlaybackSpeed();
|
||||
final long startTimerLookAheadThreshold = millis + (long)(playbackSpeed * lookAheadMilliseconds);
|
||||
// Amount of time to look ahead for the next segment,
|
||||
// and the threshold to determine if a scheduled show/hide is at the correct video time when it's run.
|
||||
//
|
||||
// This value must be greater than largest time between calls to this method (1000ms),
|
||||
// and must be adjusted for the video speed.
|
||||
//
|
||||
// To debug the stale skip logic, set this to a very large value (5000 or more)
|
||||
// then try manually seeking just before playback reaches a segment skip.
|
||||
final long speedAdjustedTimeThreshold = (long)(playbackSpeed * 1200);
|
||||
final long startTimerLookAheadThreshold = millis + speedAdjustedTimeThreshold;
|
||||
|
||||
SponsorSegment foundSegmentCurrentlyPlaying = null;
|
||||
SponsorSegment foundUpcomingSegment = null;
|
||||
@@ -344,9 +360,11 @@ public class SegmentPlaybackController {
|
||||
}
|
||||
|
||||
if (highlightSegment != null) {
|
||||
if (millis < DURATION_TO_SHOW_SKIP_BUTTON || System.currentTimeMillis() < highlightSegmentInitialShowEndTime) {
|
||||
if (millis < DURATION_TO_SHOW_SKIP_BUTTON || (highlightSegmentInitialShowEndTime != 0
|
||||
&& System.currentTimeMillis() < highlightSegmentInitialShowEndTime)) {
|
||||
SponsorBlockViewController.showSkipHighlightButton(highlightSegment);
|
||||
} else {
|
||||
highlightSegmentInitialShowEndTime = 0;
|
||||
SponsorBlockViewController.hideSkipHighlightButton();
|
||||
}
|
||||
}
|
||||
@@ -361,12 +379,9 @@ public class SegmentPlaybackController {
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
}
|
||||
|
||||
// must be greater than the average time between updates to VideoInformation time
|
||||
final long videoInformationTimeUpdateThresholdMilliseconds = 250;
|
||||
|
||||
// schedule a hide, only if the segment end is near
|
||||
final SponsorSegment segmentToHide =
|
||||
(foundSegmentCurrentlyPlaying != null && foundSegmentCurrentlyPlaying.endIsNear(millis, lookAheadMilliseconds))
|
||||
(foundSegmentCurrentlyPlaying != null && foundSegmentCurrentlyPlaying.endIsNear(millis, speedAdjustedTimeThreshold))
|
||||
? foundSegmentCurrentlyPlaying
|
||||
: null;
|
||||
|
||||
@@ -384,9 +399,13 @@ public class SegmentPlaybackController {
|
||||
return;
|
||||
}
|
||||
scheduledHideSegment = null;
|
||||
if (VideoState.getCurrent() != VideoState.PLAYING) {
|
||||
LogHelper.printDebug(() -> "Ignoring scheduled hide segment as video is paused: " + segmentToHide);
|
||||
return;
|
||||
}
|
||||
|
||||
final long videoTime = VideoInformation.getVideoTime();
|
||||
if (!segmentToHide.endIsNear(videoTime, videoInformationTimeUpdateThresholdMilliseconds)) {
|
||||
if (!segmentToHide.endIsNear(videoTime, speedAdjustedTimeThreshold)) {
|
||||
// current video time is not what's expected. User paused playback
|
||||
LogHelper.printDebug(() -> "Ignoring outdated scheduled hide: " + segmentToHide
|
||||
+ " videoInformation time: " + videoTime);
|
||||
@@ -419,10 +438,13 @@ public class SegmentPlaybackController {
|
||||
return;
|
||||
}
|
||||
scheduledUpcomingSegment = null;
|
||||
if (VideoState.getCurrent() != VideoState.PLAYING) {
|
||||
LogHelper.printDebug(() -> "Ignoring scheduled hide segment as video is paused: " + segmentToSkip);
|
||||
return;
|
||||
}
|
||||
|
||||
final long videoTime = VideoInformation.getVideoTime();
|
||||
if (!segmentToSkip.startIsNear(videoTime,
|
||||
videoInformationTimeUpdateThresholdMilliseconds)) {
|
||||
if (!segmentToSkip.startIsNear(videoTime, speedAdjustedTimeThreshold)) {
|
||||
// current video time is not what's expected. User paused playback
|
||||
LogHelper.printDebug(() -> "Ignoring outdated scheduled segment: " + segmentToSkip
|
||||
+ " videoInformation time: " + videoTime);
|
||||
@@ -488,10 +510,10 @@ public class SegmentPlaybackController {
|
||||
SponsorBlockViewController.hideSkipHighlightButton();
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
|
||||
// If trying to seek to end of the video, YouTube can seek just short of the actual end.
|
||||
// If trying to seek to end of the video, YouTube can seek just before of the actual end.
|
||||
// (especially if the video does not end on a whole second boundary).
|
||||
// This causes additional segment skip attempts, even though it cannot seek any closer to the desired time.
|
||||
// Check for and ignore repeated skip attempts of the same segment over a short time period.
|
||||
// Check for and ignore repeated skip attempts of the same segment over a small time period.
|
||||
final long now = System.currentTimeMillis();
|
||||
final long minimumMillisecondsBetweenSkippingSameSegment = 500;
|
||||
if ((lastSegmentSkipped == segmentToSkip) && (now - lastSegmentSkippedTime < minimumMillisecondsBetweenSkippingSameSegment)) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package app.revanced.integrations.utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class ByteTrieSearch extends TrieSearch<byte[]> {
|
||||
|
||||
private static final class ByteTrieNode extends TrieNode<byte[]> {
|
||||
TrieNode<byte[]> createNode() {
|
||||
return new ByteTrieNode();
|
||||
}
|
||||
char getCharValue(byte[] text, int index) {
|
||||
return (char) text[index];
|
||||
}
|
||||
}
|
||||
|
||||
public ByteTrieSearch() {
|
||||
super(new ByteTrieNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPattern(@NonNull byte[] pattern) {
|
||||
super.addPattern(pattern, pattern.length, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPattern(@NonNull byte[] pattern, @NonNull TriePatternMatchedCallback<byte[]> callback) {
|
||||
super.addPattern(pattern, pattern.length, Objects.requireNonNull(callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(@NonNull byte[] textToSearch, @Nullable Object callbackParameter) {
|
||||
return super.matches(textToSearch, textToSearch.length, callbackParameter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package app.revanced.integrations.utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Text pattern searching using a prefix tree (trie).
|
||||
*/
|
||||
public final class StringTrieSearch extends TrieSearch<String> {
|
||||
|
||||
private static final class StringTrieNode extends TrieNode<String> {
|
||||
TrieNode<String> createNode() {
|
||||
return new StringTrieNode();
|
||||
}
|
||||
char getCharValue(String text, int index) {
|
||||
return text.charAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public StringTrieSearch() {
|
||||
super(new StringTrieNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPattern(@NonNull String pattern) {
|
||||
super.addPattern(pattern, pattern.length(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPattern(@NonNull String pattern, @NonNull TriePatternMatchedCallback<String> callback) {
|
||||
super.addPattern(pattern, pattern.length(), Objects.requireNonNull(callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(@NonNull String textToSearch, @Nullable Object callbackParameter) {
|
||||
return super.matches(textToSearch, textToSearch.length(), callbackParameter);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
package app.revanced.reddit.patches;
|
||||
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public final class SanitizeUrlQueryPatch {
|
||||
/**
|
||||
* Strip query parameters from a given URL string.
|
||||
*
|
||||
* @param urlString URL string to strip query parameters from.
|
||||
* @return URL string without query parameters if possible, otherwise the original string.
|
||||
*/
|
||||
public static String stripQueryParameters(final String urlString) {
|
||||
try {
|
||||
final var url = new URL(urlString);
|
||||
|
||||
return url.getProtocol() + "://" + url.getHost() + url.getPath();
|
||||
} catch (MalformedURLException e) {
|
||||
LogHelper.printException(() -> "Can not parse URL", e);
|
||||
return urlString;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user