diff --git a/app/src/main/java/app/revanced/integrations/patches/CopyVideoUrlPatch.java b/app/src/main/java/app/revanced/integrations/patches/CopyVideoUrlPatch.java
index a38ac8fd..023c2bd6 100644
--- a/app/src/main/java/app/revanced/integrations/patches/CopyVideoUrlPatch.java
+++ b/app/src/main/java/app/revanced/integrations/patches/CopyVideoUrlPatch.java
@@ -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);
diff --git a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java
index bbadf90d..690e3e48 100644
--- a/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java
+++ b/app/src/main/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java
@@ -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;
     }
diff --git a/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java b/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java
index 0a2f257f..16270f39 100644
--- a/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java
+++ b/app/src/main/java/app/revanced/integrations/patches/SpoofSignatureVerificationPatch.java
@@ -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;
diff --git a/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java b/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java
index ccdde90d..13149541 100644
--- a/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java
+++ b/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java
@@ -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.
      */
diff --git a/app/src/main/java/app/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch.java b/app/src/main/java/app/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch.java
index b3475944..4ccd457f 100644
--- a/app/src/main/java/app/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch.java
+++ b/app/src/main/java/app/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch.java
@@ -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();
     }
 
     /**
diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java
index bd4f5a3d..1b0de152 100644
--- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java
+++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java
@@ -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),
diff --git a/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java b/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java
index 61bd92c0..9a9e0141 100644
--- a/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java
+++ b/app/src/main/java/app/revanced/integrations/settingsmenu/SponsorBlockSettingsFragment.java
@@ -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);
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/SegmentPlaybackController.java b/app/src/main/java/app/revanced/integrations/sponsorblock/SegmentPlaybackController.java
index 60efccf1..918e657e 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/SegmentPlaybackController.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/SegmentPlaybackController.java
@@ -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) {
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/SponsorBlockUtils.java b/app/src/main/java/app/revanced/integrations/sponsorblock/SponsorBlockUtils.java
index cea3360f..6f411586 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/SponsorBlockUtils.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/SponsorBlockUtils.java
@@ -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);
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/objects/SegmentCategory.java b/app/src/main/java/app/revanced/integrations/sponsorblock/objects/SegmentCategory.java
index 2a6d3059..6ed56fce 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/objects/SegmentCategory.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/objects/SegmentCategory.java
@@ -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;
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/objects/SponsorSegment.java b/app/src/main/java/app/revanced/integrations/sponsorblock/objects/SponsorSegment.java
index dff6e230..60c60598 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/objects/SponsorSegment.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/objects/SponsorSegment.java
@@ -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
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java b/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java
index cd17eb3e..a2985f4d 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java
@@ -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]);
     }
 
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/ui/NewSegmentLayout.java b/app/src/main/java/app/revanced/integrations/sponsorblock/ui/NewSegmentLayout.java
index 88ed535b..e1e09182 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/ui/NewSegmentLayout.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/ui/NewSegmentLayout.java
@@ -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();
     }
 }
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/ui/SkipSponsorButton.java b/app/src/main/java/app/revanced/integrations/sponsorblock/ui/SkipSponsorButton.java
index 65666da8..47613392 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/ui/SkipSponsorButton.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/ui/SkipSponsorButton.java
@@ -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);
         });
     }
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/ui/SponsorBlockViewController.java b/app/src/main/java/app/revanced/integrations/sponsorblock/ui/SponsorBlockViewController.java
index 5925f80c..fcbaf2da 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/ui/SponsorBlockViewController.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/ui/SponsorBlockViewController.java
@@ -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) {
diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/ui/VotingButtonController.java b/app/src/main/java/app/revanced/integrations/sponsorblock/ui/VotingButtonController.java
index 4a5a162d..0a5c499a 100644
--- a/app/src/main/java/app/revanced/integrations/sponsorblock/ui/VotingButtonController.java
+++ b/app/src/main/java/app/revanced/integrations/sponsorblock/ui/VotingButtonController.java
@@ -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() {
diff --git a/app/src/main/java/app/revanced/integrations/videoplayer/DownloadButton.java b/app/src/main/java/app/revanced/integrations/videoplayer/DownloadButton.java
index 5928e021..4b915dc0 100644
--- a/app/src/main/java/app/revanced/integrations/videoplayer/DownloadButton.java
+++ b/app/src/main/java/app/revanced/integrations/videoplayer/DownloadButton.java
@@ -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");