Skip to content
This repository has been archived by the owner on Mar 25, 2022. It is now read-only.

Mute segments #59

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SponsorBlock YouTube Vanced Implementation
In order to use this in YouTube/Vanced you must first apply the smali mods applied to vanced (the patching process used for this is currently automated using our closed source tools with no plans to open source it for the time being) (if you mod vanced directly it is not required)
* First make your edits in android studio
* Change the string "replaceMeWithsetMillisecondMethod" on PlayerController.java to the method name of YouTube package
* Change the string "replaceMeWithsetMillisecondMethod", "replaceMeWithsetVolumeMethod", and "replaceMeWithgetVolumeMethod" on PlayerController.java to the method name of YouTube package
* Compile debug apk
* Decompile this apk using apktool https://github.com/iBotPeaches/Apktool
* Take this decompiled folder and look for a folder labeled pl in one of your dex class folders
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class SkipSponsorButton extends FrameLayout {
String TAG = "SkipSponsorButton";
public CharSequence skipSponsorTextViewText;
public CharSequence skipSponsorText;
public CharSequence muteSegmentText;
public ImageView skipSponsorButtonIcon;
public TextView skipSponsorTextView;
public int currentTextColor;
Expand Down Expand Up @@ -88,7 +89,8 @@ private final void initialize(Context context) {
Resources resources = context.getResources();
this.defaultBottomMargin = resources.getDimensionPixelSize(getIdentifier(context, "skip_button_default_bottom_margin", "dimen")); // dimen:skip_button_default_bottom_margin
this.ctaBottomMargin = resources.getDimensionPixelSize(getIdentifier(context, "skip_button_cta_bottom_margin", "dimen")); // dimen:skip_button_cta_bottom_margin
this.skipSponsorText = resources.getText(getIdentifier(context, "skip_sponsor", "string")); // string:skip_ads "Skip ads"
this.skipSponsorText = resources.getText(getIdentifier(context, "skip_sponsor", "string")); // string:skip_ads "Skip segment"
this.muteSegmentText = resources.getText(getIdentifier(context, "mute_segment", "string")); // string:mute_segment "Mute segment"

this.skipSponsorBtnContainer.setOnClickListener(new View.OnClickListener() {
@Override
Expand Down Expand Up @@ -119,6 +121,14 @@ protected final void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
}

public void setMuted(boolean muted) {
if (muted) {
this.skipSponsorTextView.setText(this.muteSegmentText);
} else {
this.skipSponsorTextView.setText(this.skipSponsorText);
}
}


public static int getColor(Context context, int arg3) {
return Build.VERSION.SDK_INT < 23 ? context.getResources().getColor(arg3) : context.getColor(arg3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public static void initialize(Object viewGroup) {
}
}

public static void showSkipButton() {
skipSponsorButtonVisibility(true);
public static void showSkipButton(boolean mute) {
skipSponsorButtonVisibility(true, mute);
}
public static void hideSkipButton() {
skipSponsorButtonVisibility(false);
Expand Down Expand Up @@ -105,6 +105,10 @@ private static void setSkipBtnMargins(boolean fullScreen) {
}

private static void skipSponsorButtonVisibility(boolean visible) {
skipSponsorButtonVisibility(visible, false);
}

private static void skipSponsorButtonVisibility(boolean visible, boolean mute) {
SkipSponsorButton skipSponsorButton = _skipSponsorButton.get();
if (skipSponsorButton == null) {
Log.e(TAG, "Unable to skipSponsorButtonVisibility");
Expand All @@ -113,6 +117,7 @@ private static void skipSponsorButtonVisibility(boolean visible) {

visible &= shouldShowOnPlayerType;

skipSponsorButton.setMuted(mute);
skipSponsorButton.setVisibility(visible ? View.VISIBLE : View.GONE);
bringLayoutToFront();
}
Expand Down
83 changes: 76 additions & 7 deletions app/src/main/java/pl/jakubweg/PlayerController.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,15 @@ public class PlayerController {
public static SponsorSegment[] sponsorSegmentsOfCurrentVideo;
private static WeakReference<Object> currentPlayerController = new WeakReference<>(null);
private static Method setMillisecondMethod;
private static Method setVolumeMethod;
private static Method getVolumeMethod;
private static long allowNextSkipRequestTime = 0L;
private static String currentVideoId;
private static long currentVideoLength = 1L;
private static long lastKnownVideoTime = -1L;
private static long lastKnownVolume = -1L;
private static boolean currentlyMuted = false;
private static long muteEndTime = -1L;
private static final Runnable findAndSkipSegmentRunnable = () -> {
// Log.d(TAG, "findAndSkipSegmentRunnable");
findAndSkipSegment(false);
Expand Down Expand Up @@ -111,6 +116,10 @@ public static void onCreate(final Object o) {
try {
setMillisecondMethod = o.getClass().getMethod("replaceMeWithsetMillisecondMethod", Long.TYPE);
setMillisecondMethod.setAccessible(true);
setVolumeMethod = o.getClass().getMethod("replaceMeWithsetVolumeMethod", Long.TYPE);
setVolumeMethod.setAccessible(true);
getVolumeMethod = o.getClass().getMethod("replaceMeWithgetVolumeMethod");
getVolumeMethod.setAccessible(true);

lastKnownVideoTime = 0;
VideoInformation.lastKnownVideoTime = 0;
Expand Down Expand Up @@ -226,7 +235,12 @@ public static void setCurrentVideoTime(long millis) {

for (final SponsorSegment segment : segments) {
if (segment.start > millis) {
if (segment.start > startTimerAtMillis)
long scheduleTime = segment.start;
if (muteEndTime > millis && muteEndTime < segment.start) {
scheduleTime = muteEndTime;
}

if (scheduleTime > startTimerAtMillis)
break; // it's more then START_TIMER_BEFORE_SEGMENT_MILLIS far away
if (!segment.category.behaviour.skip)
break;
Expand All @@ -238,12 +252,12 @@ public static void setCurrentVideoTime(long millis) {
@Override
public void run() {
skipSponsorTask = null;
lastKnownVideoTime = segment.start + 1;
lastKnownVideoTime = scheduleTime + 1;
VideoInformation.lastKnownVideoTime = lastKnownVideoTime;
new Handler(Looper.getMainLooper()).post(findAndSkipSegmentRunnable);
}
};
sponsorTimer.schedule(skipSponsorTask, segment.start - millis);
sponsorTimer.schedule(skipSponsorTask, scheduleTime - millis);
} else {
if (VERBOSE)
Log.d(TAG, "skipSponsorTask is already scheduled...");
Expand Down Expand Up @@ -472,6 +486,45 @@ public static void skipToMillisecond(long millisecond) {
});
}

public static void setMute(final boolean value) {
if (setVolumeMethod == null || getVolumeMethod == null) {
Log.e(TAG, "setVolumeMethod or getVolumeMethod is null");
return;
}


final Object currentObj = currentPlayerController.get();
if (currentObj == null) {
Log.e(TAG, "currentObj is null (might have been collected by GC)");
return;
}


if (VERBOSE)
Log.d(TAG, String.format("Requesting set mute to %b on thread %s", value, Thread.currentThread().toString()));

new Handler(Looper.getMainLooper()).post(() -> {
try {
if (VERBOSE)
Log.i(TAG, "Setting to mute=" + value);
long currentVolume = getVolumeMethod.invoke(currentObj);
if (value && currentVolume > 0) {
lastKnownVolume = currentVolume;
}

if (value) {
setVolumeMethod.invoke(currentObj, 0);
} else {
setVolumeMethod.invoke(currentObj, lastKnownVolume);
}

currentlyMuted = value;
} catch (Exception e) {
Log.e(TAG, "Cannot skip to millisecond", e);
}
});
}


private static void findAndSkipSegment(boolean wasClicked) {
if (sponsorSegmentsOfCurrentVideo == null)
Expand All @@ -480,13 +533,18 @@ private static void findAndSkipSegment(boolean wasClicked) {
final long millis = lastKnownVideoTime;

for (SponsorSegment segment : sponsorSegmentsOfCurrentVideo) {
if (currentlyMuted) {
setMute(false);
muteEndTime = -1;
}

if (segment.start > millis)
break;

if (segment.end < millis)
continue;

SkipSegmentView.show();
SkipSegmentView.show(segment.actionType == SponsorBlockSettings.ActionType.MUTE);
if (!(segment.category.behaviour.skip || wasClicked))
return;

Expand All @@ -501,13 +559,24 @@ private static void findAndSkipSegment(boolean wasClicked) {
private static void skipSegment(SponsorSegment segment, boolean wasClicked) {
// if (lastSkippedSegment == segment) return;
// lastSkippedSegment = segment;
if (VERBOSE)
Log.d(TAG, "Skipping segment: " + segment.toString());
if (VERBOSE) {
if (segment.actionType == SponsorBlockSettings.ActionType.SKIP) {
Log.d(TAG, "Skipping segment: " + segment.toString());
} else if (segment.actionType == SponsorBlockSettings.ActionType.MUTE) {
Log.d(TAG, "Muting segment: " + segment.toString());
}
}

if (SponsorBlockSettings.showToastWhenSkippedAutomatically && !wasClicked)
SkipSegmentView.notifySkipped(segment);

skipToMillisecond(segment.end + 2);
if (segment.actionType == SponsorBlockSettings.ActionType.SKIP) {
skipToMillisecond(segment.end + 2);
} else if (segment.actionType == SponsorBlockSettings.ActionType.MUTE) {
setMute(true);
if (segment.end > muteEndTime) muteEndTime = segment.end;
}

SkipSegmentView.hide();
if (segment.category == SponsorBlockSettings.SegmentInfo.UNSUBMITTED) {
SponsorSegment[] newSegments = new SponsorSegment[sponsorSegmentsOfCurrentVideo.length - 1];
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/pl/jakubweg/SkipSegmentView.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public class SkipSegmentView {
public static final String TAG = "jakubweg.SkipSegmentView";
private static SponsorSegment lastNotifiedSegment;

public static void show() {
showSkipButton();
public static void show(boolean mute) {
showSkipButton(mute);
}

public static void hide() {
Expand Down
29 changes: 29 additions & 0 deletions app/src/main/java/pl/jakubweg/SponsorBlockSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class SponsorBlockSettings {
public static final String PREFERENCES_KEY_SKIPPED_SEGMENTS_TIME = "sb-skipped-segments-time";
public static final String PREFERENCES_KEY_SHOW_TIME_WITHOUT_SEGMENTS = "sb-length-without-segments";
public static final String PREFERENCES_KEY_CATEGORY_COLOR_SUFFIX = "_color";
public static final String PREFERENCES_KEY_MUTE_ENABLED = "sb-voting-enabled";

public static final SegmentBehaviour DefaultBehaviour = SegmentBehaviour.SKIP_AUTOMATICALLY;

Expand All @@ -40,9 +41,11 @@ public class SponsorBlockSettings {
public static boolean showToastWhenSkippedAutomatically = true;
public static boolean countSkips = true;
public static boolean showTimeWithoutSegments = true;
public static boolean isMuteEnabled = true;
public static int adjustNewSegmentMillis = 150;
public static String uuid = "<invalid>";
public static String sponsorBlockUrlCategories = "[]";
public static String sponsorBlockUrlActionTypes = "[%22skip%22]";
public static int skippedSegments;
public static long skippedTime;

Expand Down Expand Up @@ -124,6 +127,11 @@ public static void update(Context context) {
else
sponsorBlockUrlCategories = "[%22" + TextUtils.join("%22,%22", enabledCategories) + "%22]";

isMuteEnabled = preferences.getBoolean(PREFERENCES_KEY_MUTE_ENABLED, isMuteEnabled);
if (isMuteEnabled) {
sponsorBlockUrlMute = "[%22skip%22, %mute%22]";
}

skippedSegments = preferences.getInt(PREFERENCES_KEY_SKIPPED_SEGMENTS, skippedSegments);
skippedTime = preferences.getLong(PREFERENCES_KEY_SKIPPED_SEGMENTS_TIME, skippedTime);

Expand Down Expand Up @@ -249,4 +257,25 @@ public CharSequence getTitleWithDot() {
return Html.fromHtml(String.format("<font color=\"#%06X\">⬤</font> %s", color, title));
}
}

public enum ActionType {
SKIP("skip"),
MUTE("mute");

private String key;

private static final Map<String, SegmentInfo> mValuesMap = new HashMap<>(values().length);
static {
for (SegmentInfo value : valuesWithoutUnsubmitted())
mValuesMap.put(value.key, value);
}

ActionType(String key) {
this.key = key;
}

public static SegmentInfo byKey(String key) {
return mValuesMap.get(key);
}
}
}
6 changes: 5 additions & 1 deletion app/src/main/java/pl/jakubweg/objects/SponsorSegment.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ public class SponsorSegment implements Comparable<SponsorSegment> {
public final long start;
public final long end;
public final SponsorBlockSettings.SegmentInfo category;
public final SponsorBlockSettings.ActionType actionType;
public final String UUID;

public SponsorSegment(long start, long end, SponsorBlockSettings.SegmentInfo category, String UUID) {
public SponsorSegment(long start, long end, SponsorBlockSettings.SegmentInfo category,
SponsorBlockSettings.ActionType actionType, String UUID) {
this.start = start;
this.end = end;
this.category = category;
this.actionType = actionType;
this.UUID = UUID;
}

Expand All @@ -21,6 +24,7 @@ public String toString() {
"start=" + start +
", end=" + end +
", category='" + category + '\'' +
", actionType='" + actionType + '\'' +
'}';
}

Expand Down
6 changes: 4 additions & 2 deletions app/src/main/java/pl/jakubweg/requests/Requester.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private Requester() {}
public static synchronized SponsorSegment[] getSegments(String videoId) {
List<SponsorSegment> segments = new ArrayList<>();
try {
HttpURLConnection connection = getConnectionFromRoute(Route.GET_SEGMENTS, videoId, SponsorBlockSettings.sponsorBlockUrlCategories);
HttpURLConnection connection = getConnectionFromRoute(Route.GET_SEGMENTS, videoId, SponsorBlockSettings.sponsorBlockUrlCategories, SponsorBlockSettings.sponsorBlockUrlActionTypes);
int responseCode = connection.getResponseCode();
videoHasSegments = false;
timeWithoutSegments = "";
Expand All @@ -53,11 +53,13 @@ public static synchronized SponsorSegment[] getSegments(String videoId) {
long start = (long) (segment.getDouble(0) * 1000);
long end = (long) (segment.getDouble(1) * 1000);
String category = obj.getString("category");
String actionType = obj.getString("actionType");
String uuid = obj.getString("UUID");

SponsorBlockSettings.SegmentInfo segmentCategory = SponsorBlockSettings.SegmentInfo.byCategoryKey(category);
SponsorBlockSettings.ActionType segmentActionType = SponsorBlockSettings.ActionType.byKey(category);
if (segmentCategory != null && segmentCategory.behaviour.showOnTimeBar) {
SponsorSegment sponsorSegment = new SponsorSegment(start, end, segmentCategory, uuid);
SponsorSegment sponsorSegment = new SponsorSegment(start, end, segmentCategory, segmentActionType, uuid);
segments.add(sponsorSegment);
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/pl/jakubweg/requests/Route.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import pl.jakubweg.SponsorBlockUtils;

public class Route {
public static final Route GET_SEGMENTS = new Route(GET, "skipSegments?videoID={video_id}&categories={categories}");
public static final Route GET_SEGMENTS = new Route(GET, "skipSegments?videoID={video_id}&categories={categories}&actionTypes={actionTypes}");
public static final Route VIEWED_SEGMENT = new Route(POST, "viewedVideoSponsorTime?UUID={segment_id}");
public static final Route GET_USER_STATS = new Route(GET, "userInfo?userID={user_id}&values=[\"userName\", \"minutesSaved\", \"segmentCount\", \"viewCount\"]");
public static final Route CHANGE_USERNAME = new Route(POST, "setUsername?userID={user_id}&username={username}");
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@
<string name="sb_guidelines_popup_open">Show me</string>

<string name="skip_sponsor">Skip segment</string>
<string name="mute_segment">Mute segment</string>

<string name="litho_comments">Comments removal</string>
<string name="litho_comments_off">Comments removal is turned off (new comments / phones only)</string>
Expand Down