瀏覽代碼

fix: potential fix for toasts not being auto-closed

Sv443 11 月之前
父節點
當前提交
7f5e5f5427
共有 1 個文件被更改,包括 63 次插入54 次删除
  1. 63 54
      src/features/behavior.ts

+ 63 - 54
src/features/behavior.ts

@@ -2,6 +2,7 @@ import { clamp, interceptWindowEvent, pauseFor } from "@sv443-network/userutils"
 import { domLoaded, error, getDomain, getVideoTime, getWatchId, info, log, getVideoSelector, waitVideoElementReady } from "../utils";
 import { getFeatures } from "../config";
 import { addSelectorListener } from "../observers";
+import { initialParams } from "../constants";
 import { LogLevel } from "../types";
 
 //#region beforeunload popup
@@ -29,13 +30,13 @@ export async function initBeforeUnloadHook() {
 
 /** Closes toasts after a set amount of time */
 export async function initAutoCloseToasts() {
-  try {
-    const animTimeout = 300;
+  const animTimeout = 300;
 
-    addSelectorListener("popupContainer", "tp-yt-paper-toast#toast", {
-      all: true,
-      continuous: true,
-      listener: async (toastElems) => {
+  addSelectorListener("popupContainer", "tp-yt-paper-toast#toast", {
+    all: true,
+    continuous: true,
+    listener: async (toastElems) => {
+      try {
         for(const toastElem of toastElems) {
           if(!toastElem.hasAttribute("allow-click-through"))
             continue;
@@ -53,79 +54,84 @@ export async function initAutoCloseToasts() {
           // wait for the transition to finish
           await pauseFor(animTimeout);
 
+          toastElem.classList.remove("bytm-closing");
           toastElem.style.display = "none";
         }
-      },
-    });
+      }
+      catch(err) {
+        error("Error in automatic toast closing:", err);
+      }
+    },
+  });
 
-    log("Initialized automatic toast closing");
-  }
-  catch(err) {
-    error("Error in automatic toast closing:", err);
-  }
+  log("Initialized automatic toast closing");
 }
 
 //#region remember song time
 
-interface RemSongObj {
+interface RemVidObj {
   /** Watch ID */
   watchID: string;
-  /** Time of the song in seconds */
+  /** Time of the song/video in seconds */
   songTime: number;
   /** Timestamp this entry was last updated */
   updateTimestamp: number;
 }
 
-let remSongsCache: RemSongObj[] = [];
+let remVidsCache: RemVidObj[] = [];
 
 /**
- * Remembers the time of the last played song and resumes playback from that time  
- * CALLED BEFORE DOM IS READY!
+ * Remembers the time of the last played video and resumes playback from that time.  
+ * **Needs to be called *before* DOM is ready!**
  */
-export async function initRememberSongTime() {
-  if(getFeatures().rememberSongTimeSites !== "all" && getFeatures().rememberSongTimeSites !== getDomain())
+export async function initRestoreVideoTime() {
+  if(getFeatures().restoreVideoTimeSites !== "all" && getFeatures().restoreVideoTimeSites !== getDomain())
     return;
 
   const storedDataRaw = await GM.getValue("bytm-rem-songs");
   if(!storedDataRaw)
     await GM.setValue("bytm-rem-songs", "[]");
 
-  remSongsCache = JSON.parse(String(storedDataRaw ?? "[]")) as RemSongObj[];
+  remVidsCache = JSON.parse(String(storedDataRaw ?? "[]")) as RemVidObj[];
 
-  log(`Initialized song time remembering with ${remSongsCache.length} initial entries`);
+  log(`Initialized video time restoring with ${remVidsCache.length} initial entr${remVidsCache.length === 1 ? "y" : "ies"}`);
 
   if(location.pathname.startsWith("/watch"))
-    await restoreSongTime();
+    await restVidRestoreTime();
 
   if(!domLoaded)
-    document.addEventListener("DOMContentLoaded", remSongUpdateEntry);
+    document.addEventListener("DOMContentLoaded", restVidStartUpdateLoop);
   else
-    remSongUpdateEntry();
+    restVidStartUpdateLoop();
 }
 
-/** Tries to restore the time of the currently playing song */
-async function restoreSongTime() {
+/** Tries to restore the time of the currently playing video */
+async function restVidRestoreTime() {
   if(location.pathname.startsWith("/watch")) {
     const watchID = new URL(location.href).searchParams.get("v");
     if(!watchID)
       return;
 
-    const entry = remSongsCache.find(entry => entry.watchID === watchID);
+    if(initialParams.has("t"))
+      return info("Not restoring song time because the URL has the '&t' parameter", LogLevel.Info);
+
+    const entry = remVidsCache.find(entry => entry.watchID === watchID);
     if(entry) {
-      if(Date.now() - entry.updateTimestamp > getFeatures().rememberSongTimeDuration * 1000) {
-        await delRemSongData(entry.watchID);
+      if(Date.now() - entry.updateTimestamp > getFeatures().restoreVideoTimeDuration * 1000) {
+        await restVidDeleteEntry(entry.watchID);
         return;
       }
+      else if(isNaN(Number(entry.songTime)))
+        return;
       else {
-        if(isNaN(entry.songTime))
-          return;
         const doRestoreTime = async () => {
           const vidElem = await waitVideoElementReady();
-          const vidRestoreTime = entry.songTime - (getFeatures().rememberSongTimeReduction ?? 0);
+          const vidRestoreTime = entry.songTime - (getFeatures().restoreVideoTimeReduction ?? 0);
           vidElem.currentTime = clamp(Math.max(vidRestoreTime, 0), 0, vidElem.duration);
-          await delRemSongData(entry.watchID);
+          await restVidDeleteEntry(entry.watchID);
           info(`Restored song time to ${Math.floor(vidRestoreTime / 60)}m, ${(vidRestoreTime % 60).toFixed(1)}s`, LogLevel.Info);
         };
+
         if(!domLoaded)
           document.addEventListener("DOMContentLoaded", doRestoreTime);
         else
@@ -136,9 +142,10 @@ async function restoreSongTime() {
 }
 
 let lastSongTime = -1;
+let remVidCheckTimeout: NodeJS.Timeout | undefined;
 
-/** Only call once as this calls itself after a timeout! - Updates the currently playing song's entry in GM storage */
-async function remSongUpdateEntry() {
+/** Only call once as this calls itself after a timeout! - Updates the currently playing video's entry in GM storage */
+async function restVidStartUpdateLoop() {
   if(location.pathname.startsWith("/watch")) {
     const songTime = await getVideoTime() ?? 0;
 
@@ -154,45 +161,47 @@ async function remSongUpdateEntry() {
 
     // don't immediately update to reduce race conditions and only update if the video is playing
     // also it just sounds better if the song starts at the beginning if only a couple seconds have passed
-    if(songTime > getFeatures().rememberSongTimeMinPlayTime && !paused) {
+    if(songTime > getFeatures().restoreVideoTimeMinPlayTime && !paused) {
       const entry = {
         watchID,
         songTime,
         updateTimestamp: Date.now(),
       };
-      await setRemSongData(entry);
+      await restVidSetEntry(entry);
     }
     // if the song is rewound to the beginning, delete the entry
     else {
-      const entry = remSongsCache.find(entry => entry.watchID === watchID);
-      if(entry && songTime <= getFeatures().rememberSongTimeMinPlayTime)
-        await delRemSongData(entry.watchID);
+      const entry = remVidsCache.find(entry => entry.watchID === watchID);
+      if(entry && songTime <= getFeatures().restoreVideoTimeMinPlayTime)
+        await restVidDeleteEntry(entry.watchID);
     }
   }
 
-  const expiredEntries = remSongsCache.filter(entry => Date.now() - entry.updateTimestamp > getFeatures().rememberSongTimeDuration * 1000);
+  const expiredEntries = remVidsCache.filter(entry => Date.now() - entry.updateTimestamp > getFeatures().restoreVideoTimeDuration * 1000);
   for(const entry of expiredEntries)
-    await delRemSongData(entry.watchID);
+    await restVidDeleteEntry(entry.watchID);
 
-  // for no overlapping calls and better error handling
-  setTimeout(remSongUpdateEntry, 1000);
+  // for no overlapping calls and better error handling:
+  if(remVidCheckTimeout)
+    clearTimeout(remVidCheckTimeout);
+  remVidCheckTimeout = setTimeout(restVidStartUpdateLoop, 1000);
 }
 
-/** Adds an entry or updates it if it already exists */
-async function setRemSongData(data: RemSongObj) {
-  const foundIdx = remSongsCache.findIndex(entry => entry.watchID === data.watchID);
+/** Updates an existing or creates a new entry */
+async function restVidSetEntry(data: RemVidObj) {
+  const foundIdx = remVidsCache.findIndex(entry => entry.watchID === data.watchID);
   if(foundIdx >= 0)
-    remSongsCache[foundIdx] = data;
+    remVidsCache[foundIdx] = data;
   else
-    remSongsCache.push(data);
+    remVidsCache.push(data);
 
-  await GM.setValue("bytm-rem-songs", JSON.stringify(remSongsCache));
+  await GM.setValue("bytm-rem-songs", JSON.stringify(remVidsCache));
 }
 
 /** Deletes an entry */
-async function delRemSongData(watchID: string) {
-  remSongsCache = [...remSongsCache.filter(entry => entry.watchID !== watchID)];
-  await GM.setValue("bytm-rem-songs", JSON.stringify(remSongsCache));
+async function restVidDeleteEntry(watchID: string) {
+  remVidsCache = [...remVidsCache.filter(entry => entry.watchID !== watchID)];
+  await GM.setValue("bytm-rem-songs", JSON.stringify(remVidsCache));
 }
 
 //#region disable darkreader