mirror of
https://github.com/revanced/revanced-patches
synced 2025-02-19 10:06:48 +01:00
feat(youtube/sponsorblock): skip to video highlight (#352)
This commit is contained in:
parent
6803aa11f6
commit
04a56504a0
@ -28,7 +28,7 @@ public class PlayerTypeHookPatch {
|
|||||||
LogHelper.printException(() -> "Unknown PlayerType encountered: " + type);
|
LogHelper.printException(() -> "Unknown PlayerType encountered: " + type);
|
||||||
} else {
|
} else {
|
||||||
PlayerType.setCurrent(newType);
|
PlayerType.setCurrent(newType);
|
||||||
LogHelper.printDebug(() -> "YouTubePlayerOverlaysLayout player type was updated to " + newType);
|
LogHelper.printDebug(() -> "PlayerType was updated to: " + newType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
|||||||
try {
|
try {
|
||||||
final boolean enabled = SettingsEnum.SB_ENABLED.getBoolean();
|
final boolean enabled = SettingsEnum.SB_ENABLED.getBoolean();
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
SponsorBlockViewController.hideSkipButton();
|
SponsorBlockViewController.hideAll();
|
||||||
SponsorBlockViewController.hideNewSegmentLayout();
|
|
||||||
SegmentPlaybackController.setCurrentVideoId(null);
|
SegmentPlaybackController.setCurrentVideoId(null);
|
||||||
} else if (!SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.getBoolean()) {
|
} else if (!SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.getBoolean()) {
|
||||||
SponsorBlockViewController.hideNewSegmentLayout();
|
SponsorBlockViewController.hideNewSegmentLayout();
|
||||||
@ -141,12 +140,13 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
|||||||
addNewSegment.setOnPreferenceChangeListener((preference1, o) -> {
|
addNewSegment.setOnPreferenceChangeListener((preference1, o) -> {
|
||||||
Boolean newValue = (Boolean) o;
|
Boolean newValue = (Boolean) o;
|
||||||
if (newValue && !SettingsEnum.SB_SEEN_GUIDELINES.getBoolean()) {
|
if (newValue && !SettingsEnum.SB_SEEN_GUIDELINES.getBoolean()) {
|
||||||
SettingsEnum.SB_SEEN_GUIDELINES.saveValue(true);
|
|
||||||
new AlertDialog.Builder(preference1.getContext())
|
new AlertDialog.Builder(preference1.getContext())
|
||||||
.setTitle(str("sb_guidelines_popup_title"))
|
.setTitle(str("sb_guidelines_popup_title"))
|
||||||
.setMessage(str("sb_guidelines_popup_content"))
|
.setMessage(str("sb_guidelines_popup_content"))
|
||||||
.setNegativeButton(str("sb_guidelines_popup_already_read"), null)
|
.setNegativeButton(str("sb_guidelines_popup_already_read"), null)
|
||||||
.setPositiveButton(str("sb_guidelines_popup_open"), (dialogInterface, i) -> openGuidelines())
|
.setPositiveButton(str("sb_guidelines_popup_open"), (dialogInterface, i) -> openGuidelines())
|
||||||
|
.setOnDismissListener(dialog -> SettingsEnum.SB_SEEN_GUIDELINES.saveValue(true))
|
||||||
|
.setCancelable(false)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.saveValue(newValue);
|
SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.saveValue(newValue);
|
||||||
@ -350,7 +350,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
|
|||||||
segmentCategory.removeAll();
|
segmentCategory.removeAll();
|
||||||
|
|
||||||
Activity activity = getActivity();
|
Activity activity = getActivity();
|
||||||
for (SegmentCategory category : SegmentCategory.valuesWithoutUnsubmitted()) {
|
for (SegmentCategory category : SegmentCategory.categoriesWithoutUnsubmitted()) {
|
||||||
segmentCategory.addPreference(new SegmentCategoryListPreference(activity, category));
|
segmentCategory.addPreference(new SegmentCategoryListPreference(activity, category));
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
@ -16,7 +16,7 @@ enum class PlayerType {
|
|||||||
WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED,
|
WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED,
|
||||||
WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED,
|
WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED,
|
||||||
WATCH_WHILE_SLIDING_FULLSCREEN_DISMISSED,
|
WATCH_WHILE_SLIDING_FULLSCREEN_DISMISSED,
|
||||||
INLINE_MINIMAL,
|
INLINE_MINIMAL, // home feed video playback
|
||||||
VIRTUAL_REALITY_FULLSCREEN,
|
VIRTUAL_REALITY_FULLSCREEN,
|
||||||
WATCH_WHILE_PICTURE_IN_PICTURE;
|
WATCH_WHILE_PICTURE_IN_PICTURE;
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import static app.revanced.integrations.utils.StringRef.str;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -30,13 +31,39 @@ import app.revanced.integrations.utils.ReVancedUtils;
|
|||||||
* Class is not thread safe. All methods must be called on the main thread unless otherwise specified.
|
* Class is not thread safe. All methods must be called on the main thread unless otherwise specified.
|
||||||
*/
|
*/
|
||||||
public class SegmentPlaybackController {
|
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.
|
||||||
|
*/
|
||||||
|
private static final long HIGHLIGHT_SEGMENT_DURATION_TO_SHOW_SKIP_PROMPT = 3800;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Highlight segments have zero length, as they are a point in time.
|
||||||
|
* Draw them on screen using a fixed width bar.
|
||||||
|
* Value is independent of device dpi.
|
||||||
|
*/
|
||||||
|
private static final int HIGHLIGHT_SEGMENT_DRAW_BAR_WIDTH = 7;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String currentVideoId;
|
private static String currentVideoId;
|
||||||
@Nullable
|
@Nullable
|
||||||
private static SponsorSegment[] segmentsOfCurrentVideo;
|
private static SponsorSegment[] segmentsOfCurrentVideo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current segment that user can manually skip
|
* Highlight segment, if one exists.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static SponsorSegment highlightSegment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Because loading can take time, show the skip to highlight for a few seconds after the segments load.
|
||||||
|
* This is the end time (in milliseconds) to no longer show the initial display skip to highlight.
|
||||||
|
*/
|
||||||
|
private static long highlightSegmentInitialShowEndTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current (non-highlight) segment that user can manually skip
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private static SponsorSegment segmentCurrentlyPlaying;
|
private static SponsorSegment segmentCurrentlyPlaying;
|
||||||
@ -68,23 +95,28 @@ public class SegmentPlaybackController {
|
|||||||
Arrays.sort(segments);
|
Arrays.sort(segments);
|
||||||
segmentsOfCurrentVideo = segments;
|
segmentsOfCurrentVideo = segments;
|
||||||
calculateTimeWithoutSegments();
|
calculateTimeWithoutSegments();
|
||||||
|
|
||||||
|
for (SponsorSegment segment : segments) {
|
||||||
|
if (segment.category == SegmentCategory.HIGHLIGHT) {
|
||||||
|
highlightSegment = segment;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
highlightSegment = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean currentVideoHasSegments() {
|
public static boolean currentVideoHasSegments() {
|
||||||
return segmentsOfCurrentVideo != null && segmentsOfCurrentVideo.length > 0;
|
return segmentsOfCurrentVideo != null && segmentsOfCurrentVideo.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
static String getCurrentVideoId() {
|
|
||||||
return currentVideoId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all downloaded data
|
* Clears all downloaded data
|
||||||
*/
|
*/
|
||||||
private static void clearData() {
|
private static void clearData() {
|
||||||
currentVideoId = null;
|
currentVideoId = null;
|
||||||
segmentsOfCurrentVideo = null;
|
segmentsOfCurrentVideo = null;
|
||||||
|
highlightSegment = null;
|
||||||
|
highlightSegmentInitialShowEndTime = 0;
|
||||||
timeWithoutSegments = null;
|
timeWithoutSegments = null;
|
||||||
segmentCurrentlyPlaying = null;
|
segmentCurrentlyPlaying = null;
|
||||||
scheduledUpcomingSegment = null; // prevent any existing scheduled skip from running
|
scheduledUpcomingSegment = null; // prevent any existing scheduled skip from running
|
||||||
@ -102,8 +134,7 @@ public class SegmentPlaybackController {
|
|||||||
ReVancedUtils.verifyOnMainThread();
|
ReVancedUtils.verifyOnMainThread();
|
||||||
SponsorBlockSettings.initialize();
|
SponsorBlockSettings.initialize();
|
||||||
clearData();
|
clearData();
|
||||||
SponsorBlockViewController.hideSkipButton();
|
SponsorBlockViewController.hideAll();
|
||||||
SponsorBlockViewController.hideNewSegmentLayout();
|
|
||||||
SponsorBlockUtils.clearUnsubmittedSegmentTimes();
|
SponsorBlockUtils.clearUnsubmittedSegmentTimes();
|
||||||
LogHelper.printDebug(() -> "Initialized SponsorBlock");
|
LogHelper.printDebug(() -> "Initialized SponsorBlock");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@ -164,7 +195,19 @@ public class SegmentPlaybackController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSegmentsOfCurrentVideo(segments);
|
setSegmentsOfCurrentVideo(segments);
|
||||||
setVideoTime(VideoInformation.getVideoTime()); // check for any skips now, instead of waiting for the next update
|
|
||||||
|
final long videoTime = VideoInformation.getVideoTime();
|
||||||
|
// if the current video time is before the highlight
|
||||||
|
if (highlightSegment != null && videoTime < highlightSegment.end) {
|
||||||
|
if (highlightSegment.shouldAutoSkip()) {
|
||||||
|
skipSegment(highlightSegment, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
highlightSegmentInitialShowEndTime = System.currentTimeMillis()
|
||||||
|
+ HIGHLIGHT_SEGMENT_DURATION_TO_SHOW_SKIP_PROMPT;
|
||||||
|
}
|
||||||
|
// check for any skips now, instead of waiting for the next update to setVideoTime()
|
||||||
|
setVideoTime(videoTime);
|
||||||
});
|
});
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LogHelper.printException(() -> "executeDownloadSegments failure", ex);
|
LogHelper.printException(() -> "executeDownloadSegments failure", ex);
|
||||||
@ -196,7 +239,8 @@ public class SegmentPlaybackController {
|
|||||||
|
|
||||||
for (final SponsorSegment segment : segmentsOfCurrentVideo) {
|
for (final SponsorSegment segment : segmentsOfCurrentVideo) {
|
||||||
if (segment.category.behaviour == CategoryBehaviour.SHOW_IN_SEEKBAR
|
if (segment.category.behaviour == CategoryBehaviour.SHOW_IN_SEEKBAR
|
||||||
|| segment.category.behaviour == CategoryBehaviour.IGNORE) {
|
|| segment.category.behaviour == CategoryBehaviour.IGNORE
|
||||||
|
|| segment.category == SegmentCategory.HIGHLIGHT) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (segment.end <= millis) {
|
if (segment.end <= millis) {
|
||||||
@ -217,7 +261,7 @@ public class SegmentPlaybackController {
|
|||||||
// Also prevents showing the skip button if user seeks into the last half second of the segment.
|
// Also prevents showing the skip button if user seeks into the last half second of the segment.
|
||||||
final long minMillisOfSegmentRemainingThreshold = 500;
|
final long minMillisOfSegmentRemainingThreshold = 500;
|
||||||
if (segmentCurrentlyPlaying == segment
|
if (segmentCurrentlyPlaying == segment
|
||||||
|| !segment.timeIsNearEnd(millis, minMillisOfSegmentRemainingThreshold)) {
|
|| !segment.endIsNear(millis, minMillisOfSegmentRemainingThreshold)) {
|
||||||
foundCurrentSegment = segment;
|
foundCurrentSegment = segment;
|
||||||
} else {
|
} else {
|
||||||
LogHelper.printDebug(() -> "Ignoring segment that ends very soon: " + segment);
|
LogHelper.printDebug(() -> "Ignoring segment that ends very soon: " + segment);
|
||||||
@ -248,7 +292,7 @@ public class SegmentPlaybackController {
|
|||||||
// This check is needed to prevent scheduled hide and show from clashing with each other.
|
// This check is needed to prevent scheduled hide and show from clashing with each other.
|
||||||
final long minTimeBetweenStartEndOfSegments = 1000;
|
final long minTimeBetweenStartEndOfSegments = 1000;
|
||||||
if (foundCurrentSegment == null
|
if (foundCurrentSegment == null
|
||||||
|| !foundCurrentSegment.timeIsNearEnd(segment.start, minTimeBetweenStartEndOfSegments)) {
|
|| !foundCurrentSegment.endIsNear(segment.start, minTimeBetweenStartEndOfSegments)) {
|
||||||
foundUpcomingSegment = segment;
|
foundUpcomingSegment = segment;
|
||||||
} else {
|
} else {
|
||||||
LogHelper.printDebug(() -> "Not scheduling segment (start time is near end of current segment): " + segment);
|
LogHelper.printDebug(() -> "Not scheduling segment (start time is near end of current segment): " + segment);
|
||||||
@ -256,16 +300,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 (segmentCurrentlyPlaying != foundCurrentSegment) {
|
if (segmentCurrentlyPlaying != foundCurrentSegment) {
|
||||||
if (foundCurrentSegment == null) {
|
if (foundCurrentSegment == null) {
|
||||||
LogHelper.printDebug(() -> "Hiding segment: " + segmentCurrentlyPlaying);
|
LogHelper.printDebug(() -> "Hiding segment: " + segmentCurrentlyPlaying);
|
||||||
segmentCurrentlyPlaying = null;
|
segmentCurrentlyPlaying = null;
|
||||||
SponsorBlockViewController.hideSkipButton();
|
SponsorBlockViewController.hideSkipSegmentButton();
|
||||||
} else {
|
} else {
|
||||||
segmentCurrentlyPlaying = foundCurrentSegment;
|
segmentCurrentlyPlaying = foundCurrentSegment;
|
||||||
LogHelper.printDebug(() -> "Showing segment: " + segmentCurrentlyPlaying);
|
LogHelper.printDebug(() -> "Showing segment: " + segmentCurrentlyPlaying);
|
||||||
SponsorBlockViewController.showSkipButton(foundCurrentSegment);
|
SponsorBlockViewController.showSkipSegmentButton(foundCurrentSegment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +324,7 @@ public class SegmentPlaybackController {
|
|||||||
|
|
||||||
// schedule a hide, only if the segment end is near
|
// schedule a hide, only if the segment end is near
|
||||||
final SponsorSegment segmentToHide =
|
final SponsorSegment segmentToHide =
|
||||||
(foundCurrentSegment != null && foundCurrentSegment.timeIsNearEnd(millis, lookAheadMilliseconds))
|
(foundCurrentSegment != null && foundCurrentSegment.endIsNear(millis, lookAheadMilliseconds))
|
||||||
? foundCurrentSegment
|
? foundCurrentSegment
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
@ -294,7 +344,7 @@ public class SegmentPlaybackController {
|
|||||||
scheduledHideSegment = null;
|
scheduledHideSegment = null;
|
||||||
|
|
||||||
final long videoTime = VideoInformation.getVideoTime();
|
final long videoTime = VideoInformation.getVideoTime();
|
||||||
if (!segmentToHide.timeIsNearEnd(videoTime, videoInformationTimeUpdateThresholdMilliseconds)) {
|
if (!segmentToHide.endIsNear(videoTime, videoInformationTimeUpdateThresholdMilliseconds)) {
|
||||||
// current video time is not what's expected. User paused playback
|
// current video time is not what's expected. User paused playback
|
||||||
LogHelper.printDebug(() -> "Ignoring outdated scheduled hide: " + segmentToHide
|
LogHelper.printDebug(() -> "Ignoring outdated scheduled hide: " + segmentToHide
|
||||||
+ " videoInformation time: " + videoTime);
|
+ " videoInformation time: " + videoTime);
|
||||||
@ -306,7 +356,7 @@ public class SegmentPlaybackController {
|
|||||||
// Should not use VideoInformation time as it is less accurate,
|
// 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
|
// but this scheduled handler was scheduled precisely so we can just use the segment end time
|
||||||
segmentCurrentlyPlaying = null;
|
segmentCurrentlyPlaying = null;
|
||||||
SponsorBlockViewController.hideSkipButton();
|
SponsorBlockViewController.hideSkipSegmentButton();
|
||||||
setVideoTime(segmentToHide.end);
|
setVideoTime(segmentToHide.end);
|
||||||
}, delayUntilHide);
|
}, delayUntilHide);
|
||||||
}
|
}
|
||||||
@ -330,7 +380,7 @@ public class SegmentPlaybackController {
|
|||||||
scheduledUpcomingSegment = null;
|
scheduledUpcomingSegment = null;
|
||||||
|
|
||||||
final long videoTime = VideoInformation.getVideoTime();
|
final long videoTime = VideoInformation.getVideoTime();
|
||||||
if (!segmentToSkip.timeIsNearStart(videoTime,
|
if (!segmentToSkip.startIsNear(videoTime,
|
||||||
videoInformationTimeUpdateThresholdMilliseconds)) {
|
videoInformationTimeUpdateThresholdMilliseconds)) {
|
||||||
// current video time is not what's expected. User paused playback
|
// current video time is not what's expected. User paused playback
|
||||||
LogHelper.printDebug(() -> "Ignoring outdated scheduled segment: " + segmentToSkip
|
LogHelper.printDebug(() -> "Ignoring outdated scheduled segment: " + segmentToSkip
|
||||||
@ -343,7 +393,7 @@ public class SegmentPlaybackController {
|
|||||||
} else {
|
} else {
|
||||||
LogHelper.printDebug(() -> "Running scheduled show segment: " + segmentToSkip);
|
LogHelper.printDebug(() -> "Running scheduled show segment: " + segmentToSkip);
|
||||||
segmentCurrentlyPlaying = segmentToSkip;
|
segmentCurrentlyPlaying = segmentToSkip;
|
||||||
SponsorBlockViewController.showSkipButton(segmentToSkip);
|
SponsorBlockViewController.showSkipSegmentButton(segmentToSkip);
|
||||||
}
|
}
|
||||||
}, delayUntilSkip);
|
}, delayUntilSkip);
|
||||||
}
|
}
|
||||||
@ -357,7 +407,7 @@ public class SegmentPlaybackController {
|
|||||||
private static SponsorSegment lastSegmentSkipped;
|
private static SponsorSegment lastSegmentSkipped;
|
||||||
private static long lastSegmentSkippedTime;
|
private static long lastSegmentSkippedTime;
|
||||||
|
|
||||||
private static void skipSegment(@NonNull SponsorSegment segment, boolean userManuallySkipped) {
|
private static void skipSegment(@NonNull SponsorSegment segmentToSkip, boolean userManuallySkipped) {
|
||||||
try {
|
try {
|
||||||
// If trying to seek to end of the video, YouTube can seek just short of the actual end.
|
// 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).
|
// (especially if the video does not end on a whole second boundary).
|
||||||
@ -365,23 +415,27 @@ public class SegmentPlaybackController {
|
|||||||
// Check for and ignore repeated skip attempts of the same segment over a short time period.
|
// Check for and ignore repeated skip attempts of the same segment over a short time period.
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
final long minimumMillisecondsBetweenSkippingSameSegment = 500;
|
final long minimumMillisecondsBetweenSkippingSameSegment = 500;
|
||||||
if ((lastSegmentSkipped == segment) && (now - lastSegmentSkippedTime < minimumMillisecondsBetweenSkippingSameSegment)) {
|
if ((lastSegmentSkipped == segmentToSkip) && (now - lastSegmentSkippedTime < minimumMillisecondsBetweenSkippingSameSegment)) {
|
||||||
LogHelper.printDebug(() -> "Ignoring skip segment request (already skipped as close as possible): " + segment);
|
LogHelper.printDebug(() -> "Ignoring skip segment request (already skipped as close as possible): " + segmentToSkip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogHelper.printDebug(() -> "Skipping segment: " + segment);
|
LogHelper.printDebug(() -> "Skipping segment: " + segmentToSkip);
|
||||||
lastSegmentSkipped = segment;
|
lastSegmentSkipped = segmentToSkip;
|
||||||
lastSegmentSkippedTime = now;
|
lastSegmentSkippedTime = now;
|
||||||
segmentCurrentlyPlaying = null;
|
segmentCurrentlyPlaying = null;
|
||||||
scheduledHideSegment = null; // if a scheduled has not run yet
|
scheduledHideSegment = null;
|
||||||
scheduledUpcomingSegment = null;
|
scheduledUpcomingSegment = null;
|
||||||
SponsorBlockViewController.hideSkipButton();
|
if (segmentToSkip == highlightSegment) {
|
||||||
|
highlightSegmentInitialShowEndTime = 0;
|
||||||
|
}
|
||||||
|
SponsorBlockViewController.hideSkipHighlightButton();
|
||||||
|
SponsorBlockViewController.hideSkipSegmentButton();
|
||||||
|
|
||||||
final boolean seekSuccessful = VideoInformation.seekTo(segment.end);
|
final boolean seekSuccessful = VideoInformation.seekTo(segmentToSkip.end);
|
||||||
if (!seekSuccessful) {
|
if (!seekSuccessful) {
|
||||||
// can happen when switching videos and is normal
|
// can happen when switching videos and is normal
|
||||||
LogHelper.printDebug(() -> "Could not skip segment (seek unsuccessful): " + segment);
|
LogHelper.printDebug(() -> "Could not skip segment (seek unsuccessful): " + segmentToSkip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,10 +443,10 @@ public class SegmentPlaybackController {
|
|||||||
// check for any smaller embedded segments, and count those as autoskipped
|
// check for any smaller embedded segments, and count those as autoskipped
|
||||||
final boolean showSkipToast = SettingsEnum.SB_SHOW_TOAST_ON_SKIP.getBoolean();
|
final boolean showSkipToast = SettingsEnum.SB_SHOW_TOAST_ON_SKIP.getBoolean();
|
||||||
for (final SponsorSegment otherSegment : segmentsOfCurrentVideo) {
|
for (final SponsorSegment otherSegment : segmentsOfCurrentVideo) {
|
||||||
if (segment.end <= otherSegment.start) {
|
if (segmentToSkip.end < otherSegment.start) {
|
||||||
break; // no other segments can be contained
|
break; // no other segments can be contained
|
||||||
}
|
}
|
||||||
if (segment.containsSegment(otherSegment)) { // includes checking the segment against itself
|
if (segmentToSkip.containsSegment(otherSegment)) { // includes checking the segment against itself
|
||||||
otherSegment.didAutoSkipped = true; // skipped this segment as well
|
otherSegment.didAutoSkipped = true; // skipped this segment as well
|
||||||
if (showSkipToast) {
|
if (showSkipToast) {
|
||||||
showSkippedSegmentToast(otherSegment);
|
showSkippedSegmentToast(otherSegment);
|
||||||
@ -401,19 +455,19 @@ public class SegmentPlaybackController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segment.category == SegmentCategory.UNSUBMITTED) {
|
if (segmentToSkip.category == SegmentCategory.UNSUBMITTED) {
|
||||||
// skipped segment was a preview of unsubmitted segment
|
// skipped segment was a preview of unsubmitted segment
|
||||||
// remove the segment from the UI view
|
// remove the segment from the UI view
|
||||||
SponsorBlockUtils.setNewSponsorSegmentPreviewed();
|
SponsorBlockUtils.setNewSponsorSegmentPreviewed();
|
||||||
SponsorSegment[] newSegments = new SponsorSegment[segmentsOfCurrentVideo.length - 1];
|
SponsorSegment[] newSegments = new SponsorSegment[segmentsOfCurrentVideo.length - 1];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (SponsorSegment sponsorSegment : segmentsOfCurrentVideo) {
|
for (SponsorSegment segment : segmentsOfCurrentVideo) {
|
||||||
if (sponsorSegment != segment)
|
if (segment != segmentToSkip)
|
||||||
newSegments[i++] = sponsorSegment;
|
newSegments[i++] = segment;
|
||||||
}
|
}
|
||||||
setSegmentsOfCurrentVideo(newSegments);
|
setSegmentsOfCurrentVideo(newSegments);
|
||||||
} else {
|
} else {
|
||||||
SponsorBlockUtils.sendViewRequestAsync(segment);
|
SponsorBlockUtils.sendViewRequestAsync(segmentToSkip);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LogHelper.printException(() -> "skipSegment failure", ex);
|
LogHelper.printException(() -> "skipSegment failure", ex);
|
||||||
@ -433,7 +487,7 @@ public class SegmentPlaybackController {
|
|||||||
}
|
}
|
||||||
toastSegmentSkipped = segment;
|
toastSegmentSkipped = segment;
|
||||||
|
|
||||||
final long delayToToastMilliseconds = 200; // also the maximum time between skips to be considered skipping multiple segments
|
final long delayToToastMilliseconds = 250; // also the maximum time between skips to be considered skipping multiple segments
|
||||||
ReVancedUtils.runOnMainThreadDelayed(() -> {
|
ReVancedUtils.runOnMainThreadDelayed(() -> {
|
||||||
try {
|
try {
|
||||||
if (toastSegmentSkipped == null) { // video was changed just after skipping segment
|
if (toastSegmentSkipped == null) { // video was changed just after skipping segment
|
||||||
@ -452,12 +506,20 @@ public class SegmentPlaybackController {
|
|||||||
}, delayToToastMilliseconds);
|
}, delayToToastMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onSkipSponsorClicked() {
|
/**
|
||||||
if (segmentCurrentlyPlaying != null) {
|
* @param segment can be either a highlight or a regular manual skip segment
|
||||||
skipSegment(segmentCurrentlyPlaying, true);
|
*/
|
||||||
} else {
|
public static void onSkipSegmentClicked(@NonNull SponsorSegment segment) {
|
||||||
SponsorBlockViewController.hideSkipButton();
|
try {
|
||||||
LogHelper.printException(() -> "error: segment not available to skip"); // should never happen
|
if (segment != highlightSegment && segment != segmentCurrentlyPlaying) {
|
||||||
|
LogHelper.printException(() -> "error: segment not available to skip"); // should never happen
|
||||||
|
SponsorBlockViewController.hideSkipSegmentButton();
|
||||||
|
SponsorBlockViewController.hideSkipHighlightButton();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
skipSegment(segment, true);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LogHelper.printException(() -> "onSkipSegmentClicked failure", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,17 +574,17 @@ public class SegmentPlaybackController {
|
|||||||
* Injection point
|
* Injection point
|
||||||
*/
|
*/
|
||||||
public static void setSponsorBarThickness(final int thickness) {
|
public static void setSponsorBarThickness(final int thickness) {
|
||||||
try {
|
setSponsorBarThickness((float) thickness);
|
||||||
setSponsorBarThickness((float) thickness);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
LogHelper.printException(() -> "setSponsorBarThickness failure", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setSponsorBarThickness(final float thickness) {
|
public static void setSponsorBarThickness(final float thickness) {
|
||||||
if (sponsorBarThickness != thickness) {
|
try {
|
||||||
LogHelper.printDebug(() -> String.format("setSponsorBarThickness: %.2f", thickness));
|
if (sponsorBarThickness != thickness) {
|
||||||
sponsorBarThickness = thickness;
|
LogHelper.printDebug(() -> String.format("setSponsorBarThickness: %.2f", thickness));
|
||||||
|
sponsorBarThickness = thickness;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LogHelper.printException(() -> "setSponsorBarThickness failure", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,6 +626,16 @@ public class SegmentPlaybackController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int highlightSegmentTimeBarScreenWidth = -1; // actual pixel width to use
|
||||||
|
private static int getHighlightSegmentTimeBarScreenWidth() {
|
||||||
|
if (highlightSegmentTimeBarScreenWidth == -1) {
|
||||||
|
highlightSegmentTimeBarScreenWidth = (int) TypedValue.applyDimension(
|
||||||
|
TypedValue.COMPLEX_UNIT_DIP, HIGHLIGHT_SEGMENT_DRAW_BAR_WIDTH,
|
||||||
|
ReVancedUtils.getContext().getResources().getDisplayMetrics());
|
||||||
|
}
|
||||||
|
return highlightSegmentTimeBarScreenWidth;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point
|
* Injection point
|
||||||
*/
|
*/
|
||||||
@ -582,8 +654,13 @@ public class SegmentPlaybackController {
|
|||||||
|
|
||||||
final float tmp1 = (1f / currentVideoLength) * (absoluteRight - absoluteLeft);
|
final float tmp1 = (1f / currentVideoLength) * (absoluteRight - absoluteLeft);
|
||||||
for (SponsorSegment segment : segmentsOfCurrentVideo) {
|
for (SponsorSegment segment : segmentsOfCurrentVideo) {
|
||||||
float left = segment.start * tmp1 + absoluteLeft;
|
final float left = segment.start * tmp1 + absoluteLeft;
|
||||||
float right = segment.end * tmp1 + absoluteLeft;
|
final float right;
|
||||||
|
if (segment.category == SegmentCategory.HIGHLIGHT) {
|
||||||
|
right = left + getHighlightSegmentTimeBarScreenWidth();
|
||||||
|
} else {
|
||||||
|
right = segment.end * tmp1 + absoluteLeft;
|
||||||
|
}
|
||||||
canvas.drawRect(left, top, right, bottom, segment.category.paint);
|
canvas.drawRect(left, top, right, bottom, segment.category.paint);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
@ -29,11 +29,13 @@ public class SponsorBlockSettings {
|
|||||||
JSONObject barTypesObject = settingsJson.getJSONObject("barTypes");
|
JSONObject barTypesObject = settingsJson.getJSONObject("barTypes");
|
||||||
JSONArray categorySelectionsArray = settingsJson.getJSONArray("categorySelections");
|
JSONArray categorySelectionsArray = settingsJson.getJSONArray("categorySelections");
|
||||||
|
|
||||||
for (SegmentCategory category : SegmentCategory.valuesWithoutUnsubmitted()) {
|
for (SegmentCategory category : SegmentCategory.categoriesWithoutUnsubmitted()) {
|
||||||
// clear existing behavior, as browser plugin exports no value for ignored categories
|
// clear existing behavior, as browser plugin exports no behavior for ignored categories
|
||||||
category.behaviour = CategoryBehaviour.IGNORE;
|
category.behaviour = CategoryBehaviour.IGNORE;
|
||||||
JSONObject categoryObject = barTypesObject.getJSONObject(category.key);
|
if (barTypesObject.has(category.key)) {
|
||||||
category.setColor(categoryObject.getString("color"));
|
JSONObject categoryObject = barTypesObject.getJSONObject(category.key);
|
||||||
|
category.setColor(categoryObject.getString("color"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < categorySelectionsArray.length(); i++) {
|
for (int i = 0; i < categorySelectionsArray.length(); i++) {
|
||||||
@ -47,16 +49,19 @@ public class SponsorBlockSettings {
|
|||||||
|
|
||||||
final int desktopKey = categorySelectionObject.getInt("option");
|
final int desktopKey = categorySelectionObject.getInt("option");
|
||||||
CategoryBehaviour behaviour = CategoryBehaviour.byDesktopKey(desktopKey);
|
CategoryBehaviour behaviour = CategoryBehaviour.byDesktopKey(desktopKey);
|
||||||
if (behaviour != null) {
|
if (behaviour == null) {
|
||||||
category.behaviour = behaviour;
|
ReVancedUtils.showToastLong(categoryKey + " unknown behavior key: " + desktopKey);
|
||||||
|
} else if (category == SegmentCategory.HIGHLIGHT && behaviour == CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE) {
|
||||||
|
ReVancedUtils.showToastLong("Skip-once behavior not allowed for " + category.key);
|
||||||
|
category.behaviour = CategoryBehaviour.SKIP_AUTOMATICALLY; // use closest match
|
||||||
} else {
|
} else {
|
||||||
LogHelper.printException(() -> "Unknown segment category behavior key: " + desktopKey);
|
category.behaviour = behaviour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SegmentCategory.updateEnabledCategories();
|
SegmentCategory.updateEnabledCategories();
|
||||||
|
|
||||||
SharedPreferences.Editor editor = SharedPrefCategory.SPONSOR_BLOCK.preferences.edit();
|
SharedPreferences.Editor editor = SharedPrefCategory.SPONSOR_BLOCK.preferences.edit();
|
||||||
for (SegmentCategory category : SegmentCategory.valuesWithoutUnsubmitted()) {
|
for (SegmentCategory category : SegmentCategory.categoriesWithoutUnsubmitted()) {
|
||||||
category.save(editor);
|
category.save(editor);
|
||||||
}
|
}
|
||||||
editor.apply();
|
editor.apply();
|
||||||
@ -117,17 +122,19 @@ public class SponsorBlockSettings {
|
|||||||
JSONObject barTypesObject = new JSONObject(); // categories' colors
|
JSONObject barTypesObject = new JSONObject(); // categories' colors
|
||||||
JSONArray categorySelectionsArray = new JSONArray(); // categories' behavior
|
JSONArray categorySelectionsArray = new JSONArray(); // categories' behavior
|
||||||
|
|
||||||
SegmentCategory[] categories = SegmentCategory.valuesWithoutUnsubmitted();
|
SegmentCategory[] categories = SegmentCategory.categoriesWithoutUnsubmitted();
|
||||||
for (SegmentCategory category : categories) {
|
for (SegmentCategory category : categories) {
|
||||||
JSONObject categoryObject = new JSONObject();
|
JSONObject categoryObject = new JSONObject();
|
||||||
String categoryKey = category.key;
|
String categoryKey = category.key;
|
||||||
categoryObject.put("color", category.colorString());
|
categoryObject.put("color", category.colorString());
|
||||||
barTypesObject.put(categoryKey, categoryObject);
|
barTypesObject.put(categoryKey, categoryObject);
|
||||||
|
|
||||||
JSONObject behaviorObject = new JSONObject();
|
if (category.behaviour != CategoryBehaviour.IGNORE) {
|
||||||
behaviorObject.put("name", categoryKey);
|
JSONObject behaviorObject = new JSONObject();
|
||||||
behaviorObject.put("option", category.behaviour.desktopKey);
|
behaviorObject.put("name", categoryKey);
|
||||||
categorySelectionsArray.put(behaviorObject);
|
behaviorObject.put("option", category.behaviour.desktopKey);
|
||||||
|
categorySelectionsArray.put(behaviorObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
json.put("userID", SettingsEnum.SB_UUID.getString());
|
json.put("userID", SettingsEnum.SB_UUID.getString());
|
||||||
json.put("isVip", SettingsEnum.SB_IS_VIP.getBoolean());
|
json.put("isVip", SettingsEnum.SB_IS_VIP.getBoolean());
|
||||||
@ -182,7 +189,7 @@ public class SponsorBlockSettings {
|
|||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
String uuid = SettingsEnum.SB_UUID.getString();
|
String uuid = SettingsEnum.SB_UUID.getString();
|
||||||
if (uuid == null || uuid.isEmpty()) {
|
if (uuid.isEmpty()) {
|
||||||
uuid = (UUID.randomUUID().toString() +
|
uuid = (UUID.randomUUID().toString() +
|
||||||
UUID.randomUUID().toString() +
|
UUID.randomUUID().toString() +
|
||||||
UUID.randomUUID().toString())
|
UUID.randomUUID().toString())
|
||||||
|
@ -15,10 +15,8 @@ import java.lang.ref.WeakReference;
|
|||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@ -74,8 +72,8 @@ public class SponsorBlockUtils {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
try {
|
try {
|
||||||
SegmentCategory category = SegmentCategory.valuesWithoutUnsubmitted()[which];
|
SegmentCategory category = SegmentCategory.categoriesWithoutHighlights()[which];
|
||||||
boolean enableButton;
|
final boolean enableButton;
|
||||||
if (category.behaviour == CategoryBehaviour.IGNORE) {
|
if (category.behaviour == CategoryBehaviour.IGNORE) {
|
||||||
ReVancedUtils.showToastLong(str("sb_new_segment_disabled_category"));
|
ReVancedUtils.showToastLong(str("sb_new_segment_disabled_category"));
|
||||||
enableButton = false;
|
enableButton = false;
|
||||||
@ -100,7 +98,7 @@ public class SponsorBlockUtils {
|
|||||||
Context context = ((AlertDialog) dialog).getContext();
|
Context context = ((AlertDialog) dialog).getContext();
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
|
|
||||||
SegmentCategory[] categories = SegmentCategory.valuesWithoutUnsubmitted();
|
SegmentCategory[] categories = SegmentCategory.categoriesWithoutHighlights();
|
||||||
CharSequence[] titles = new CharSequence[categories.length];
|
CharSequence[] titles = new CharSequence[categories.length];
|
||||||
for (int i = 0, length = categories.length; i < length; i++) {
|
for (int i = 0, length = categories.length; i < length; i++) {
|
||||||
titles[i] = categories[i].getTitleWithColorDot();
|
titles[i] = categories[i].getTitleWithColorDot();
|
||||||
@ -167,7 +165,9 @@ public class SponsorBlockUtils {
|
|||||||
}
|
}
|
||||||
SponsorSegment segment = currentSegments[which];
|
SponsorSegment segment = currentSegments[which];
|
||||||
|
|
||||||
SegmentVote[] voteOptions = SegmentVote.values();
|
SegmentVote[] voteOptions = (segment.category == SegmentCategory.HIGHLIGHT)
|
||||||
|
? SegmentVote.voteTypesWithoutCategoryChange // highlight segments cannot change category
|
||||||
|
: SegmentVote.values();
|
||||||
CharSequence[] items = new CharSequence[voteOptions.length];
|
CharSequence[] items = new CharSequence[voteOptions.length];
|
||||||
|
|
||||||
for (int i = 0; i < voteOptions.length; i++) {
|
for (int i = 0; i < voteOptions.length; i++) {
|
||||||
@ -195,7 +195,7 @@ public class SponsorBlockUtils {
|
|||||||
})
|
})
|
||||||
.show();
|
.show();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LogHelper.printException(() -> "onPreviewClicked failure", ex);
|
LogHelper.printException(() -> "segmentVoteClickListener failure", ex);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -218,11 +218,12 @@ public class SponsorBlockUtils {
|
|||||||
final String uuid = SettingsEnum.SB_UUID.getString();
|
final String uuid = SettingsEnum.SB_UUID.getString();
|
||||||
final long start = newSponsorSegmentStartMillis;
|
final long start = newSponsorSegmentStartMillis;
|
||||||
final long end = newSponsorSegmentEndMillis;
|
final long end = newSponsorSegmentEndMillis;
|
||||||
final String videoId = SegmentPlaybackController.getCurrentVideoId();
|
final String videoId = VideoInformation.getCurrentVideoId();
|
||||||
final long videoLength = VideoInformation.getCurrentVideoLength();
|
final long videoLength = VideoInformation.getCurrentVideoLength();
|
||||||
final SegmentCategory segmentCategory = newUserCreatedSegmentCategory;
|
final SegmentCategory segmentCategory = newUserCreatedSegmentCategory;
|
||||||
if (start < 0 || end < 0 || start >= end || videoLength <= 0 || segmentCategory == null || videoId == null || uuid == null) {
|
if (start < 0 || end < 0 || start >= end || videoLength <= 0 || videoId.isEmpty()
|
||||||
LogHelper.printException(() -> "Unable to submit times, invalid parameters");
|
|| segmentCategory == null || uuid.isEmpty()) {
|
||||||
|
LogHelper.printException(() -> "invalid parameters");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearUnsubmittedSegmentTimes();
|
clearUnsubmittedSegmentTimes();
|
||||||
@ -258,9 +259,13 @@ public class SponsorBlockUtils {
|
|||||||
public static void onPublishClicked() {
|
public static void onPublishClicked() {
|
||||||
try {
|
try {
|
||||||
ReVancedUtils.verifyOnMainThread();
|
ReVancedUtils.verifyOnMainThread();
|
||||||
if (!newSponsorSegmentPreviewed) {
|
if (newSponsorSegmentStartMillis < 0 || newSponsorSegmentEndMillis < 0) {
|
||||||
|
ReVancedUtils.showToastShort(str("sb_new_segment_mark_locations_first"));
|
||||||
|
} else if (newSponsorSegmentStartMillis >= newSponsorSegmentEndMillis) {
|
||||||
|
ReVancedUtils.showToastShort(str("sb_new_segment_start_is_before_end"));
|
||||||
|
} else if (!newSponsorSegmentPreviewed && newSponsorSegmentStartMillis != 0) {
|
||||||
ReVancedUtils.showToastLong(str("sb_new_segment_preview_segment_first"));
|
ReVancedUtils.showToastLong(str("sb_new_segment_preview_segment_first"));
|
||||||
} else if (newSponsorSegmentStartMillis >= 0 && newSponsorSegmentStartMillis < newSponsorSegmentEndMillis) {
|
} else {
|
||||||
long length = (newSponsorSegmentEndMillis - newSponsorSegmentStartMillis) / 1000;
|
long length = (newSponsorSegmentEndMillis - newSponsorSegmentStartMillis) / 1000;
|
||||||
long start = (newSponsorSegmentStartMillis) / 1000;
|
long start = (newSponsorSegmentStartMillis) / 1000;
|
||||||
long end = (newSponsorSegmentEndMillis) / 1000;
|
long end = (newSponsorSegmentEndMillis) / 1000;
|
||||||
@ -273,8 +278,6 @@ public class SponsorBlockUtils {
|
|||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.setPositiveButton(android.R.string.yes, segmentReadyDialogButtonListener)
|
.setPositiveButton(android.R.string.yes, segmentReadyDialogButtonListener)
|
||||||
.show();
|
.show();
|
||||||
} else {
|
|
||||||
ReVancedUtils.showToastShort(str("sb_new_segment_mark_locations_first"));
|
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LogHelper.printException(() -> "onPublishClicked failure", ex);
|
LogHelper.printException(() -> "onPublishClicked failure", ex);
|
||||||
@ -303,29 +306,32 @@ public class SponsorBlockUtils {
|
|||||||
} else if (currentVideoLength < (10 * 60 * 60 * 1000)) {
|
} else if (currentVideoLength < (10 * 60 * 60 * 1000)) {
|
||||||
formatPattern = "H:mm:ss"; // less than 10 hours
|
formatPattern = "H:mm:ss"; // less than 10 hours
|
||||||
} else {
|
} else {
|
||||||
formatPattern = "HH:mm:ss"; // why is this on YouTube
|
formatPattern = "HH:mm:ss"; // why is this on YouTube
|
||||||
}
|
}
|
||||||
voteSegmentTimeFormatter.applyPattern(formatPattern);
|
voteSegmentTimeFormatter.applyPattern(formatPattern);
|
||||||
|
|
||||||
final int numberOfSegments = currentSegments.length;
|
final int numberOfSegments = currentSegments.length;
|
||||||
List<CharSequence> titles = new ArrayList<>(numberOfSegments);
|
CharSequence[] titles = new CharSequence[numberOfSegments];
|
||||||
for (int i = 0; i < numberOfSegments; i++) {
|
for (int i = 0; i < numberOfSegments; i++) {
|
||||||
SponsorSegment segment = currentSegments[i];
|
SponsorSegment segment = currentSegments[i];
|
||||||
if (segment.category == SegmentCategory.UNSUBMITTED) {
|
if (segment.category == SegmentCategory.UNSUBMITTED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String start = voteSegmentTimeFormatter.format(new Date(segment.start));
|
|
||||||
String end = voteSegmentTimeFormatter.format(new Date(segment.end));
|
|
||||||
StringBuilder htmlBuilder = new StringBuilder();
|
StringBuilder htmlBuilder = new StringBuilder();
|
||||||
htmlBuilder.append(String.format("<b><font color=\"#%06X\">⬤</font> %s<br> %s to %s",
|
htmlBuilder.append(String.format("<b><font color=\"#%06X\">⬤</font> %s<br>",
|
||||||
segment.category.color, segment.category.title, start, end));
|
segment.category.color, segment.category.title));
|
||||||
|
htmlBuilder.append(voteSegmentTimeFormatter.format(new Date(segment.start)));
|
||||||
|
if (segment.category != SegmentCategory.HIGHLIGHT) {
|
||||||
|
htmlBuilder.append(" to ").append(voteSegmentTimeFormatter.format(new Date(segment.end)));
|
||||||
|
}
|
||||||
|
htmlBuilder.append("</b>");
|
||||||
if (i + 1 != numberOfSegments) // prevents trailing new line after last segment
|
if (i + 1 != numberOfSegments) // prevents trailing new line after last segment
|
||||||
htmlBuilder.append("<br>");
|
htmlBuilder.append("<br>");
|
||||||
titles.add(Html.fromHtml(htmlBuilder.toString()));
|
titles[i] = Html.fromHtml(htmlBuilder.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
new AlertDialog.Builder(context)
|
new AlertDialog.Builder(context)
|
||||||
.setItems(titles.toArray(new CharSequence[0]), segmentVoteClickListener)
|
.setItems(titles, segmentVoteClickListener)
|
||||||
.show();
|
.show();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LogHelper.printException(() -> "onVotingClicked failure", ex);
|
LogHelper.printException(() -> "onVotingClicked failure", ex);
|
||||||
@ -335,7 +341,7 @@ public class SponsorBlockUtils {
|
|||||||
private static void onNewCategorySelect(@NonNull SponsorSegment segment, @NonNull Context context) {
|
private static void onNewCategorySelect(@NonNull SponsorSegment segment, @NonNull Context context) {
|
||||||
try {
|
try {
|
||||||
ReVancedUtils.verifyOnMainThread();
|
ReVancedUtils.verifyOnMainThread();
|
||||||
final SegmentCategory[] values = SegmentCategory.valuesWithoutUnsubmitted();
|
final SegmentCategory[] values = SegmentCategory.categoriesWithoutHighlights();
|
||||||
CharSequence[] titles = new CharSequence[values.length];
|
CharSequence[] titles = new CharSequence[values.length];
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
titles[i] = values[i].getTitleWithColorDot();
|
titles[i] = values[i].getTitleWithColorDot();
|
||||||
@ -353,7 +359,11 @@ public class SponsorBlockUtils {
|
|||||||
public static void onPreviewClicked() {
|
public static void onPreviewClicked() {
|
||||||
try {
|
try {
|
||||||
ReVancedUtils.verifyOnMainThread();
|
ReVancedUtils.verifyOnMainThread();
|
||||||
if (newSponsorSegmentStartMillis >= 0 && newSponsorSegmentStartMillis < newSponsorSegmentEndMillis) {
|
if (newSponsorSegmentStartMillis < 0 || newSponsorSegmentEndMillis < 0) {
|
||||||
|
ReVancedUtils.showToastShort(str("sb_new_segment_mark_locations_first"));
|
||||||
|
} else if (newSponsorSegmentStartMillis >= newSponsorSegmentEndMillis) {
|
||||||
|
ReVancedUtils.showToastShort(str("sb_new_segment_start_is_before_end"));
|
||||||
|
} else {
|
||||||
VideoInformation.seekTo(newSponsorSegmentStartMillis - 2500);
|
VideoInformation.seekTo(newSponsorSegmentStartMillis - 2500);
|
||||||
final SponsorSegment[] original = SegmentPlaybackController.getSegmentsOfCurrentVideo();
|
final SponsorSegment[] original = SegmentPlaybackController.getSegmentsOfCurrentVideo();
|
||||||
final SponsorSegment[] segments = original == null ? new SponsorSegment[1] : Arrays.copyOf(original, original.length + 1);
|
final SponsorSegment[] segments = original == null ? new SponsorSegment[1] : Arrays.copyOf(original, original.length + 1);
|
||||||
@ -362,8 +372,6 @@ public class SponsorBlockUtils {
|
|||||||
newSponsorSegmentStartMillis, newSponsorSegmentEndMillis, false);
|
newSponsorSegmentStartMillis, newSponsorSegmentEndMillis, false);
|
||||||
|
|
||||||
SegmentPlaybackController.setSegmentsOfCurrentVideo(segments);
|
SegmentPlaybackController.setSegmentsOfCurrentVideo(segments);
|
||||||
} else {
|
|
||||||
ReVancedUtils.showToastShort(str("sb_new_segment_mark_locations_first"));
|
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LogHelper.printException(() -> "onPreviewClicked failure", ex);
|
LogHelper.printException(() -> "onPreviewClicked failure", ex);
|
||||||
|
@ -11,32 +11,29 @@ import app.revanced.integrations.utils.ReVancedUtils;
|
|||||||
import app.revanced.integrations.utils.StringRef;
|
import app.revanced.integrations.utils.StringRef;
|
||||||
|
|
||||||
public enum CategoryBehaviour {
|
public enum CategoryBehaviour {
|
||||||
SKIP_AUTOMATICALLY("skip", 2, sf("sb_skip_automatically"), true),
|
SKIP_AUTOMATICALLY("skip", 2, true, sf("sb_skip_automatically")),
|
||||||
// desktop does not have skip-once behavior. Key is unique to ReVanced
|
// desktop does not have skip-once behavior. Key is unique to ReVanced
|
||||||
SKIP_AUTOMATICALLY_ONCE("skip-once", 4, sf("sb_skip_automatically_once"), true),
|
SKIP_AUTOMATICALLY_ONCE("skip-once", 3, true, sf("sb_skip_automatically_once")),
|
||||||
MANUAL_SKIP("manual-skip", 1, sf("sb_skip_showbutton"), false),
|
MANUAL_SKIP("manual-skip", 1, false, sf("sb_skip_showbutton")),
|
||||||
SHOW_IN_SEEKBAR("seekbar-only", 0, sf("sb_skip_seekbaronly"), false),
|
SHOW_IN_SEEKBAR("seekbar-only", 0, false, sf("sb_skip_seekbaronly")),
|
||||||
// Ignore is the default behavior if no desktop behavior key is present
|
// ignored categories are not exported to json, and ignore is the default behavior when importing
|
||||||
IGNORE("ignore", 3, sf("sb_skip_ignore"), false);
|
IGNORE("ignore", -1, false, sf("sb_skip_ignore"));
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String key;
|
public final String key;
|
||||||
public final int desktopKey;
|
public final int desktopKey;
|
||||||
@NonNull
|
|
||||||
public final StringRef name;
|
|
||||||
/**
|
/**
|
||||||
* If the segment should skip automatically
|
* If the segment should skip automatically
|
||||||
*/
|
*/
|
||||||
public final boolean skip;
|
public final boolean skipAutomatically;
|
||||||
|
@NonNull
|
||||||
|
public final StringRef description;
|
||||||
|
|
||||||
CategoryBehaviour(String key,
|
CategoryBehaviour(String key, int desktopKey, boolean skipAutomatically, StringRef description) {
|
||||||
int desktopKey,
|
|
||||||
StringRef name,
|
|
||||||
boolean skip) {
|
|
||||||
this.key = Objects.requireNonNull(key);
|
this.key = Objects.requireNonNull(key);
|
||||||
this.desktopKey = desktopKey;
|
this.desktopKey = desktopKey;
|
||||||
this.name = Objects.requireNonNull(name);
|
this.skipAutomatically = skipAutomatically;
|
||||||
this.skip = skip;
|
this.description = Objects.requireNonNull(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -60,31 +57,60 @@ public enum CategoryBehaviour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String[] behaviorKeys;
|
private static String[] behaviorKeys;
|
||||||
private static String[] behaviorNames;
|
private static String[] behaviorDescriptions;
|
||||||
|
|
||||||
|
private static String[] behaviorKeysWithoutSkipOnce;
|
||||||
|
private static String[] behaviorDescriptionsWithoutSkipOnce;
|
||||||
|
|
||||||
private static void createNameAndKeyArrays() {
|
private static void createNameAndKeyArrays() {
|
||||||
ReVancedUtils.verifyOnMainThread();
|
ReVancedUtils.verifyOnMainThread();
|
||||||
|
|
||||||
CategoryBehaviour[] behaviours = values();
|
CategoryBehaviour[] behaviours = values();
|
||||||
behaviorKeys = new String[behaviours.length];
|
final int behaviorLength = behaviours.length;
|
||||||
behaviorNames = new String[behaviours.length];
|
behaviorKeys = new String[behaviorLength];
|
||||||
for (int i = 0, length = behaviours.length; i < length; i++) {
|
behaviorDescriptions = new String[behaviorLength];
|
||||||
CategoryBehaviour behaviour = behaviours[i];
|
behaviorKeysWithoutSkipOnce = new String[behaviorLength - 1];
|
||||||
behaviorKeys[i] = behaviour.key;
|
behaviorDescriptionsWithoutSkipOnce = new String[behaviorLength - 1];
|
||||||
behaviorNames[i] = behaviour.name.toString();
|
|
||||||
|
int behaviorIndex = 0, behaviorHighlightIndex = 0;
|
||||||
|
while (behaviorIndex < behaviorLength) {
|
||||||
|
CategoryBehaviour behaviour = behaviours[behaviorIndex];
|
||||||
|
String key = behaviour.key;
|
||||||
|
String description = behaviour.description.toString();
|
||||||
|
behaviorKeys[behaviorIndex] = key;
|
||||||
|
behaviorDescriptions[behaviorIndex] = description;
|
||||||
|
behaviorIndex++;
|
||||||
|
if (behaviour != SKIP_AUTOMATICALLY_ONCE) {
|
||||||
|
behaviorKeysWithoutSkipOnce[behaviorHighlightIndex] = key;
|
||||||
|
behaviorDescriptionsWithoutSkipOnce[behaviorHighlightIndex] = description;
|
||||||
|
behaviorHighlightIndex++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] getBehaviorNames() {
|
static String[] getBehaviorKeys() {
|
||||||
if (behaviorNames == null) {
|
|
||||||
createNameAndKeyArrays();
|
|
||||||
}
|
|
||||||
return behaviorNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getBehaviorKeys() {
|
|
||||||
if (behaviorKeys == null) {
|
if (behaviorKeys == null) {
|
||||||
createNameAndKeyArrays();
|
createNameAndKeyArrays();
|
||||||
}
|
}
|
||||||
return behaviorKeys;
|
return behaviorKeys;
|
||||||
}
|
}
|
||||||
|
static String[] getBehaviorKeysWithoutSkipOnce() {
|
||||||
|
if (behaviorKeysWithoutSkipOnce == null) {
|
||||||
|
createNameAndKeyArrays();
|
||||||
|
}
|
||||||
|
return behaviorKeysWithoutSkipOnce;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String[] getBehaviorDescriptions() {
|
||||||
|
if (behaviorDescriptions == null) {
|
||||||
|
createNameAndKeyArrays();
|
||||||
|
}
|
||||||
|
return behaviorDescriptions;
|
||||||
|
}
|
||||||
|
static String[] getBehaviorDescriptionsWithoutSkipOnce() {
|
||||||
|
if (behaviorDescriptionsWithoutSkipOnce == null) {
|
||||||
|
createNameAndKeyArrays();
|
||||||
|
}
|
||||||
|
return behaviorDescriptionsWithoutSkipOnce;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import app.revanced.integrations.settings.SettingsEnum;
|
||||||
import app.revanced.integrations.settings.SharedPrefCategory;
|
import app.revanced.integrations.settings.SharedPrefCategory;
|
||||||
import app.revanced.integrations.utils.LogHelper;
|
import app.revanced.integrations.utils.LogHelper;
|
||||||
import app.revanced.integrations.utils.StringRef;
|
import app.revanced.integrations.utils.StringRef;
|
||||||
@ -33,6 +34,11 @@ public enum SegmentCategory {
|
|||||||
MANUAL_SKIP, 0xFFFF00),
|
MANUAL_SKIP, 0xFFFF00),
|
||||||
INTERACTION("interaction", sf("sb_segments_interaction"), sf("sb_segments_interaction_sum"), sf("sb_skip_button_interaction"), sf("sb_skipped_interaction"),
|
INTERACTION("interaction", sf("sb_segments_interaction"), sf("sb_segments_interaction_sum"), sf("sb_skip_button_interaction"), sf("sb_skipped_interaction"),
|
||||||
MANUAL_SKIP, 0xCC00FF),
|
MANUAL_SKIP, 0xCC00FF),
|
||||||
|
/**
|
||||||
|
* Unique category that is treated differently than the rest.
|
||||||
|
*/
|
||||||
|
HIGHLIGHT("poi_highlight", sf("sb_segments_highlight"), sf("sb_segments_highlight_sum"), sf("sb_skip_button_highlight"), sf("sb_skipped_highlight"),
|
||||||
|
MANUAL_SKIP, 0xFF1684),
|
||||||
INTRO("intro", sf("sb_segments_intro"), sf("sb_segments_intro_sum"),
|
INTRO("intro", sf("sb_segments_intro"), sf("sb_segments_intro_sum"),
|
||||||
sf("sb_skip_button_intro_beginning"), sf("sb_skip_button_intro_middle"), sf("sb_skip_button_intro_end"),
|
sf("sb_skip_button_intro_beginning"), sf("sb_skip_button_intro_middle"), sf("sb_skip_button_intro_end"),
|
||||||
sf("sb_skipped_intro_beginning"), sf("sb_skipped_intro_middle"), sf("sb_skipped_intro_end"),
|
sf("sb_skipped_intro_beginning"), sf("sb_skipped_intro_middle"), sf("sb_skipped_intro_end"),
|
||||||
@ -50,7 +56,10 @@ public enum SegmentCategory {
|
|||||||
UNSUBMITTED("unsubmitted", StringRef.empty, StringRef.empty, sf("sb_skip_button_unsubmitted"), sf("sb_skipped_unsubmitted"),
|
UNSUBMITTED("unsubmitted", StringRef.empty, StringRef.empty, sf("sb_skip_button_unsubmitted"), sf("sb_skipped_unsubmitted"),
|
||||||
SKIP_AUTOMATICALLY, 0xFFFFFF);
|
SKIP_AUTOMATICALLY, 0xFFFFFF);
|
||||||
|
|
||||||
private static final SegmentCategory[] mValuesWithoutUnsubmitted = new SegmentCategory[]{
|
private static final StringRef skipSponsorTextCompact = sf("sb_skip_button_compact");
|
||||||
|
private static final StringRef skipSponsorTextCompactHighlight = sf("sb_skip_button_compact_highlight");
|
||||||
|
|
||||||
|
private static final SegmentCategory[] categoriesWithoutHighlights = new SegmentCategory[]{
|
||||||
SPONSOR,
|
SPONSOR,
|
||||||
SELF_PROMO,
|
SELF_PROMO,
|
||||||
INTERACTION,
|
INTERACTION,
|
||||||
@ -60,7 +69,19 @@ public enum SegmentCategory {
|
|||||||
FILLER,
|
FILLER,
|
||||||
MUSIC_OFFTOPIC,
|
MUSIC_OFFTOPIC,
|
||||||
};
|
};
|
||||||
private static final Map<String, SegmentCategory> mValuesMap = new HashMap<>(2 * mValuesWithoutUnsubmitted.length);
|
|
||||||
|
private static final SegmentCategory[] categoriesWithoutUnsubmitted = new SegmentCategory[]{
|
||||||
|
SPONSOR,
|
||||||
|
SELF_PROMO,
|
||||||
|
INTERACTION,
|
||||||
|
HIGHLIGHT,
|
||||||
|
INTRO,
|
||||||
|
OUTRO,
|
||||||
|
PREVIEW,
|
||||||
|
FILLER,
|
||||||
|
MUSIC_OFFTOPIC,
|
||||||
|
};
|
||||||
|
private static final Map<String, SegmentCategory> mValuesMap = new HashMap<>(2 * categoriesWithoutUnsubmitted.length);
|
||||||
|
|
||||||
private static final String COLOR_PREFERENCE_KEY_SUFFIX = "_color";
|
private static final String COLOR_PREFERENCE_KEY_SUFFIX = "_color";
|
||||||
|
|
||||||
@ -70,13 +91,18 @@ public enum SegmentCategory {
|
|||||||
public static String sponsorBlockAPIFetchCategories = "[]";
|
public static String sponsorBlockAPIFetchCategories = "[]";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
for (SegmentCategory value : mValuesWithoutUnsubmitted)
|
for (SegmentCategory value : categoriesWithoutUnsubmitted)
|
||||||
mValuesMap.put(value.key, value);
|
mValuesMap.put(value.key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static SegmentCategory[] valuesWithoutUnsubmitted() {
|
public static SegmentCategory[] categoriesWithoutUnsubmitted() {
|
||||||
return mValuesWithoutUnsubmitted;
|
return categoriesWithoutUnsubmitted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static SegmentCategory[] categoriesWithoutHighlights() {
|
||||||
|
return categoriesWithoutHighlights;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -87,7 +113,7 @@ public enum SegmentCategory {
|
|||||||
public static void loadFromPreferences() {
|
public static void loadFromPreferences() {
|
||||||
SharedPreferences preferences = SharedPrefCategory.SPONSOR_BLOCK.preferences;
|
SharedPreferences preferences = SharedPrefCategory.SPONSOR_BLOCK.preferences;
|
||||||
LogHelper.printDebug(() -> "loadFromPreferences");
|
LogHelper.printDebug(() -> "loadFromPreferences");
|
||||||
for (SegmentCategory category : valuesWithoutUnsubmitted()) {
|
for (SegmentCategory category : categoriesWithoutUnsubmitted()) {
|
||||||
category.load(preferences);
|
category.load(preferences);
|
||||||
}
|
}
|
||||||
updateEnabledCategories();
|
updateEnabledCategories();
|
||||||
@ -97,7 +123,7 @@ public enum SegmentCategory {
|
|||||||
* Must be called if behavior of any category is changed
|
* Must be called if behavior of any category is changed
|
||||||
*/
|
*/
|
||||||
public static void updateEnabledCategories() {
|
public static void updateEnabledCategories() {
|
||||||
SegmentCategory[] categories = valuesWithoutUnsubmitted();
|
SegmentCategory[] categories = categoriesWithoutUnsubmitted();
|
||||||
List<String> enabledCategories = new ArrayList<>(categories.length);
|
List<String> enabledCategories = new ArrayList<>(categories.length);
|
||||||
for (SegmentCategory category : categories) {
|
for (SegmentCategory category : categories) {
|
||||||
if (category.behaviour != CategoryBehaviour.IGNORE) {
|
if (category.behaviour != CategoryBehaviour.IGNORE) {
|
||||||
@ -157,6 +183,7 @@ public enum SegmentCategory {
|
|||||||
* If value is changed, then also call {@link #save(SharedPreferences.Editor)}
|
* If value is changed, then also call {@link #save(SharedPreferences.Editor)}
|
||||||
*/
|
*/
|
||||||
public int color;
|
public int color;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If value is changed, then also call {@link #updateEnabledCategories()}
|
* If value is changed, then also call {@link #updateEnabledCategories()}
|
||||||
*/
|
*/
|
||||||
@ -272,17 +299,23 @@ public enum SegmentCategory {
|
|||||||
* @return the skip button text
|
* @return the skip button text
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getSkipButtonText(long segmentStartTime, long videoLength) {
|
StringRef getSkipButtonText(long segmentStartTime, long videoLength) {
|
||||||
|
if (SettingsEnum.SB_USE_COMPACT_SKIPBUTTON.getBoolean()) {
|
||||||
|
return (this == SegmentCategory.HIGHLIGHT)
|
||||||
|
? skipSponsorTextCompactHighlight
|
||||||
|
: skipSponsorTextCompact;
|
||||||
|
}
|
||||||
|
|
||||||
if (videoLength == 0) {
|
if (videoLength == 0) {
|
||||||
return skipButtonTextBeginning.toString(); // video is still loading. Assume it's the beginning
|
return skipButtonTextBeginning; // video is still loading. Assume it's the beginning
|
||||||
}
|
}
|
||||||
final float position = segmentStartTime / (float) videoLength;
|
final float position = segmentStartTime / (float) videoLength;
|
||||||
if (position < 0.25f) {
|
if (position < 0.25f) {
|
||||||
return skipButtonTextBeginning.toString();
|
return skipButtonTextBeginning;
|
||||||
} else if (position < 0.75f) {
|
} else if (position < 0.75f) {
|
||||||
return skipButtonTextMiddle.toString();
|
return skipButtonTextMiddle;
|
||||||
}
|
}
|
||||||
return skipButtonTextEnd.toString();
|
return skipButtonTextEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -291,16 +324,16 @@ public enum SegmentCategory {
|
|||||||
* @return 'skipped segment' toast message
|
* @return 'skipped segment' toast message
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getSkippedToastText(long segmentStartTime, long videoLength) {
|
StringRef getSkippedToastText(long segmentStartTime, long videoLength) {
|
||||||
if (videoLength == 0) {
|
if (videoLength == 0) {
|
||||||
return skippedToastBeginning.toString(); // video is still loading. Assume it's the beginning
|
return skippedToastBeginning; // video is still loading. Assume it's the beginning
|
||||||
}
|
}
|
||||||
final float position = segmentStartTime / (float) videoLength;
|
final float position = segmentStartTime / (float) videoLength;
|
||||||
if (position < 0.25f) {
|
if (position < 0.25f) {
|
||||||
return skippedToastBeginning.toString();
|
return skippedToastBeginning;
|
||||||
} else if (position < 0.75f) {
|
} else if (position < 0.75f) {
|
||||||
return skippedToastMiddle.toString();
|
return skippedToastMiddle;
|
||||||
}
|
}
|
||||||
return skippedToastEnd.toString();
|
return skippedToastEnd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,16 @@ public class SegmentCategoryListPreference extends ListPreference {
|
|||||||
|
|
||||||
public SegmentCategoryListPreference(Context context, SegmentCategory category) {
|
public SegmentCategoryListPreference(Context context, SegmentCategory category) {
|
||||||
super(context);
|
super(context);
|
||||||
|
final boolean isHighlightCategory = category == SegmentCategory.HIGHLIGHT;
|
||||||
this.category = Objects.requireNonNull(category);
|
this.category = Objects.requireNonNull(category);
|
||||||
setKey(category.key);
|
setKey(category.key);
|
||||||
setDefaultValue(category.behaviour.key);
|
setDefaultValue(category.behaviour.key);
|
||||||
setEntries(CategoryBehaviour.getBehaviorNames());
|
setEntries(isHighlightCategory
|
||||||
setEntryValues(CategoryBehaviour.getBehaviorKeys());
|
? CategoryBehaviour.getBehaviorDescriptionsWithoutSkipOnce()
|
||||||
|
: CategoryBehaviour.getBehaviorDescriptions());
|
||||||
|
setEntryValues(isHighlightCategory
|
||||||
|
? CategoryBehaviour.getBehaviorKeysWithoutSkipOnce()
|
||||||
|
: CategoryBehaviour.getBehaviorKeys());
|
||||||
setSummary(category.description.toString());
|
setSummary(category.description.toString());
|
||||||
updateTitle();
|
updateTitle();
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,11 @@ public class SponsorSegment implements Comparable<SponsorSegment> {
|
|||||||
DOWNVOTE(sf("sb_vote_downvote"), 0, true),
|
DOWNVOTE(sf("sb_vote_downvote"), 0, true),
|
||||||
CATEGORY_CHANGE(sf("sb_vote_category"), -1, true); // apiVoteType is not used for category change
|
CATEGORY_CHANGE(sf("sb_vote_category"), -1, true); // apiVoteType is not used for category change
|
||||||
|
|
||||||
|
public static final SegmentVote[] voteTypesWithoutCategoryChange = {
|
||||||
|
UPVOTE,
|
||||||
|
DOWNVOTE,
|
||||||
|
};
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final StringRef title;
|
public final StringRef title;
|
||||||
public final int apiVoteType;
|
public final int apiVoteType;
|
||||||
@ -51,36 +56,28 @@ public class SponsorSegment implements Comparable<SponsorSegment> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldAutoSkip() {
|
public boolean shouldAutoSkip() {
|
||||||
return category.behaviour.skip && !(didAutoSkipped && category.behaviour == CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE);
|
return category.behaviour.skipAutomatically && !(didAutoSkipped && category.behaviour == CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param nearThreshold threshold to declare the time parameter is near this segment. Must be a positive number
|
* @param nearThreshold threshold to declare the time parameter is near this segment. Must be a positive number
|
||||||
*/
|
*/
|
||||||
public boolean timeIsNearStart(long videoTime, long nearThreshold) {
|
public boolean startIsNear(long videoTime, long nearThreshold) {
|
||||||
return Math.abs(start - videoTime) <= nearThreshold;
|
return Math.abs(start - videoTime) <= nearThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param nearThreshold threshold to declare the time parameter is near this segment. Must be a positive number
|
* @param nearThreshold threshold to declare the time parameter is near this segment. Must be a positive number
|
||||||
*/
|
*/
|
||||||
public boolean timeIsNearEnd(long videoTime, long nearThreshold) {
|
public boolean endIsNear(long videoTime, long nearThreshold) {
|
||||||
return Math.abs(end - videoTime) <= nearThreshold;
|
return Math.abs(end - videoTime) <= nearThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param nearThreshold threshold to declare the time parameter is near this segment
|
* @return if the time parameter is within this segment
|
||||||
* @return if the time parameter is within or close to this segment
|
|
||||||
*/
|
*/
|
||||||
public boolean timeIsInsideOrNear(long videoTime, long nearThreshold) {
|
public boolean containsTime(long videoTime) {
|
||||||
return (start - nearThreshold) <= videoTime && videoTime < (end + nearThreshold);
|
return start <= videoTime && videoTime < end;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return if the time parameter is outside this segment
|
|
||||||
*/
|
|
||||||
public boolean timeIsOutside(long videoTime) {
|
|
||||||
return start < videoTime || end <= videoTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,7 +99,7 @@ public class SponsorSegment implements Comparable<SponsorSegment> {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getSkipButtonText() {
|
public String getSkipButtonText() {
|
||||||
return category.getSkipButtonText(start, VideoInformation.getCurrentVideoLength());
|
return category.getSkipButtonText(start, VideoInformation.getCurrentVideoLength()).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,7 +107,7 @@ public class SponsorSegment implements Comparable<SponsorSegment> {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getSkippedToastText() {
|
public String getSkippedToastText() {
|
||||||
return category.getSkippedToastText(start, VideoInformation.getCurrentVideoLength());
|
return category.getSkippedToastText(start, VideoInformation.getCurrentVideoLength()).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,19 +65,15 @@ public class SBRequester {
|
|||||||
JSONArray segment = obj.getJSONArray("segment");
|
JSONArray segment = obj.getJSONArray("segment");
|
||||||
final long start = (long) (segment.getDouble(0) * 1000);
|
final long start = (long) (segment.getDouble(0) * 1000);
|
||||||
final long end = (long) (segment.getDouble(1) * 1000);
|
final long end = (long) (segment.getDouble(1) * 1000);
|
||||||
if ((end - start) < minSegmentDuration)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
String categoryKey = obj.getString("category");
|
|
||||||
String uuid = obj.getString("UUID");
|
String uuid = obj.getString("UUID");
|
||||||
boolean locked = obj.getInt("locked") == 1;
|
final boolean locked = obj.getInt("locked") == 1;
|
||||||
|
String categoryKey = obj.getString("category");
|
||||||
SegmentCategory segmentCategory = SegmentCategory.byCategoryKey(categoryKey);
|
SegmentCategory category = SegmentCategory.byCategoryKey(categoryKey);
|
||||||
if (segmentCategory == null) {
|
if (category == null) {
|
||||||
LogHelper.printException(() -> "Received unknown category: " + categoryKey); // should never happen
|
LogHelper.printException(() -> "Received unknown category: " + categoryKey); // should never happen
|
||||||
} else if (segmentCategory.behaviour != CategoryBehaviour.IGNORE) {
|
} else if ((end - start) >= minSegmentDuration || category == SegmentCategory.HIGHLIGHT) {
|
||||||
SponsorSegment sponsorSegment = new SponsorSegment(segmentCategory, uuid, start, end, locked);
|
segments.add(new SponsorSegment(category, uuid, start, end, locked));
|
||||||
segments.add(sponsorSegment);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogHelper.printDebug(() -> {
|
LogHelper.printDebug(() -> {
|
||||||
|
@ -4,10 +4,8 @@ import static app.revanced.integrations.utils.ReVancedUtils.getResourceColor;
|
|||||||
import static app.revanced.integrations.utils.ReVancedUtils.getResourceDimension;
|
import static app.revanced.integrations.utils.ReVancedUtils.getResourceDimension;
|
||||||
import static app.revanced.integrations.utils.ReVancedUtils.getResourceDimensionPixelSize;
|
import static app.revanced.integrations.utils.ReVancedUtils.getResourceDimensionPixelSize;
|
||||||
import static app.revanced.integrations.utils.ReVancedUtils.getResourceIdentifier;
|
import static app.revanced.integrations.utils.ReVancedUtils.getResourceIdentifier;
|
||||||
import static app.revanced.integrations.utils.StringRef.str;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@ -16,9 +14,10 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import app.revanced.integrations.settings.SettingsEnum;
|
|
||||||
import app.revanced.integrations.sponsorblock.SegmentPlaybackController;
|
import app.revanced.integrations.sponsorblock.SegmentPlaybackController;
|
||||||
import app.revanced.integrations.sponsorblock.objects.SponsorSegment;
|
import app.revanced.integrations.sponsorblock.objects.SponsorSegment;
|
||||||
import app.revanced.integrations.utils.LogHelper;
|
import app.revanced.integrations.utils.LogHelper;
|
||||||
@ -27,9 +26,9 @@ public class SkipSponsorButton extends FrameLayout {
|
|||||||
private static final boolean highContrast = true;
|
private static final boolean highContrast = true;
|
||||||
private final LinearLayout skipSponsorBtnContainer;
|
private final LinearLayout skipSponsorBtnContainer;
|
||||||
private final TextView skipSponsorTextView;
|
private final TextView skipSponsorTextView;
|
||||||
private final CharSequence skipSponsorTextCompact;
|
|
||||||
private final Paint background;
|
private final Paint background;
|
||||||
private final Paint border;
|
private final Paint border;
|
||||||
|
private SponsorSegment segment;
|
||||||
final int defaultBottomMargin;
|
final int defaultBottomMargin;
|
||||||
final int ctaBottomMargin;
|
final int ctaBottomMargin;
|
||||||
|
|
||||||
@ -61,11 +60,9 @@ public class SkipSponsorButton extends FrameLayout {
|
|||||||
skipSponsorTextView = Objects.requireNonNull((TextView) findViewById(getResourceIdentifier(context, "sb_skip_sponsor_button_text", "id"))); // id:skip_ad_button_text;
|
skipSponsorTextView = Objects.requireNonNull((TextView) findViewById(getResourceIdentifier(context, "sb_skip_sponsor_button_text", "id"))); // id:skip_ad_button_text;
|
||||||
defaultBottomMargin = getResourceDimensionPixelSize("skip_button_default_bottom_margin"); // dimen:skip_button_default_bottom_margin
|
defaultBottomMargin = getResourceDimensionPixelSize("skip_button_default_bottom_margin"); // dimen:skip_button_default_bottom_margin
|
||||||
ctaBottomMargin = getResourceDimensionPixelSize("skip_button_cta_bottom_margin"); // dimen:skip_button_cta_bottom_margin
|
ctaBottomMargin = getResourceDimensionPixelSize("skip_button_cta_bottom_margin"); // dimen:skip_button_cta_bottom_margin
|
||||||
skipSponsorTextCompact = str("sb_skip_button_compact"); // string:skip_ads "Skip ads"
|
|
||||||
|
|
||||||
skipSponsorBtnContainer.setOnClickListener(v -> {
|
skipSponsorBtnContainer.setOnClickListener(v -> {
|
||||||
LogHelper.printDebug(() -> "Skip button clicked");
|
SegmentPlaybackController.onSkipSegmentClicked(segment);
|
||||||
SegmentPlaybackController.onSkipSponsorClicked();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,10 +87,9 @@ public class SkipSponsorButton extends FrameLayout {
|
|||||||
/**
|
/**
|
||||||
* @return true, if this button state was changed
|
* @return true, if this button state was changed
|
||||||
*/
|
*/
|
||||||
public boolean updateSkipButtonText(SponsorSegment segment) {
|
public boolean updateSkipButtonText(@NonNull SponsorSegment segment) {
|
||||||
CharSequence newText = SettingsEnum.SB_USE_COMPACT_SKIPBUTTON.getBoolean()
|
this.segment = segment;
|
||||||
? skipSponsorTextCompact
|
CharSequence newText = segment.getSkipButtonText();
|
||||||
: segment.getSkipButtonText();
|
|
||||||
if (newText.equals(skipSponsorTextView.getText())) {
|
if (newText.equals(skipSponsorTextView.getText())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,13 @@ import app.revanced.integrations.utils.ReVancedUtils;
|
|||||||
public class SponsorBlockViewController {
|
public class SponsorBlockViewController {
|
||||||
private static WeakReference<RelativeLayout> inlineSponsorOverlayRef = new WeakReference<>(null);
|
private static WeakReference<RelativeLayout> inlineSponsorOverlayRef = new WeakReference<>(null);
|
||||||
private static WeakReference<ViewGroup> youtubeOverlaysLayoutRef = new WeakReference<>(null);
|
private static WeakReference<ViewGroup> youtubeOverlaysLayoutRef = new WeakReference<>(null);
|
||||||
|
private static WeakReference<SkipSponsorButton> skipHighlightButtonRef = new WeakReference<>(null);
|
||||||
private static WeakReference<SkipSponsorButton> skipSponsorButtonRef = new WeakReference<>(null);
|
private static WeakReference<SkipSponsorButton> skipSponsorButtonRef = new WeakReference<>(null);
|
||||||
private static WeakReference<NewSegmentLayout> newSegmentLayoutRef = new WeakReference<>(null);
|
private static WeakReference<NewSegmentLayout> newSegmentLayoutRef = new WeakReference<>(null);
|
||||||
private static boolean canShowViewElements = true;
|
private static boolean canShowViewElements;
|
||||||
|
private static boolean newSegmentLayoutVisible;
|
||||||
|
@Nullable
|
||||||
|
private static SponsorSegment skipHighlight;
|
||||||
@Nullable
|
@Nullable
|
||||||
private static SponsorSegment skipSegment;
|
private static SponsorSegment skipSegment;
|
||||||
|
|
||||||
@ -51,161 +55,155 @@ public class SponsorBlockViewController {
|
|||||||
try {
|
try {
|
||||||
LogHelper.printDebug(() -> "initializing");
|
LogHelper.printDebug(() -> "initializing");
|
||||||
|
|
||||||
RelativeLayout layout = new RelativeLayout(ReVancedUtils.getContext());
|
Context context = ReVancedUtils.getContext();
|
||||||
|
RelativeLayout layout = new RelativeLayout(context);
|
||||||
layout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT));
|
layout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT));
|
||||||
LayoutInflater.from(ReVancedUtils.getContext()).inflate(getResourceIdentifier("inline_sponsor_overlay", "layout"), layout);
|
LayoutInflater.from(context).inflate(getResourceIdentifier("inline_sponsor_overlay", "layout"), layout);
|
||||||
inlineSponsorOverlayRef = new WeakReference<>(layout);
|
inlineSponsorOverlayRef = new WeakReference<>(layout);
|
||||||
|
|
||||||
ViewGroup viewGroup = (ViewGroup) obj;
|
ViewGroup viewGroup = (ViewGroup) obj;
|
||||||
viewGroup.addView(layout, viewGroup.getChildCount() - 2);
|
viewGroup.addView(layout);
|
||||||
|
viewGroup.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onChildViewAdded(View parent, View child) {
|
||||||
|
// ensure SB buttons and controls are always on top, otherwise the endscreen cards can cover the skip button
|
||||||
|
RelativeLayout layout = inlineSponsorOverlayRef.get();
|
||||||
|
if (layout != null) {
|
||||||
|
layout.bringToFront();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onChildViewRemoved(View parent, View child) {
|
||||||
|
}
|
||||||
|
});
|
||||||
youtubeOverlaysLayoutRef = new WeakReference<>(viewGroup);
|
youtubeOverlaysLayoutRef = new WeakReference<>(viewGroup);
|
||||||
|
|
||||||
|
skipHighlightButtonRef = new WeakReference<>(
|
||||||
|
Objects.requireNonNull(layout.findViewById(getResourceIdentifier("sb_skip_highlight_button", "id"))));
|
||||||
skipSponsorButtonRef = new WeakReference<>(
|
skipSponsorButtonRef = new WeakReference<>(
|
||||||
Objects.requireNonNull(layout.findViewById(getResourceIdentifier("sb_skip_sponsor_button", "id"))));
|
Objects.requireNonNull(layout.findViewById(getResourceIdentifier("sb_skip_sponsor_button", "id"))));
|
||||||
|
|
||||||
newSegmentLayoutRef = new WeakReference<>(
|
newSegmentLayoutRef = new WeakReference<>(
|
||||||
Objects.requireNonNull(layout.findViewById(getResourceIdentifier("sb_new_segment_view", "id"))));
|
Objects.requireNonNull(layout.findViewById(getResourceIdentifier("sb_new_segment_view", "id"))));
|
||||||
|
|
||||||
|
newSegmentLayoutVisible = false;
|
||||||
|
skipHighlight = null;
|
||||||
|
skipSegment = null;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LogHelper.printException(() -> "initialize failure", ex);
|
LogHelper.printException(() -> "initialize failure", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showSkipButton(@NonNull SponsorSegment info) {
|
public static void hideAll() {
|
||||||
skipSegment = Objects.requireNonNull(info);
|
hideSkipHighlightButton();
|
||||||
updateSkipButton();
|
hideSkipSegmentButton();
|
||||||
|
hideNewSegmentLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void hideSkipButton() {
|
public static void showSkipHighlightButton(@NonNull SponsorSegment segment) {
|
||||||
skipSegment = null;
|
skipHighlight = Objects.requireNonNull(segment);
|
||||||
updateSkipButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void updateSkipButton() {
|
|
||||||
SkipSponsorButton skipSponsorButton = skipSponsorButtonRef.get();
|
|
||||||
if (skipSponsorButton == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (skipSegment == null) {
|
|
||||||
setSkipSponsorButtonVisibility(false);
|
|
||||||
} else {
|
|
||||||
final boolean layoutNeedsUpdating = skipSponsorButton.updateSkipButtonText(skipSegment);
|
|
||||||
if (layoutNeedsUpdating) {
|
|
||||||
bringLayoutToFront();
|
|
||||||
}
|
|
||||||
setSkipSponsorButtonVisibility(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showNewSegmentLayout() {
|
|
||||||
setNewSegmentLayoutVisibility(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void hideNewSegmentLayout() {
|
|
||||||
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
||||||
if (newSegmentLayout == null) {
|
// don't show highlight button if create new segment is visible
|
||||||
|
final boolean buttonVisibility = newSegmentLayout != null && newSegmentLayout.getVisibility() != View.VISIBLE;
|
||||||
|
updateSkipButton(skipHighlightButtonRef.get(), segment, buttonVisibility);
|
||||||
|
}
|
||||||
|
public static void showSkipSegmentButton(@NonNull SponsorSegment segment) {
|
||||||
|
skipSegment = Objects.requireNonNull(segment);
|
||||||
|
updateSkipButton(skipSponsorButtonRef.get(), segment, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void hideSkipHighlightButton() {
|
||||||
|
skipHighlight = null;
|
||||||
|
updateSkipButton(skipHighlightButtonRef.get(), null, false);
|
||||||
|
}
|
||||||
|
public static void hideSkipSegmentButton() {
|
||||||
|
skipSegment = null;
|
||||||
|
updateSkipButton(skipSponsorButtonRef.get(), null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateSkipButton(@Nullable SkipSponsorButton button,
|
||||||
|
@Nullable SponsorSegment segment, boolean visible) {
|
||||||
|
if (button == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setNewSegmentLayoutVisibility(false);
|
if (segment != null) {
|
||||||
|
button.updateSkipButtonText(segment);
|
||||||
|
}
|
||||||
|
setViewVisibility(button, visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void toggleNewSegmentLayoutVisibility() {
|
public static void toggleNewSegmentLayoutVisibility() {
|
||||||
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
||||||
if (newSegmentLayout == null) {
|
if (newSegmentLayout == null) { // should never happen
|
||||||
LogHelper.printException(() -> "toggleNewSegmentLayoutVisibility failure");
|
LogHelper.printException(() -> "toggleNewSegmentLayoutVisibility failure");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setNewSegmentLayoutVisibility(newSegmentLayout.getVisibility() == View.VISIBLE ? false : true);
|
newSegmentLayoutVisible = (newSegmentLayout.getVisibility() != View.VISIBLE);
|
||||||
|
if (skipHighlight != null) {
|
||||||
|
setViewVisibility(skipHighlightButtonRef.get(), !newSegmentLayoutVisible);
|
||||||
|
}
|
||||||
|
setViewVisibility(newSegmentLayout, newSegmentLayoutVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void playerTypeChanged(PlayerType playerType) {
|
public static void hideNewSegmentLayout() {
|
||||||
|
newSegmentLayoutVisible = false;
|
||||||
|
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
||||||
|
if (newSegmentLayout == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setViewVisibility(newSegmentLayout, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setViewVisibility(@Nullable View view, boolean visible) {
|
||||||
|
if (view == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
visible &= canShowViewElements;
|
||||||
|
final int desiredVisibility = visible ? View.VISIBLE : View.GONE;
|
||||||
|
if (view.getVisibility() != desiredVisibility) {
|
||||||
|
view.setVisibility(desiredVisibility);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void playerTypeChanged(@NonNull PlayerType playerType) {
|
||||||
try {
|
try {
|
||||||
final boolean isWatchFullScreen = playerType == PlayerType.WATCH_WHILE_FULLSCREEN;
|
final boolean isWatchFullScreen = playerType == PlayerType.WATCH_WHILE_FULLSCREEN;
|
||||||
canShowViewElements = (isWatchFullScreen || playerType == PlayerType.WATCH_WHILE_MAXIMIZED);
|
canShowViewElements = (isWatchFullScreen || playerType == PlayerType.WATCH_WHILE_MAXIMIZED);
|
||||||
|
|
||||||
setSkipButtonMargins(isWatchFullScreen);
|
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
||||||
setNewSegmentLayoutMargins(isWatchFullScreen);
|
setNewSegmentLayoutMargins(newSegmentLayout, isWatchFullScreen);
|
||||||
updateSkipButton();
|
setViewVisibility(newSegmentLayoutRef.get(), newSegmentLayoutVisible);
|
||||||
|
|
||||||
|
SkipSponsorButton skipHighlightButton = skipHighlightButtonRef.get();
|
||||||
|
setSkipButtonMargins(skipHighlightButton, isWatchFullScreen);
|
||||||
|
setViewVisibility(skipHighlightButton, skipHighlight != null);
|
||||||
|
|
||||||
|
SkipSponsorButton skipSponsorButton = skipSponsorButtonRef.get();
|
||||||
|
setSkipButtonMargins(skipSponsorButton, isWatchFullScreen);
|
||||||
|
setViewVisibility(skipSponsorButton, skipSegment != null);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LogHelper.printException(() -> "Player type changed error", ex);
|
LogHelper.printException(() -> "Player type changed failure", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setSkipButtonMargins(boolean fullScreen) {
|
private static void setNewSegmentLayoutMargins(@Nullable NewSegmentLayout layout, boolean fullScreen) {
|
||||||
SkipSponsorButton skipSponsorButton = skipSponsorButtonRef.get();
|
if (layout != null) {
|
||||||
if (skipSponsorButton == null) {
|
setLayoutMargins(layout, fullScreen, layout.defaultBottomMargin, layout.ctaBottomMargin);
|
||||||
LogHelper.printException(() -> "setSkipButtonMargins failure");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) skipSponsorButton.getLayoutParams();
|
|
||||||
if (params == null) {
|
|
||||||
LogHelper.printException(() -> "setSkipButtonMargins failure");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
params.bottomMargin = fullScreen ? skipSponsorButton.ctaBottomMargin : skipSponsorButton.defaultBottomMargin;
|
|
||||||
skipSponsorButton.setLayoutParams(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setSkipSponsorButtonVisibility(boolean visible) {
|
|
||||||
SkipSponsorButton skipSponsorButton = skipSponsorButtonRef.get();
|
|
||||||
if (skipSponsorButton == null) {
|
|
||||||
LogHelper.printException(() -> "setSkipSponsorButtonVisibility failure");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
visible &= canShowViewElements;
|
|
||||||
|
|
||||||
final int desiredVisibility = visible ? View.VISIBLE : View.GONE;
|
|
||||||
if (skipSponsorButton.getVisibility() != desiredVisibility) {
|
|
||||||
skipSponsorButton.setVisibility(desiredVisibility);
|
|
||||||
if (visible) {
|
|
||||||
bringLayoutToFront();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static void setSkipButtonMargins(@Nullable SkipSponsorButton button, boolean fullScreen) {
|
||||||
private static void setNewSegmentLayoutMargins(boolean fullScreen) {
|
if (button != null) {
|
||||||
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
setLayoutMargins(button, fullScreen, button.defaultBottomMargin, button.ctaBottomMargin);
|
||||||
if (newSegmentLayout == null) {
|
|
||||||
LogHelper.printException(() -> "Unable to setNewSegmentLayoutMargins (button is null)");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) newSegmentLayout.getLayoutParams();
|
private static void setLayoutMargins(@NonNull View view, boolean fullScreen,
|
||||||
|
int defaultBottomMargin, int ctaBottomMargin) {
|
||||||
|
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
|
||||||
if (params == null) {
|
if (params == null) {
|
||||||
LogHelper.printException(() -> "Unable to setNewSegmentLayoutMargins (params are null)");
|
LogHelper.printException(() -> "Unable to setNewSegmentLayoutMargins (params are null)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
params.bottomMargin = fullScreen ? newSegmentLayout.ctaBottomMargin : newSegmentLayout.defaultBottomMargin;
|
params.bottomMargin = fullScreen ? ctaBottomMargin : defaultBottomMargin;
|
||||||
newSegmentLayout.setLayoutParams(params);
|
view.setLayoutParams(params);
|
||||||
}
|
|
||||||
|
|
||||||
private static void setNewSegmentLayoutVisibility(boolean visible) {
|
|
||||||
NewSegmentLayout newSegmentLayout = newSegmentLayoutRef.get();
|
|
||||||
if (newSegmentLayout == null) {
|
|
||||||
LogHelper.printException(() -> "setNewSegmentLayoutVisibility failure");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
visible &= canShowViewElements;
|
|
||||||
|
|
||||||
final int desiredVisibility = visible ? View.VISIBLE : View.GONE;
|
|
||||||
if (newSegmentLayout.getVisibility() != desiredVisibility) {
|
|
||||||
newSegmentLayout.setVisibility(desiredVisibility);
|
|
||||||
if (visible) {
|
|
||||||
bringLayoutToFront();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void bringLayoutToFront() {
|
|
||||||
RelativeLayout layout = inlineSponsorOverlayRef.get();
|
|
||||||
if (layout != null) {
|
|
||||||
// needed to keep skip button overtop end screen cards
|
|
||||||
layout.bringToFront();
|
|
||||||
layout.requestLayout();
|
|
||||||
layout.invalidate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user