1
mirror of https://github.com/revanced/revanced-integrations synced 2025-11-19 03:23:27 +01:00

Compare commits

...

58 Commits

Author SHA1 Message Date
semantic-release-bot
8ef81235d7 chore(release): 0.115.0-dev.1 [skip ci]
# [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](c7d2a9b310))
2023-07-26 13:51:32 +00:00
johnconner122
c7d2a9b310 feat(YouTube - Hide layout components): Hide chips shelf (#448) 2023-07-26 15:47:56 +02:00
oSumAtrIX
d7fc06a647 ci: clean after building 2023-07-21 19:17:06 +02:00
semantic-release-bot
67cf3e2eb4 chore(release): 0.114.0 [skip ci]
# [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](8c61561d63))

### Features

* **youtube/theme:** add a switch to enable/disable custom seekbar color ([#442](https://github.com/ReVanced/revanced-integrations/issues/442)) ([2a784a4](2a784a47d1))
2023-07-21 15:08:36 +00:00
oSumAtrIX
dcd97f3143 chore: merge branch dev to main (#444) 2023-07-21 17:04:35 +02:00
oSumAtrIX
e1011e42df ci: do not cache build directory 2023-07-21 16:58:00 +02:00
semantic-release-bot
e2f25cd5ae chore(release): 0.114.0-dev.1 [skip ci]
# [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](2a784a47d1))
2023-07-20 17:28:49 +00:00
LisoUseInAIKyrios
2a784a47d1 feat(youtube/theme): add a switch to enable/disable custom seekbar color (#442) 2023-07-20 21:26:50 +04:00
semantic-release-bot
dc591ac7ed chore(release): 0.113.1-dev.1 [skip ci]
## [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](8c61561d63))
2023-07-20 17:24:01 +00:00
Vu Hoan Huy
8c61561d63 fix(Tiktok - Settings): check for null when opening ads settings (#443) 2023-07-20 19:22:07 +02:00
semantic-release-bot
8920e1dfe8 chore(release): 0.113.0 [skip ci]
# [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](821a32ee40))
* **YouTube - Hide Shorts Components:** hide sound button ([a2b1630](a2b1630df8))
* **YouTube - Spoof client:** show video time and chapters while using seekbar ([#435](https://github.com/ReVanced/revanced-integrations/issues/435)) ([a0f831a](a0f831ac3f))
* **youtube/return-youtube-dislike:** fix dislikes not showing in some situations ([#439](https://github.com/ReVanced/revanced-integrations/issues/439)) ([7a28c2f](7a28c2fa13))
* **youtube/sponsorblock:** fix some segments skipping slightly too late ([#436](https://github.com/ReVanced/revanced-integrations/issues/436)) ([f694928](f69492819e))

### Features

* **YouTube - Hide ads:** hide new type of buttoned ad ([9f21c72](9f21c7268e))
* **youtube:** rename `video-speed` to `playback-speed` ([#438](https://github.com/ReVanced/revanced-integrations/issues/438)) ([630776f](630776fd35))
2023-07-20 00:04:52 +00:00
oSumAtrIX
59f7733f99 chore: merge branch dev to main (#437) 2023-07-20 02:02:44 +02:00
semantic-release-bot
6104e263ce chore(release): 0.113.0-dev.5 [skip ci]
# [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](a0f831ac3f))
2023-07-19 23:20:00 +00:00
LisoUseInAIKyrios
a0f831ac3f fix(YouTube - Spoof client): show video time and chapters while using seekbar (#435) 2023-07-20 01:17:18 +02:00
semantic-release-bot
2f39f32a52 chore(release): 0.113.0-dev.4 [skip ci]
# [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](821a32ee40))
2023-07-19 23:16:41 +00:00
Vu Hoan Huy
821a32ee40 fix(Tiktok - Settings): bump compatibility (#440)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-07-20 01:14:10 +02:00
semantic-release-bot
d3533824f4 chore(release): 0.113.0-dev.3 [skip ci]
# [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](7a28c2fa13))
2023-07-16 16:42:35 +00:00
LisoUseInAIKyrios
7a28c2fa13 fix(youtube/return-youtube-dislike): fix dislikes not showing in some situations (#439) 2023-07-16 20:39:51 +04:00
semantic-release-bot
5056adbc3c chore(release): 0.113.0-dev.2 [skip ci]
# [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](9f21c7268e))
2023-07-16 00:27:07 +00:00
oSumAtrIX
9f21c7268e feat(YouTube - Hide ads): hide new type of buttoned ad 2023-07-16 02:24:52 +02:00
semantic-release-bot
42750409b7 chore(release): 0.113.0-dev.1 [skip ci]
# [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](630776fd35))
2023-07-15 12:34:24 +00:00
KAZI MMT
630776fd35 feat(youtube): rename video-speed to playback-speed (#438) 2023-07-15 16:32:21 +04:00
semantic-release-bot
0e18f209dc chore(release): 0.112.1-dev.2 [skip ci]
## [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](a2b1630df8))
2023-07-15 01:44:06 +00:00
oSumAtrIX
a2b1630df8 fix(YouTube - Hide Shorts Components): hide sound button 2023-07-15 03:42:01 +02:00
semantic-release-bot
e78ef6df9c chore(release): 0.112.1-dev.1 [skip ci]
## [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](f69492819e))
2023-07-14 08:37:50 +00:00
LisoUseInAIKyrios
f69492819e fix(youtube/sponsorblock): fix some segments skipping slightly too late (#436) 2023-07-14 12:35:20 +04:00
semantic-release-bot
59850b2c04 chore(release): 0.112.0 [skip ci]
# [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](ea7ee56276))
* **youtube/hide-layout-components:**  hide mix playlists ([789e0c8](789e0c8bcb))

### Features

* remove unnecessary notice ([be3955f](be3955fee4))
* **youtube:** support version `18.23.35` ([#433](https://github.com/revanced/revanced-integrations/issues/433)) ([dec7348](dec7348203))
2023-07-08 02:35:51 +00:00
oSumAtrIX
cfc7081971 chore: merge branch dev to main (#431) 2023-07-08 04:32:50 +02:00
semantic-release-bot
6f0248cc1a chore(release): 0.112.0-dev.3 [skip ci]
# [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](789e0c8bcb))
2023-07-08 02:31:18 +00:00
oSumAtrIX
789e0c8bcb fix(youtube/hide-layout-components): hide mix playlists 2023-07-08 04:28:12 +02:00
semantic-release-bot
e783142741 chore(release): 0.112.0-dev.2 [skip ci]
# [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](dec7348203))
2023-07-07 23:04:32 +00:00
oSumAtrIX
dec7348203 feat(youtube): support version 18.23.35 (#433)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2023-07-08 01:02:42 +02:00
oSumAtrIX
7b61cc8567 build: update gradle 2023-07-05 23:07:30 +02:00
semantic-release-bot
b8b9edad64 chore(release): 0.112.0-dev.1 [skip ci]
# [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](be3955fee4))
2023-07-05 13:59:10 +00:00
oSumAtrIX
be3955fee4 feat: remove unnecessary notice 2023-07-05 15:57:17 +02:00
semantic-release-bot
3da3ce9e9a chore(release): 0.111.3-dev.1 [skip ci]
## [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](ea7ee56276))
2023-07-05 08:43:51 +00:00
johnconner122
ea7ee56276 fix(youtube/hide-ads): remove duplicate filter (#432) 2023-07-05 10:41:57 +02:00
LisoUseInAIKyrios
8b01ca0c0e chore: delete old unused migration code 2023-07-04 03:01:23 +04:00
semantic-release-bot
170685b920 chore(release): 0.111.2 [skip ci]
## [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](d947de2e03))
* **youtube/spoof-signature-verification:** remove auto re-enable functionality ([#428](https://github.com/revanced/revanced-integrations/issues/428)) ([8afe82c](8afe82c0e0))
2023-07-03 21:38:05 +00:00
oSumAtrIX
f46cbaa3fe chore: merge branch dev to main (#429) 2023-07-03 23:35:33 +02:00
semantic-release-bot
e9947fd66a chore(release): 0.111.2-dev.2 [skip ci]
## [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](d947de2e03))
2023-07-03 19:30:58 +00:00
LisoUseInAIKyrios
d947de2e03 fix(reddit/sanitize-sharing-links): update patch to support latest app version (#430) 2023-07-03 23:29:04 +04:00
semantic-release-bot
e9f797824e chore(release): 0.111.2-dev.1 [skip ci]
## [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](8afe82c0e0))
2023-07-02 08:27:45 +00:00
LisoUseInAIKyrios
8afe82c0e0 fix(youtube/spoof-signature-verification): remove auto re-enable functionality (#428) 2023-07-02 12:25:51 +04:00
semantic-release-bot
bb9120ebae chore(release): 0.111.1 [skip ci]
## [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](d7a3973ef1))
* **youtube/disable-fullscreen-panels:** prompt to restart after turning on/off ([#426](https://github.com/revanced/revanced-integrations/issues/426)) ([328ecff](328ecff18b))

### Performance Improvements

* return earlier when possible ([#427](https://github.com/revanced/revanced-integrations/issues/427)) ([12f3f97](12f3f97552))
2023-07-01 00:39:21 +00:00
oSumAtrIX
bc91b35994 chore: merge branch dev to main (#425) 2023-07-01 02:36:52 +02:00
semantic-release-bot
f3f8026c1e chore(release): 0.111.1-dev.3 [skip ci]
## [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](12f3f97552))
2023-06-27 01:30:40 +00:00
Jim Man
12f3f97552 perf: return earlier when possible (#427) 2023-06-27 03:28:29 +02:00
semantic-release-bot
b4c0619abb chore(release): 0.111.1-dev.2 [skip ci]
## [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)

### Bug Fixes

* **youtube/disable-fullscreen-panels:** prompt to restart after turning on/off ([#426](https://github.com/revanced/revanced-integrations/issues/426)) ([328ecff](328ecff18b))
2023-06-25 18:52:48 +00:00
LisoUseInAIKyrios
328ecff18b fix(youtube/disable-fullscreen-panels): prompt to restart after turning on/off (#426) 2023-06-25 22:50:39 +04:00
semantic-release-bot
40c07769e2 chore(release): 0.111.1-dev.1 [skip ci]
## [0.111.1-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.111.0...v0.111.1-dev.1) (2023-06-23)

### 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](d7a3973ef1))
2023-06-23 13:47:50 +00:00
LisoUseInAIKyrios
d7a3973ef1 fix(youtube/client-spoof): update settings text for known side effects of spoof signature (#424) 2023-06-23 17:45:47 +04:00
semantic-release-bot
db9b0e312d chore(release): 0.111.0 [skip ci]
# [0.111.0](https://github.com/revanced/revanced-integrations/compare/v0.110.0...v0.111.0) (2023-06-21)

### Bug Fixes

* don't include all Litho patches, when not included ([9952581](9952581a32))
* **reddit/hide-ads:** only filter promoted links ([efc2b9b](efc2b9b6a3))
* **youtube/client-spoof:** use new visitor data to work around playback issues ([be9c948](be9c948ce6))
* **youtube/hide-layout-components:** preserve gap when hiding expandable chips ([b47a214](b47a214067))
* **youtube:** separate `hide-ads` to `hide-layout-components` patch ([bdce029](bdce0298c4))

### Features

* **youtube/hide-layout-components:** separate hiding expandable chips and chapters ([80fb3a3](80fb3a31dd))
2023-06-21 23:31:43 +00:00
oSumAtrIX
190481cb39 chore: merge branch dev to main (#421) 2023-06-22 01:29:48 +02:00
semantic-release-bot
4f4a096318 chore(release): 0.111.0-dev.3 [skip ci]
# [0.111.0-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.111.0-dev.2...v0.111.0-dev.3) (2023-06-21)

### Bug Fixes

* **youtube/client-spoof:** use new visitor data to work around playback issues ([be9c948](be9c948ce6))
2023-06-21 23:26:58 +00:00
oSumAtrIX
be9c948ce6 fix(youtube/client-spoof): use new visitor data to work around playback issues
See 81ca451480
2023-06-22 01:13:14 +02:00
semantic-release-bot
4f66d05573 chore(release): 0.111.0-dev.2 [skip ci]
# [0.111.0-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.111.0-dev.1...v0.111.0-dev.2) (2023-06-18)

### Bug Fixes

* **youtube/hide-layout-components:** preserve gap when hiding expandable chips ([b47a214](b47a214067))
2023-06-18 17:46:56 +00:00
oSumAtrIX
b47a214067 fix(youtube/hide-layout-components): preserve gap when hiding expandable chips 2023-06-18 19:44:37 +02:00
35 changed files with 860 additions and 705 deletions

9
.gitattributes vendored Normal file
View 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

View File

@@ -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

View File

@@ -1,3 +1,230 @@
# [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)
### Bug Fixes
* **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))
## [0.111.1-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.111.0...v0.111.1-dev.1) (2023-06-23)
### 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))
# [0.111.0](https://github.com/revanced/revanced-integrations/compare/v0.110.0...v0.111.0) (2023-06-21)
### Bug Fixes
* don't include all Litho patches, when not included ([9952581](https://github.com/revanced/revanced-integrations/commit/9952581a325b780f7dea074cc4ed138d7ac2758b))
* **reddit/hide-ads:** only filter promoted links ([efc2b9b](https://github.com/revanced/revanced-integrations/commit/efc2b9b6a39de93d6cc1052dfcea457aeaf949b2))
* **youtube/client-spoof:** use new visitor data to work around playback issues ([be9c948](https://github.com/revanced/revanced-integrations/commit/be9c948ce6135ec7fad4d7e7dc18be64e9dbb3eb))
* **youtube/hide-layout-components:** preserve gap when hiding expandable chips ([b47a214](https://github.com/revanced/revanced-integrations/commit/b47a214067031c099df990d4c83a1d96ab7b3c34))
* **youtube:** separate `hide-ads` to `hide-layout-components` patch ([bdce029](https://github.com/revanced/revanced-integrations/commit/bdce0298c404be6e5c3ae6854f3609d82ad76e28))
### Features
* **youtube/hide-layout-components:** separate hiding expandable chips and chapters ([80fb3a3](https://github.com/revanced/revanced-integrations/commit/80fb3a31dd4604b0d1d72c6033624d2d780746ea))
# [0.111.0-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.111.0-dev.2...v0.111.0-dev.3) (2023-06-21)
### Bug Fixes
* **youtube/client-spoof:** use new visitor data to work around playback issues ([be9c948](https://github.com/revanced/revanced-integrations/commit/be9c948ce6135ec7fad4d7e7dc18be64e9dbb3eb))
# [0.111.0-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.111.0-dev.1...v0.111.0-dev.2) (2023-06-18)
### Bug Fixes
* **youtube/hide-layout-components:** preserve gap when hiding expandable chips ([b47a214](https://github.com/revanced/revanced-integrations/commit/b47a214067031c099df990d4c83a1d96ab7b3c34))
# [0.111.0-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.110.1-dev.3...v0.111.0-dev.1) (2023-06-18)

View File

@@ -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;

View File

@@ -2,15 +2,20 @@ package app.revanced.integrations.patches;
import static app.revanced.integrations.utils.ReVancedUtils.containsAny;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 {
/**
* Enable/disable all workarounds that are required due to signature spoofing.
*/
private static final boolean WORKAROUND = true;
/**
* Protobuf parameters used for autoplay in scrim.
* Prepend this parameter to mute video playback (for autoplay in feed)
@@ -18,10 +23,12 @@ public class SpoofSignatureVerificationPatch {
private static final String PROTOBUF_PARAMETER_SCRIM = "SAFgAXgB";
/**
* Protobuf parameter of shorts and YouTube stories.
* Protobuf parameter also used by
* <a href="https://github.com/yt-dlp/yt-dlp/blob/81ca451480051d7ce1a31c017e005358345a9149/yt_dlp/extractor/youtube.py#L3602">yt-dlp</a>
* <br>
* Known issue: captions are positioned on upper area in the player.
*/
private static final String PROTOBUF_PARAMETER_SHORTS = "8AEB"; // "8AEByAMTuAQP"
private static final String PROTOBUF_PLAYER_PARAMS = "CgIQBg==";
/**
* Target Protobuf parameters.
@@ -31,28 +38,6 @@ public class SpoofSignatureVerificationPatch {
"SAFg" // Autoplay in scrim
};
/**
* On app first start, the first video played usually contains a single non-default window setting value
* and all other subtitle settings for the video are (incorrect) default shorts window settings.
* For this situation, the shorts settings must be replaced.
*
* But some videos use multiple text positions on screen (such as https://youtu.be/3hW1rMNC89o),
* and by chance many of the subtitles uses window positions that match a default shorts position.
* To handle these videos, selectively allowing the shorts specific window settings to 'pass thru' unchanged,
* but only if the video contains multiple non-default subtitle window positions.
*
* Do not enable 'pass thru mode' until this many non default subtitle settings are observed for a single video.
*/
private static final int NUMBER_OF_NON_DEFAULT_SUBTITLES_BEFORE_ENABLING_PASSTHRU = 2;
/**
* The number of non default subtitle settings encountered for the current video.
*/
private static int numberOfNonDefaultSettingsObserved;
@Nullable
private static String currentVideoId;
/**
* Injection point.
*
@@ -66,17 +51,18 @@ public class SpoofSignatureVerificationPatch {
LogHelper.printDebug(() -> "Original protobuf parameter value: " + originalValue);
// Video is Short or Story.
var isPlayingShorts = originalValue.contains(PROTOBUF_PARAMETER_SHORTS);
if (isPlayingShorts) return originalValue;
if (!WORKAROUND) return PROTOBUF_PLAYER_PARAMS;
var isPlayingVideo = originalValue.contains(PROTOBUF_PLAYER_PARAMS);
if (isPlayingVideo) return originalValue;
boolean isPlayingFeed = containsAny(originalValue, PROTOBUF_PARAMETER_TARGETS) && PlayerType.getCurrent() == PlayerType.INLINE_MINIMAL;
if (isPlayingFeed) {
// Videos in feed won't autoplay with sound.
return PROTOBUF_PARAMETER_SCRIM + PROTOBUF_PARAMETER_SHORTS;
return PROTOBUF_PARAMETER_SCRIM + PROTOBUF_PLAYER_PARAMS;
} else {
// Spoof the parameter to prevent playback issues.
return PROTOBUF_PARAMETER_SHORTS;
return PROTOBUF_PLAYER_PARAMS;
}
} catch (Exception ex) {
LogHelper.printException(() -> "overrideProtobufParameter failure", ex);
@@ -85,140 +71,25 @@ public class SpoofSignatureVerificationPatch {
return originalValue;
}
/**
* 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
*
* @param responseCode HTTP status code of the completed YouTube connection
* Injection point.
*/
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);
}
}
/**
* Last WindowsSetting constructor values. Values are checked for changes to reduce log spam.
*/
private static int lastAp, lastAh, lastAv;
private static boolean lastVs, lastSd;
/**
* Injection point. Overrides values passed into SubtitleWindowSettings constructor.
*
* @param ap anchor position. A bitmask with 6 bit fields, that appears to indicate the layout position on screen
* @param ah anchor horizontal. A percentage [0, 100], that appears to be a horizontal text anchor point
* @param av anchor vertical. A percentage [0, 100], that appears to be a vertical text anchor point
* @param vs appears to indicate if subtitles exist, and the value is always true.
* @param sd function is not entirely clear
*/
public static int[] getSubtitleWindowSettingsOverride(int ap, int ah, int av, boolean vs, boolean sd) {
final boolean signatureSpoofing = SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean();
if (SettingsEnum.DEBUG.getBoolean()) {
if (ap != lastAp || ah != lastAh || av != lastAv || vs != lastVs || sd != lastSd) {
LogHelper.printDebug(() -> "video: " + VideoInformation.getVideoId() + " spoof: " + signatureSpoofing
+ " ap:" + ap + " ah:" + ah + " av:" + av + " vs:" + vs + " sd:" + sd);
lastAp = ap;
lastAh = ah;
lastAv = av;
lastVs = vs;
lastSd = sd;
}
}
// Videos with custom captions that specify screen positions appear to always have correct screen positions (even with spoofing).
// But for auto generated and most other captions, the spoof incorrectly gives various default Shorts caption settings.
// Check for these known default shorts captions parameters, and replace with the known correct values.
//
// If a regular video uses a custom subtitle setting that match a default short setting,
// then this will incorrectly replace the setting.
// But, if the video uses multiple subtitles in different screen locations, then detect the non-default values
// and do not replace any window settings for the video (regardless if they match a shorts default).
if (signatureSpoofing && !PlayerType.getCurrent().isNoneOrHidden()
&& numberOfNonDefaultSettingsObserved < NUMBER_OF_NON_DEFAULT_SUBTITLES_BEFORE_ENABLING_PASSTHRU) {
for (SubtitleWindowReplacementSettings setting : SubtitleWindowReplacementSettings.values()) {
if (setting.match(ap, ah, av, vs, sd)) {
return setting.replacementSetting();
}
}
numberOfNonDefaultSettingsObserved++;
LogHelper.printDebug(() ->
numberOfNonDefaultSettingsObserved < NUMBER_OF_NON_DEFAULT_SUBTITLES_BEFORE_ENABLING_PASSTHRU
? "Non default subtitle found."
: "Multiple non default subtitles found. Allowing all subtitles for this video to pass thru unchanged.");
}
return new int[]{ap, ah, av};
public static boolean getSeekbarThumbnailOverrideValue() {
return SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean();
}
/**
* Injection point.
*
* @param view seekbar thumbnail view. Includes both shorts and regular videos.
*/
public static void setCurrentVideoId(@NonNull String videoId) {
try {
if (videoId.equals(currentVideoId)) {
return;
}
currentVideoId = videoId;
numberOfNonDefaultSettingsObserved = 0;
} catch (Exception ex) {
LogHelper.printException(() -> "setCurrentVideoId 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);
}
}
/**
* Known incorrect default Shorts subtitle parameters, and the corresponding correct (non-Shorts) values.
*/
private enum SubtitleWindowReplacementSettings {
DEFAULT_SHORTS_PARAMETERS_1(10, 50, 0, true, false,
34, 50, 95),
DEFAULT_SHORTS_PARAMETERS_2(9, 20, 0, true, false,
34, 50, 90),
DEFAULT_SHORTS_PARAMETERS_3(9, 20, 0, true, true,
33, 20, 100);
// original values
final int ap, ah, av;
final boolean vs, sd;
// replacement int values
final int[] replacement;
SubtitleWindowReplacementSettings(int ap, int ah, int av, boolean vs, boolean sd,
int replacementAp, int replacementAh, int replacementAv) {
this.ap = ap;
this.ah = ah;
this.av = av;
this.vs = vs;
this.sd = sd;
this.replacement = new int[]{replacementAp, replacementAh, replacementAv};
}
boolean match(int ap, int ah, int av, boolean vs, boolean sd) {
return this.ap == ap && this.ah == ah && this.av == av && this.vs == vs && this.sd == sd;
}
int[] replacementSetting() {
return replacement;
}
}
}

View File

@@ -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;
}
}

View File

@@ -23,6 +23,7 @@ public final class AdsFilter extends Filter {
"_buttoned_layout",
"full_width_square_image_layout",
"_ad_with",
"text_image_button_group_layout",
"video_display_button_group_layout",
"landscape_image_wide_button_layout"
);

View File

@@ -2,22 +2,21 @@ package app.revanced.integrations.patches.components;
import android.os.Build;
import android.view.View;
import androidx.annotation.RequiresApi;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.ReVancedUtils;
@RequiresApi(api = Build.VERSION_CODES.N)
public final class LayoutComponentsFilter extends Filter {
private final String[] exceptions;
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() {
@@ -104,7 +103,7 @@ public final class LayoutComponentsFilter extends Filter {
final var expandableMetadata = new StringFilterGroup(
SettingsEnum.HIDE_EXPANDABLE_CHIP,
"expandable_metadata"
"inline_expander"
);
final var chapters = new StringFilterGroup(
@@ -137,21 +136,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,
@@ -174,29 +163,12 @@ public final class LayoutComponentsFilter extends Filter {
channelMemberShelf
);
final var carouselAd = new StringFilterGroup(
SettingsEnum.HIDE_GENERAL_ADS,
"carousel_ad"
);
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())
@@ -205,18 +177,12 @@ public final class LayoutComponentsFilter extends Filter {
if (ReVancedUtils.containsAny(path, exceptions))
return false; // Exceptions are not filtered.
if (super.isFiltered(path, identifier, _protobufBufferArray))
return true;
return isMixPlaylistFiltered(_protobufBufferArray);
return super.isFiltered(path, identifier, _protobufBufferArray);
}
/**
* Hide the view, which shows ads in the homepage.
*
* @param view The view, which shows ads.
*/
public static void hideAdAttributionView(View view) {
ReVancedUtils.hideViewBy1dpUnderCondition(SettingsEnum.HIDE_GENERAL_ADS, view);
// Called from a different place then the other filters.
public static boolean filterMixPlaylists(final byte[] bytes) {
return mixPlaylists.isEnabled() && mixPlaylists.check(bytes).isFiltered();
}
}

View File

@@ -1,11 +1,9 @@
package app.revanced.integrations.patches.components;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -14,6 +12,10 @@ import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
abstract class FilterGroup<T> {
final static class FilterGroupResult {
private final boolean filtered;
@@ -49,7 +51,7 @@ abstract class FilterGroup<T> {
}
public boolean isEnabled() {
return setting.getBoolean();
return setting == null || setting.getBoolean();
}
public abstract FilterGroupResult check(final T stack);
@@ -83,9 +85,10 @@ final class CustomFilterGroup extends StringFilterGroup {
class ByteArrayFilterGroup extends FilterGroup<byte[]> {
// Modified implementation from https://stackoverflow.com/a/1507813
private int indexOf(final byte[] data, final byte[] pattern) {
if (data.length == 0)
return -1;
// Computes the failure function using a boot-strapping process,
// where the pattern is matched against itself.
final int[] failure = new int[pattern.length];
int j = 0;
@@ -103,7 +106,6 @@ class ByteArrayFilterGroup extends FilterGroup<byte[]> {
// KMP matching algorithm.
j = 0;
if (data.length == 0) return -1;
for (int i = 0; i < data.length; i++) {
while (j > 0 && pattern[j] != data[i]) {
@@ -130,7 +132,8 @@ class ByteArrayFilterGroup extends FilterGroup<byte[]> {
public FilterGroupResult check(final byte[] bytes) {
var matched = false;
for (byte[] filter : filters) {
if (indexOf(bytes, filter) == -1) continue;
if (indexOf(bytes, filter) == -1)
continue;
matched = true;
break;
@@ -181,7 +184,8 @@ abstract class FilterGroupList<V, T extends FilterGroup<V>> implements Iterable<
protected boolean contains(final V stack) {
for (T filterGroup : this) {
if (!filterGroup.isEnabled()) continue;
if (!filterGroup.isEnabled())
continue;
var result = filterGroup.check(stack);
if (result.isFiltered()) {
@@ -205,7 +209,8 @@ abstract class Filter {
final protected ByteArrayFilterGroupList protobufBufferFilterGroups = new ByteArrayFilterGroupList();
/**
* Check if the given path, identifier or protobuf buffer is filtered by any {@link FilterGroup}.
* Check if the given path, identifier or protobuf buffer is filtered by any
* {@link FilterGroup}. Method is called off the main thread.
*
* @return True if filtered, false otherwise.
*/
@@ -232,34 +237,39 @@ abstract class Filter {
@RequiresApi(api = Build.VERSION_CODES.N)
@SuppressWarnings("unused")
public final class LithoFilterPatch {
private static final Filter[] filters = new Filter[]{
new DummyFilter() // Replaced by patch.
private static final Filter[] filters = new Filter[] {
new DummyFilter() // Replaced by patch.
};
/**
* Injection point. Called off the main thread.
*/
@SuppressWarnings("unused")
public static boolean filter(final StringBuilder pathBuilder, final String identifier, final ByteBuffer protobufBuffer) {
// TODO: Maybe this can be moved to the Filter class, to prevent unnecessary string creation
// because some filters might not need the path.
public static boolean filter(final StringBuilder pathBuilder, final String identifier,
final ByteBuffer protobufBuffer) {
// TODO: Maybe this can be moved to the Filter class, to prevent unnecessary
// string creation
// because some filters might not need the path.
var path = pathBuilder.toString();
// It is assumed that protobufBuffer is empty as well in this case.
if (path.isEmpty()) return false;
if (path.isEmpty())
return false;
LogHelper.printDebug(() -> String.format(
"Searching (ID: %s, Buffer-size: %s): %s",
identifier, protobufBuffer.remaining(), path
));
identifier, protobufBuffer.remaining(), path));
var protobufBufferArray = protobufBuffer.array();
for (var filter : filters) {
var filtered = filter.isFiltered(path, identifier, protobufBufferArray);
LogHelper.printDebug(() ->
String.format("%s (ID: %s): %s", filtered ? "Filtered" : "Unfiltered", identifier, path)
);
LogHelper.printDebug(
() -> String.format("%s (ID: %s): %s", filtered ? "Filtered" : "Unfiltered", identifier, path));
if (filtered) return true;
if (filtered)
return true;
}
return false;

View File

@@ -0,0 +1,21 @@
package app.revanced.integrations.patches.components;
// 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(final String path, final String identifier, final byte[] protobufBufferArray) {
isPlaybackSpeedMenuVisible = super.isFiltered(path, identifier, protobufBufferArray);
return false;
}
}

View File

@@ -1,33 +1,22 @@
package app.revanced.integrations.patches.components;
import android.view.View;
import app.revanced.integrations.settings.SettingsEnum;
import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar;
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 com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar;
import app.revanced.integrations.settings.SettingsEnum;
public final class ShortsFilter extends Filter {
// Set by patch.
public static PivotBar pivotBar;
@SuppressLint("StaticFieldLeak")
final StringFilterGroupList shortsFilterGroup = new StringFilterGroupList();
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"
);
public ShortsFilter() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
final var thanksButton = new StringFilterGroup(
SettingsEnum.HIDE_SHORTS_THANKS_BUTTON,
"suggested_action"
@@ -48,6 +37,11 @@ public final class ShortsFilter extends Filter {
"reel_pivot_button"
);
final var infoPanel = new StringFilterGroup(
SettingsEnum.HIDE_SHORTS_INFO_PANEL,
"shorts_info_panel_overview"
);
final var channelBar = new StringFilterGroup(
SettingsEnum.HIDE_SHORTS_CHANNEL_BAR,
"reel_channel_bar"
@@ -61,19 +55,20 @@ public final class ShortsFilter extends Filter {
"shorts_video_cell"
);
this.pathFilterGroups.addAll(joinButton, subscribeButton, soundButton, channelBar);
this.identifierFilterGroups.addAll(shorts, thanksButton);
shortsFilterGroup.addAll(soundButton, infoPanel);
pathFilterGroups.addAll(joinButton, subscribeButton, channelBar);
identifierFilterGroups.addAll(shorts, thanksButton);
}
@Override
boolean isFiltered(final String path, final String identifier,
final byte[] protobufBufferArray) {
// Filter the path only when reelChannelBar is visible.
if (reelChannelBar.check(path).isFiltered())
if (this.pathFilterGroups.contains(path)) return true;
// Shorts info panel path appears outside of reelChannelBar path.
if (infoPanel.isEnabled() && infoPanel.check(path).isFiltered()) return true;
if (shortsFilterGroup.contains(path)) return true;
return this.identifierFilterGroups.contains(identifier);
}

View File

@@ -0,0 +1,23 @@
package app.revanced.integrations.patches.components;
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(final String path, final String identifier, final byte[] protobufBufferArray) {
isVideoQualityMenuVisible = super.isFiltered(path, identifier, protobufBufferArray);
return false;
}
}

View File

@@ -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) {}
});
}
}

View File

@@ -0,0 +1,94 @@
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) {// Hide the video quality menu.
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) {
}
});
}
}

View File

@@ -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.
*/

View File

@@ -1,16 +1,24 @@
package app.revanced.integrations.patches.playback.speed;
import static app.revanced.integrations.patches.playback.quality.OldVideoQualityMenuPatch.addRecyclerListener;
import android.preference.ListPreference;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import com.facebook.litho.ComponentHost;
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;
public class CustomVideoSpeedPatch {
public class CustomPlaybackSpeedPatch {
/**
* Maximum playback speed, exclusive value. Custom speeds must be less than this value.
*/
@@ -19,17 +27,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 +45,7 @@ public class CustomVideoSpeedPatch {
private static String[] preferenceListEntries, preferenceListEntryValues;
static {
loadSpeeds();
loadCustomSpeeds();
}
private static void resetCustomSpeeds(@NonNull String toastMessage) {
@@ -45,33 +53,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 +95,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 +108,32 @@ public class CustomVideoSpeedPatch {
preference.setEntries(preferenceListEntries);
preference.setEntryValues(preferenceListEntryValues);
}
/*
* To reduce copy 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 &&
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.
}
}

View File

@@ -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);
}

View File

@@ -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));

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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() {

View File

@@ -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 {

View File

@@ -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;
@@ -198,7 +199,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 +239,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 +269,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 +277,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 +357,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 +376,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 +396,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 +435,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 +507,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)) {

View File

@@ -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;
}
}
}

View File

@@ -2,40 +2,71 @@ package app.revanced.tiktok.settingsmenu;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.bytedance.ies.ugc.aweme.commercialize.compliance.personalization.AdPersonalizationActivity;
import app.revanced.tiktok.utils.LogHelper;
import app.revanced.tiktok.utils.ReVancedUtils;
import com.bytedance.ies.ugc.aweme.commercialize.compliance.personalization.AdPersonalizationActivity;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class SettingsMenu {
public static void initializeSettings(AdPersonalizationActivity base) {
public static Object createSettingsEntry(String entryClazzName, String entryInfoClazzName) {
try {
Class<?> entryClazz = Class.forName(entryClazzName);
Class<?> entryInfoClazz = Class.forName(entryInfoClazzName);
Constructor<?> entryConstructor = entryClazz.getConstructor(entryInfoClazz);
Constructor<?> entryInfoConstructor = entryInfoClazz.getDeclaredConstructors()[0];
Object buttonInfo = entryInfoConstructor.newInstance("Revanced settings", null, (View.OnClickListener) view -> startSettingsActivity());
return entryConstructor.newInstance(buttonInfo);
} catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException |
InstantiationException e) {
throw new RuntimeException(e);
}
}
/***
* Initialize the settings menu.
* @param base The activity to initialize the settings menu on.
* @return Whether the settings menu should be initialized.
*/
public static boolean initializeSettings(AdPersonalizationActivity base) {
Bundle extras = base.getIntent().getExtras();
if (extras != null && !extras.getBoolean("revanced", false)) return false;
SettingsStatus.load();
LinearLayout linearLayout = new LinearLayout(base);
linearLayout.setLayoutParams(new LinearLayout.LayoutParams(-1, -1));
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setFitsSystemWindows(true);
linearLayout.setTransitionGroup(true);
FrameLayout fragment = new FrameLayout(base);
fragment.setLayoutParams(new FrameLayout.LayoutParams(-1, -1));
int fragmentId = View.generateViewId();
fragment.setId(fragmentId);
linearLayout.addView(fragment);
base.setContentView(linearLayout);
PreferenceFragment preferenceFragment = new ReVancedSettingsFragment();
base.getFragmentManager().beginTransaction().replace(fragmentId, preferenceFragment).commit();
return true;
}
public static void startSettingsActivity() {
private static void startSettingsActivity() {
Context appContext = ReVancedUtils.getAppContext();
if (appContext != null) {
Intent intent = new Intent(appContext, AdPersonalizationActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("revanced", true);
appContext.startActivity(intent);
} else {
LogHelper.debug(SettingsMenu.class, "ReVancedUtils.getAppContext() return null");

View File

@@ -4,7 +4,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:8.0.1")
classpath("com.android.tools.build:gradle:7.4.2")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20")
}
}

View File

@@ -0,0 +1,19 @@
package android.support.v7.widget;
import android.content.Context;
import android.view.View;
public class RecyclerView extends View {
public RecyclerView(Context context) {
super(context);
}
public View getChildAt(@SuppressWarnings("unused") final int index) {
return null;
}
public int getChildCount() {
return 0;
}
}

View File

@@ -0,0 +1,10 @@
package com.facebook.litho;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
public final class ComponentHost extends RecyclerView {
public ComponentHost(Context context) {
super(context);
}
}

View File

@@ -1,3 +1,4 @@
org.gradle.jvmargs = -Xmx2048m
org.gradle.parallel = true
org.gradle.caching = true
android.useAndroidX = true
version = 0.111.0-dev.1
version = 0.115.0-dev.1

Binary file not shown.

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