Ver código fonte

fix: better auto-like channel ID format and parsing

Sv443 11 meses atrás
pai
commit
8a721e918f
4 arquivos alterados com 31 adições e 9 exclusões
  1. 1 1
      src/components/toast.ts
  2. 5 1
      src/features/index.ts
  3. 6 7
      src/features/input.ts
  4. 19 0
      src/utils/misc.ts

+ 1 - 1
src/components/toast.ts

@@ -21,7 +21,7 @@ type ToastProps = {
 
 type IconToastProps = ToastProps & (
   | {
-    icon: ResourceKey;
+    icon: ResourceKey & `icon-${string}`;
   }
   | {
     iconSrc: string | Promise<string>;

+ 5 - 1
src/features/index.ts

@@ -83,14 +83,17 @@ const options = {
  * Contains all possible features with their default values and other configuration.  
  *   
  * **Required props:**
+ * <!-------------------------------------------------------------------------------------------------------------------------------------------------------->
  * | Property             | Description                                                                                                                      |
  * | :------------------- | :------------------------------------------------------------------------------------------------------------------------------- |
  * | `type`               | type of the feature configuration element - use autocomplete or check `FeatureTypeProps` in `src/types.ts`                       |
  * | `category`           | category of the feature - use autocomplete or check `FeatureCategory` in `src/types.ts`                                          |
  * | `default`            | default value of the feature - type of the value depends on the given `type`                                                     |
  * | `enable(value: any)` | (required if reloadRequired = false) - function that will be called when the feature is enabled / initialized for the first time |
- *   
+ * 
+ * 
  * **Optional props:**
+ * <!-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
  * | Property                                                       | Description                                                                                                                                              |
  * | :------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |
  * | `disable: (newValue: any) => void`                             | for type `toggle` only - function that will be called when the feature is disabled - can be a synchronous or asynchronous function                       |
@@ -108,6 +111,7 @@ const options = {
  * | `hidden: boolean`                                              | if true, the feature will not be shown in the settings - default is undefined (false)                                                                    |
  * | `valueHidden: boolean`                                         | If true, the value of the feature will be hidden in the settings and via the plugin interface - default is undefined (false)                             |
  * | `normalize: (val: any) => any`                                 | Function that will be called to normalize the value before it is saved - useful for trimming strings or other simple operations                          |
+ * | `renderValue: (val: any) => string`                            | If provided, is called before rendering the value's label in the config menu                                                                             |
  * 
  * TODO: go through all features and set as many as possible to reloadRequired = false
  */

+ 6 - 7
src/features/input.ts

@@ -1,5 +1,5 @@
 import { DataStore, clamp, compress, decompress } from "@sv443-network/userutils";
-import { error, getVideoTime, info, log, warn, getVideoSelector, getDomain, compressionSupported, t, clearNode, resourceToHTMLString } from "../utils";
+import { error, getVideoTime, info, log, warn, getVideoSelector, getDomain, compressionSupported, t, clearNode, resourceToHTMLString, getCurrentChannelId } from "../utils";
 import type { Domain } from "../types";
 import { isCfgMenuOpen } from "../menu/menu_old";
 import { disableBeforeUnload } from "./behavior";
@@ -158,7 +158,7 @@ let canCompress = false;
 /** DataStore instance for all auto-liked channels */
 export const autoLikeStore = new DataStore<{
   channels: {
-    /** 24-character channel ID or user ID without the @ */
+    /** 24-character channel ID or user ID including the @ prefix */
     id: string;
     /** Channel name (for display purposes only) */
     name: string;
@@ -196,7 +196,6 @@ export async function initAutoLike() {
       siteEvents.on("songTitleChanged", () => {
         timeout && clearTimeout(timeout);
         timeout = setTimeout(() => {
-          // TODO: support multiple artists
           const artistEls = document.querySelectorAll<HTMLAnchorElement>("ytmusic-player-bar .content-info-wrapper .subtitle a.yt-formatted-string[href]");
           const channelIds = [...artistEls].map(a => a.href.split("/").pop()).filter(a => typeof a === "string") as string[];
 
@@ -223,7 +222,7 @@ export async function initAutoLike() {
 
       siteEvents.on("pathChanged", (path) => {
         if(getFeature("autoLikeChannelToggleBtn") && path.match(/\/channel\/.+/)) {
-          const chanId = path.split("/").pop(); // TODO:FIXME: this doesn't work for paths like /channel/@User/videos
+          const chanId = getCurrentChannelId();
           if(!chanId)
             return error("Couldn't extract channel ID from URL");
 
@@ -260,8 +259,8 @@ export async function initAutoLike() {
           addSelectorListener<HTMLAnchorElement, "yt">("watchMetadata", "#owner ytd-channel-name yt-formatted-string a", {
             listener(chanElem) {
               let chanId = chanElem.href.split("/").pop();
-              if(chanId?.startsWith("@"))
-                chanId = chanId.slice(1);
+              if(!chanId?.startsWith("@"))
+                chanId = `@${chanId}`;
 
               const likeChan = autoLikeStore.getData().channels.find((ch) => ch.id === chanId);
               if(!likeChan || !likeChan.enabled)
@@ -286,7 +285,7 @@ export async function initAutoLike() {
 
       siteEvents.on("pathChanged", (path) => {
         if(path.match(/(\/?@|\/channel\/).+/)) {
-          const chanId = path.split("/").pop()?.replace(/@/g, "");
+          const chanId = getCurrentChannelId();
           if(!chanId)
             return error("Couldn't extract channel ID from URL");
 

+ 19 - 0
src/utils/misc.ts

@@ -75,6 +75,25 @@ export function getWatchId() {
   return pathname.includes("/watch") ? searchParams.get("v") : null;
 }
 
+/**
+ * Returns the ID of the current channel in the format `@User` or `UC...` from URLs with the path `/@User`, `/@User/videos`, `/channel/UC...` or `/channel/UC.../videos`  
+ * Returns null if the current page is not a channel page or there was an error parsing the URL
+ */
+export function getCurrentChannelId() {
+  try {
+    const { pathname } = new URL(location.href);
+    if(pathname.includes("/channel/"))
+      return pathname.split("/channel/")[1].split("/")[0];
+    else if(pathname.includes("/@"))
+      return pathname.split("/@")[1].split("/")[0];
+    else
+      return null;
+  }
+  catch(e) {
+    return null;
+  }
+}
+
 /** Quality identifier for a thumbnail - from highest to lowest res: `maxresdefault` > `sddefault` > `hqdefault` > `mqdefault` > `default` */
 type ThumbQuality = `${"maxres" | "sd" | "hq" | "mq" | ""}default`;