Skip to content
This repository has been archived by the owner on Dec 11, 2024. It is now read-only.

Commit

Permalink
feat(YouTube - Overlay buttons): Add Whitelist overlay button
Browse files Browse the repository at this point in the history
  • Loading branch information
anddea committed May 27, 2024
1 parent 83bf7b2 commit 564a044
Show file tree
Hide file tree
Showing 12 changed files with 598 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ public static void changeVisibilityNegatedImmediate() {
if (instance != null) instance.setVisibilityNegatedImmediate();
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package app.revanced.integrations.youtube.patches.overlaybutton;

import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.Nullable;

import app.revanced.integrations.shared.utils.Logger;
import app.revanced.integrations.youtube.settings.Settings;
import app.revanced.integrations.youtube.settings.preference.WhitelistedChannelsPreference;
import app.revanced.integrations.youtube.whitelist.Whitelist;

@SuppressWarnings("unused")
public class Whitelists extends BottomControlButton {
@Nullable
private static Whitelists instance;

public Whitelists(ViewGroup bottomControlsViewGroup) {
super(
bottomControlsViewGroup,
"whitelist_button",
Settings.OVERLAY_BUTTON_WHITELIST,
view -> Whitelist.showWhitelistDialog(view.getContext()),
view -> {
WhitelistedChannelsPreference.showWhitelistedChannelDialog(view.getContext());
return true;
}
);
}

/**
* Injection point.
*/
public static void initialize(View bottomControlsViewGroup) {
try {
if (bottomControlsViewGroup instanceof ViewGroup viewGroup) {
instance = new Whitelists(viewGroup);
}
} catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex);
}
}

/**
* Injection point.
*/
public static void changeVisibility(boolean showing, boolean animation) {
if (instance != null) instance.setVisibility(showing, animation);
}

public static void changeVisibilityNegatedImmediate() {
if (instance != null) instance.setVisibilityNegatedImmediate();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public static boolean RememberPlaybackSpeed() {
return false;
}

public static boolean SponsorBlock() {
// Replace this with true if the SponsorBlock patch succeeds
return false;
}

public static boolean ToolBarComponents() {
// Replace this with true if the Toolbar components patch succeeds
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import app.revanced.integrations.youtube.patches.utils.PatchStatus;
import app.revanced.integrations.youtube.settings.Settings;
import app.revanced.integrations.youtube.shared.VideoInformation;
import app.revanced.integrations.youtube.whitelist.Whitelist;

@SuppressWarnings("unused")
public class PlaybackSpeedPatch {
Expand All @@ -21,13 +22,16 @@ public static void newVideoStarted(@NonNull String newlyLoadedChannelId, @NonNul
@NonNull String newlyLoadedVideoId, @NonNull String newlyLoadedVideoTitle,
final long newlyLoadedVideoLength, boolean newlyLoadedLiveStreamValue) {
isLiveStream = newlyLoadedLiveStreamValue;
Logger.printDebug(() -> "newVideoStarted: " + newlyLoadedVideoId);

if (Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_LIVE.get() && newlyLoadedLiveStreamValue)
return;

Logger.printDebug(() -> "newVideoStarted: " + newlyLoadedVideoId);
float defaultPlaybackSpeed = Settings.DEFAULT_PLAYBACK_SPEED.get();
if (Whitelist.isChannelWhitelistedPlaybackSpeed(newlyLoadedChannelId))
defaultPlaybackSpeed = 1.0f;

VideoInformation.overridePlaybackSpeed(Settings.DEFAULT_PLAYBACK_SPEED.get());
VideoInformation.overridePlaybackSpeed(defaultPlaybackSpeed);
}

/**
Expand All @@ -41,9 +45,13 @@ public static float getPlaybackSpeedInShorts(final float playbackSpeed) {
if (Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_LIVE.get() && isLiveStream)
return playbackSpeed;

float defaultPlaybackSpeed = Settings.DEFAULT_PLAYBACK_SPEED.get();
if (Whitelist.isChannelWhitelistedPlaybackSpeed(VideoInformation.getChannelId()))
defaultPlaybackSpeed = 1.0f;

Logger.printDebug(() -> "getPlaybackSpeedInShorts: " + playbackSpeed);

return Settings.DEFAULT_PLAYBACK_SPEED.get();
return defaultPlaybackSpeed;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting OVERLAY_BUTTON_COPY_VIDEO_URL_TIMESTAMP = new BooleanSetting("revanced_overlay_button_copy_video_url_timestamp", FALSE);
public static final BooleanSetting OVERLAY_BUTTON_EXTERNAL_DOWNLOADER = new BooleanSetting("revanced_overlay_button_external_downloader", FALSE);
public static final BooleanSetting OVERLAY_BUTTON_SPEED_DIALOG = new BooleanSetting("revanced_overlay_button_speed_dialog", TRUE);
public static final BooleanSetting OVERLAY_BUTTON_WHITELIST = new BooleanSetting("revanced_overlay_button_whitelist", FALSE);
public static final BooleanSetting OVERLAY_BUTTON_TIME_ORDERED_PLAYLIST = new BooleanSetting("revanced_overlay_button_time_ordered_playlist", FALSE);
public static final StringSetting EXTERNAL_DOWNLOADER_PACKAGE_NAME = new StringSetting("revanced_external_downloader_package_name", "com.deniscerri.ytdl");
public static final BooleanSetting EXTERNAL_DOWNLOADER_ACTION_BUTTON = new BooleanSetting("revanced_external_downloader_action", FALSE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import androidx.annotation.NonNull;

import app.revanced.integrations.shared.settings.Setting;
import app.revanced.integrations.youtube.patches.utils.PatchStatus;
import app.revanced.integrations.youtube.settings.Settings;
import app.revanced.integrations.youtube.utils.ExtendedUtils;

Expand Down Expand Up @@ -48,6 +49,7 @@ public static void initializeReVancedSettings(@NonNull Activity activity) {
SpeedOverlayPreferenceLinks();
QuickActionsPreferenceLinks();
TabletLayoutLinks();
WhitelistPreferenceLinks();
}

/**
Expand Down Expand Up @@ -200,4 +202,16 @@ private static void SpeedOverlayPreferenceLinks() {
Settings.SPEED_OVERLAY_VALUE
);
}

private static void WhitelistPreferenceLinks() {
final boolean enabled = PatchStatus.RememberPlaybackSpeed() || PatchStatus.SponsorBlock();
final String [] whitelistKey = { Settings.OVERLAY_BUTTON_WHITELIST.key, "revanced_whitelist_settings" };

for (String key: whitelistKey) {
final Preference preference = mPreferenceManager.findPreference(key);
if (preference != null) {
preference.setEnabled(enabled);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package app.revanced.integrations.youtube.settings.preference;

import static app.revanced.integrations.shared.utils.StringRef.str;

import android.app.AlertDialog;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;

import org.apache.commons.lang3.BooleanUtils;

import java.util.ArrayList;

import app.revanced.integrations.shared.utils.Utils;
import app.revanced.integrations.youtube.patches.utils.PatchStatus;
import app.revanced.integrations.youtube.utils.ThemeUtils;
import app.revanced.integrations.youtube.whitelist.VideoChannel;
import app.revanced.integrations.youtube.whitelist.Whitelist;
import app.revanced.integrations.youtube.whitelist.Whitelist.WhitelistType;

/**
* @noinspection ALL
*/
public class WhitelistedChannelsPreference extends Preference implements Preference.OnPreferenceClickListener {

private static final WhitelistType whitelistTypePlaybackSpeed = WhitelistType.PLAYBACK_SPEED;
private static final WhitelistType whitelistTypeSponsorBlock = WhitelistType.SPONSOR_BLOCK;
private static final boolean playbackSpeedIncluded = PatchStatus.RememberPlaybackSpeed();
private static final boolean sponsorBlockIncluded = PatchStatus.SponsorBlock();
private static String[] mEntries;
private static WhitelistType[] mEntryValues;

static {
final int entrySize = BooleanUtils.toInteger(playbackSpeedIncluded)
+ BooleanUtils.toInteger(sponsorBlockIncluded);

if (entrySize != 0 && mEntries == null && mEntryValues == null) {
mEntries = new String[entrySize];
mEntryValues = new WhitelistType[entrySize];

int index = 0;
if (playbackSpeedIncluded) {
mEntries[index] = " " + whitelistTypePlaybackSpeed.getFriendlyName() + " ";
mEntryValues[index] = whitelistTypePlaybackSpeed;
index++;
}
if (sponsorBlockIncluded) {
mEntries[index] = " " + whitelistTypeSponsorBlock.getFriendlyName() + " ";
mEntryValues[index] = whitelistTypeSponsorBlock;
}
}
}

private void init() {
setOnPreferenceClickListener(this);
}

public WhitelistedChannelsPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public WhitelistedChannelsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public WhitelistedChannelsPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public WhitelistedChannelsPreference(Context context) {
super(context);
init();
}

@Override
public boolean onPreferenceClick(Preference preference) {
showWhitelistedChannelDialog(getContext());

return true;
}

public static void showWhitelistedChannelDialog(Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(str("revanced_whitelist_settings_title"));
builder.setItems(mEntries, (dialog, which) -> showWhitelistedChannelDialog(context, mEntryValues[which]));
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
}

private static void showWhitelistedChannelDialog(Context context, WhitelistType whitelistType) {
final ArrayList<VideoChannel> mEntries = Whitelist.getWhitelistedChannels(whitelistType);

AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(whitelistType.getFriendlyName());

if (mEntries.isEmpty()) {
TextView emptyView = new TextView(context);
emptyView.setText(str("revanced_whitelist_empty"));
emptyView.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
emptyView.setTextSize(16);
emptyView.setPadding(60, 40, 60, 0);
builder.setView(emptyView);
} else {
LinearLayout entriesContainer = new LinearLayout(context);
entriesContainer.setOrientation(LinearLayout.VERTICAL);
for (final VideoChannel entry : mEntries) {
String author = entry.getChannelName();
View entryView = getEntryView(context, author, v -> {
new AlertDialog.Builder(context)
.setMessage(str("revanced_whitelist_remove_dialog_message", author, whitelistType.getFriendlyName()))
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
Whitelist.removeFromWhitelist(whitelistType, entry.getChannelId());
entriesContainer.removeView(entriesContainer.findViewWithTag(author));
})
.setNegativeButton(android.R.string.cancel, null)
.show();
});
entryView.setTag(author);
entriesContainer.addView(entryView);
}
builder.setView(entriesContainer);
}

builder.setPositiveButton(android.R.string.ok, null);
builder.show();
}

private static View getEntryView(Context context, CharSequence entry, View.OnClickListener onDeleteClickListener) {
LinearLayout.LayoutParams entryContainerParams = new LinearLayout.LayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
entryContainerParams.setMargins(60, 40, 60, 0);

LinearLayout.LayoutParams entryLabelLayoutParams = new LinearLayout.LayoutParams(
0, LinearLayout.LayoutParams.WRAP_CONTENT, 1);
entryLabelLayoutParams.gravity = Gravity.CENTER;

LinearLayout entryContainer = new LinearLayout(context);
entryContainer.setOrientation(LinearLayout.HORIZONTAL);
entryContainer.setLayoutParams(entryContainerParams);

TextView entryLabel = new TextView(context);
entryLabel.setText(entry);
entryLabel.setLayoutParams(entryLabelLayoutParams);
entryLabel.setTextSize(16);
entryLabel.setOnClickListener(onDeleteClickListener);

ImageButton deleteButton = new ImageButton(context);
deleteButton.setImageDrawable(ThemeUtils.getTrashButtonDrawable());
deleteButton.setOnClickListener(onDeleteClickListener);
deleteButton.setBackground(null);

entryContainer.addView(entryLabel);
entryContainer.addView(deleteButton);
return entryContainer;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,26 @@ public static String getVideoId() {
return videoId;
}

/**
* Channel Name of the last video opened. Includes Shorts.
*
* @return The channel name of the video.
*/
@NonNull
public static String getChannelName() {
return channelName;
}

/**
* ChannelId of the last video opened. Includes Shorts.
*
* @return The channel id of the video.
*/
@NonNull
public static String getChannelId() {
return channelId;
}

public static boolean getLiveStreamState() {
return videoIsLiveStream;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import app.revanced.integrations.youtube.sponsorblock.objects.SponsorSegment;
import app.revanced.integrations.youtube.sponsorblock.requests.SBRequester;
import app.revanced.integrations.youtube.sponsorblock.ui.SponsorBlockViewController;
import app.revanced.integrations.youtube.whitelist.Whitelist;

/**
* Handles showing, scheduling, and skipping of all {@link SponsorSegment} for the current video.
Expand Down Expand Up @@ -228,6 +229,10 @@ public static void newVideoStarted(@NonNull String newlyLoadedChannelId, @NonNul
videoLength = newlyLoadedVideoLength;
Logger.printDebug(() -> "newVideoStarted: " + newlyLoadedVideoId);

if (Whitelist.isChannelWhitelistedSponsorBlock(newlyLoadedChannelId)) {
return;
}

Utils.runOnBackgroundThread(() -> {
try {
executeDownloadSegments(newlyLoadedVideoId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ public static Drawable getBackButtonDrawable() {
return getDrawable(drawableName);
}

public static Drawable getTrashButtonDrawable() {
final String drawableName = isDarkTheme()
? "yt_outline_trash_can_white_24"
: "yt_outline_trash_can_black_24";

return getDrawable(drawableName);
}

public static int getTextColor() {
final String colorName = isDarkTheme()
? "yt_white1"
Expand Down
Loading

0 comments on commit 564a044

Please sign in to comment.