Ver código fonte

ref: consolidate naming scheme

Sv443 1 mês atrás
pai
commit
b3b490adb7
6 arquivos alterados com 68 adições e 68 exclusões
  1. 6 6
      contributing.md
  2. 26 26
      src/features/behavior.ts
  3. 3 3
      src/features/layout.ts
  4. 14 14
      src/siteEvents.ts
  5. 11 11
      src/utils/misc.ts
  6. 8 8
      src/utils/xhr.ts

+ 6 - 6
contributing.md

@@ -890,18 +890,18 @@ The usage and example blocks on each are written in TypeScript but can be used i
 > Signature:
 > ```ts
 > unsafeWindow.BYTM.getThumbnailUrl(
->   watchID: string,
+>   videoID: string,
 >   qualityOrIndex: "maxresdefault" | "sddefault" | "hqdefault" | "mqdefault" | "default" | 0 | 1 | 2 | 3
 > ): string
 > ```
 >   
 > Description:  
-> Returns the URL to the thumbnail of the video with the specified watch/video ID and quality (resolution).  
+> Returns the URL to the thumbnail of the video with the specified video ID and quality (resolution).  
 > If an index number is passed, 0 will return a very low resolution thumbnail and 1-3 will return a very low resolution preview frame from the video (if available).  
 > For some videos, different qualities and indexes are not available. That is why using [`getBestThumbnailUrl()`](#getbestthumbnailurl) is recommended in most cases.  
 >   
 > Arguments:
-> - `watchID` - The watch/video ID of the video to get the thumbnail for
+> - `videoID` - The video ID of the video to get the thumbnail for
 > - `qualityOrIndex` - The quality or index of the thumbnail to get. If no quality is specified, `maxresdefault` (highest resolution) is used.  
 >   Quality values sorted by highest res first: `maxresdefault` > `sddefault` > `hqdefault` > `mqdefault` > `default`.
 >   
@@ -918,11 +918,11 @@ The usage and example blocks on each are written in TypeScript but can be used i
 > ### getBestThumbnailUrl()
 > Signature:
 > ```ts
-> unsafeWindow.BYTM.getBestThumbnailUrl(watchID: string): Promise<string | undefined>
+> unsafeWindow.BYTM.getBestThumbnailUrl(videoID: string): Promise<string | undefined>
 > ```
 >   
 > Description:  
-> Returns the URL to the best resolution thumbnail of the video with the specified watch/video ID.  
+> Returns the URL to the best resolution thumbnail of the video with the specified video ID.  
 > Will sequentially try to get the highest quality thumbnail available until one is found.  
 > Resolution priority list: `maxresdefault` > `sddefault` > `hqdefault` > `0`  
 >   
@@ -933,7 +933,7 @@ The usage and example blocks on each are written in TypeScript but can be used i
 > May throw if an error occurs while fetching the thumbnails.  
 >   
 > Arguments:
-> - `watchID` - The watch/video ID of the video to get the thumbnail for
+> - `videoID` - The video ID of the video to get the thumbnail for
 >   
 > <details><summary><b>Example <i>(click to expand)</i></b></summary>
 > 

+ 26 - 26
src/features/behavior.ts

@@ -1,5 +1,5 @@
 import { autoPlural, clamp, interceptWindowEvent, isDomLoaded, pauseFor } from "@sv443-network/userutils";
-import { error, getDomain, getVideoTime, getWatchId, info, log, waitVideoElementReady, clearNode, getCurrentMediaType, getVideoElement, scrollToCurrentSongInQueue } from "../utils/index.js";
+import { error, getDomain, getVideoTime, getWatchId, info, log, waitVideoElementReady, clearNode, getCurrentMediaType, getVideoElement, scrollToCurrentSongInQueue, warn } from "../utils/index.js";
 import { getFeature } from "../config.js";
 import { addSelectorListener } from "../observers.js";
 import { initialParams } from "../constants.js";
@@ -109,11 +109,11 @@ export async function initAutoScrollToActiveSong() {
 
 interface RemVidObj {
   /** Watch ID */
-  watchID: string;
+  id: string;
   /** Time of the song/video in seconds */
-  songTime: number;
+  time: number;
   /** Timestamp this entry was last updated */
-  updateTimestamp: number;
+  updated: number;
 }
 
 /**
@@ -159,29 +159,29 @@ async function remTimeRestoreTime() {
   const remVids = JSON.parse(await GM.getValue("bytm-rem-songs", "[]")) as RemVidObj[];
 
   if(location.pathname.startsWith("/watch")) {
-    const watchID = new URL(location.href).searchParams.get("v");
-    if(!watchID)
+    const videoID = new URL(location.href).searchParams.get("v");
+    if(!videoID)
       return;
 
     if(initialParams.has("t"))
       return info("Not restoring song time because the URL has the '&t' parameter", LogLevel.Info);
 
-    const entry = remVids.find(entry => entry.watchID === watchID);
+    const entry = remVids.find(entry => entry.id === videoID);
     if(entry) {
-      if(Date.now() - entry.updateTimestamp > getFeature("rememberSongTimeDuration") * 1000) {
-        await remTimeDeleteEntry(entry.watchID);
+      if(Date.now() - entry.updated > getFeature("rememberSongTimeDuration") * 1000) {
+        await remTimeDeleteEntry(entry.id);
         return;
       }
-      else if(isNaN(Number(entry.songTime)))
-        return;
+      else if(isNaN(Number(entry.time)) || entry.time < 0)
+        return warn("Invalid time in remembered song time entry:", entry);
       else {
         let vidElem: HTMLVideoElement;
         const doRestoreTime = async () => {
           if(!vidElem)
             vidElem = await waitVideoElementReady();
-          const vidRestoreTime = entry.songTime - (getFeature("rememberSongTimeReduction") ?? 0);
+          const vidRestoreTime = entry.time - (getFeature("rememberSongTimeReduction") ?? 0);
           vidElem.currentTime = clamp(Math.max(vidRestoreTime, 0), 0, vidElem.duration);
-          await remTimeDeleteEntry(entry.watchID);
+          await remTimeDeleteEntry(entry.id);
           info(`Restored ${getDomain() === "ytm" ? getCurrentMediaType() : "video"} time to ${Math.floor(vidRestoreTime / 60)}m, ${(vidRestoreTime % 60).toFixed(1)}s`, LogLevel.Info);
         };
 
@@ -202,10 +202,10 @@ async function remTimeStartUpdateLoop() {
   const remVids = JSON.parse(await GM.getValue("bytm-rem-songs", "[]")) as RemVidObj[];
 
   if(location.pathname.startsWith("/watch")) {
-    const watchID = getWatchId();
+    const id = getWatchId();
     const songTime = await getVideoTime() ?? 0;
 
-    if(watchID && songTime !== lastSongTime) {
+    if(id && songTime !== lastSongTime) {
       lastSongTime = songTime;
 
       const paused = getVideoElement()?.paused ?? false;
@@ -214,24 +214,24 @@ async function remTimeStartUpdateLoop() {
       // also it just sounds better if the song starts at the beginning if only a couple seconds have passed
       if(songTime > getFeature("rememberSongTimeMinPlayTime") && !paused) {
         const entry = {
-          watchID,
-          songTime,
-          updateTimestamp: Date.now(),
+          id,
+          time: songTime,
+          updated: Date.now(),
         };
         await remTimeUpsertEntry(entry);
       }
       // if the song is rewound to the beginning, update the entry accordingly
       else if(!paused) {
-        const entry = remVids.find(entry => entry.watchID === watchID);
-        if(entry && songTime <= entry.songTime)
-          await remTimeUpsertEntry({ ...entry, songTime, updateTimestamp: Date.now() });
+        const entry = remVids.find(entry => entry.id === id);
+        if(entry && songTime <= entry.time)
+          await remTimeUpsertEntry({ ...entry, time: songTime, updated: Date.now() });
       }
     }
   }
 
-  const expiredEntries = remVids.filter(entry => Date.now() - entry.updateTimestamp > getFeature("rememberSongTimeDuration") * 1000);
+  const expiredEntries = remVids.filter(entry => Date.now() - entry.updated > getFeature("rememberSongTimeDuration") * 1000);
   for(const entry of expiredEntries)
-    await remTimeDeleteEntry(entry.watchID);
+    await remTimeDeleteEntry(entry.id);
 
   // for no overlapping calls and better error handling:
   if(remVidCheckTimeout)
@@ -242,7 +242,7 @@ async function remTimeStartUpdateLoop() {
 /** Updates an existing or inserts a new entry to be remembered */
 async function remTimeUpsertEntry(data: RemVidObj) {
   const remVids = JSON.parse(await GM.getValue("bytm-rem-songs", "[]")) as RemVidObj[];
-  const foundIdx = remVids.findIndex(entry => entry.watchID === data.watchID);
+  const foundIdx = remVids.findIndex(entry => entry.id === data.id);
 
   if(foundIdx >= 0)
     remVids[foundIdx] = data;
@@ -253,8 +253,8 @@ async function remTimeUpsertEntry(data: RemVidObj) {
 }
 
 /** Deletes an entry in the "remember cache" */
-async function remTimeDeleteEntry(watchID: string) {
+async function remTimeDeleteEntry(videoID: string) {
   const remVids = (JSON.parse(await GM.getValue("bytm-rem-songs", "[]")) as RemVidObj[])
-    .filter(entry => entry.watchID !== watchID);
+    .filter(entry => entry.id !== videoID);
   await GM.setValue("bytm-rem-songs", JSON.stringify(remVids));
 }

+ 3 - 3
src/features/layout.ts

@@ -729,13 +729,13 @@ export async function initShowVotes() {
   addSelectorListener("playerBar", ".middle-controls-buttons ytmusic-like-button-renderer", {
     async listener(voteCont: HTMLElement): Promise<void> {
       try {
-        const watchId = getWatchId();
-        if(!watchId) {
+        const videoID = getWatchId();
+        if(!videoID) {
           await siteEvents.once("watchIdChanged");
           return initShowVotes();
         }
 
-        const voteObj = await fetchVideoVotes(watchId);
+        const voteObj = await fetchVideoVotes(videoID);
         if(!voteObj || !("likes" in voteObj) || !("dislikes" in voteObj) || !("rating" in voteObj))
           return error("Couldn't fetch votes from the Return YouTube Dislike API");
 

+ 14 - 14
src/siteEvents.ts

@@ -33,7 +33,7 @@ export interface SiteEventsMap {
    */
   songTitleChanged: (newTitle: string, oldTitle: string | null) => void;
   /**
-   * Emitted whenever the current song's watch ID changes.  
+   * Emitted whenever the current song's watch/video ID changes.  
    * If `oldId` is `null`, this is the first song played in the session.
    */
   watchIdChanged: (newId: string, oldId: string | null) => void;
@@ -81,7 +81,7 @@ export function removeAllObservers() {
   observers = [];
 }
 
-let lastWatchId: string | null = null;
+let lastVidId: string | null = null;
 let lastPathname: string | null = null;
 let lastFullscreen: boolean;
 
@@ -183,8 +183,8 @@ export async function initSiteEvents() {
             const urlRefObs = new MutationObserver(([ { target } ]) => {
               if(!target || !(target as HTMLAnchorElement)?.href?.includes("/watch"))
                 return;
-              const watchId = new URL((target as HTMLAnchorElement).href).searchParams.get("v");
-              checkWatchIdChange(watchId);
+              const videoID = new URL((target as HTMLAnchorElement).href).searchParams.get("v");
+              checkVideoIdChange(videoID);
             });
 
             urlRefObs.observe(el, {
@@ -194,8 +194,8 @@ export async function initSiteEvents() {
         });
       }
       if(getDomain() === "ytm") {
-        setInterval(checkWatchIdChange, 250);
-        checkWatchIdChange();
+        setInterval(checkVideoIdChange, 250);
+        checkVideoIdChange();
       }
     }, {
       once: true,
@@ -230,19 +230,19 @@ export function emitSiteEvent<TKey extends keyof SiteEventsMap>(key: TKey, ...ar
 //#region other
 
 /** Checks if the watch ID has changed and emits a `watchIdChanged` siteEvent if it has */
-function checkWatchIdChange(newId?: string | null) {
-  const newWatchId = newId ?? new URL(location.href).searchParams.get("v");
-  if(newWatchId && newWatchId !== lastWatchId) {
-    info(`Detected watch ID change - old ID: "${lastWatchId}" - new ID: "${newWatchId}"`);
-    emitSiteEvent("watchIdChanged", newWatchId, lastWatchId);
-    lastWatchId = newWatchId;
+function checkVideoIdChange(newID?: string | null) {
+  const newVidID = newID ?? new URL(location.href).searchParams.get("v");
+  if(newVidID && newVidID !== lastVidId) {
+    info(`Detected watch ID change - old ID: "${lastVidId}" - new ID: "${newVidID}"`);
+    emitSiteEvent("watchIdChanged", newVidID, lastVidId);
+    lastVidId = newVidID;
   }
 }
 
 /** Periodically called to check for changes in the URL and emit associated siteEvents */
 export function runIntervalChecks() {
-  if(!lastWatchId)
-    checkWatchIdChange();
+  if(!lastVidId)
+    checkVideoIdChange();
 
   if(location.pathname !== lastPathname) {
     emitSiteEvent("pathChanged", String(location.pathname), lastPathname);

+ 11 - 11
src/utils/misc.ts

@@ -122,28 +122,28 @@ export function isValidChannelId(channelId: string) {
 /** Quality identifier for a thumbnail - from highest to lowest res: `maxresdefault` > `sddefault` > `hqdefault` > `mqdefault` > `default` */
 type ThumbQuality = `${"maxres" | "sd" | "hq" | "mq"}default` | "default";
 
-/** Returns the thumbnail URL for a video with the given watch ID and quality (defaults to "hqdefault") */
-export function getThumbnailUrl(watchId: string, quality?: ThumbQuality): string
-/** Returns the thumbnail URL for a video with the given watch ID and index (0 is low quality thumbnail, 1-3 are low quality frames from the video) */
-export function getThumbnailUrl(watchId: string, index?: 0 | 1 | 2 | 3): string
+/** Returns the thumbnail URL for a video with the given video ID and quality (defaults to "hqdefault") */
+export function getThumbnailUrl(videoID: string, quality?: ThumbQuality): string
+/** Returns the thumbnail URL for a video with the given video ID and index (0 is low quality thumbnail, 1-3 are low quality frames from the video) */
+export function getThumbnailUrl(videoID: string, index?: 0 | 1 | 2 | 3): string
 /** Returns the thumbnail URL for a video with either a given quality identifier or index */
-export function getThumbnailUrl(watchId: string, qualityOrIndex: Prettify<ThumbQuality | 0 | 1 | 2 | 3> = "maxresdefault") {
-  return `https://img.youtube.com/vi/${watchId}/${qualityOrIndex}.jpg`;
+export function getThumbnailUrl(videoID: string, qualityOrIndex: Prettify<ThumbQuality | 0 | 1 | 2 | 3> = "maxresdefault") {
+  return `https://img.youtube.com/vi/${videoID}/${qualityOrIndex}.jpg`;
 }
 
-/** Returns the best available thumbnail URL for a video with the given watch ID */
-export async function getBestThumbnailUrl(watchId: string) {
+/** Returns the best available thumbnail URL for a video with the given video ID */
+export async function getBestThumbnailUrl(videoID: string) {
   try {
     const priorityList = ["maxresdefault", "sddefault", "hqdefault", 0];
 
     for(const quality of priorityList) {
       let response: GM.Response<unknown> | undefined;
-      const url = getThumbnailUrl(watchId, quality as ThumbQuality);
+      const url = getThumbnailUrl(videoID, quality as ThumbQuality);
       try {
         response = await sendRequest({ url, method: "HEAD", timeout: 6_000 });
       }
       catch(err) {
-        error(`Error while sending HEAD request to thumbnail URL for video '${watchId}' with quality '${quality}':`, err);
+        error(`Error while sending HEAD request to thumbnail URL for video ID '${videoID}' with quality '${quality}':`, err);
         void err;
       }
       if(response && response.status < 300 && response.status >= 200)
@@ -151,7 +151,7 @@ export async function getBestThumbnailUrl(watchId: string) {
     }
   }
   catch(err) {
-    throw new Error(`Couldn't get thumbnail URL for video '${watchId}': ${err}`);
+    throw new Error(`Couldn't get thumbnail URL for video ID '${videoID}': ${err}`);
   }
 }
 

+ 8 - 8
src/utils/xhr.ts

@@ -64,24 +64,24 @@ const voteCacheTTL = 1000 * 60 * 10;
 
 /**
  * Fetches the votes object for a YouTube video from the [Return YouTube Dislike API.](https://returnyoutubedislike.com/docs)
- * @param watchId The watch ID of the video
+ * @param videoID The video ID of the video
  */
-export async function fetchVideoVotes(watchId: string): Promise<VideoVotesObj | undefined> {
+export async function fetchVideoVotes(videoID: string): Promise<VideoVotesObj | undefined> {
   try {
-    if(voteCache.has(watchId)) {
-      const cached = voteCache.get(watchId)!;
+    if(voteCache.has(videoID)) {
+      const cached = voteCache.get(videoID)!;
       if(Date.now() - cached.timestamp < voteCacheTTL) {
-        info(`Returning cached video votes for watch ID '${watchId}':`, cached);
+        info(`Returning cached video votes for video ID '${videoID}':`, cached);
         return cached;
       }
       else
-        voteCache.delete(watchId);
+        voteCache.delete(videoID);
     }
 
     const votesRaw = JSON.parse(
       (await sendRequest({
         method: "GET",
-        url: `https://returnyoutubedislikeapi.com/votes?videoId=${watchId}`,
+        url: `https://returnyoutubedislikeapi.com/votes?videoId=${videoID}`,
       })).response
     ) as RYDVotesObj;
 
@@ -99,7 +99,7 @@ export async function fetchVideoVotes(watchId: string): Promise<VideoVotesObj |
     };
     voteCache.set(votesObj.id, votesObj);
 
-    info(`Fetched video votes for watch ID '${watchId}':`, votesObj);
+    info(`Fetched video votes for watch ID '${videoID}':`, votesObj);
 
     return votesObj;
   }