mirror of
https://github.com/revanced/revanced-integrations.git
synced 2024-12-01 00:02:55 +01:00
feat(youtube/sponsorblock): automatically hide skip button (#365)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
parent
80dc8f0421
commit
75dad2f307
@ -8,7 +8,7 @@ import app.revanced.integrations.utils.ReVancedUtils;
|
||||
public class CopyVideoUrlPatch {
|
||||
public static void copyUrl(Boolean withTimestamp) {
|
||||
try {
|
||||
String url = String.format("https://youtu.be/%s", VideoInformation.getCurrentVideoId());
|
||||
String url = String.format("https://youtu.be/%s", VideoInformation.getVideoId());
|
||||
if (withTimestamp) {
|
||||
long seconds = VideoInformation.getVideoTime() / 1000;
|
||||
url += String.format("?t=%s", seconds);
|
||||
|
@ -56,7 +56,7 @@ public class ReturnYouTubeDislikePatch {
|
||||
return replacement;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(() -> "onComponentCreated AtomicReference failure", ex);
|
||||
LogHelper.printException(() -> "onLithoTextLoaded failure", ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ public class SpoofSignatureVerificationPatch {
|
||||
final boolean signatureSpoofing = SettingsEnum.SIGNATURE_SPOOFING.getBoolean();
|
||||
if (SettingsEnum.DEBUG.getBoolean()) {
|
||||
if (ap != lastAp || ah != lastAh || av != lastAv || vs != lastVs || sd != lastSd) {
|
||||
LogHelper.printDebug(() -> "video: " + VideoInformation.getCurrentVideoId() + " spoof: " + signatureSpoofing
|
||||
LogHelper.printDebug(() -> "video: " + VideoInformation.getVideoId() + " spoof: " + signatureSpoofing
|
||||
+ " ap:" + ap + " ah:" + ah + " av:" + av + " vs:" + vs + " sd:" + sd);
|
||||
lastAp = ap;
|
||||
lastAh = ah;
|
||||
|
@ -42,7 +42,7 @@ public final class VideoInformation {
|
||||
try {
|
||||
seekMethod = thisRef.getClass().getMethod(SEEK_METHOD_NAME, Long.TYPE);
|
||||
seekMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(() -> "Failed to initialize", ex);
|
||||
}
|
||||
}
|
||||
@ -141,26 +141,25 @@ public final class VideoInformation {
|
||||
* @return The id of the video. Empty string if not set yet.
|
||||
*/
|
||||
@NonNull
|
||||
public static String getCurrentVideoId() {
|
||||
public static String getVideoId() {
|
||||
return videoId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current playback speed.
|
||||
*/
|
||||
public static float getCurrentPlaybackSpeed() {
|
||||
public static float getPlaybackSpeed() {
|
||||
return playbackSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of the current video playing.
|
||||
* Includes Shorts playback.
|
||||
* Length of the current video playing. Includes Shorts and YouTube Stories.
|
||||
*
|
||||
* @return The length of the video in milliseconds.
|
||||
* If the video is not yet loaded, or if the video is playing in the background with no video visible,
|
||||
* then this returns zero.
|
||||
*/
|
||||
public static long getCurrentVideoLength() {
|
||||
public static long getVideoLength() {
|
||||
return videoLength;
|
||||
}
|
||||
|
||||
@ -172,7 +171,7 @@ public final class VideoInformation {
|
||||
* should use the callback video time and avoid using this method
|
||||
* (in situations of recursive hook callbacks, the value returned here may be outdated).
|
||||
*
|
||||
* Includes Shorts playback.
|
||||
* Includes Shorts and YouTube Stories.
|
||||
*
|
||||
* @return The time of the video in milliseconds. -1 if not set yet.
|
||||
*/
|
||||
|
@ -49,7 +49,7 @@ public final class RememberPlaybackSpeedPatch {
|
||||
* Overrides the video speed. Called after video loads, and immediately after user selects a different playback speed
|
||||
*/
|
||||
public static float getPlaybackSpeedOverride() {
|
||||
return VideoInformation.getCurrentPlaybackSpeed();
|
||||
return VideoInformation.getPlaybackSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,7 +147,8 @@ public enum SettingsEnum {
|
||||
SB_ENABLED("sb-enabled", BOOLEAN, TRUE, SPONSOR_BLOCK),
|
||||
SB_VOTING_ENABLED("sb-voting-enabled", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
|
||||
SB_CREATE_NEW_SEGMENT_ENABLED("sb-new-segment-enabled", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
|
||||
SB_USE_COMPACT_SKIPBUTTON("sb-use-compact-skip-button", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
|
||||
SB_USE_COMPACT_SKIP_BUTTON("sb-use-compact-skip-button", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
|
||||
SB_AUTO_HIDE_SKIP_BUTTON("sb-auto-hide-skip-segment-button", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
|
||||
SB_SHOW_TOAST_ON_SKIP("show-toast", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
|
||||
SB_TRACK_SKIP_COUNT("count-skips", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
|
||||
SB_UUID("uuid", STRING, "", SPONSOR_BLOCK),
|
||||
|
@ -47,6 +47,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
private SwitchPreference addNewSegment;
|
||||
private SwitchPreference votingEnabled;
|
||||
private SwitchPreference compactSkipButton;
|
||||
private SwitchPreference autoHideSkipSegmentButton;
|
||||
private SwitchPreference showSkipToast;
|
||||
private SwitchPreference trackSkips;
|
||||
private SwitchPreference showTimeWithoutSegments;
|
||||
@ -79,9 +80,12 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
votingEnabled.setChecked(SettingsEnum.SB_VOTING_ENABLED.getBoolean());
|
||||
votingEnabled.setEnabled(enabled);
|
||||
|
||||
compactSkipButton.setChecked(SettingsEnum.SB_USE_COMPACT_SKIPBUTTON.getBoolean());
|
||||
compactSkipButton.setChecked(SettingsEnum.SB_USE_COMPACT_SKIP_BUTTON.getBoolean());
|
||||
compactSkipButton.setEnabled(enabled);
|
||||
|
||||
autoHideSkipSegmentButton.setChecked(SettingsEnum.SB_AUTO_HIDE_SKIP_BUTTON.getBoolean());
|
||||
autoHideSkipSegmentButton.setEnabled(enabled);
|
||||
|
||||
showSkipToast.setChecked(SettingsEnum.SB_SHOW_TOAST_ON_SKIP.getBoolean());
|
||||
showSkipToast.setEnabled(enabled);
|
||||
|
||||
@ -91,10 +95,10 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
showTimeWithoutSegments.setChecked(SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.getBoolean());
|
||||
showTimeWithoutSegments.setEnabled(enabled);
|
||||
|
||||
newSegmentStep.setText(String.valueOf(SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getInt()));
|
||||
newSegmentStep.setText(SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getObjectValue().toString());
|
||||
newSegmentStep.setEnabled(enabled);
|
||||
|
||||
minSegmentDuration.setText(String.valueOf(SettingsEnum.SB_MIN_DURATION.getFloat()));
|
||||
minSegmentDuration.setText(SettingsEnum.SB_MIN_DURATION.getObjectValue().toString());
|
||||
minSegmentDuration.setEnabled(enabled);
|
||||
|
||||
privateUserId.setText(SettingsEnum.SB_UUID.getString());
|
||||
@ -132,57 +136,17 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
return true;
|
||||
});
|
||||
|
||||
addNewSegment = new SwitchPreference(context);
|
||||
addNewSegment.setTitle(str("sb_enable_create_segment"));
|
||||
addNewSegment.setSummaryOn(str("sb_enable_create_segment_sum_on"));
|
||||
addNewSegment.setSummaryOff(str("sb_enable_create_segment_sum_off"));
|
||||
preferenceScreen.addPreference(addNewSegment);
|
||||
addNewSegment.setOnPreferenceChangeListener((preference1, o) -> {
|
||||
Boolean newValue = (Boolean) o;
|
||||
if (newValue && !SettingsEnum.SB_SEEN_GUIDELINES.getBoolean()) {
|
||||
new AlertDialog.Builder(preference1.getContext())
|
||||
.setTitle(str("sb_guidelines_popup_title"))
|
||||
.setMessage(str("sb_guidelines_popup_content"))
|
||||
.setNegativeButton(str("sb_guidelines_popup_already_read"), null)
|
||||
.setPositiveButton(str("sb_guidelines_popup_open"), (dialogInterface, i) -> openGuidelines())
|
||||
.setOnDismissListener(dialog -> SettingsEnum.SB_SEEN_GUIDELINES.saveValue(true))
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
|
||||
votingEnabled = new SwitchPreference(context);
|
||||
votingEnabled.setTitle(str("sb_enable_voting"));
|
||||
votingEnabled.setSummaryOn(str("sb_enable_voting_sum_on"));
|
||||
votingEnabled.setSummaryOff(str("sb_enable_voting_sum_off"));
|
||||
preferenceScreen.addPreference(votingEnabled);
|
||||
votingEnabled.setOnPreferenceChangeListener((preference1, newValue) -> {
|
||||
SettingsEnum.SB_VOTING_ENABLED.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
|
||||
compactSkipButton = new SwitchPreference(context);
|
||||
compactSkipButton.setTitle(str("sb_enable_compact_skip_button"));
|
||||
compactSkipButton.setSummaryOn(str("sb_enable_compact_skip_button_sum_on"));
|
||||
compactSkipButton.setSummaryOff(str("sb_enable_compact_skip_button_sum_off"));
|
||||
preferenceScreen.addPreference(compactSkipButton);
|
||||
compactSkipButton.setOnPreferenceChangeListener((preference1, newValue) -> {
|
||||
SettingsEnum.SB_USE_COMPACT_SKIPBUTTON.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
|
||||
addGeneralCategory(context, preferenceScreen);
|
||||
addAppearanceCategory(context, preferenceScreen);
|
||||
|
||||
segmentCategory = new PreferenceCategory(context);
|
||||
segmentCategory.setTitle(str("sb_diff_segments"));
|
||||
preferenceScreen.addPreference(segmentCategory);
|
||||
updateSegmentCategories();
|
||||
|
||||
addCreateSegmentCategory(context, preferenceScreen);
|
||||
|
||||
addGeneralCategory(context, preferenceScreen);
|
||||
|
||||
statsCategory = new PreferenceCategory(context);
|
||||
statsCategory.setTitle(str("sb_stats"));
|
||||
preferenceScreen.addPreference(statsCategory);
|
||||
@ -196,20 +160,43 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
}
|
||||
}
|
||||
|
||||
private void addGeneralCategory(final Context context, PreferenceScreen screen) {
|
||||
final PreferenceCategory category = new PreferenceCategory(context);
|
||||
private void addAppearanceCategory(Context context, PreferenceScreen screen) {
|
||||
PreferenceCategory category = new PreferenceCategory(context);
|
||||
screen.addPreference(category);
|
||||
category.setTitle(str("sb_general"));
|
||||
category.setTitle(str("sb_appearance_category"));
|
||||
|
||||
Preference guidelinePreferences = new Preference(context);
|
||||
guidelinePreferences.setTitle(str("sb_guidelines_preference_title"));
|
||||
guidelinePreferences.setSummary(str("sb_guidelines_preference_sum"));
|
||||
guidelinePreferences.setOnPreferenceClickListener(preference1 -> {
|
||||
openGuidelines();
|
||||
votingEnabled = new SwitchPreference(context);
|
||||
votingEnabled.setTitle(str("sb_enable_voting"));
|
||||
votingEnabled.setSummaryOn(str("sb_enable_voting_sum_on"));
|
||||
votingEnabled.setSummaryOff(str("sb_enable_voting_sum_off"));
|
||||
category.addPreference(votingEnabled);
|
||||
votingEnabled.setOnPreferenceChangeListener((preference1, newValue) -> {
|
||||
SettingsEnum.SB_VOTING_ENABLED.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
category.addPreference(guidelinePreferences);
|
||||
|
||||
compactSkipButton = new SwitchPreference(context);
|
||||
compactSkipButton.setTitle(str("sb_enable_compact_skip_button"));
|
||||
compactSkipButton.setSummaryOn(str("sb_enable_compact_skip_button_sum_on"));
|
||||
compactSkipButton.setSummaryOff(str("sb_enable_compact_skip_button_sum_off"));
|
||||
category.addPreference(compactSkipButton);
|
||||
compactSkipButton.setOnPreferenceChangeListener((preference1, newValue) -> {
|
||||
SettingsEnum.SB_USE_COMPACT_SKIP_BUTTON.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
|
||||
autoHideSkipSegmentButton = new SwitchPreference(context);
|
||||
autoHideSkipSegmentButton.setTitle(str("sb_enable_auto_hide_skip_segment_button"));
|
||||
autoHideSkipSegmentButton.setSummaryOn(str("sb_enable_auto_hide_skip_segment_button_sum_on"));
|
||||
autoHideSkipSegmentButton.setSummaryOff(str("sb_enable_auto_hide_skip_segment_button_sum_off"));
|
||||
category.addPreference(autoHideSkipSegmentButton);
|
||||
autoHideSkipSegmentButton.setOnPreferenceChangeListener((preference1, newValue) -> {
|
||||
SettingsEnum.SB_AUTO_HIDE_SKIP_BUTTON.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
|
||||
showSkipToast = new SwitchPreference(context);
|
||||
showSkipToast.setTitle(str("sb_general_skiptoast"));
|
||||
@ -226,19 +213,6 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
});
|
||||
category.addPreference(showSkipToast);
|
||||
|
||||
|
||||
trackSkips = new SwitchPreference(context);
|
||||
trackSkips.setTitle(str("sb_general_skipcount"));
|
||||
trackSkips.setSummaryOn(str("sb_general_skipcount_sum_on"));
|
||||
trackSkips.setSummaryOff(str("sb_general_skipcount_sum_off"));
|
||||
trackSkips.setOnPreferenceChangeListener((preference1, newValue) -> {
|
||||
SettingsEnum.SB_TRACK_SKIP_COUNT.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
category.addPreference(trackSkips);
|
||||
|
||||
|
||||
showTimeWithoutSegments = new SwitchPreference(context);
|
||||
showTimeWithoutSegments.setTitle(str("sb_general_time_without"));
|
||||
showTimeWithoutSegments.setSummaryOn(str("sb_general_time_without_sum_on"));
|
||||
@ -249,7 +223,34 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
return true;
|
||||
});
|
||||
category.addPreference(showTimeWithoutSegments);
|
||||
}
|
||||
|
||||
private void addCreateSegmentCategory(Context context, PreferenceScreen screen) {
|
||||
PreferenceCategory category = new PreferenceCategory(context);
|
||||
screen.addPreference(category);
|
||||
category.setTitle(str("sb_create_segment_category"));
|
||||
|
||||
addNewSegment = new SwitchPreference(context);
|
||||
addNewSegment.setTitle(str("sb_enable_create_segment"));
|
||||
addNewSegment.setSummaryOn(str("sb_enable_create_segment_sum_on"));
|
||||
addNewSegment.setSummaryOff(str("sb_enable_create_segment_sum_off"));
|
||||
category.addPreference(addNewSegment);
|
||||
addNewSegment.setOnPreferenceChangeListener((preference1, o) -> {
|
||||
Boolean newValue = (Boolean) o;
|
||||
if (newValue && !SettingsEnum.SB_SEEN_GUIDELINES.getBoolean()) {
|
||||
new AlertDialog.Builder(preference1.getContext())
|
||||
.setTitle(str("sb_guidelines_popup_title"))
|
||||
.setMessage(str("sb_guidelines_popup_content"))
|
||||
.setNegativeButton(str("sb_guidelines_popup_already_read"), null)
|
||||
.setPositiveButton(str("sb_guidelines_popup_open"), (dialogInterface, i) -> openGuidelines())
|
||||
.setOnDismissListener(dialog -> SettingsEnum.SB_SEEN_GUIDELINES.saveValue(true))
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
|
||||
newSegmentStep = new EditTextPreference(context);
|
||||
newSegmentStep.setTitle(str("sb_general_adjusting"));
|
||||
@ -266,6 +267,31 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
});
|
||||
category.addPreference(newSegmentStep);
|
||||
|
||||
Preference guidelinePreferences = new Preference(context);
|
||||
guidelinePreferences.setTitle(str("sb_guidelines_preference_title"));
|
||||
guidelinePreferences.setSummary(str("sb_guidelines_preference_sum"));
|
||||
guidelinePreferences.setOnPreferenceClickListener(preference1 -> {
|
||||
openGuidelines();
|
||||
return true;
|
||||
});
|
||||
category.addPreference(guidelinePreferences);
|
||||
}
|
||||
|
||||
private void addGeneralCategory(final Context context, PreferenceScreen screen) {
|
||||
PreferenceCategory category = new PreferenceCategory(context);
|
||||
screen.addPreference(category);
|
||||
category.setTitle(str("sb_general"));
|
||||
|
||||
trackSkips = new SwitchPreference(context);
|
||||
trackSkips.setTitle(str("sb_general_skipcount"));
|
||||
trackSkips.setSummaryOn(str("sb_general_skipcount_sum_on"));
|
||||
trackSkips.setSummaryOff(str("sb_general_skipcount_sum_off"));
|
||||
trackSkips.setOnPreferenceChangeListener((preference1, newValue) -> {
|
||||
SettingsEnum.SB_TRACK_SKIP_COUNT.saveValue(newValue);
|
||||
updateUI();
|
||||
return true;
|
||||
});
|
||||
category.addPreference(trackSkips);
|
||||
|
||||
minSegmentDuration = new EditTextPreference(context);
|
||||
minSegmentDuration.setTitle(str("sb_general_min_duration"));
|
||||
@ -277,7 +303,6 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
});
|
||||
category.addPreference(minSegmentDuration);
|
||||
|
||||
|
||||
privateUserId = new EditTextPreference(context);
|
||||
privateUserId.setTitle(str("sb_general_uuid"));
|
||||
privateUserId.setSummary(str("sb_general_uuid_sum"));
|
||||
@ -293,7 +318,6 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
});
|
||||
category.addPreference(privateUserId);
|
||||
|
||||
|
||||
apiUrl = new Preference(context);
|
||||
apiUrl.setTitle(str("sb_general_api_url"));
|
||||
apiUrl.setSummary(Html.fromHtml(str("sb_general_api_url_sum")));
|
||||
@ -327,7 +351,6 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
});
|
||||
category.addPreference(apiUrl);
|
||||
|
||||
|
||||
importExport = new EditTextPreference(context);
|
||||
importExport.setTitle(str("sb_settings_ie"));
|
||||
importExport.setSummary(str("sb_settings_ie_sum"));
|
||||
@ -365,7 +388,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
|
||||
{
|
||||
Preference preference = new Preference(context);
|
||||
screen.addPreference(preference);
|
||||
category.addPreference(preference);
|
||||
preference.setTitle(str("sb_about_api"));
|
||||
preference.setSummary(str("sb_about_api_sum"));
|
||||
preference.setOnPreferenceClickListener(preference1 -> {
|
||||
@ -378,7 +401,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
||||
|
||||
{
|
||||
Preference preference = new Preference(context);
|
||||
screen.addPreference(preference);
|
||||
category.addPreference(preference);
|
||||
preference.setSummary(str("sb_about_made_by"));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
preference.setSingleLineTitle(false);
|
||||
|
@ -11,7 +11,10 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.integrations.patches.VideoInformation;
|
||||
@ -32,11 +35,12 @@ import app.revanced.integrations.utils.ReVancedUtils;
|
||||
*/
|
||||
public class SegmentPlaybackController {
|
||||
/**
|
||||
* Length of time to show a highlight segment manual skip.
|
||||
* Because there is no scheduled hide of a skip to highlight,
|
||||
* effectively this time value is rounded up to the next second.
|
||||
* Length of time to show a skip button for a highlight segment,
|
||||
* or a regular segment if {@link SettingsEnum#SB_AUTO_HIDE_SKIP_BUTTON} is enabled.
|
||||
*
|
||||
* Because Effectively, this value is rounded up to the next second.
|
||||
*/
|
||||
private static final long HIGHLIGHT_SEGMENT_DURATION_TO_SHOW_SKIP_PROMPT = 3800;
|
||||
private static final long DURATION_TO_SHOW_SKIP_BUTTON = 3800;
|
||||
|
||||
/*
|
||||
* Highlight segments have zero length, as they are a point in time.
|
||||
@ -48,7 +52,7 @@ public class SegmentPlaybackController {
|
||||
@Nullable
|
||||
private static String currentVideoId;
|
||||
@Nullable
|
||||
private static SponsorSegment[] segmentsOfCurrentVideo;
|
||||
private static SponsorSegment[] segments;
|
||||
|
||||
/**
|
||||
* Highlight segment, if one exists.
|
||||
@ -63,12 +67,12 @@ public class SegmentPlaybackController {
|
||||
private static long highlightSegmentInitialShowEndTime;
|
||||
|
||||
/**
|
||||
* Current (non-highlight) segment that user can manually skip.
|
||||
* Currently playing (non-highlight) segment that user can manually skip.
|
||||
*/
|
||||
@Nullable
|
||||
private static SponsorSegment segmentCurrentlyPlaying;
|
||||
/**
|
||||
* Currently playing manual skip segment, that is scheduled to hide.
|
||||
* Currently playing manual skip segment that is scheduled to hide.
|
||||
* This will always be NULL or equal to {@link #segmentCurrentlyPlaying}.
|
||||
*/
|
||||
@Nullable
|
||||
@ -79,6 +83,22 @@ public class SegmentPlaybackController {
|
||||
@Nullable
|
||||
private static SponsorSegment scheduledUpcomingSegment;
|
||||
|
||||
/**
|
||||
* Used to prevent re-showing a previously hidden skip button when exiting an embedded segment.
|
||||
* Only used when {@link SettingsEnum#SB_AUTO_HIDE_SKIP_BUTTON} is enabled.
|
||||
*
|
||||
* A collection of segments that have automatically hidden the skip button for, and all segments in this list
|
||||
* contain the current video time. Segment are removed when playback exits the segment.
|
||||
*/
|
||||
private static final List<SponsorSegment> hiddenSkipSegmentsForCurrentVideoTime = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* System time (in milliseconds) of when to hide the skip button of {@link #segmentCurrentlyPlaying}.
|
||||
* Value is zero if playback is not inside a segment ({@link #segmentCurrentlyPlaying} is null),
|
||||
* or if {@link SettingsEnum#SB_AUTO_HIDE_SKIP_BUTTON} is not enabled.
|
||||
*/
|
||||
private static long skipSegmentButtonEndTime;
|
||||
|
||||
@Nullable
|
||||
private static String timeWithoutSegments;
|
||||
|
||||
@ -87,16 +107,16 @@ public class SegmentPlaybackController {
|
||||
private static float sponsorBarThickness = 2f;
|
||||
|
||||
@Nullable
|
||||
public static SponsorSegment[] getSegmentsOfCurrentVideo() {
|
||||
return segmentsOfCurrentVideo;
|
||||
static SponsorSegment[] getSegments() {
|
||||
return segments;
|
||||
}
|
||||
|
||||
static void setSegmentsOfCurrentVideo(@NonNull SponsorSegment[] segments) {
|
||||
Arrays.sort(segments);
|
||||
segmentsOfCurrentVideo = segments;
|
||||
private static void setSegments(@NonNull SponsorSegment[] videoSegments) {
|
||||
Arrays.sort(videoSegments);
|
||||
segments = videoSegments;
|
||||
calculateTimeWithoutSegments();
|
||||
|
||||
for (SponsorSegment segment : segments) {
|
||||
for (SponsorSegment segment : videoSegments) {
|
||||
if (segment.category == SegmentCategory.HIGHLIGHT) {
|
||||
highlightSegment = segment;
|
||||
return;
|
||||
@ -105,8 +125,34 @@ public class SegmentPlaybackController {
|
||||
highlightSegment = null;
|
||||
}
|
||||
|
||||
public static boolean currentVideoHasSegments() {
|
||||
return segmentsOfCurrentVideo != null && segmentsOfCurrentVideo.length > 0;
|
||||
static void addUnsubmittedSegment(@NonNull SponsorSegment segment) {
|
||||
Objects.requireNonNull(segment);
|
||||
if (segments == null) {
|
||||
segments = new SponsorSegment[1];
|
||||
} else {
|
||||
segments = Arrays.copyOf(segments, segments.length + 1);
|
||||
}
|
||||
segments[segments.length - 1] = segment;
|
||||
setSegments(segments);
|
||||
}
|
||||
|
||||
static void removeUnsubmittedSegments() {
|
||||
if (segments == null || segments.length == 0) {
|
||||
return;
|
||||
}
|
||||
List<SponsorSegment> replacement = new ArrayList<>();
|
||||
for (SponsorSegment segment : segments) {
|
||||
if (segment.category != SegmentCategory.UNSUBMITTED) {
|
||||
replacement.add(segment);
|
||||
}
|
||||
}
|
||||
if (replacement.size() != segments.length) {
|
||||
setSegments(replacement.toArray(new SponsorSegment[0]));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean videoHasSegments() {
|
||||
return segments != null && segments.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,15 +160,17 @@ public class SegmentPlaybackController {
|
||||
*/
|
||||
private static void clearData() {
|
||||
currentVideoId = null;
|
||||
segmentsOfCurrentVideo = null;
|
||||
segments = null;
|
||||
highlightSegment = null;
|
||||
highlightSegmentInitialShowEndTime = 0;
|
||||
timeWithoutSegments = null;
|
||||
segmentCurrentlyPlaying = null;
|
||||
scheduledUpcomingSegment = null; // prevent any existing scheduled skip from running
|
||||
scheduledUpcomingSegment = null;
|
||||
scheduledHideSegment = null;
|
||||
toastSegmentSkipped = null; // prevent any scheduled skip toasts from showing
|
||||
skipSegmentButtonEndTime = 0;
|
||||
toastSegmentSkipped = null;
|
||||
toastNumberOfSegmentsSkipped = 0;
|
||||
hiddenSkipSegmentsForCurrentVideoTime.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,11 +214,9 @@ public class SegmentPlaybackController {
|
||||
currentVideoId = videoId;
|
||||
LogHelper.printDebug(() -> "setCurrentVideoId: " + videoId);
|
||||
|
||||
//noinspection UnnecessaryLocalVariable
|
||||
String videoIdToDownload = videoId; // make a copy, to use off main thread
|
||||
ReVancedUtils.runOnBackgroundThread(() -> {
|
||||
try {
|
||||
executeDownloadSegments(videoIdToDownload);
|
||||
executeDownloadSegments(videoId);
|
||||
} catch (Exception e) {
|
||||
LogHelper.printException(() -> "Failed to download segments", e);
|
||||
}
|
||||
@ -189,12 +235,12 @@ public class SegmentPlaybackController {
|
||||
SponsorSegment[] segments = SBRequester.getSegments(videoId);
|
||||
|
||||
ReVancedUtils.runOnMainThread(()-> {
|
||||
if (!videoId.equals(currentVideoId)) {
|
||||
if (!videoId.equals(SegmentPlaybackController.currentVideoId)) {
|
||||
// user changed videos before get segments network call could complete
|
||||
LogHelper.printDebug(() -> "Ignoring segments for prior video: " + videoId);
|
||||
return;
|
||||
}
|
||||
setSegmentsOfCurrentVideo(segments);
|
||||
setSegments(segments);
|
||||
|
||||
final long videoTime = VideoInformation.getVideoTime();
|
||||
// if the current video time is before the highlight
|
||||
@ -203,8 +249,7 @@ public class SegmentPlaybackController {
|
||||
skipSegment(highlightSegment, false);
|
||||
return;
|
||||
}
|
||||
highlightSegmentInitialShowEndTime = System.currentTimeMillis()
|
||||
+ HIGHLIGHT_SEGMENT_DURATION_TO_SHOW_SKIP_PROMPT;
|
||||
highlightSegmentInitialShowEndTime = System.currentTimeMillis() + DURATION_TO_SHOW_SKIP_BUTTON;
|
||||
}
|
||||
// check for any skips now, instead of waiting for the next update to setVideoTime()
|
||||
setVideoTime(videoTime);
|
||||
@ -223,21 +268,23 @@ public class SegmentPlaybackController {
|
||||
try {
|
||||
if (!SettingsEnum.SB_ENABLED.getBoolean()
|
||||
|| PlayerType.getCurrent().isNoneOrHidden() // shorts playback
|
||||
|| segmentsOfCurrentVideo == null || segmentsOfCurrentVideo.length == 0) {
|
||||
|| segments == null || segments.length == 0) {
|
||||
return;
|
||||
}
|
||||
LogHelper.printDebug(() -> "setVideoTime: " + millis);
|
||||
|
||||
updateHiddenSegments(millis);
|
||||
|
||||
// to debug the timing logic, set this to a very large value (5000 or more)
|
||||
// then try manually seeking just playback reaches a skip/hide of different segments
|
||||
final long lookAheadMilliseconds = 1500; // must be larger than the average time between calls to this method
|
||||
final float playbackSpeed = VideoInformation.getCurrentPlaybackSpeed();
|
||||
final float playbackSpeed = VideoInformation.getPlaybackSpeed();
|
||||
final long startTimerLookAheadThreshold = millis + (long)(playbackSpeed * lookAheadMilliseconds);
|
||||
|
||||
SponsorSegment foundCurrentSegment = null;
|
||||
SponsorSegment foundSegmentCurrentlyPlaying = null;
|
||||
SponsorSegment foundUpcomingSegment = null;
|
||||
|
||||
for (final SponsorSegment segment : segmentsOfCurrentVideo) {
|
||||
for (final SponsorSegment segment : segments) {
|
||||
if (segment.category.behaviour == CategoryBehaviour.SHOW_IN_SEEKBAR
|
||||
|| segment.category.behaviour == CategoryBehaviour.IGNORE
|
||||
|| segment.category == SegmentCategory.HIGHLIGHT) {
|
||||
@ -255,14 +302,14 @@ public class SegmentPlaybackController {
|
||||
}
|
||||
|
||||
// first found segment, or it's an embedded segment and fully inside the outer segment
|
||||
if (foundCurrentSegment == null || foundCurrentSegment.containsSegment(segment)) {
|
||||
if (foundSegmentCurrentlyPlaying == null || foundSegmentCurrentlyPlaying.containsSegment(segment)) {
|
||||
// If the found segment is not currently displayed, then do not show if the segment is nearly over.
|
||||
// This check prevents the skip button text from rapidly changing when multiple segments end at nearly the same time.
|
||||
// Also prevents showing the skip button if user seeks into the last half second of the segment.
|
||||
final long minMillisOfSegmentRemainingThreshold = 500;
|
||||
// Also prevents showing the skip button if user seeks into the last 800ms of the segment.
|
||||
final long minMillisOfSegmentRemainingThreshold = 800;
|
||||
if (segmentCurrentlyPlaying == segment
|
||||
|| !segment.endIsNear(millis, minMillisOfSegmentRemainingThreshold)) {
|
||||
foundCurrentSegment = segment;
|
||||
foundSegmentCurrentlyPlaying = segment;
|
||||
} else {
|
||||
LogHelper.printDebug(() -> "Ignoring segment that ends very soon: " + segment);
|
||||
}
|
||||
@ -284,15 +331,16 @@ public class SegmentPlaybackController {
|
||||
// upcoming manual skip
|
||||
|
||||
// do not schedule upcoming segment, if it is not fully contained inside the current segment
|
||||
if ((foundCurrentSegment == null || foundCurrentSegment.containsSegment(segment))
|
||||
if ((foundSegmentCurrentlyPlaying == null || foundSegmentCurrentlyPlaying.containsSegment(segment))
|
||||
// use the most inner upcoming segment
|
||||
&& (foundUpcomingSegment == null || foundUpcomingSegment.containsSegment(segment))) {
|
||||
|
||||
// Only schedule, if the segment start time is not near the end time of the current segment.
|
||||
// This check is needed to prevent scheduled hide and show from clashing with each other.
|
||||
// Instead the upcoming segment will be handled when the current segment scheduled hide calls back into this method.
|
||||
final long minTimeBetweenStartEndOfSegments = 1000;
|
||||
if (foundCurrentSegment == null
|
||||
|| !foundCurrentSegment.endIsNear(segment.start, minTimeBetweenStartEndOfSegments)) {
|
||||
if (foundSegmentCurrentlyPlaying == null
|
||||
|| !foundSegmentCurrentlyPlaying.endIsNear(segment.start, minTimeBetweenStartEndOfSegments)) {
|
||||
foundUpcomingSegment = segment;
|
||||
} else {
|
||||
LogHelper.printDebug(() -> "Not scheduling segment (start time is near end of current segment): " + segment);
|
||||
@ -300,23 +348,22 @@ public class SegmentPlaybackController {
|
||||
}
|
||||
}
|
||||
|
||||
if (highlightSegment != null && (millis < HIGHLIGHT_SEGMENT_DURATION_TO_SHOW_SKIP_PROMPT
|
||||
|| System.currentTimeMillis() < highlightSegmentInitialShowEndTime)) {
|
||||
SponsorBlockViewController.showSkipHighlightButton(highlightSegment);
|
||||
} else {
|
||||
SponsorBlockViewController.hideSkipHighlightButton();
|
||||
if (highlightSegment != null) {
|
||||
if (millis < DURATION_TO_SHOW_SKIP_BUTTON || System.currentTimeMillis() < highlightSegmentInitialShowEndTime) {
|
||||
SponsorBlockViewController.showSkipHighlightButton(highlightSegment);
|
||||
} else {
|
||||
SponsorBlockViewController.hideSkipHighlightButton();
|
||||
}
|
||||
}
|
||||
|
||||
if (segmentCurrentlyPlaying != foundCurrentSegment) {
|
||||
if (foundCurrentSegment == null) {
|
||||
LogHelper.printDebug(() -> "Hiding segment: " + segmentCurrentlyPlaying);
|
||||
segmentCurrentlyPlaying = null;
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
} else {
|
||||
segmentCurrentlyPlaying = foundCurrentSegment;
|
||||
LogHelper.printDebug(() -> "Showing segment: " + segmentCurrentlyPlaying);
|
||||
SponsorBlockViewController.showSkipSegmentButton(foundCurrentSegment);
|
||||
}
|
||||
if (segmentCurrentlyPlaying != foundSegmentCurrentlyPlaying) {
|
||||
setSegmentCurrentlyPlaying(foundSegmentCurrentlyPlaying);
|
||||
} else if (foundSegmentCurrentlyPlaying != null
|
||||
&& skipSegmentButtonEndTime != 0 && skipSegmentButtonEndTime <= System.currentTimeMillis()) {
|
||||
LogHelper.printDebug(() -> "Auto hiding skip button for segment: " + segmentCurrentlyPlaying);
|
||||
skipSegmentButtonEndTime = 0;
|
||||
hiddenSkipSegmentsForCurrentVideoTime.add(foundSegmentCurrentlyPlaying);
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
}
|
||||
|
||||
// must be greater than the average time between updates to VideoInformation time
|
||||
@ -324,8 +371,8 @@ public class SegmentPlaybackController {
|
||||
|
||||
// schedule a hide, only if the segment end is near
|
||||
final SponsorSegment segmentToHide =
|
||||
(foundCurrentSegment != null && foundCurrentSegment.endIsNear(millis, lookAheadMilliseconds))
|
||||
? foundCurrentSegment
|
||||
(foundSegmentCurrentlyPlaying != null && foundSegmentCurrentlyPlaying.endIsNear(millis, lookAheadMilliseconds))
|
||||
? foundSegmentCurrentlyPlaying
|
||||
: null;
|
||||
|
||||
if (scheduledHideSegment != segmentToHide) {
|
||||
@ -355,8 +402,7 @@ public class SegmentPlaybackController {
|
||||
// Instead call back into setVideoTime to check everything again.
|
||||
// Should not use VideoInformation time as it is less accurate,
|
||||
// but this scheduled handler was scheduled precisely so we can just use the segment end time
|
||||
segmentCurrentlyPlaying = null;
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
setSegmentCurrentlyPlaying(null);
|
||||
setVideoTime(segmentToHide.end);
|
||||
}, delayUntilHide);
|
||||
}
|
||||
@ -392,8 +438,7 @@ public class SegmentPlaybackController {
|
||||
skipSegment(segmentToSkip, false);
|
||||
} else {
|
||||
LogHelper.printDebug(() -> "Running scheduled show segment: " + segmentToSkip);
|
||||
segmentCurrentlyPlaying = segmentToSkip;
|
||||
SponsorBlockViewController.showSkipSegmentButton(segmentToSkip);
|
||||
setSegmentCurrentlyPlaying(segmentToSkip);
|
||||
}
|
||||
}, delayUntilSkip);
|
||||
}
|
||||
@ -403,12 +448,51 @@ public class SegmentPlaybackController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all previously hidden segments that are not longer contained in the given video time.
|
||||
*/
|
||||
private static void updateHiddenSegments(long currentVideoTime) {
|
||||
Iterator<SponsorSegment> i = hiddenSkipSegmentsForCurrentVideoTime.iterator();
|
||||
while (i.hasNext()) {
|
||||
SponsorSegment hiddenSegment = i.next();
|
||||
if (!hiddenSegment.containsTime(currentVideoTime)) {
|
||||
LogHelper.printDebug(() -> "Resetting hide skip button: " + hiddenSegment);
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setSegmentCurrentlyPlaying(@Nullable SponsorSegment segment) {
|
||||
if (segment == null) {
|
||||
if (segmentCurrentlyPlaying != null) LogHelper.printDebug(() -> "Hiding segment: " + segmentCurrentlyPlaying);
|
||||
segmentCurrentlyPlaying = null;
|
||||
skipSegmentButtonEndTime = 0;
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
return;
|
||||
}
|
||||
segmentCurrentlyPlaying = segment;
|
||||
skipSegmentButtonEndTime = 0;
|
||||
if (SettingsEnum.SB_AUTO_HIDE_SKIP_BUTTON.getBoolean()) {
|
||||
if (hiddenSkipSegmentsForCurrentVideoTime.contains(segment)) {
|
||||
// Playback exited a nested segment and the outer segment skip button was previously hidden.
|
||||
LogHelper.printDebug(() -> "Ignoring previously auto-hidden segment: " + segment);
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
return;
|
||||
}
|
||||
skipSegmentButtonEndTime = System.currentTimeMillis() + DURATION_TO_SHOW_SKIP_BUTTON;
|
||||
}
|
||||
LogHelper.printDebug(() -> "Showing segment: " + segment);
|
||||
SponsorBlockViewController.showSkipSegmentButton(segment);
|
||||
}
|
||||
|
||||
private static SponsorSegment lastSegmentSkipped;
|
||||
private static long lastSegmentSkippedTime;
|
||||
|
||||
private static void skipSegment(@NonNull SponsorSegment segmentToSkip, boolean userManuallySkipped) {
|
||||
try {
|
||||
SponsorBlockViewController.hideSkipHighlightButton();
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
|
||||
// If trying to seek to end of the video, YouTube can seek just short of the actual end.
|
||||
// (especially if the video does not end on a whole second boundary).
|
||||
// This causes additional segment skip attempts, even though it cannot seek any closer to the desired time.
|
||||
@ -423,15 +507,14 @@ public class SegmentPlaybackController {
|
||||
LogHelper.printDebug(() -> "Skipping segment: " + segmentToSkip);
|
||||
lastSegmentSkipped = segmentToSkip;
|
||||
lastSegmentSkippedTime = now;
|
||||
segmentCurrentlyPlaying = null;
|
||||
setSegmentCurrentlyPlaying(null);
|
||||
scheduledHideSegment = null;
|
||||
scheduledUpcomingSegment = null;
|
||||
if (segmentToSkip == highlightSegment) {
|
||||
highlightSegmentInitialShowEndTime = 0;
|
||||
}
|
||||
SponsorBlockViewController.hideSkipHighlightButton();
|
||||
SponsorBlockViewController.hideSkipSegmentButton();
|
||||
|
||||
// If the seek is successful, then the seek causes a recursive call back into this class.
|
||||
final boolean seekSuccessful = VideoInformation.seekTo(segmentToSkip.end);
|
||||
if (!seekSuccessful) {
|
||||
// can happen when switching videos and is normal
|
||||
@ -442,12 +525,13 @@ public class SegmentPlaybackController {
|
||||
if (!userManuallySkipped) {
|
||||
// check for any smaller embedded segments, and count those as autoskipped
|
||||
final boolean showSkipToast = SettingsEnum.SB_SHOW_TOAST_ON_SKIP.getBoolean();
|
||||
for (final SponsorSegment otherSegment : segmentsOfCurrentVideo) {
|
||||
for (final SponsorSegment otherSegment : segments) {
|
||||
if (segmentToSkip.end < otherSegment.start) {
|
||||
break; // no other segments can be contained
|
||||
}
|
||||
if (segmentToSkip.containsSegment(otherSegment)) { // includes checking the segment against itself
|
||||
otherSegment.didAutoSkipped = true; // skipped this segment as well
|
||||
if (otherSegment == segmentToSkip ||
|
||||
(otherSegment.category != SegmentCategory.HIGHLIGHT && segmentToSkip.containsSegment(otherSegment))) {
|
||||
otherSegment.didAutoSkipped = true;
|
||||
if (showSkipToast) {
|
||||
showSkippedSegmentToast(otherSegment);
|
||||
}
|
||||
@ -456,16 +540,8 @@ public class SegmentPlaybackController {
|
||||
}
|
||||
|
||||
if (segmentToSkip.category == SegmentCategory.UNSUBMITTED) {
|
||||
// skipped segment was a preview of unsubmitted segment
|
||||
// remove the segment from the UI view
|
||||
removeUnsubmittedSegments();
|
||||
SponsorBlockUtils.setNewSponsorSegmentPreviewed();
|
||||
SponsorSegment[] newSegments = new SponsorSegment[segmentsOfCurrentVideo.length - 1];
|
||||
int i = 0;
|
||||
for (SponsorSegment segment : segmentsOfCurrentVideo) {
|
||||
if (segment != segmentToSkip)
|
||||
newSegments[i++] = segment;
|
||||
}
|
||||
setSegmentsOfCurrentVideo(newSegments);
|
||||
} else {
|
||||
SponsorBlockUtils.sendViewRequestAsync(segmentToSkip);
|
||||
}
|
||||
@ -578,13 +654,9 @@ public class SegmentPlaybackController {
|
||||
}
|
||||
|
||||
public static void setSponsorBarThickness(final float thickness) {
|
||||
try {
|
||||
if (sponsorBarThickness != thickness) {
|
||||
LogHelper.printDebug(() -> String.format("setSponsorBarThickness: %.2f", thickness));
|
||||
sponsorBarThickness = thickness;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(() -> "setSponsorBarThickness failure", ex);
|
||||
if (sponsorBarThickness != thickness) {
|
||||
LogHelper.printDebug(() -> String.format("setSponsorBarThickness: %.2f", thickness));
|
||||
sponsorBarThickness = thickness;
|
||||
}
|
||||
}
|
||||
|
||||
@ -606,17 +678,39 @@ public class SegmentPlaybackController {
|
||||
}
|
||||
|
||||
private static void calculateTimeWithoutSegments() {
|
||||
final long currentVideoLength = VideoInformation.getCurrentVideoLength();
|
||||
final long currentVideoLength = VideoInformation.getVideoLength();
|
||||
if (!SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.getBoolean() || currentVideoLength <= 0
|
||||
|| segmentsOfCurrentVideo == null || segmentsOfCurrentVideo.length == 0) {
|
||||
|| segments == null || segments.length == 0) {
|
||||
timeWithoutSegments = null;
|
||||
return;
|
||||
}
|
||||
|
||||
long timeWithoutSegmentsValue = currentVideoLength + 500; // YouTube:tm:
|
||||
for (SponsorSegment segment : segmentsOfCurrentVideo) {
|
||||
timeWithoutSegmentsValue -= segment.length();
|
||||
boolean foundNonhighlightSegments = false;
|
||||
long timeWithoutSegmentsValue = currentVideoLength;
|
||||
|
||||
for (int i = 0, length = segments.length; i < length; i++) {
|
||||
SponsorSegment segment = segments[i];
|
||||
if (segment.category == SegmentCategory.HIGHLIGHT) {
|
||||
continue;
|
||||
}
|
||||
foundNonhighlightSegments = true;
|
||||
long start = segment.start;
|
||||
final long end = segment.end;
|
||||
// To prevent nested segments from incorrectly counting additional time,
|
||||
// check if the segment overlaps any earlier segments.
|
||||
for (int j = 0; j < i; j++) {
|
||||
start = Math.max(start, segments[j].end);
|
||||
}
|
||||
if (start < end) {
|
||||
timeWithoutSegmentsValue -= (end - start);
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundNonhighlightSegments) {
|
||||
timeWithoutSegments = null;
|
||||
return;
|
||||
}
|
||||
|
||||
final long hours = timeWithoutSegmentsValue / 3600000;
|
||||
final long minutes = (timeWithoutSegmentsValue / 60000) % 60;
|
||||
final long seconds = (timeWithoutSegmentsValue / 1000) % 60;
|
||||
@ -643,9 +737,9 @@ public class SegmentPlaybackController {
|
||||
public static void drawSponsorTimeBars(final Canvas canvas, final float posY) {
|
||||
try {
|
||||
if (sponsorBarThickness < 0.1) return;
|
||||
if (segmentsOfCurrentVideo == null) return;
|
||||
final long currentVideoLength = VideoInformation.getCurrentVideoLength();
|
||||
if (currentVideoLength <= 0) return;
|
||||
if (segments == null) return;
|
||||
final long videoLength = VideoInformation.getVideoLength();
|
||||
if (videoLength <= 0) return;
|
||||
|
||||
final float thicknessDiv2 = sponsorBarThickness / 2;
|
||||
final float top = posY - thicknessDiv2;
|
||||
@ -653,8 +747,8 @@ public class SegmentPlaybackController {
|
||||
final float absoluteLeft = sponsorBarLeft;
|
||||
final float absoluteRight = sponsorBarRight;
|
||||
|
||||
final float tmp1 = (1f / currentVideoLength) * (absoluteRight - absoluteLeft);
|
||||
for (SponsorSegment segment : segmentsOfCurrentVideo) {
|
||||
final float tmp1 = (1f / videoLength) * (absoluteRight - absoluteLeft);
|
||||
for (SponsorSegment segment : segments) {
|
||||
final float left = segment.start * tmp1 + absoluteLeft;
|
||||
final float right;
|
||||
if (segment.category == SegmentCategory.HIGHLIGHT) {
|
||||
|
@ -15,7 +15,6 @@ import java.lang.ref.WeakReference;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
@ -157,13 +156,13 @@ public class SponsorBlockUtils {
|
||||
private static final DialogInterface.OnClickListener segmentVoteClickListener = (dialog, which) -> {
|
||||
try {
|
||||
final Context context = ((AlertDialog) dialog).getContext();
|
||||
SponsorSegment[] currentSegments = SegmentPlaybackController.getSegmentsOfCurrentVideo();
|
||||
if (currentSegments == null || currentSegments.length == 0) {
|
||||
SponsorSegment[] segments = SegmentPlaybackController.getSegments();
|
||||
if (segments == null || segments.length == 0) {
|
||||
// should never be reached
|
||||
LogHelper.printException(() -> "Segment is no longer available on the client");
|
||||
return;
|
||||
}
|
||||
SponsorSegment segment = currentSegments[which];
|
||||
SponsorSegment segment = segments[which];
|
||||
|
||||
SegmentVote[] voteOptions = (segment.category == SegmentCategory.HIGHLIGHT)
|
||||
? SegmentVote.voteTypesWithoutCategoryChange // highlight segments cannot change category
|
||||
@ -218,8 +217,8 @@ public class SponsorBlockUtils {
|
||||
final String uuid = SettingsEnum.SB_UUID.getString();
|
||||
final long start = newSponsorSegmentStartMillis;
|
||||
final long end = newSponsorSegmentEndMillis;
|
||||
final String videoId = VideoInformation.getCurrentVideoId();
|
||||
final long videoLength = VideoInformation.getCurrentVideoLength();
|
||||
final String videoId = VideoInformation.getVideoId();
|
||||
final long videoLength = VideoInformation.getVideoLength();
|
||||
final SegmentCategory segmentCategory = newUserCreatedSegmentCategory;
|
||||
if (start < 0 || end < 0 || start >= end || videoLength <= 0 || videoId.isEmpty()
|
||||
|| segmentCategory == null || uuid.isEmpty()) {
|
||||
@ -287,33 +286,33 @@ public class SponsorBlockUtils {
|
||||
public static void onVotingClicked(@NonNull Context context) {
|
||||
try {
|
||||
ReVancedUtils.verifyOnMainThread();
|
||||
SponsorSegment[] currentSegments = SegmentPlaybackController.getSegmentsOfCurrentVideo();
|
||||
if (currentSegments == null || currentSegments.length == 0) {
|
||||
// button is hidden if no segments exist.
|
||||
SponsorSegment[] segments = SegmentPlaybackController.getSegments();
|
||||
if (segments == null || segments.length == 0) {
|
||||
// Button is hidden if no segments exist.
|
||||
// But if prior video had segments, and current video does not,
|
||||
// then the button persists until the overlay fades out (this is intentional, as abruptly hiding the button is jarring)
|
||||
// then the button persists until the overlay fades out (this is intentional, as abruptly hiding the button is jarring).
|
||||
ReVancedUtils.showToastShort(str("sb_vote_no_segments"));
|
||||
return;
|
||||
}
|
||||
|
||||
// use same time formatting as shown in the video player
|
||||
final long currentVideoLength = VideoInformation.getCurrentVideoLength();
|
||||
final long videoLength = VideoInformation.getVideoLength();
|
||||
final String formatPattern;
|
||||
if (currentVideoLength < (10 * 60 * 1000)) {
|
||||
if (videoLength < (10 * 60 * 1000)) {
|
||||
formatPattern = "m:ss.SSS"; // less than 10 minutes
|
||||
} else if (currentVideoLength < (60 * 60 * 1000)) {
|
||||
} else if (videoLength < (60 * 60 * 1000)) {
|
||||
formatPattern = "mm:ss.SSS"; // less than 1 hour
|
||||
} else if (currentVideoLength < (10 * 60 * 60 * 1000)) {
|
||||
} else if (videoLength < (10 * 60 * 60 * 1000)) {
|
||||
formatPattern = "H:mm:ss.SSS"; // less than 10 hours
|
||||
} else {
|
||||
formatPattern = "HH:mm:ss.SSS"; // why is this on YouTube
|
||||
}
|
||||
voteSegmentTimeFormatter.applyPattern(formatPattern);
|
||||
|
||||
final int numberOfSegments = currentSegments.length;
|
||||
final int numberOfSegments = segments.length;
|
||||
CharSequence[] titles = new CharSequence[numberOfSegments];
|
||||
for (int i = 0; i < numberOfSegments; i++) {
|
||||
SponsorSegment segment = currentSegments[i];
|
||||
SponsorSegment segment = segments[i];
|
||||
if (segment.category == SegmentCategory.UNSUBMITTED) {
|
||||
continue;
|
||||
}
|
||||
@ -364,14 +363,11 @@ public class SponsorBlockUtils {
|
||||
} else if (newSponsorSegmentStartMillis >= newSponsorSegmentEndMillis) {
|
||||
ReVancedUtils.showToastShort(str("sb_new_segment_start_is_before_end"));
|
||||
} else {
|
||||
SegmentPlaybackController.removeUnsubmittedSegments(); // If user hits preview more than once before playing.
|
||||
SegmentPlaybackController.addUnsubmittedSegment(
|
||||
new SponsorSegment(SegmentCategory.UNSUBMITTED, null,
|
||||
newSponsorSegmentStartMillis, newSponsorSegmentEndMillis, false));
|
||||
VideoInformation.seekTo(newSponsorSegmentStartMillis - 2500);
|
||||
final SponsorSegment[] original = SegmentPlaybackController.getSegmentsOfCurrentVideo();
|
||||
final SponsorSegment[] segments = original == null ? new SponsorSegment[1] : Arrays.copyOf(original, original.length + 1);
|
||||
|
||||
segments[segments.length - 1] = new SponsorSegment(SegmentCategory.UNSUBMITTED, null,
|
||||
newSponsorSegmentStartMillis, newSponsorSegmentEndMillis, false);
|
||||
|
||||
SegmentPlaybackController.setSegmentsOfCurrentVideo(segments);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(() -> "onPreviewClicked failure", ex);
|
||||
|
@ -300,7 +300,7 @@ public enum SegmentCategory {
|
||||
*/
|
||||
@NonNull
|
||||
StringRef getSkipButtonText(long segmentStartTime, long videoLength) {
|
||||
if (SettingsEnum.SB_USE_COMPACT_SKIPBUTTON.getBoolean()) {
|
||||
if (SettingsEnum.SB_USE_COMPACT_SKIP_BUTTON.getBoolean()) {
|
||||
return (this == SegmentCategory.HIGHLIGHT)
|
||||
? skipSponsorTextCompactHighlight
|
||||
: skipSponsorTextCompact;
|
||||
|
@ -1,13 +1,14 @@
|
||||
package app.revanced.integrations.sponsorblock.objects;
|
||||
|
||||
import static app.revanced.integrations.utils.StringRef.sf;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.integrations.patches.VideoInformation;
|
||||
import app.revanced.integrations.utils.StringRef;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static app.revanced.integrations.utils.StringRef.sf;
|
||||
|
||||
public class SponsorSegment implements Comparable<SponsorSegment> {
|
||||
public enum SegmentVote {
|
||||
UPVOTE(sf("sb_vote_upvote"), 1,false),
|
||||
@ -99,7 +100,7 @@ public class SponsorSegment implements Comparable<SponsorSegment> {
|
||||
*/
|
||||
@NonNull
|
||||
public String getSkipButtonText() {
|
||||
return category.getSkipButtonText(start, VideoInformation.getCurrentVideoLength()).toString();
|
||||
return category.getSkipButtonText(start, VideoInformation.getVideoLength()).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,12 +108,30 @@ public class SponsorSegment implements Comparable<SponsorSegment> {
|
||||
*/
|
||||
@NonNull
|
||||
public String getSkippedToastText() {
|
||||
return category.getSkippedToastText(start, VideoInformation.getCurrentVideoLength()).toString();
|
||||
return category.getSkippedToastText(start, VideoInformation.getVideoLength()).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SponsorSegment o) {
|
||||
return (int) (this.start - o.start);
|
||||
// If both segments start at the same time, then sort with the longer segment first.
|
||||
// This keeps the seekbar drawing correct since it draws the segments using the sorted order.
|
||||
return start == o.start ? Long.compare(o.length(), length()) : Long.compare(start, o.start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SponsorSegment)) return false;
|
||||
SponsorSegment other = (SponsorSegment) o;
|
||||
return Objects.equals(UUID, other.UUID)
|
||||
&& category == other.category
|
||||
&& start == other.start
|
||||
&& end == other.end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(UUID);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -97,6 +97,33 @@ public class SBRequester {
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(() -> "Failed to get segments", ex, str("sb_sponsorblock_connection_failure_generic"));
|
||||
}
|
||||
|
||||
// Crude debug tests to verify random features
|
||||
// Could benefit from:
|
||||
// 1) collection of YouTube videos with test segment times (verify client skip timing matches the video, verify seekbar draws correctly)
|
||||
// 2) unit tests (verify everything else)
|
||||
if (false) {
|
||||
segments.clear();
|
||||
// Test auto-hide skip button:
|
||||
// Button should appear only once
|
||||
segments.add(new SponsorSegment(SegmentCategory.INTRO, "debug", 5000, 120000, false));
|
||||
// Button should appear only once
|
||||
segments.add(new SponsorSegment(SegmentCategory.SELF_PROMO, "debug", 10000, 60000, false));
|
||||
// Button should appear only once
|
||||
segments.add(new SponsorSegment(SegmentCategory.INTERACTION, "debug", 15000, 20000, false));
|
||||
// Button should appear _twice_ (at 21s and 27s)
|
||||
segments.add(new SponsorSegment(SegmentCategory.SPONSOR, "debug", 21000, 30000, false));
|
||||
// Button should appear only once
|
||||
segments.add(new SponsorSegment(SegmentCategory.OUTRO, "debug", 24000, 27000, false));
|
||||
|
||||
|
||||
// Test seekbar visibility:
|
||||
// All three segments should be viewable on the seekbar
|
||||
segments.add(new SponsorSegment(SegmentCategory.MUSIC_OFFTOPIC, "debug", 200000, 300000, false));
|
||||
segments.add(new SponsorSegment(SegmentCategory.SPONSOR, "debug", 200000, 250000, false));
|
||||
segments.add(new SponsorSegment(SegmentCategory.SELF_PROMO, "debug", 200000, 330000, false));
|
||||
}
|
||||
|
||||
return segments.toArray(new SponsorSegment[0]);
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
package app.revanced.integrations.sponsorblock.ui;
|
||||
|
||||
import static app.revanced.integrations.utils.ReVancedUtils.getResourceDimensionPixelSize;
|
||||
import static app.revanced.integrations.utils.ReVancedUtils.getResourceIdentifier;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
@ -11,114 +8,119 @@ import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import app.revanced.integrations.patches.VideoInformation;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.sponsorblock.SponsorBlockUtils;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
public class NewSegmentLayout extends FrameLayout {
|
||||
import static app.revanced.integrations.utils.ReVancedUtils.getResourceDimensionPixelSize;
|
||||
import static app.revanced.integrations.utils.ReVancedUtils.getResourceIdentifier;
|
||||
|
||||
public final class NewSegmentLayout extends FrameLayout {
|
||||
private static final ColorStateList rippleColorStateList = new ColorStateList(
|
||||
new int[][]{new int[]{android.R.attr.state_enabled}},
|
||||
new int[]{0x33ffffff} // sets the ripple color to white
|
||||
);
|
||||
private final int rippleEffectId;
|
||||
|
||||
final int defaultBottomMargin;
|
||||
final int ctaBottomMargin;
|
||||
|
||||
public NewSegmentLayout(Context context) {
|
||||
public NewSegmentLayout(final Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public NewSegmentLayout(Context context, AttributeSet attributeSet) {
|
||||
public NewSegmentLayout(final Context context, final AttributeSet attributeSet) {
|
||||
this(context, attributeSet, 0);
|
||||
}
|
||||
|
||||
public NewSegmentLayout(Context context, AttributeSet attributeSet, int defStyleAttr) {
|
||||
public NewSegmentLayout(final Context context, final AttributeSet attributeSet, final int defStyleAttr) {
|
||||
this(context, attributeSet, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public NewSegmentLayout(Context context, AttributeSet attributeSet, int defStyleAttr, int defStyleRes) {
|
||||
public NewSegmentLayout(final Context context, final AttributeSet attributeSet,
|
||||
final int defStyleAttr, final int defStyleRes) {
|
||||
super(context, attributeSet, defStyleAttr, defStyleRes);
|
||||
|
||||
LayoutInflater.from(context).inflate(getResourceIdentifier(context, "new_segment", "layout"), this, true);
|
||||
LayoutInflater.from(context).inflate(
|
||||
getResourceIdentifier(context, "new_segment", "layout"), this, true
|
||||
);
|
||||
|
||||
TypedValue rippleEffect = new TypedValue();
|
||||
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, rippleEffect, true);
|
||||
rippleEffectId = rippleEffect.resourceId;
|
||||
|
||||
// LinearLayout newSegmentContainer = findViewById(getResourceIdentifier(context, "sb_new_segment_container", "id"));
|
||||
initializeButton(
|
||||
context,
|
||||
"sb_new_segment_rewind",
|
||||
() -> VideoInformation.seekToRelative(-SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getInt()),
|
||||
"Rewind button clicked"
|
||||
);
|
||||
|
||||
ImageButton rewindButton = findViewById(getResourceIdentifier(context, "sb_new_segment_rewind", "id"));
|
||||
if (rewindButton == null) {
|
||||
LogHelper.printException(() -> "Could not find rewindButton");
|
||||
} else {
|
||||
setClickEffect(rewindButton);
|
||||
rewindButton.setOnClickListener(v -> {
|
||||
LogHelper.printDebug(() -> "Rewind button clicked");
|
||||
VideoInformation.seekToRelative(-SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getInt());
|
||||
});
|
||||
}
|
||||
ImageButton forwardButton = findViewById(getResourceIdentifier(context, "sb_new_segment_forward", "id"));
|
||||
if (forwardButton == null) {
|
||||
LogHelper.printException(() -> "Could not find forwardButton");
|
||||
} else {
|
||||
setClickEffect(forwardButton);
|
||||
forwardButton.setOnClickListener(v -> {
|
||||
LogHelper.printDebug(() -> "Forward button clicked");
|
||||
VideoInformation.seekToRelative(SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getInt());
|
||||
});
|
||||
}
|
||||
ImageButton adjustButton = findViewById(getResourceIdentifier(context, "sb_new_segment_adjust", "id"));
|
||||
if (adjustButton == null) {
|
||||
LogHelper.printException(() -> "Could not find adjustButton");
|
||||
} else {
|
||||
setClickEffect(adjustButton);
|
||||
adjustButton.setOnClickListener(v -> {
|
||||
LogHelper.printDebug(() -> "Adjust button clicked");
|
||||
SponsorBlockUtils.onMarkLocationClicked();
|
||||
});
|
||||
}
|
||||
ImageButton compareButton = findViewById(getResourceIdentifier(context, "sb_new_segment_compare", "id"));
|
||||
if (compareButton == null) {
|
||||
LogHelper.printException(() -> "Could not find compareButton");
|
||||
} else {
|
||||
setClickEffect(compareButton);
|
||||
compareButton.setOnClickListener(v -> {
|
||||
LogHelper.printDebug(() -> "Compare button clicked");
|
||||
SponsorBlockUtils.onPreviewClicked();
|
||||
});
|
||||
}
|
||||
ImageButton editButton = findViewById(getResourceIdentifier(context, "sb_new_segment_edit", "id"));
|
||||
if (editButton == null) {
|
||||
LogHelper.printException(() -> "Could not find editButton");
|
||||
} else {
|
||||
setClickEffect(editButton);
|
||||
editButton.setOnClickListener(v -> {
|
||||
LogHelper.printDebug(() -> "Edit button clicked");
|
||||
SponsorBlockUtils.onEditByHandClicked();
|
||||
});
|
||||
}
|
||||
ImageButton publishButton = findViewById(getResourceIdentifier(context, "sb_new_segment_publish", "id"));
|
||||
if (publishButton == null) {
|
||||
LogHelper.printException(() -> "Could not find publishButton");
|
||||
} else {
|
||||
setClickEffect(publishButton);
|
||||
publishButton.setOnClickListener(v -> {
|
||||
LogHelper.printDebug(() -> "Publish button clicked");
|
||||
SponsorBlockUtils.onPublishClicked();
|
||||
});
|
||||
}
|
||||
initializeButton(
|
||||
context,
|
||||
"sb_new_segment_forward",
|
||||
() -> VideoInformation.seekToRelative(SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getInt()),
|
||||
"Forward button clicked"
|
||||
);
|
||||
|
||||
initializeButton(
|
||||
context,
|
||||
"sb_new_segment_adjust",
|
||||
SponsorBlockUtils::onMarkLocationClicked,
|
||||
"Adjust button clicked"
|
||||
);
|
||||
|
||||
initializeButton(
|
||||
context,
|
||||
"sb_new_segment_compare",
|
||||
SponsorBlockUtils::onPreviewClicked,
|
||||
"Compare button clicked"
|
||||
);
|
||||
|
||||
initializeButton(
|
||||
context,
|
||||
"sb_new_segment_edit",
|
||||
SponsorBlockUtils::onEditByHandClicked,
|
||||
"Edit button clicked"
|
||||
);
|
||||
|
||||
initializeButton(
|
||||
context,
|
||||
"sb_new_segment_publish",
|
||||
SponsorBlockUtils::onPublishClicked,
|
||||
"Publish button clicked"
|
||||
);
|
||||
|
||||
defaultBottomMargin = getResourceDimensionPixelSize("brand_interaction_default_bottom_margin");
|
||||
ctaBottomMargin = getResourceDimensionPixelSize("brand_interaction_cta_bottom_margin");
|
||||
}
|
||||
|
||||
private void setClickEffect(ImageButton btn) {
|
||||
btn.setBackgroundResource(rippleEffectId);
|
||||
/**
|
||||
* Initializes a segment button with the given resource identifier name with the given handler and a ripple effect.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param resourceIdentifierName The resource identifier name for the button.
|
||||
* @param handler The handler for the button's click event.
|
||||
* @param debugMessage The debug message to print when the button is clicked.
|
||||
*/
|
||||
private void initializeButton(final Context context, final String resourceIdentifierName,
|
||||
final ButtonOnClickHandlerFunction handler, final String debugMessage) {
|
||||
final ImageButton button = findViewById(getResourceIdentifier(context, resourceIdentifierName, "id"));
|
||||
|
||||
RippleDrawable rippleDrawable = (RippleDrawable) btn.getBackground();
|
||||
// Add ripple effect
|
||||
button.setBackgroundResource(rippleEffectId);
|
||||
RippleDrawable rippleDrawable = (RippleDrawable) button.getBackground();
|
||||
rippleDrawable.setColor(rippleColorStateList);
|
||||
|
||||
int[][] states = new int[][]{new int[]{android.R.attr.state_enabled}};
|
||||
int[] colors = new int[]{0x33ffffff}; // sets the ripple color to white
|
||||
button.setOnClickListener((v) -> {
|
||||
handler.apply();
|
||||
LogHelper.printDebug(() -> debugMessage);
|
||||
});
|
||||
}
|
||||
|
||||
ColorStateList colorStateList = new ColorStateList(states, colors);
|
||||
rippleDrawable.setColor(colorStateList);
|
||||
@FunctionalInterface
|
||||
public interface ButtonOnClickHandlerFunction {
|
||||
void apply();
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
@ -20,7 +21,6 @@ import java.util.Objects;
|
||||
|
||||
import app.revanced.integrations.sponsorblock.SegmentPlaybackController;
|
||||
import app.revanced.integrations.sponsorblock.objects.SponsorSegment;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
public class SkipSponsorButton extends FrameLayout {
|
||||
private static final boolean highContrast = true;
|
||||
@ -62,6 +62,8 @@ public class SkipSponsorButton extends FrameLayout {
|
||||
ctaBottomMargin = getResourceDimensionPixelSize("skip_button_cta_bottom_margin"); // dimen:skip_button_cta_bottom_margin
|
||||
|
||||
skipSponsorBtnContainer.setOnClickListener(v -> {
|
||||
// The view controller handles hiding this button, but hide it here as well just in case something goofs.
|
||||
setVisibility(View.GONE);
|
||||
SegmentPlaybackController.onSkipSegmentClicked(segment);
|
||||
});
|
||||
}
|
||||
|
@ -55,6 +55,9 @@ public class SponsorBlockViewController {
|
||||
try {
|
||||
LogHelper.printDebug(() -> "initializing");
|
||||
|
||||
// hide any old components, just in case they somehow are still hanging around
|
||||
hideAll();
|
||||
|
||||
Context context = ReVancedUtils.getContext();
|
||||
RelativeLayout layout = new RelativeLayout(context);
|
||||
layout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||
@ -103,7 +106,7 @@ public class SponsorBlockViewController {
|
||||
skipHighlight = Objects.requireNonNull(segment);
|
||||
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
||||
// don't show highlight button if create new segment is visible
|
||||
final boolean buttonVisibility = newSegmentLayout != null && newSegmentLayout.getVisibility() != View.VISIBLE;
|
||||
final boolean buttonVisibility = newSegmentLayout == null || newSegmentLayout.getVisibility() != View.VISIBLE;
|
||||
updateSkipButton(skipHighlightButtonRef.get(), segment, buttonVisibility);
|
||||
}
|
||||
public static void showSkipSegmentButton(@NonNull SponsorSegment segment) {
|
||||
@ -146,11 +149,7 @@ public class SponsorBlockViewController {
|
||||
|
||||
public static void hideNewSegmentLayout() {
|
||||
newSegmentLayoutVisible = false;
|
||||
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
||||
if (newSegmentLayout == null) {
|
||||
return;
|
||||
}
|
||||
setViewVisibility(newSegmentLayout, false);
|
||||
setViewVisibility(newSegmentLayoutRef.get(), false);
|
||||
}
|
||||
|
||||
private static void setViewVisibility(@Nullable View view, boolean visible) {
|
||||
|
@ -106,7 +106,7 @@ public class VotingButtonController {
|
||||
|
||||
private static boolean shouldBeShown() {
|
||||
return SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_VOTING_ENABLED.getBoolean()
|
||||
&& SegmentPlaybackController.currentVideoHasSegments() && !VideoInformation.isAtEndOfVideo();
|
||||
&& SegmentPlaybackController.videoHasSegments() && !VideoInformation.isAtEndOfVideo();
|
||||
}
|
||||
|
||||
public static void hide() {
|
||||
|
@ -52,7 +52,7 @@ public class DownloadButton extends BottomControlButton {
|
||||
|
||||
// Launch PowerTube intent
|
||||
try {
|
||||
String content = String.format("https://youtu.be/%s", VideoInformation.getCurrentVideoId());
|
||||
String content = String.format("https://youtu.be/%s", VideoInformation.getVideoId());
|
||||
|
||||
Intent intent = new Intent("android.intent.action.SEND");
|
||||
intent.setType("text/plain");
|
||||
|
Loading…
Reference in New Issue
Block a user