You've already forked revanced-integrations
mirror of
https://github.com/revanced/revanced-integrations
synced 2025-11-19 03:23:27 +01:00
Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a87e366035 | ||
|
|
d4a23ed5c9 | ||
|
|
767201ce05 | ||
|
|
64cfe9c579 | ||
|
|
25978ae4a4 | ||
|
|
1f48749958 | ||
|
|
ee1f895e87 | ||
|
|
645669bbc0 | ||
|
|
d4c3b74a9a | ||
|
|
24367cea3f | ||
|
|
1e3970c3f2 | ||
|
|
c3e88c79e9 | ||
|
|
b8f0e632c1 | ||
|
|
c0c778b3e6 | ||
|
|
fe74f6d8a6 | ||
|
|
5f1e35ae36 | ||
|
|
6ceff7c9b3 | ||
|
|
d9349d4e88 | ||
|
|
b59ee31d57 | ||
|
|
2c8b23426f | ||
|
|
72a3cd0fac | ||
|
|
6272e4b467 | ||
|
|
cf892de4bb | ||
|
|
e978ed2c14 | ||
|
|
570f9eaba1 | ||
|
|
571cf12dca | ||
|
|
09c7605f1f | ||
|
|
66040302a9 | ||
|
|
98b31c17b9 | ||
|
|
c517c03e6f | ||
|
|
f10b202c93 | ||
|
|
3fb337b856 | ||
|
|
d82b9898a8 | ||
|
|
0a90289dc5 | ||
|
|
dfd6e7fcce | ||
|
|
e93ce3eaa9 | ||
|
|
695c59efd4 | ||
|
|
22bc4405cf | ||
|
|
63ee425050 | ||
|
|
7f18520646 | ||
|
|
d18bc1856b | ||
|
|
af86dd8ec6 | ||
|
|
2ebadaf07f | ||
|
|
197f0034a1 | ||
|
|
06c5a9b2b8 | ||
|
|
cb404086ad | ||
|
|
18192ac73e | ||
|
|
e357ac664b | ||
|
|
2f2a595c89 | ||
|
|
502feaf444 | ||
|
|
b4e03412ee | ||
|
|
f8cb38e57a | ||
|
|
9e5e81875a | ||
|
|
c3c16563ea | ||
|
|
302b57d8f0 | ||
|
|
d86655874b | ||
|
|
cc2bab4e39 | ||
|
|
85971bcd5e | ||
|
|
f475c28f3d | ||
|
|
ac81695747 | ||
|
|
3427f885fb | ||
|
|
9bdac3356d | ||
|
|
fd69010def | ||
|
|
6aa0ca9556 | ||
|
|
98eaf9c3f2 | ||
|
|
8e36da0b19 | ||
|
|
1433b34c7e | ||
|
|
6da66be067 | ||
|
|
b5a93a0cd9 | ||
|
|
ac69b36773 | ||
|
|
81d3afd065 | ||
|
|
8b4bed8ab3 | ||
|
|
b13d692ef1 | ||
|
|
fb20ae19e8 | ||
|
|
889a7d8460 | ||
|
|
d28d65734e | ||
|
|
1c021b1a50 | ||
|
|
06bebd7017 | ||
|
|
d745e29395 | ||
|
|
69a585da6f | ||
|
|
7050cefe10 | ||
|
|
afa9d3cbb1 | ||
|
|
6762ea4178 | ||
|
|
a92c932a20 | ||
|
|
3698a502c3 | ||
|
|
5566cfdda9 | ||
|
|
97efc17da7 | ||
|
|
8fdde7046d | ||
|
|
74c96beb20 | ||
|
|
7014518673 | ||
|
|
ac3a835215 | ||
|
|
39450109ab | ||
|
|
db718242e7 | ||
|
|
59c2459353 | ||
|
|
f06935ddac | ||
|
|
8127f8b390 | ||
|
|
f4650b1139 | ||
|
|
0be0ffd42a | ||
|
|
a061614d86 | ||
|
|
486019802c | ||
|
|
0253fef2aa | ||
|
|
8483a225fb | ||
|
|
867645ea5b | ||
|
|
52a2073175 | ||
|
|
0e6a92fb33 | ||
|
|
658e11ac12 | ||
|
|
1755662a7a | ||
|
|
8bd84031d4 | ||
|
|
c5ca35e42c | ||
|
|
c266fdbf44 | ||
|
|
07acc4dc1f | ||
|
|
34a6829aaf | ||
|
|
c372e0e9bd | ||
|
|
f5a4e6f3bf | ||
|
|
576991a7df | ||
|
|
ab88a1f3d7 | ||
|
|
5ab26a427b |
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.9.0
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Checkout Repo
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
java-version: '11'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
- name: Build with Gradle
|
||||
|
||||
343
CHANGELOG.md
343
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -7,14 +7,14 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 32
|
||||
buildToolsVersion = "32.0.0"
|
||||
compileSdk = 33
|
||||
buildToolsVersion = "33.0.0"
|
||||
namespace = "app.revanced.integrations"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "app.revanced.integrations"
|
||||
minSdk = 23
|
||||
targetSdk = 32
|
||||
targetSdk = 33
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
multiDexEnabled = false
|
||||
@@ -45,4 +45,5 @@ android {
|
||||
dependencies {
|
||||
compileOnly(project(mapOf("path" to ":dummy")))
|
||||
compileOnly("androidx.annotation:annotation:1.5.0")
|
||||
compileOnly("androidx.appcompat:appcompat:1.5.1")
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import app.revanced.integrations.patches.HideShortsButtonPatch;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
public class AdRemoverAPI {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
final class ButtonsPatch extends Filter {
|
||||
private final BlockRule actionButtonsRule;
|
||||
private final BlockRule dislikeRule;
|
||||
private final BlockRule actionBarRule;
|
||||
|
||||
private final BlockRule[] rules;
|
||||
|
||||
public ButtonsPatch() {
|
||||
BlockRule like = new BlockRule(SettingsEnum.HIDE_LIKE_BUTTON, "|like_button");
|
||||
dislikeRule = new BlockRule(SettingsEnum.HIDE_DISLIKE_BUTTON, "dislike_button");
|
||||
BlockRule download = new BlockRule(SettingsEnum.HIDE_DOWNLOAD_BUTTON, "download_button");
|
||||
actionButtonsRule = new BlockRule(SettingsEnum.HIDE_ACTION_BUTTON, "ContainerType|video_action_button");
|
||||
BlockRule playlist = new BlockRule(SettingsEnum.HIDE_PLAYLIST_BUTTON, "save_to_playlist_button");
|
||||
rules = new BlockRule[]{like, dislikeRule, download, actionButtonsRule, playlist};
|
||||
|
||||
actionBarRule = new BlockRule(null, "video_action_bar");
|
||||
|
||||
this.pathRegister.registerAll(
|
||||
like,
|
||||
dislikeRule,
|
||||
download,
|
||||
playlist
|
||||
);
|
||||
}
|
||||
|
||||
private boolean hideActionBar() {
|
||||
for (BlockRule rule : rules) if (!rule.isEnabled()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filter(final String path, final String identifier) {
|
||||
if (hideActionBar() && actionBarRule.check(identifier).isBlocked()) return true;
|
||||
|
||||
var currentIsActionButton = actionButtonsRule.check(path).isBlocked();
|
||||
|
||||
if (dislikeRule.check(path).isBlocked()) ActionButton.doNotBlockCounter = 4;
|
||||
|
||||
if (currentIsActionButton && ActionButton.doNotBlockCounter-- > 0) {
|
||||
if (SettingsEnum.HIDE_SHARE_BUTTON.getBoolean()) {
|
||||
LogHelper.debug(ButtonsPatch.class, "Hiding share button");
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
if ((currentIsActionButton && ActionButton.doNotBlockCounter <= 0 && actionButtonsRule.isEnabled()) || pathRegister.contains(path)) {
|
||||
LogHelper.debug(ButtonsPatch.class, "Blocked: " + path);
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
static class ActionButton {
|
||||
public static int doNotBlockCounter = 4;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
final class CommentsPatch extends Filter {
|
||||
|
||||
public CommentsPatch() {
|
||||
var comments = new BlockRule(SettingsEnum.HIDE_COMMENTS_SECTION, "video_metadata_carousel", "_comments");
|
||||
var previewComment = new BlockRule(
|
||||
SettingsEnum.HIDE_PREVIEW_COMMENT,
|
||||
"carousel_item",
|
||||
"comments_entry_point_teaser",
|
||||
"comments_entry_point_simplebox"
|
||||
);
|
||||
|
||||
this.pathRegister.registerAll(
|
||||
comments,
|
||||
previewComment
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean filter(String path, String _identifier) {
|
||||
if (!pathRegister.contains(path)) return false;
|
||||
|
||||
LogHelper.debug(CommentsPatch.class, "Blocked: " + path);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
public final class FixPlaybackPatch {
|
||||
private static Thread currentThread = null;
|
||||
private static String videoId;
|
||||
|
||||
public static void newVideoLoaded(final String videoId) {
|
||||
if (!SettingsEnum.FIX_PLAYBACK.getBoolean()) return;
|
||||
|
||||
if (videoId.equals(FixPlaybackPatch.videoId)) return;
|
||||
else FixPlaybackPatch.videoId = videoId;
|
||||
|
||||
if (currentThread != null) {
|
||||
currentThread.interrupt();
|
||||
}
|
||||
|
||||
currentThread = new Thread(() -> {
|
||||
try {
|
||||
while (true) {
|
||||
var currentVideoTime = VideoInformation.getVideoTime();
|
||||
|
||||
if (currentVideoTime > -1) {
|
||||
VideoInformation.seekTo(Integer.MAX_VALUE);
|
||||
VideoInformation.seekTo(currentVideoTime);
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.sleep(10);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
LogHelper.debug(FixPlaybackPatch.class, "Thread was interrupted");
|
||||
}
|
||||
});
|
||||
|
||||
currentThread.start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.adremover.AdRemoverAPI;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
|
||||
public final class GeneralAdsPatch extends Filter {
|
||||
private final String[] IGNORE = {
|
||||
"home_video_with_context",
|
||||
"related_video_with_context",
|
||||
"comment_thread", // skip blocking anything in the comments
|
||||
"download_",
|
||||
"library_recent_shelf",
|
||||
"menu",
|
||||
"root",
|
||||
"-count",
|
||||
"-space",
|
||||
"-button",
|
||||
"playlist_add_to_option_wrapper" // do not block on "add to playlist" flyout menu
|
||||
};
|
||||
|
||||
private final BlockRule custom = new CustomBlockRule(
|
||||
SettingsEnum.ADREMOVER_CUSTOM_ENABLED,
|
||||
SettingsEnum.ADREMOVER_CUSTOM_REMOVAL
|
||||
);
|
||||
|
||||
public GeneralAdsPatch() {
|
||||
var communityPosts = new BlockRule(SettingsEnum.ADREMOVER_COMMUNITY_POSTS_REMOVAL, "post_base_wrapper");
|
||||
var communityGuidelines = new BlockRule(SettingsEnum.ADREMOVER_COMMUNITY_GUIDELINES_REMOVAL, "community_guidelines");
|
||||
var compactBanner = new BlockRule(SettingsEnum.ADREMOVER_COMPACT_BANNER_REMOVAL, "compact_banner");
|
||||
var inFeedSurvey = new BlockRule(SettingsEnum.ADREMOVER_FEED_SURVEY_REMOVAL, "in_feed_survey");
|
||||
var medicalPanel = new BlockRule(SettingsEnum.ADREMOVER_MEDICAL_PANEL_REMOVAL, "medical_panel");
|
||||
var paidContent = new BlockRule(SettingsEnum.ADREMOVER_PAID_CONTENT_REMOVAL, "paid_content_overlay");
|
||||
var merchandise = new BlockRule(SettingsEnum.ADREMOVER_MERCHANDISE_REMOVAL, "product_carousel");
|
||||
var infoPanel = new BlockRule(SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL, "publisher_transparency_panel", "single_item_information_panel");
|
||||
var suggestions = new BlockRule(SettingsEnum.ADREMOVER_SUGGESTIONS_REMOVAL, "horizontal_video_shelf");
|
||||
var latestPosts = new BlockRule(SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS, "post_shelf");
|
||||
var channelGuidelines = new BlockRule(SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES, "channel_guidelines_entry_banner");
|
||||
var artistCard = new BlockRule(SettingsEnum.HIDE_ARTIST_CARD, "official_card");
|
||||
var selfSponsor = new BlockRule(SettingsEnum.ADREMOVER_SELF_SPONSOR_REMOVAL, "cta_shelf_card");
|
||||
var chapterTeaser = new BlockRule(SettingsEnum.ADREMOVER_CHAPTER_TEASER_REMOVAL, "expandable_metadata");
|
||||
var graySeparator = new BlockRule(SettingsEnum.ADREMOVER_GRAY_SEPARATOR,
|
||||
"cell_divider" // layout residue (gray line above the buttoned ad),
|
||||
);
|
||||
var buttonedAd = new BlockRule(SettingsEnum.ADREMOVER_BUTTONED_REMOVAL,
|
||||
"video_display_full_buttoned_layout",
|
||||
"full_width_square_image_layout",
|
||||
"_ad_with",
|
||||
"landscape_image_wide_button_layout"
|
||||
);
|
||||
var generalAds = new BlockRule(
|
||||
SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL,
|
||||
"ads_video_with_context",
|
||||
"banner_text_icon",
|
||||
"watch_metadata_app_promo",
|
||||
"video_display_full_layout"
|
||||
);
|
||||
var movieAds = new BlockRule(
|
||||
SettingsEnum.ADREMOVER_MOVIE_REMOVAL,
|
||||
"browsy_bar",
|
||||
"compact_movie",
|
||||
"horizontal_movie_shelf",
|
||||
"movie_and_show_upsell_card",
|
||||
"compact_tvfilm_item"
|
||||
);
|
||||
|
||||
this.pathRegister.registerAll(
|
||||
generalAds,
|
||||
buttonedAd,
|
||||
communityPosts,
|
||||
paidContent,
|
||||
suggestions,
|
||||
latestPosts,
|
||||
movieAds,
|
||||
chapterTeaser,
|
||||
communityGuidelines,
|
||||
compactBanner,
|
||||
inFeedSurvey,
|
||||
medicalPanel,
|
||||
merchandise,
|
||||
infoPanel,
|
||||
channelGuidelines,
|
||||
artistCard,
|
||||
selfSponsor
|
||||
);
|
||||
|
||||
var carouselAd = new BlockRule(SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL,
|
||||
"carousel_ad"
|
||||
);
|
||||
var shorts = new BlockRule(SettingsEnum.ADREMOVER_SHORTS_REMOVAL,
|
||||
"reels_player_overlay",
|
||||
"shorts_shelf",
|
||||
"inline_shorts"
|
||||
);
|
||||
|
||||
this.identifierRegister.registerAll(
|
||||
shorts,
|
||||
graySeparator,
|
||||
carouselAd
|
||||
);
|
||||
}
|
||||
|
||||
public boolean filter(final String path, final String identifier) {
|
||||
BlockResult result;
|
||||
|
||||
if (custom.isEnabled() && custom.check(path).isBlocked())
|
||||
result = BlockResult.CUSTOM;
|
||||
else if (ReVancedUtils.containsAny(path, IGNORE))
|
||||
result = BlockResult.IGNORED;
|
||||
else if (pathRegister.contains(path) || identifierRegister.contains(identifier))
|
||||
result = BlockResult.DEFINED;
|
||||
else
|
||||
result = BlockResult.UNBLOCKED;
|
||||
|
||||
log(String.format("%s (ID: %s): %s", result.message, identifier, path));
|
||||
|
||||
return result.filter;
|
||||
}
|
||||
|
||||
private enum BlockResult {
|
||||
UNBLOCKED(false, "Unblocked"),
|
||||
IGNORED(false, "Ignored"),
|
||||
DEFINED(true, "Blocked"),
|
||||
CUSTOM(true, "Custom");
|
||||
|
||||
final Boolean filter;
|
||||
final String message;
|
||||
|
||||
BlockResult(boolean filter, String message) {
|
||||
this.filter = filter;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide a view.
|
||||
*
|
||||
* @param condition The setting to check for hiding the view.
|
||||
* @param view The view to hide.
|
||||
*/
|
||||
private static void hideView(SettingsEnum condition, View view) {
|
||||
if (!condition.getBoolean()) return;
|
||||
|
||||
log("Hiding view with setting: " + condition);
|
||||
|
||||
AdRemoverAPI.HideViewWithLayout1dp(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the view, which shows ads in the homepage.
|
||||
*
|
||||
* @param view The view, which shows ads.
|
||||
*/
|
||||
public static void hideAdAttributionView(View view) {
|
||||
hideView(SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL, view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the view, which shows reels in the homepage.
|
||||
*
|
||||
* @param view The view, which shows reels.
|
||||
*/
|
||||
public static void hideReelView(View view) {
|
||||
hideView(SettingsEnum.ADREMOVER_SHORTS_REMOVAL, view);
|
||||
}
|
||||
|
||||
private static void log(String message) {
|
||||
LogHelper.debug(GeneralAdsPatch.class, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.adremover.AdRemoverAPI;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideAlbumCardsPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.hidealbumcards.patch.HideAlbumCardsPatch
|
||||
public static void hideAlbumCards(View view) {
|
||||
if (!SettingsEnum.HIDE_ALBUM_CARDS.getBoolean()) return;
|
||||
AdRemoverAPI.HideViewWithLayout1dp(view);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.widget.ImageView;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
public class HideCaptionsButtonPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.hidecaptionsbutton.patch.HideCaptionsButtonPatch
|
||||
public static void hideCaptionsButton(ImageView imageView) {
|
||||
imageView.setVisibility(SettingsEnum.HIDE_CAPTIONS_BUTTON.getBoolean() ? ImageView.GONE : ImageView.VISIBLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.adremover.AdRemoverAPI;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideCrowdfundingBoxPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.hidecrowdfundingbox.patch.HideCrowdfundingBoxPatch
|
||||
public static void hideCrowdfundingBox(View view) {
|
||||
if (!SettingsEnum.HIDE_CROWDFUNDING_BOX.getBoolean()) return;
|
||||
AdRemoverAPI.HideViewWithLayout1dp(view);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,9 @@ import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideEmailAddressPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.personalinformation.patch.HideEmailAddressPatch
|
||||
public static boolean hideEmailAddress() {
|
||||
return SettingsEnum.HIDE_EMAIL_ADDRESS.getBoolean();
|
||||
public static int hideEmailAddress(int originalValue) {
|
||||
if (SettingsEnum.HIDE_EMAIL_ADDRESS.getBoolean())
|
||||
return 8;
|
||||
return originalValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideEndscreenCardsPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.hideendscreencards.bytecode.patch.HideEndscreenCardsPatch
|
||||
public static void hideEndscreen(View view) {
|
||||
if (!SettingsEnum.HIDE_ENDSCREEN_CARDS.getBoolean()) return;
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.adremover.AdRemoverAPI;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideHomeAdsPatch {
|
||||
|
||||
/**
|
||||
* Used by package app.revanced.extensions.Extensions
|
||||
*
|
||||
* @param view
|
||||
*/
|
||||
public static void HideHomeAds(View view) {
|
||||
if (!SettingsEnum.HOME_ADS_REMOVAL.getBoolean()) return;
|
||||
AdRemoverAPI.HideViewWithLayout1dp(view);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideInfoCardSuggestionsPatch {
|
||||
|
||||
public static void hideInfoCardSuggestions(View view) {
|
||||
if (!SettingsEnum.INFO_CARDS_SHOWN.getBoolean()) {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideInfocardsPatch {
|
||||
public static void hideInfocardsIncognito(View view) {
|
||||
if (!SettingsEnum.HIDE_INFO_CARDS.getBoolean()) return;
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public static boolean hideInfocardsMethodCall() {
|
||||
return SettingsEnum.HIDE_INFO_CARDS.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.adremover.AdRemoverAPI;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideMixPlaylistsPatch {
|
||||
|
||||
public static void hideMixPlaylists(View view) {
|
||||
if (!SettingsEnum.HIDE_MIX_PLAYLISTS.getBoolean()) return;
|
||||
AdRemoverAPI.HideViewWithLayout1dp(view);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideShortsCommentsButtonPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.comments.patch.CommentsPatch
|
||||
public static void hideShortsCommentsButton(View view) {
|
||||
if (!SettingsEnum.HIDE_SHORTS_COMMENTS_BUTTON.getBoolean()) return;
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideWatchinVRPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.watchinvr.patch.HideWatchinVRPatch
|
||||
public static boolean hideWatchinVR() {
|
||||
return SettingsEnum.HIDE_WATCH_IN_VR.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -13,32 +13,9 @@ import java.util.function.Consumer;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
|
||||
/**
|
||||
* Helper functions.
|
||||
*/
|
||||
final class Extensions {
|
||||
static boolean containsAny(final String value, final String... targets) {
|
||||
for (String string : targets)
|
||||
if (value.contains(string)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean any(LithoBlockRegister register, String path) {
|
||||
for (var rule : register) {
|
||||
if (!rule.isEnabled()) continue;
|
||||
|
||||
var result = rule.check(path);
|
||||
if (result.isBlocked()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final class BlockRule {
|
||||
class BlockRule {
|
||||
final static class BlockResult {
|
||||
private final boolean blocked;
|
||||
private final SettingsEnum setting;
|
||||
@@ -57,7 +34,7 @@ final class BlockRule {
|
||||
}
|
||||
}
|
||||
|
||||
private final SettingsEnum setting;
|
||||
protected final SettingsEnum setting;
|
||||
private final String[] blocks;
|
||||
|
||||
/**
|
||||
@@ -76,12 +53,26 @@ final class BlockRule {
|
||||
}
|
||||
|
||||
public BlockResult check(final String string) {
|
||||
return new BlockResult(setting, string != null && Extensions.containsAny(string, blocks));
|
||||
return new BlockResult(setting, string != null && ReVancedUtils.containsAny(string, blocks));
|
||||
}
|
||||
}
|
||||
|
||||
final class CustomBlockRule extends BlockRule {
|
||||
/**
|
||||
* Initialize a new rule for components.
|
||||
*
|
||||
* @param setting The setting which controls the blocking of the components.
|
||||
* @param filter The setting which contains the list of component names.
|
||||
*/
|
||||
public CustomBlockRule(final SettingsEnum setting, final SettingsEnum filter) {
|
||||
super(setting, filter.getString().split(","));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class Filter {
|
||||
final LithoBlockRegister register = new LithoBlockRegister();
|
||||
final protected LithoBlockRegister pathRegister = new LithoBlockRegister();
|
||||
final protected LithoBlockRegister identifierRegister = new LithoBlockRegister();
|
||||
|
||||
abstract boolean filter(final String path, final String identifier);
|
||||
}
|
||||
@@ -111,12 +102,26 @@ final class LithoBlockRegister implements Iterable<BlockRule> {
|
||||
public Spliterator<BlockRule> spliterator() {
|
||||
return blocks.spliterator();
|
||||
}
|
||||
|
||||
public boolean contains(String path) {
|
||||
for (var rule : this) {
|
||||
if (!rule.isEnabled()) continue;
|
||||
|
||||
var result = rule.check(path);
|
||||
if (result.isBlocked()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public final class LithoFilterPatch {
|
||||
private static final Filter[] filters = new Filter[]{
|
||||
new GeneralBytecodeAdsPatch(),
|
||||
new ButtonsPatch()
|
||||
new GeneralAdsPatch(),
|
||||
new ButtonsPatch(),
|
||||
new CommentsPatch(),
|
||||
};
|
||||
|
||||
public static boolean filter(final StringBuilder pathBuilder, final String identifier) {
|
||||
@@ -133,152 +138,3 @@ public final class LithoFilterPatch {
|
||||
}
|
||||
}
|
||||
|
||||
final class ButtonsPatch extends Filter {
|
||||
private final BlockRule actionButtonsRule;
|
||||
private final BlockRule dislikeRule;
|
||||
private final BlockRule actionBarRule;
|
||||
|
||||
private final BlockRule[] rules;
|
||||
|
||||
public ButtonsPatch() {
|
||||
BlockRule like = new BlockRule(SettingsEnum.HIDE_LIKE_BUTTON, "|like_button");
|
||||
dislikeRule = new BlockRule(SettingsEnum.HIDE_DISLIKE_BUTTON, "dislike_button");
|
||||
BlockRule download = new BlockRule(SettingsEnum.HIDE_DOWNLOAD_BUTTON, "download_button");
|
||||
actionButtonsRule = new BlockRule(SettingsEnum.HIDE_ACTION_BUTTON, "ContainerType|video_action_button");
|
||||
BlockRule playlist = new BlockRule(SettingsEnum.HIDE_PLAYLIST_BUTTON, "save_to_playlist_button");
|
||||
rules = new BlockRule[]{like, dislikeRule, download, actionButtonsRule, playlist};
|
||||
|
||||
actionBarRule = new BlockRule(null, "video_action_bar");
|
||||
|
||||
this.register.registerAll(
|
||||
like,
|
||||
dislikeRule,
|
||||
download,
|
||||
playlist
|
||||
);
|
||||
}
|
||||
|
||||
private boolean hideActionBar() {
|
||||
for (BlockRule rule : rules) if (!rule.isEnabled()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filter(final String path, final String identifier) {
|
||||
if (hideActionBar() && actionBarRule.check(identifier).isBlocked()) return true;
|
||||
|
||||
var currentIsActionButton = actionButtonsRule.check(path).isBlocked();
|
||||
|
||||
if (dislikeRule.check(path).isBlocked()) ActionButton.doNotBlockCounter = 4;
|
||||
|
||||
if (currentIsActionButton && ActionButton.doNotBlockCounter-- > 0) {
|
||||
if (SettingsEnum.HIDE_SHARE_BUTTON.getBoolean()) {
|
||||
LogHelper.debug(ButtonsPatch.class, "Hiding share button");
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
if ((currentIsActionButton && ActionButton.doNotBlockCounter <= 0 && actionButtonsRule.isEnabled()) || Extensions.any(register, path)) {
|
||||
LogHelper.debug(ButtonsPatch.class, "Blocked: " + path);
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
static class ActionButton {
|
||||
public static int doNotBlockCounter = 4;
|
||||
}
|
||||
}
|
||||
|
||||
class GeneralBytecodeAdsPatch extends Filter {
|
||||
private final BlockRule identifierBlock;
|
||||
|
||||
public GeneralBytecodeAdsPatch() {
|
||||
var comments = new BlockRule(SettingsEnum.ADREMOVER_COMMENTS_REMOVAL, "comments_");
|
||||
var communityPosts = new BlockRule(SettingsEnum.ADREMOVER_COMMUNITY_POSTS_REMOVAL, "post_base_wrapper");
|
||||
var communityGuidelines = new BlockRule(SettingsEnum.ADREMOVER_COMMUNITY_GUIDELINES_REMOVAL, "community_guidelines");
|
||||
var compactBanner = new BlockRule(SettingsEnum.ADREMOVER_COMPACT_BANNER_REMOVAL, "compact_banner");
|
||||
var inFeedSurvey = new BlockRule(SettingsEnum.ADREMOVER_FEED_SURVEY_REMOVAL, "in_feed_survey");
|
||||
var medicalPanel = new BlockRule(SettingsEnum.ADREMOVER_MEDICAL_PANEL_REMOVAL, "medical_panel");
|
||||
var paidContent = new BlockRule(SettingsEnum.ADREMOVER_PAID_CONTECT_REMOVAL, "paid_content_overlay");
|
||||
var merchandise = new BlockRule(SettingsEnum.ADREMOVER_MERCHANDISE_REMOVAL, "product_carousel");
|
||||
var shorts = new BlockRule(SettingsEnum.ADREMOVER_SHORTS_SHELF_REMOVAL, "shorts_shelf");
|
||||
var infoPanel = new BlockRule(SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL, "publisher_transparency_panel", "single_item_information_panel");
|
||||
var suggestions = new BlockRule(SettingsEnum.ADREMOVER_SUGGESTIONS_REMOVAL, "horizontal_video_shelf");
|
||||
var latestPosts = new BlockRule(SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS, "post_shelf");
|
||||
var channelGuidelines = new BlockRule(SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES, "channel_guidelines_entry_banner");
|
||||
var generalAds = new BlockRule(
|
||||
SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL,
|
||||
// could be required
|
||||
//"full_width_square_image_layout",
|
||||
"video_display_full_buttoned_layout",
|
||||
"_ad",
|
||||
"ad_",
|
||||
"ads_video_with_context",
|
||||
"cell_divider",
|
||||
"reels_player_overlay",
|
||||
"shelf_header",
|
||||
"watch_metadata_app_promo",
|
||||
"video_display_full_layout"
|
||||
);
|
||||
var movieAds = new BlockRule(
|
||||
SettingsEnum.ADREMOVER_MOVIE_REMOVAL,
|
||||
"browsy_bar",
|
||||
"compact_movie",
|
||||
"horizontal_movie_shelf",
|
||||
"movie_and_show_upsell_card"
|
||||
);
|
||||
|
||||
this.register.registerAll(
|
||||
generalAds,
|
||||
communityPosts,
|
||||
paidContent,
|
||||
shorts,
|
||||
suggestions,
|
||||
latestPosts,
|
||||
movieAds,
|
||||
comments,
|
||||
communityGuidelines,
|
||||
compactBanner,
|
||||
inFeedSurvey,
|
||||
medicalPanel,
|
||||
merchandise,
|
||||
infoPanel,
|
||||
channelGuidelines
|
||||
);
|
||||
|
||||
// Block for the ComponentContext.identifier field
|
||||
identifierBlock = new BlockRule(SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL, "carousel_ad");
|
||||
}
|
||||
|
||||
public boolean filter(final String path, final String identifier) {
|
||||
// Do not block on these
|
||||
if (Extensions.containsAny(path,
|
||||
"home_video_with_context",
|
||||
"related_video_with_context",
|
||||
"search_video_with_context",
|
||||
"download_",
|
||||
"library_recent_shelf",
|
||||
"menu",
|
||||
"root",
|
||||
"-count",
|
||||
"-space",
|
||||
"-button"
|
||||
)) return false;
|
||||
|
||||
for (var rule : register) {
|
||||
if (!rule.isEnabled()) continue;
|
||||
|
||||
var result = rule.check(path);
|
||||
if (result.isBlocked()) {
|
||||
LogHelper.debug(GeneralBytecodeAdsPatch.class, "Blocked: " + path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (identifierBlock.check(identifier).isBlocked()) {
|
||||
LogHelper.debug(GeneralBytecodeAdsPatch.class, "Blocked: " + identifier);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import app.revanced.integrations.utils.ThemeHelper;
|
||||
|
||||
public class LithoThemePatch {
|
||||
// color constants used in relation with litho components
|
||||
private static final int[] WHITECONSTANTS = {
|
||||
-1, // comments chip background
|
||||
-394759, // music related results panel background
|
||||
-83886081, // video chapters list background
|
||||
};
|
||||
|
||||
private static final int[] DARKCONSTANTS = {
|
||||
-14145496, // explore drawer background
|
||||
-14606047, // comments chip background
|
||||
-15198184, // music related results panel background
|
||||
-15790321, // comments chip background (new layout)
|
||||
-98492127 // video chapters list background
|
||||
};
|
||||
|
||||
// Used by app.revanced.patches.youtube.layout.theme.patch.LithoThemePatch
|
||||
public static int applyLithoTheme(int originalValue) {
|
||||
var isDarkTheme = ThemeHelper.isDarkTheme();
|
||||
|
||||
if ((isDarkTheme && anyEquals(originalValue, DARKCONSTANTS)) || (!isDarkTheme && anyEquals(originalValue, WHITECONSTANTS)))
|
||||
return 0;
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
private static boolean anyEquals(int value, int... of) {
|
||||
for (int v : of) if (value == v) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import static app.revanced.integrations.sponsorblock.StringRef.str;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
|
||||
public class MicroGSupport {
|
||||
private static final String MICROG_VENDOR = "com.mgoogle";
|
||||
private static final String MICROG_PACKAGE_NAME = "com.mgoogle.android.gms";
|
||||
private static final String VANCED_MICROG_DOWNLOAD_LINK = "https://github.com/TeamVanced/VancedMicroG/releases/latest";
|
||||
|
||||
public static void checkAvailability() {
|
||||
var context = ReVancedUtils.getContext();
|
||||
assert context != null;
|
||||
try {
|
||||
context.getPackageManager().getPackageInfo(MICROG_PACKAGE_NAME, PackageManager.GET_ACTIVITIES);
|
||||
LogHelper.debug(ReVancedUtils.class, "MicroG is installed on the device");
|
||||
} catch (PackageManager.NameNotFoundException exception) {
|
||||
LogHelper.printException(ReVancedUtils.class, "MicroG was not found", exception);
|
||||
Toast.makeText(context, str("microg_not_installed_warning"), Toast.LENGTH_LONG).show();
|
||||
|
||||
var intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(VANCED_MICROG_DOWNLOAD_LINK));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class OpenLinksDirectlyPatch {
|
||||
|
||||
public static String parseRedirectUri(String uri) {
|
||||
if (SettingsEnum.OPEN_LINKS_DIRECTLY.getBoolean()) {
|
||||
Matcher matcher = Pattern.compile("&q=(http.+?)&v=").matcher(uri);
|
||||
return matcher.find() ? URLDecoder.decode(matcher.group(1)) : uri;
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,15 @@ public class ReturnYouTubeDislikePatch {
|
||||
|
||||
/**
|
||||
* Called when the like/dislike button is clicked
|
||||
*
|
||||
* @param vote -1 (dislike), 0 (none) or 1 (like)
|
||||
*/
|
||||
public static void sendVote(int vote) {
|
||||
ReturnYouTubeDislike.sendVote(vote);
|
||||
for (ReturnYouTubeDislike.Vote v : ReturnYouTubeDislike.Vote.values()) {
|
||||
if (v.value == vote) {
|
||||
ReturnYouTubeDislike.sendVote(v);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
/**
|
||||
* Hooking class for the current playing video.
|
||||
*/
|
||||
public final class VideoInformation {
|
||||
private static final String SEEK_METHOD_NAME = "seekTo";
|
||||
|
||||
private static WeakReference<Object> playerController;
|
||||
private static Method seekMethod;
|
||||
|
||||
private static long videoLength = 1;
|
||||
private static long videoTime = -1;
|
||||
|
||||
|
||||
/**
|
||||
* Hook into PlayerController.onCreate() method.
|
||||
*
|
||||
* @param thisRef Reference to the player controller object.
|
||||
*/
|
||||
public static void playerController_onCreateHook(final Object thisRef) {
|
||||
playerController = new WeakReference<>(thisRef);
|
||||
videoLength = 1;
|
||||
videoTime = -1;
|
||||
|
||||
try {
|
||||
seekMethod = thisRef.getClass().getMethod(SEEK_METHOD_NAME, Long.TYPE);
|
||||
seekMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
LogHelper.debug(VideoInformation.class, "Failed to initialize: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the video length.
|
||||
*
|
||||
* @param length The length of the video in milliseconds.
|
||||
*/
|
||||
public static void setVideoLength(final long length) {
|
||||
LogHelper.debug(VideoInformation.class, "Setting current video length to " + length);
|
||||
videoLength = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the video time.
|
||||
*
|
||||
* @param time The time of the video in milliseconds.
|
||||
*/
|
||||
public static void setVideoTime(final long time) {
|
||||
LogHelper.debug(VideoInformation.class, "Current video time " + time);
|
||||
videoTime = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek on the current video.
|
||||
*
|
||||
* @param millisecond The millisecond to seek the video to.
|
||||
*/
|
||||
public static void seekTo(final long millisecond) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (seekMethod == null) {
|
||||
LogHelper.debug(VideoInformation.class, "seekMethod was null");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
LogHelper.debug(VideoInformation.class, "Seeking to " + millisecond);
|
||||
seekMethod.invoke(playerController.get(), millisecond);
|
||||
} catch (Exception ex) {
|
||||
LogHelper.debug(VideoInformation.class, "Failed to seek: " + ex.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of the current video playing.
|
||||
*
|
||||
* @return The length of the video in milliseconds. 1 if not set yet.
|
||||
*/
|
||||
public static long getCurrentVideoLength() {
|
||||
return videoLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time of the current video playing.
|
||||
*
|
||||
* @return The time of the video in milliseconds. -1 if not set yet.
|
||||
*/
|
||||
public static long getVideoTime() {
|
||||
return videoTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class ZoomHapticsPatch {
|
||||
public static boolean shouldVibrate() {
|
||||
return !SettingsEnum.DISABLE_ZOOM_HAPTICS.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.integrations.patches;
|
||||
package app.revanced.integrations.patches.playback.quality;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.integrations.patches;
|
||||
package app.revanced.integrations.patches.playback.quality;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
@@ -15,7 +15,7 @@ import app.revanced.integrations.utils.LogHelper;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
import app.revanced.integrations.utils.SharedPrefHelper;
|
||||
|
||||
public class VideoQualityPatch {
|
||||
public class RememberVideoQualityPatch {
|
||||
|
||||
public static int selectedQuality1 = -2;
|
||||
private static Boolean newVideo = false;
|
||||
@@ -27,22 +27,22 @@ public class VideoQualityPatch {
|
||||
try {
|
||||
SharedPrefHelper.saveString(context, SharedPrefHelper.SharedPrefNames.REVANCED_PREFS, "wifi_quality", defaultQuality + "");
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(VideoQualityPatch.class, "Failed to change default WI-FI quality:" + ex);
|
||||
LogHelper.printException(RememberVideoQualityPatch.class, "Failed to change default WI-FI quality:" + ex);
|
||||
Toast.makeText(context, "Failed to change default WI-FI quality:", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
LogHelper.debug(VideoQualityPatch.class, "Changing default Wi-Fi quality to: " + defaultQuality);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Changing default Wi-Fi quality to: " + defaultQuality);
|
||||
Toast.makeText(context, "Changing default Wi-Fi quality to: " + defaultQuality, Toast.LENGTH_SHORT).show();
|
||||
} else if (isConnectedMobile(context)) {
|
||||
try {
|
||||
SharedPrefHelper.saveString(context, SharedPrefHelper.SharedPrefNames.REVANCED_PREFS, "mobile_quality", defaultQuality + "");
|
||||
} catch (Exception ex) {
|
||||
LogHelper.debug(VideoQualityPatch.class, "Failed to change default mobile data quality" + ex);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Failed to change default mobile data quality" + ex);
|
||||
Toast.makeText(context, "Failed to change default mobile data quality", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
LogHelper.debug(VideoQualityPatch.class, "Changing default mobile data quality to:" + defaultQuality);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Changing default mobile data quality to:" + defaultQuality);
|
||||
Toast.makeText(context, "Changing default mobile data quality to:" + defaultQuality, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
LogHelper.debug(VideoQualityPatch.class, "No internet connection.");
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "No internet connection.");
|
||||
Toast.makeText(context, "No internet connection.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
userChangedQuality = false;
|
||||
@@ -76,34 +76,34 @@ public class VideoQualityPatch {
|
||||
int selectedQuality2 = qualities.length - selectedQuality1 + 1;
|
||||
index++;
|
||||
if (selectedQuality2 == index) {
|
||||
LogHelper.debug(VideoQualityPatch.class, "Quality index is: " + index + " and corresponding value is: " + convertedQuality);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Quality index is: " + index + " and corresponding value is: " + convertedQuality);
|
||||
changeDefaultQuality(convertedQuality);
|
||||
return selectedQuality2;
|
||||
}
|
||||
}
|
||||
}
|
||||
newVideo = false;
|
||||
LogHelper.debug(VideoQualityPatch.class, "Quality: " + quality);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Quality: " + quality);
|
||||
Context context = ReVancedUtils.getContext();
|
||||
if (context == null) {
|
||||
LogHelper.printException(VideoQualityPatch.class, "Context is null or settings not initialized, returning quality: " + quality);
|
||||
LogHelper.printException(RememberVideoQualityPatch.class, "Context is null or settings not initialized, returning quality: " + quality);
|
||||
return quality;
|
||||
}
|
||||
if (isConnectedWifi(context)) {
|
||||
preferredQuality = SharedPrefHelper.getInt(context, SharedPrefHelper.SharedPrefNames.REVANCED_PREFS, "wifi_quality", -2);
|
||||
LogHelper.debug(VideoQualityPatch.class, "Wi-Fi connection detected, preferred quality: " + preferredQuality);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Wi-Fi connection detected, preferred quality: " + preferredQuality);
|
||||
} else if (isConnectedMobile(context)) {
|
||||
preferredQuality = SharedPrefHelper.getInt(context, SharedPrefHelper.SharedPrefNames.REVANCED_PREFS, "mobile_quality", -2);
|
||||
LogHelper.debug(VideoQualityPatch.class, "Mobile data connection detected, preferred quality: " + preferredQuality);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Mobile data connection detected, preferred quality: " + preferredQuality);
|
||||
} else {
|
||||
LogHelper.debug(VideoQualityPatch.class, "No Internet connection!");
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "No Internet connection!");
|
||||
return quality;
|
||||
}
|
||||
if (preferredQuality == -2) {
|
||||
return quality;
|
||||
}
|
||||
for (int streamQuality2 : iStreamQualities) {
|
||||
LogHelper.debug(VideoQualityPatch.class, "Quality at index " + index + ": " + streamQuality2);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Quality at index " + index + ": " + streamQuality2);
|
||||
index++;
|
||||
}
|
||||
for (Integer iStreamQuality : iStreamQualities) {
|
||||
@@ -116,16 +116,16 @@ public class VideoQualityPatch {
|
||||
return quality;
|
||||
}
|
||||
int qualityIndex = iStreamQualities.indexOf(quality);
|
||||
LogHelper.debug(VideoQualityPatch.class, "Index of quality " + quality + " is " + qualityIndex);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Index of quality " + quality + " is " + qualityIndex);
|
||||
try {
|
||||
Class<?> cl = qInterface.getClass();
|
||||
Method m = cl.getMethod(qIndexMethod, Integer.TYPE);
|
||||
LogHelper.debug(VideoQualityPatch.class, "Method is: " + qIndexMethod);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Method is: " + qIndexMethod);
|
||||
m.invoke(qInterface, iStreamQualities.get(qualityIndex));
|
||||
LogHelper.debug(VideoQualityPatch.class, "Quality changed to: " + qualityIndex);
|
||||
LogHelper.debug(RememberVideoQualityPatch.class, "Quality changed to: " + qualityIndex);
|
||||
return qualityIndex;
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(VideoQualityPatch.class, "Failed to set quality", ex);
|
||||
LogHelper.printException(RememberVideoQualityPatch.class, "Failed to set quality", ex);
|
||||
Toast.makeText(context, "Failed to set quality", Toast.LENGTH_SHORT).show();
|
||||
return qualityIndex;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package app.revanced.integrations.patches.playback.speed;
|
||||
|
||||
public class CustomVideoSpeedPatch {
|
||||
public static final float[] videoSpeeds = { 0, 0 }; // Values are useless as they are being overridden by the respective patch
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.integrations.whitelist.requests;
|
||||
package app.revanced.integrations.requests;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
@@ -18,9 +18,9 @@ public class Requester {
|
||||
String url = apiUrl + route.compile(params).getCompiledRoute();
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.setRequestMethod(route.getMethod().name());
|
||||
if (route != WhitelistRoutes.GET_CHANNEL_DETAILS) {
|
||||
connection.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
}
|
||||
// TODO: change the user agent string
|
||||
connection.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.integrations.whitelist.requests;
|
||||
package app.revanced.integrations.requests;
|
||||
|
||||
public class Route {
|
||||
private final String route;
|
||||
@@ -1,8 +1,5 @@
|
||||
package app.revanced.integrations.returnyoutubedislike;
|
||||
|
||||
import static app.revanced.integrations.videoplayer.VideoInformation.currentVideoId;
|
||||
import static app.revanced.integrations.videoplayer.VideoInformation.dislikeCount;
|
||||
|
||||
import android.content.Context;
|
||||
import android.icu.text.CompactDecimalFormat;
|
||||
import android.os.Build;
|
||||
@@ -19,7 +16,24 @@ import app.revanced.integrations.utils.ReVancedUtils;
|
||||
import app.revanced.integrations.utils.SharedPrefHelper;
|
||||
|
||||
public class ReturnYouTubeDislike {
|
||||
private static String currentVideoId;
|
||||
public static Integer dislikeCount;
|
||||
|
||||
private static boolean isEnabled;
|
||||
private static boolean segmentedButton;
|
||||
|
||||
public enum Vote {
|
||||
LIKE(1),
|
||||
DISLIKE(-1),
|
||||
LIKE_REMOVE(0);
|
||||
|
||||
public int value;
|
||||
|
||||
Vote(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static Thread _dislikeFetchThread = null;
|
||||
private static Thread _votingThread = null;
|
||||
private static Registration registration;
|
||||
@@ -60,6 +74,8 @@ public class ReturnYouTubeDislike {
|
||||
dislikeCount = null;
|
||||
if (!isEnabled) return;
|
||||
|
||||
currentVideoId = videoId;
|
||||
|
||||
try {
|
||||
if (_dislikeFetchThread != null && _dislikeFetchThread.getState() != Thread.State.TERMINATED) {
|
||||
LogHelper.debug(ReturnYouTubeDislike.class, "Interrupting the thread. Current state " + _dislikeFetchThread.getState());
|
||||
@@ -77,31 +93,29 @@ public class ReturnYouTubeDislike {
|
||||
if (!isEnabled) return;
|
||||
|
||||
try {
|
||||
// Contains a pathBuilder string, used to distinguish from other litho components:
|
||||
// video_action_bar.eml|27b56b54d5dcba20|video_action_bar_unwrapper.eml|c5a1d399b660e52e|CellType
|
||||
// |ScrollableContainerType|ContainerType|ContainerType|dislike_button.eml|966ee2cd7db5e29f
|
||||
// |video_actipathBuilder=video_action_bar.eml|27b56b54d5dcba20|video_action_bar_unwrapper.eml
|
||||
// |c5a1d399b660e52e|CellType|ScrollableContainerType|ContainerType|ContainerType|dislike_button.eml
|
||||
// |966ee2cd7db5e29f|video_action_toggle_button.eml|8fd9d44a8e3c9162|video_action_button.eml
|
||||
// |9dd3b4b44979c3af|ContainerType|TextType|on_toggle_button.eml|8fd9d44a8e3c9162|video_action_button.eml
|
||||
// |9dd3b4b44979c3af|ContainerType|TextType|
|
||||
if (!conversionContext.toString().contains("|dislike_button.eml|")) return;
|
||||
var conversionContextString = conversionContext.toString();
|
||||
|
||||
// Check for new component
|
||||
if (conversionContextString.contains("|segmented_like_dislike_button.eml|"))
|
||||
segmentedButton = true;
|
||||
else if (!conversionContextString.contains("|dislike_button.eml|"))
|
||||
return;
|
||||
|
||||
LogHelper.debug(ReturnYouTubeDislike.class, "dislike button was created");
|
||||
|
||||
// Have to block the current thread until fetching is done
|
||||
// There's no known way to edit the text after creation yet
|
||||
if (_dislikeFetchThread != null) _dislikeFetchThread.join();
|
||||
|
||||
if (dislikeCount != null) {
|
||||
updateDislikeText(textRef, formatDislikes(dislikeCount));
|
||||
}
|
||||
if (dislikeCount == null) return;
|
||||
|
||||
updateDislike(textRef, dislikeCount);
|
||||
LogHelper.debug(ReturnYouTubeDislike.class, "Updated text on component" + conversionContextString);
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(ReturnYouTubeDislike.class, "Error while trying to set dislikes text", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendVote(int vote) {
|
||||
public static void sendVote(Vote vote) {
|
||||
if (!isEnabled) return;
|
||||
|
||||
Context context = ReVancedUtils.getContext();
|
||||
@@ -129,16 +143,23 @@ public class ReturnYouTubeDislike {
|
||||
_votingThread.start();
|
||||
}
|
||||
|
||||
private static void updateDislikeText(AtomicReference<Object> textRef, String text) {
|
||||
SpannableString oldString = (SpannableString) textRef.get();
|
||||
SpannableString newString = new SpannableString(text);
|
||||
private static void updateDislike(AtomicReference<Object> textRef, Integer dislikeCount) {
|
||||
SpannableString oldSpannableString = (SpannableString) textRef.get();
|
||||
|
||||
// parse the buttons string
|
||||
// if the button is segmented, only get the like count as a string
|
||||
var oldButtonString = oldSpannableString.toString();
|
||||
if (segmentedButton) oldButtonString = oldButtonString.split(" \\| ")[0];
|
||||
|
||||
var dislikeString = formatDislikes(dislikeCount);
|
||||
SpannableString newString = new SpannableString(
|
||||
segmentedButton ? (oldButtonString + " | " + dislikeString) : dislikeString
|
||||
);
|
||||
|
||||
// Copy style (foreground color, etc) to new string
|
||||
Object[] spans = oldString.getSpans(0, oldString.length(), Object.class);
|
||||
for (Object span : spans) {
|
||||
int flags = oldString.getSpanFlags(span);
|
||||
newString.setSpan(span, 0, newString.length(), flags);
|
||||
}
|
||||
Object[] spans = oldSpannableString.getSpans(0, oldSpannableString.length(), Object.class);
|
||||
for (Object span : spans)
|
||||
newString.setSpan(span, 0, newString.length(), oldSpannableString.getSpanFlags(span));
|
||||
|
||||
textRef.set(newString);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user