1
mirror of https://github.com/revanced/revanced-integrations synced 2025-11-21 18:35:37 +01:00

Compare commits

..

16 Commits

Author SHA1 Message Date
semantic-release-bot
c8784a5966 chore(release): 0.106.0-dev.4 [skip ci]
# [0.106.0-dev.4](https://github.com/revanced/revanced-integrations/compare/v0.106.0-dev.3...v0.106.0-dev.4) (2023-04-30)

### Bug Fixes

* **youtube/return-youtube-dislike:** support old UI layouts ([#378](https://github.com/revanced/revanced-integrations/issues/378)) ([d3f8fb9](d3f8fb9739))
2023-04-30 19:43:40 +00:00
LisoUseInAIKyrios
d3f8fb9739 fix(youtube/return-youtube-dislike): support old UI layouts (#378) 2023-04-30 23:41:13 +04:00
semantic-release-bot
ff0d64287c chore(release): 0.106.0-dev.3 [skip ci]
# [0.106.0-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.106.0-dev.2...v0.106.0-dev.3) (2023-04-30)

### Features

* **youtube/hide-get-premium:** hide get premium advertisements under video player ([#376](https://github.com/revanced/revanced-integrations/issues/376)) ([36fd284](36fd2844c4))
2023-04-30 18:36:38 +00:00
LisoUseInAIKyrios
36fd2844c4 feat(youtube/hide-get-premium): hide get premium advertisements under video player (#376) 2023-04-30 22:34:37 +04:00
oSumAtrIX
0de83fff0e chore: update gradle and dependencies 2023-04-30 05:27:21 +02:00
semantic-release-bot
24a609288f chore(release): 0.106.0-dev.2 [skip ci]
# [0.106.0-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.106.0-dev.1...v0.106.0-dev.2) (2023-04-30)

### Features

* add appreciation message for new contributors ([78d56d4](78d56d4fe1))
2023-04-30 01:17:18 +00:00
oSumAtrIX
78d56d4fe1 feat: add appreciation message for new contributors 2023-04-30 03:15:36 +02:00
semantic-release-bot
27fdcfff08 chore(release): 0.106.0-dev.1 [skip ci]
# [0.106.0-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.105.1-dev.2...v0.106.0-dev.1) (2023-04-28)

### Features

* **youtube/spoof-app-version:** user selectable version to spoof ([#375](https://github.com/revanced/revanced-integrations/issues/375)) ([f6f6c93](f6f6c93c57))
2023-04-28 17:53:58 +00:00
LisoUseInAIKyrios
f6f6c93c57 feat(youtube/spoof-app-version): user selectable version to spoof (#375) 2023-04-28 21:52:09 +04:00
semantic-release-bot
a661dac623 chore(release): 0.105.1-dev.2 [skip ci]
## [0.105.1-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.105.1-dev.1...v0.105.1-dev.2) (2023-04-28)

### Bug Fixes

* **youtube/spoof-signature-verification:** more fixes for subtitle window positions  ([#374](https://github.com/revanced/revanced-integrations/issues/374)) ([8cc1b6e](8cc1b6ea4a))
2023-04-28 08:51:38 +00:00
LisoUseInAIKyrios
8cc1b6ea4a fix(youtube/spoof-signature-verification): more fixes for subtitle window positions (#374) 2023-04-28 12:49:41 +04:00
semantic-release-bot
829895874b chore(release): 0.105.1-dev.1 [skip ci]
## [0.105.1-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.105.0...v0.105.1-dev.1) (2023-04-28)

### Bug Fixes

* **youtube:** no longer need to restart the app after changing `copy-video-url` or `downloads` patch ([#372](https://github.com/revanced/revanced-integrations/issues/372)) ([6b15514](6b15514885))
2023-04-28 06:18:05 +00:00
LisoUseInAIKyrios
6b15514885 fix(youtube): no longer need to restart the app after changing copy-video-url or downloads patch (#372)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-04-28 10:16:08 +04:00
semantic-release-bot
5b53e02613 chore(release): 0.105.0 [skip ci]
# [0.105.0](https://github.com/revanced/revanced-integrations/compare/v0.104.0...v0.105.0) (2023-04-27)

### Bug Fixes

* **youtube/minimized-playback:** disable minimized playback for shorts ([#371](https://github.com/revanced/revanced-integrations/issues/371)) ([df4b03f](df4b03fed5))
* **youtube/return-youtube-dislike:** fix dislikes using wrong font if dark mode is enabled during video playback ([#368](https://github.com/revanced/revanced-integrations/issues/368)) ([3b37a3b](3b37a3b41f))
* **youtube/spoof-signature-verification:** additional fixes for subtitle window positions ([#369](https://github.com/revanced/revanced-integrations/issues/369)) ([6f2ae31](6f2ae313cf))

### Features

* **youtube/sponsorblock:** automatically hide skip button ([#365](https://github.com/revanced/revanced-integrations/issues/365)) ([75dad2f](75dad2f307))
2023-04-27 21:37:45 +00:00
oSumAtrIX
2deacc5035 chore: merge branch dev to main (#370) 2023-04-27 23:35:22 +02:00
oSumAtrIX
46d70a3e00 refactor: use better method name 2023-04-27 21:08:32 +02:00
19 changed files with 339 additions and 117 deletions

2
.github/config.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
firstPRMergeComment: >
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.

View File

@@ -1,3 +1,59 @@
# [0.106.0-dev.4](https://github.com/revanced/revanced-integrations/compare/v0.106.0-dev.3...v0.106.0-dev.4) (2023-04-30)
### Bug Fixes
* **youtube/return-youtube-dislike:** support old UI layouts ([#378](https://github.com/revanced/revanced-integrations/issues/378)) ([d3f8fb9](https://github.com/revanced/revanced-integrations/commit/d3f8fb97399aafe98a4198234338c6d0196a7e75))
# [0.106.0-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.106.0-dev.2...v0.106.0-dev.3) (2023-04-30)
### Features
* **youtube/hide-get-premium:** hide get premium advertisements under video player ([#376](https://github.com/revanced/revanced-integrations/issues/376)) ([36fd284](https://github.com/revanced/revanced-integrations/commit/36fd2844c468a4a9af3fe6ee5e62775f1e8dbe56))
# [0.106.0-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.106.0-dev.1...v0.106.0-dev.2) (2023-04-30)
### Features
* add appreciation message for new contributors ([78d56d4](https://github.com/revanced/revanced-integrations/commit/78d56d4fe182999555ddf5881a10880e3726782e))
# [0.106.0-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.105.1-dev.2...v0.106.0-dev.1) (2023-04-28)
### Features
* **youtube/spoof-app-version:** user selectable version to spoof ([#375](https://github.com/revanced/revanced-integrations/issues/375)) ([f6f6c93](https://github.com/revanced/revanced-integrations/commit/f6f6c93c57bdbec13f09acd802f58554cb981f3a))
## [0.105.1-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.105.1-dev.1...v0.105.1-dev.2) (2023-04-28)
### Bug Fixes
* **youtube/spoof-signature-verification:** more fixes for subtitle window positions ([#374](https://github.com/revanced/revanced-integrations/issues/374)) ([8cc1b6e](https://github.com/revanced/revanced-integrations/commit/8cc1b6ea4af4e642fb2d97233d50f34b0113f2c0))
## [0.105.1-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.105.0...v0.105.1-dev.1) (2023-04-28)
### Bug Fixes
* **youtube:** no longer need to restart the app after changing `copy-video-url` or `downloads` patch ([#372](https://github.com/revanced/revanced-integrations/issues/372)) ([6b15514](https://github.com/revanced/revanced-integrations/commit/6b155148854fbfe155c9384ba8976b5ddf3d5992))
# [0.105.0](https://github.com/revanced/revanced-integrations/compare/v0.104.0...v0.105.0) (2023-04-27)
### Bug Fixes
* **youtube/minimized-playback:** disable minimized playback for shorts ([#371](https://github.com/revanced/revanced-integrations/issues/371)) ([df4b03f](https://github.com/revanced/revanced-integrations/commit/df4b03fed5a0622b18bf4a8dca1940d26a590d8f))
* **youtube/return-youtube-dislike:** fix dislikes using wrong font if dark mode is enabled during video playback ([#368](https://github.com/revanced/revanced-integrations/issues/368)) ([3b37a3b](https://github.com/revanced/revanced-integrations/commit/3b37a3b41f7bfbc4a6d6d12e2deb2acd9bb2ccc8))
* **youtube/spoof-signature-verification:** additional fixes for subtitle window positions ([#369](https://github.com/revanced/revanced-integrations/issues/369)) ([6f2ae31](https://github.com/revanced/revanced-integrations/commit/6f2ae313cf492166d64e5e33e759f2b234191b64))
### Features
* **youtube/sponsorblock:** automatically hide skip button ([#365](https://github.com/revanced/revanced-integrations/issues/365)) ([75dad2f](https://github.com/revanced/revanced-integrations/commit/75dad2f3071c19aa097ebdc7bd83d1ce9afb78ea))
# [0.105.0-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.105.0-dev.1...v0.105.0-dev.2) (2023-04-27)

View File

@@ -44,7 +44,7 @@ android {
dependencies {
compileOnly(project(mapOf("path" to ":dummy")))
compileOnly("androidx.annotation:annotation:1.6.0")
compileOnly("androidx.appcompat:appcompat:1.6.1")
compileOnly("androidx.appcompat:appcompat:1.7.0-alpha02")
compileOnly("com.squareup.okhttp3:okhttp:5.0.0-alpha.11")
compileOnly("com.squareup.retrofit2:retrofit:2.9.0")
}

View File

@@ -0,0 +1,12 @@
package app.revanced.integrations.patches;
import app.revanced.integrations.settings.SettingsEnum;
public class HideGetPremiumPatch {
/**
* Injection point.
*/
public static boolean hideGetPremiumView() {
return SettingsEnum.HIDE_GET_PREMIUM.getBoolean();
}
}

View File

@@ -2,6 +2,7 @@ package app.revanced.integrations.patches;
import static app.revanced.integrations.utils.StringRef.str;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -28,6 +29,7 @@ public class MicroGSupport {
context.startActivity(intent);
}
@TargetApi(26)
public static void checkAvailability() {
var context = Objects.requireNonNull(ReVancedUtils.getContext());
@@ -41,10 +43,11 @@ public class MicroGSupport {
System.exit(0);
}
try (var client = context.getContentResolver().acquireContentProviderClient(VANCED_MICROG_PROVIDER)) {
if (client != null) return;
LogHelper.printInfo(() -> "Vanced MicroG is not running in the background");
startIntent(context, DONT_KILL_MY_APP_LINK, str("microg_not_running_warning"));
}
}
}
}

View File

@@ -4,7 +4,7 @@ import app.revanced.integrations.shared.PlayerType;
public class MinimizedPlaybackPatch {
public static boolean playbackIsNotShort() {
public static boolean isPlaybackNotShort() {
return !PlayerType.getCurrent().isNoneOrHidden();
}

View File

@@ -2,23 +2,114 @@ package app.revanced.integrations.patches;
import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote;
import android.text.Editable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextWatcher;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicReference;
import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
public class ReturnYouTubeDislikePatch {
/**
* Resource identifier of old UI dislike button.
*/
private static final int OLD_UI_DISLIKE_BUTTON_RESOURCE_ID
= ReVancedUtils.getResourceIdentifier("dislike_button", "id");
/**
* Dislikes text label used by old UI.
*/
@NonNull
private static WeakReference<TextView> oldUITextViewRef = new WeakReference<>(null);
/**
* Original old UI 'Dislikes' text before patch modifications.
* Required to reset the dislikes when changing videos and RYD is not available.
* Set only once during the first load.
*/
private static Spanned oldUIOriginalSpan;
/**
* Replacement span that contains dislike value. Used by {@link #oldUiTextWatcher}.
*/
@Nullable
private static Spanned oldUIReplacementSpan;
/**
* Old UI dislikes can be set multiple times by YouTube.
* To prevent it from reverting changes made here, this listener overrides any future changes YouTube makes.
*/
private static final TextWatcher oldUiTextWatcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void afterTextChanged(Editable s) {
if (oldUIReplacementSpan == null || oldUIReplacementSpan.toString().equals(s.toString())) {
return;
}
s.replace(0, s.length(), oldUIReplacementSpan);
}
};
private static void updateOldUIDislikesTextView() {
TextView oldUITextView = oldUITextViewRef.get();
if (oldUITextView == null) {
return;
}
Spanned dislikes = ReturnYouTubeDislike.getDislikesSpanForRegularVideo(oldUIOriginalSpan, false);
if (dislikes == null) { // Dislikes not available.
// Must reset text back to original as the TextView may contain dislikes of a prior video.
dislikes = oldUIOriginalSpan;
}
oldUIReplacementSpan = dislikes;
if (!dislikes.equals(oldUITextView.getText())) {
oldUITextView.setText(dislikes);
}
}
/**
* Injection point. Called on main thread.
*
* Used when spoofing the older app versions of {@link SpoofAppVersionPatch}.
*/
public static void setOldUILayoutDislikes(int buttonViewResourceId, @NonNull TextView textView) {
try {
if (!SettingsEnum.RYD_ENABLED.getBoolean()
|| buttonViewResourceId != OLD_UI_DISLIKE_BUTTON_RESOURCE_ID) {
return;
}
if (oldUIOriginalSpan == null) {
// Use value of the first instance, as it appears TextViews can be recycled
// and might contain dislikes previously added by the patch.
oldUIOriginalSpan = (Spanned) textView.getText();
}
oldUITextViewRef = new WeakReference<>(textView);
// No way to check if a listener is already attached, so remove and add again.
textView.removeTextChangedListener(oldUiTextWatcher);
textView.addTextChangedListener(oldUiTextWatcher);
updateOldUIDislikesTextView();
} catch (Exception ex) {
LogHelper.printException(() -> "setOldUILayoutDislikes failure", ex);
}
}
/**
* Injection point.
*/
public static void newVideoLoaded(String videoId) {
public static void newVideoLoaded(@NonNull String videoId) {
try {
if (!SettingsEnum.RYD_ENABLED.getBoolean()) return;
ReturnYouTubeDislike.newVideoLoaded(videoId);
@@ -97,6 +188,7 @@ public class ReturnYouTubeDislikePatch {
for (Vote v : Vote.values()) {
if (v.value == vote) {
ReturnYouTubeDislike.sendVote(v);
updateOldUIDislikesTextView();
return;
}
}

View File

@@ -5,10 +5,8 @@ import app.revanced.integrations.settings.SettingsEnum;
public class SpoofAppVersionPatch {
public static String getYouTubeVersionOverride(String version) {
if (SettingsEnum.SPOOF_APP_VERSION.getBoolean()){
// Override with the most recent version that does not show the new UI player layout.
// If the new UI shows up for some users, then change this to an older version (such as 17.29.34).
return "17.30.34";
if (SettingsEnum.SPOOF_APP_VERSION.getBoolean()) {
return SettingsEnum.SPOOF_APP_VERSION_TARGET.getString();
}
return version;
}

View File

@@ -31,13 +31,27 @@ public class SpoofSignatureVerificationPatch {
"SAFg" // Autoplay in scrim
};
@Nullable
private static String currentVideoId;
/**
* 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;
/**
* If any of the subtitles settings encountered from the current video have been non default values.
* The number of non default subtitle settings encountered for the current video.
*/
private static boolean nonDefaultSubtitlesEncountered;
private static int numberOfNonDefaultSettingsObserved;
@Nullable
private static String currentVideoId;
/**
* Injection point.
@@ -137,15 +151,19 @@ public class SpoofSignatureVerificationPatch {
// 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 && !nonDefaultSubtitlesEncountered && !PlayerType.getCurrent().isNoneOrHidden()) {
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();
}
}
// Settings appear to be custom subtitles.
nonDefaultSubtitlesEncountered = true;
LogHelper.printDebug(() -> "Non default subtitles found. Using existing settings without replacement.");
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};
@@ -160,7 +178,7 @@ public class SpoofSignatureVerificationPatch {
return;
}
currentVideoId = videoId;
nonDefaultSubtitlesEncountered = false;
numberOfNonDefaultSettingsObserved = 0;
} catch (Exception ex) {
LogHelper.printException(() -> "setCurrentVideoId failure", ex);
}

View File

@@ -76,7 +76,7 @@ public class ReturnYouTubeDislike {
/**
* If {@link #currentVideoId} and the RYD data is for the last shorts loaded.
*/
private static volatile boolean lastVideoLoadedWasShort;
private static volatile boolean dislikeDataIsShort;
/**
* Stores the results of the vote api fetch, and used as a barrier to wait until fetch completes.
@@ -141,7 +141,7 @@ public class ReturnYouTubeDislike {
LogHelper.printDebug(() -> "Clearing data");
}
currentVideoId = videoId;
lastVideoLoadedWasShort = false;
dislikeDataIsShort = false;
voteFetchFuture = null;
originalDislikeSpan = null;
replacementLikeDislikeSpan = null;
@@ -198,7 +198,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.
lastVideoLoadedWasShort = PlayerType.getCurrent().isNoneOrHidden();
dislikeDataIsShort = PlayerType.getCurrent().isNoneOrHidden();
// No need to wrap the call in a try/catch,
// as any exceptions are propagated out in the later Future#Get call.
@@ -224,7 +224,15 @@ public class ReturnYouTubeDislike {
return null;
}
if (lastVideoLoadedWasShort) {
return getDislikesSpanForRegularVideo((Spannable) original, isSegmentedButton);
}
/**
* @return NULL if the span does not need changing or if RYD is not available.
*/
@Nullable
public static SpannableString getDislikesSpanForRegularVideo(@NonNull Spanned original, boolean isSegmentedButton) {
if (dislikeDataIsShort) {
// user:
// 1, opened a video
// 2. opened a short (without closing the regular video)
@@ -234,14 +242,14 @@ public class ReturnYouTubeDislike {
return null;
}
return waitForFetchAndUpdateReplacementSpan((Spannable) original, isSegmentedButton);
return waitForFetchAndUpdateReplacementSpan(original, isSegmentedButton);
}
/**
* Called when a Shorts dislike Spannable is created.
*/
public static SpannableString getDislikeSpanForShort(@NonNull Spanned original) {
lastVideoLoadedWasShort = true; // it's now certain the video and data are a short
dislikeDataIsShort = true; // it's now certain the video and data are a short
return waitForFetchAndUpdateReplacementSpan(original, false);
}
@@ -313,7 +321,7 @@ public class ReturnYouTubeDislike {
try {
// 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 || lastVideoLoadedWasShort != PlayerType.getCurrent().isNoneOrHidden()) {
if (videoIdToVoteFor == null || 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

@@ -19,13 +19,12 @@ import app.revanced.integrations.utils.StringRef;
public enum SettingsEnum {
//Download Settings
// TODO: DOWNLOAD_PATH("revanced_download_path", STRING, Environment.getExternalStorageDirectory().getPath() + "/Download"),
DOWNLOADS_BUTTON_SHOWN("revanced_downloads_enabled", BOOLEAN, TRUE, true),
DOWNLOADS_BUTTON_SHOWN("revanced_downloads_enabled", BOOLEAN, TRUE),
DOWNLOADS_PACKAGE_NAME("revanced_downloads_package_name", STRING, "org.schabi.newpipe" /* NewPipe */, parents(DOWNLOADS_BUTTON_SHOWN)),
// Copy video URL settings
COPY_VIDEO_URL_BUTTON_SHOWN("revanced_copy_video_url_enabled", BOOLEAN, TRUE, true),
COPY_VIDEO_URL_TIMESTAMP_BUTTON_SHOWN("revanced_copy_video_url_timestamp_enabled", BOOLEAN, TRUE, true),
COPY_VIDEO_URL_BUTTON_SHOWN("revanced_copy_video_url_enabled", BOOLEAN, TRUE),
COPY_VIDEO_URL_TIMESTAMP_BUTTON_SHOWN("revanced_copy_video_url_timestamp_enabled", BOOLEAN, TRUE),
// Video settings
OLD_STYLE_VIDEO_QUALITY_PLAYER_SETTINGS("revanced_use_old_style_quality_settings", BOOLEAN, TRUE),
@@ -92,6 +91,7 @@ public enum SettingsEnum {
HIDE_ENDSCREEN_CARDS("revanced_hide_endscreen_cards", BOOLEAN, TRUE),
HIDE_FLOATING_MICROPHONE_BUTTON("revanced_hide_floating_microphone_button", BOOLEAN, TRUE, true),
HIDE_FULLSCREEN_PANELS("revanced_hide_fullscreen_panels", BOOLEAN, TRUE),
HIDE_GET_PREMIUM("revanced_hide_get_premium", BOOLEAN, TRUE),
HIDE_INFO_CARDS("revanced_hide_infocards", BOOLEAN, TRUE),
HIDE_PLAYER_BUTTONS("revanced_hide_player_buttons", BOOLEAN, FALSE),
HIDE_PREVIEW_COMMENT("revanced_hide_preview_comment", BOOLEAN, FALSE, true),
@@ -103,6 +103,7 @@ public enum SettingsEnum {
HIDE_WATCH_IN_VR("revanced_hide_watch_in_vr", BOOLEAN, FALSE, true),
PLAYER_POPUP_PANELS("revanced_player_popup_panels_enabled", BOOLEAN, FALSE),
SPOOF_APP_VERSION("revanced_spoof_app_version", BOOLEAN, FALSE, true, "revanced_spoof_app_version_user_dialog_message"),
SPOOF_APP_VERSION_TARGET("revanced_spoof_app_version_target", STRING, "17.30.35", true, parents(SPOOF_APP_VERSION)),
USE_TABLET_MINIPLAYER("revanced_tablet_miniplayer", BOOLEAN, FALSE, true),
WIDE_SEARCHBAR("revanced_wide_searchbar", BOOLEAN, FALSE, true),

View File

@@ -20,33 +20,17 @@ import app.revanced.integrations.settings.SharedPrefCategory;
public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
/**
* If ReturnYouTubeDislike is enabled
*/
private SwitchPreference enabledPreference;
/**
* If dislikes are shown as percentage
* If dislikes are shown as percentage.
*/
private SwitchPreference percentagePreference;
/**
* If segmented like/dislike button uses smaller compact layout
* If segmented like/dislike button uses smaller compact layout.
*/
private SwitchPreference compactLayoutPreference;
private void updateUIState() {
enabledPreference.setSummary(SettingsEnum.RYD_ENABLED.getBoolean()
? str("revanced_ryd_enable_summary_on")
: str("revanced_ryd_enable_summary_off"));
percentagePreference.setSummary(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.getBoolean()
? str("revanced_ryd_dislike_percentage_summary_on")
: str("revanced_ryd_dislike_percentage_summary_off"));
percentagePreference.setEnabled(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.isAvailable());
compactLayoutPreference.setSummary(SettingsEnum.RYD_USE_COMPACT_LAYOUT.getBoolean()
? str("revanced_ryd_compact_layout_summary_on")
: str("revanced_ryd_compact_layout_summary_off"));
compactLayoutPreference.setEnabled(SettingsEnum.RYD_USE_COMPACT_LAYOUT.isAvailable());
}
@@ -59,9 +43,11 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(context);
setPreferenceScreen(preferenceScreen);
enabledPreference = new SwitchPreference(context);
SwitchPreference enabledPreference = new SwitchPreference(context);
enabledPreference.setChecked(SettingsEnum.RYD_ENABLED.getBoolean());
enabledPreference.setTitle(str("revanced_ryd_enable_title"));
enabledPreference.setSummaryOn(str("revanced_ryd_enable_summary_on"));
enabledPreference.setSummaryOff(str("revanced_ryd_enable_summary_off"));
enabledPreference.setOnPreferenceChangeListener((pref, newValue) -> {
final boolean rydIsEnabled = (Boolean) newValue;
SettingsEnum.RYD_ENABLED.saveValue(rydIsEnabled);
@@ -75,6 +61,8 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
percentagePreference = new SwitchPreference(context);
percentagePreference.setChecked(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.getBoolean());
percentagePreference.setTitle(str("revanced_ryd_dislike_percentage_title"));
percentagePreference.setSummaryOn(str("revanced_ryd_dislike_percentage_summary_on"));
percentagePreference.setSummaryOff(str("revanced_ryd_dislike_percentage_summary_off"));
percentagePreference.setOnPreferenceChangeListener((pref, newValue) -> {
SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.saveValue(newValue);
ReturnYouTubeDislike.clearCache();
@@ -86,6 +74,8 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
compactLayoutPreference = new SwitchPreference(context);
compactLayoutPreference.setChecked(SettingsEnum.RYD_USE_COMPACT_LAYOUT.getBoolean());
compactLayoutPreference.setTitle(str("revanced_ryd_compact_layout_title"));
compactLayoutPreference.setSummaryOn(str("revanced_ryd_compact_layout_summary_on"));
compactLayoutPreference.setSummaryOff(str("revanced_ryd_compact_layout_summary_off"));
compactLayoutPreference.setOnPreferenceChangeListener((pref, newValue) -> {
SettingsEnum.RYD_USE_COMPACT_LAYOUT.saveValue(newValue);
ReturnYouTubeDislike.clearCache();
@@ -185,7 +175,7 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
}
}
private String createSummaryText(int value, String summaryStringZeroKey, String summaryStringOneOrMoreKey) {
private static String createSummaryText(int value, String summaryStringZeroKey, String summaryStringOneOrMoreKey) {
if (value == 0) {
return str(summaryStringZeroKey);
}

View File

@@ -1,66 +1,64 @@
package app.revanced.integrations.videoplayer;
import android.support.constraint.ConstraintLayout;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.ImageView;
import java.lang.ref.WeakReference;
import androidx.annotation.NonNull;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
import java.lang.ref.WeakReference;
import java.util.Objects;
public abstract class BottomControlButton {
WeakReference<ImageView> button = new WeakReference<>(null);
ConstraintLayout constraintLayout;
Boolean isButtonEnabled;
Boolean isShowing;
private static final Animation fadeIn = ReVancedUtils.getResourceAnimation("fade_in");
private static final Animation fadeOut = ReVancedUtils.getResourceAnimation("fade_out");
private final WeakReference<ImageView> buttonRef;
private final SettingsEnum setting;
protected boolean isVisible;
private Animation fadeIn;
private Animation fadeOut;
public BottomControlButton(Object obj, String viewId, Boolean isEnabled, View.OnClickListener onClickListener) {
try {
LogHelper.printDebug(() -> "Initializing button with id: " + viewId);
constraintLayout = (ConstraintLayout) obj;
isButtonEnabled = isEnabled;
ImageView imageView = constraintLayout.findViewById(ReVancedUtils.getResourceIdentifier(viewId, "id"));
if (imageView == null) {
LogHelper.printException(() -> "Couldn't find ImageView with id: " + viewId);
return;
}
imageView.setOnClickListener(onClickListener);
button = new WeakReference<>(imageView);
fadeIn = ReVancedUtils.getResourceAnimation("fade_in");
fadeOut = ReVancedUtils.getResourceAnimation("fade_out");
fadeIn.setDuration(ReVancedUtils.getResourceInteger("fade_duration_fast"));
fadeOut.setDuration(ReVancedUtils.getResourceInteger("fade_duration_scheduled"));
isShowing = true;
setVisibility(false);
} catch (Exception e) {
LogHelper.printException(() -> "Failed to initialize button with id: " + viewId, e);
}
static {
// TODO: check if these durations are correct.
fadeIn.setDuration(ReVancedUtils.getResourceInteger("fade_duration_fast"));
fadeOut.setDuration(ReVancedUtils.getResourceInteger("fade_duration_scheduled"));
}
public void setVisibility(boolean showing) {
if (isShowing == showing) return;
public BottomControlButton(@NonNull ViewGroup bottomControlsViewGroup, @NonNull String imageViewButtonId,
@NonNull SettingsEnum booleanSetting, @NonNull View.OnClickListener onClickListener) {
LogHelper.printDebug(() -> "Initializing button: " + imageViewButtonId);
isShowing = showing;
ImageView imageView = button.get();
if (constraintLayout == null || imageView == null)
return;
if (showing && isButtonEnabled) {
LogHelper.printDebug(() -> "Fading in");
imageView.setVisibility(View.VISIBLE);
imageView.startAnimation(fadeIn);
if (booleanSetting.returnType != SettingsEnum.ReturnType.BOOLEAN) {
throw new IllegalArgumentException();
}
else if (imageView.getVisibility() == View.VISIBLE) {
LogHelper.printDebug(() -> "Fading out");
setting = booleanSetting;
// Create the button.
ImageView imageView = Objects.requireNonNull(bottomControlsViewGroup.findViewById(
ReVancedUtils.getResourceIdentifier(imageViewButtonId, "id")
));
imageView.setOnClickListener(onClickListener);
imageView.setVisibility(View.GONE);
buttonRef = new WeakReference<>(imageView);
}
public void setVisibility(boolean visible) {
if (isVisible == visible) return;
isVisible = visible;
ImageView imageView = buttonRef.get();
if (imageView == null) {
return;
}
imageView.clearAnimation();
if (visible && setting.getBoolean()) {
imageView.startAnimation(fadeIn);
imageView.setVisibility(View.VISIBLE);
} else if (imageView.getVisibility() == View.VISIBLE) {
imageView.startAnimation(fadeOut);
imageView.setVisibility(View.GONE);
}

View File

@@ -1,25 +1,40 @@
package app.revanced.integrations.videoplayer;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import app.revanced.integrations.patches.CopyVideoUrlPatch;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.LogHelper;
public class CopyVideoUrlButton extends BottomControlButton {
public static CopyVideoUrlButton instance;
@Nullable
private static CopyVideoUrlButton instance;
public CopyVideoUrlButton(Object obj) {
public CopyVideoUrlButton(ViewGroup viewGroup) {
super(
obj,
viewGroup,
"copy_video_url_button",
SettingsEnum.COPY_VIDEO_URL_BUTTON_SHOWN.getBoolean(),
SettingsEnum.COPY_VIDEO_URL_BUTTON_SHOWN,
view -> CopyVideoUrlPatch.copyUrl(false)
);
}
/**
* Injection point.
*/
public static void initializeButton(Object obj) {
instance = new CopyVideoUrlButton(obj);
try {
instance = new CopyVideoUrlButton((ViewGroup) obj);
} catch (Exception ex) {
LogHelper.printException(() -> "initializeButton failure", ex);
}
}
/**
* Injection point.
*/
public static void changeVisibility(boolean showing) {
if (instance != null) instance.setVisibility(showing);
}

View File

@@ -1,24 +1,40 @@
package app.revanced.integrations.videoplayer;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import app.revanced.integrations.patches.CopyVideoUrlPatch;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.LogHelper;
public class CopyVideoUrlTimestampButton extends BottomControlButton {
public static CopyVideoUrlTimestampButton instance;
@Nullable
private static CopyVideoUrlTimestampButton instance;
public CopyVideoUrlTimestampButton(Object obj) {
public CopyVideoUrlTimestampButton(ViewGroup bottomControlsViewGroup) {
super(
obj,
bottomControlsViewGroup,
"copy_video_url_timestamp_button",
SettingsEnum.COPY_VIDEO_URL_TIMESTAMP_BUTTON_SHOWN.getBoolean(),
SettingsEnum.COPY_VIDEO_URL_TIMESTAMP_BUTTON_SHOWN,
view -> CopyVideoUrlPatch.copyUrl(true)
);
}
public static void initializeButton(Object obj) {
instance = new CopyVideoUrlTimestampButton(obj);
/**
* Injection point.
*/
public static void initializeButton(Object bottomControlsViewGroup) {
try {
instance = new CopyVideoUrlTimestampButton((ViewGroup) bottomControlsViewGroup);
} catch (Exception ex) {
LogHelper.printException(() -> "initializeButton failure", ex);
}
}
/**
* Injection point.
*/
public static void changeVisibility(boolean showing) {
if (instance != null) instance.setVisibility(showing);
}

View File

@@ -3,6 +3,9 @@ package app.revanced.integrations.videoplayer;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import app.revanced.integrations.patches.VideoInformation;
import app.revanced.integrations.settings.SettingsEnum;
@@ -11,21 +14,32 @@ import app.revanced.integrations.utils.ReVancedUtils;
import app.revanced.integrations.utils.StringRef;
public class DownloadButton extends BottomControlButton {
public static DownloadButton instance;
@Nullable
private static DownloadButton instance;
public DownloadButton(Object obj) {
public DownloadButton(ViewGroup viewGroup) {
super(
obj,
viewGroup,
"download_button",
SettingsEnum.DOWNLOADS_BUTTON_SHOWN.getBoolean(),
SettingsEnum.DOWNLOADS_BUTTON_SHOWN,
DownloadButton::onDownloadClick
);
}
/**
* Injection point.
*/
public static void initializeButton(Object obj) {
instance = new DownloadButton(obj);
try {
instance = new DownloadButton((ViewGroup) obj);
} catch (Exception ex) {
LogHelper.printException(() -> "initializeButton failure", ex);
}
}
/**
* Injection point.
*/
public static void changeVisibility(boolean showing) {
if (instance != null) instance.setVisibility(showing);
}
@@ -38,7 +52,6 @@ public class DownloadButton extends BottomControlButton {
boolean packageEnabled = false;
try {
assert context != null;
packageEnabled = context.getPackageManager().getApplicationInfo(downloaderPackageName, 0).enabled;
} catch (PackageManager.NameNotFoundException error) {
LogHelper.printDebug(() -> "Downloader could not be found: " + error);

View File

@@ -5,7 +5,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
classpath("com.android.tools.build:gradle:8.0.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20")
// NOTE: Do not place your application dependencies here; they belong

View File

@@ -1,3 +1,3 @@
org.gradle.jvmargs = -Xmx2048m
android.useAndroidX = true
version = 0.105.0-dev.2
version = 0.106.0-dev.4

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists