Переглянути джерело

feat: cfg menu support for custom value rendering

Sv443 11 місяців тому
батько
коміт
fc2db68f56
6 змінених файлів з 44 додано та 27 видалено
  1. 23 16
      assets/translations/README.md
  2. 1 0
      assets/translations/en_US.json
  3. 2 2
      src/config.ts
  4. 3 1
      src/index.ts
  5. 11 8
      src/menu/menu_old.ts
  6. 4 0
      src/types.ts

+ 23 - 16
assets/translations/README.md

@@ -20,15 +20,15 @@ To submit or edit a translation, please follow [this guide](../../contributing.m
 ### Translation progress:
 |   | Locale | Translated keys | Based on |
 | :----: | ------ | --------------- | :------: |
-| ─ | [`en_US`](./en_US.json) | 204 (default locale) |  |
-| ⚠ | [`de_DE`](./de_DE.json) | `203/204` (99.5%) | ─ |
-| ─ | [`en_UK`](./en_UK.json) | `204/204` (100%) | `en_US` |
-| ⚠ | [`es_ES`](./es_ES.json) | `203/204` (99.5%) | ─ |
-| ⚠ | [`fr_FR`](./fr_FR.json) | `203/204` (99.5%) | ─ |
-| ⚠ | [`hi_IN`](./hi_IN.json) | `203/204` (99.5%) | ─ |
-| ⚠ | [`ja_JA`](./ja_JA.json) | `203/204` (99.5%) | ─ |
-| ⚠ | [`pt_BR`](./pt_BR.json) | `203/204` (99.5%) | ─ |
-| ⚠ | [`zh_CN`](./zh_CN.json) | `203/204` (99.5%) | ─ |
+| ─ | [`en_US`](./en_US.json) | 205 (default locale) |  |
+| ⚠ | [`de_DE`](./de_DE.json) | `203/205` (99%) | ─ |
+| ─ | [`en_UK`](./en_UK.json) | `205/205` (100%) | `en_US` |
+| ⚠ | [`es_ES`](./es_ES.json) | `203/205` (99%) | ─ |
+| ⚠ | [`fr_FR`](./fr_FR.json) | `203/205` (99%) | ─ |
+| ⚠ | [`hi_IN`](./hi_IN.json) | `203/205` (99%) | ─ |
+| ⚠ | [`ja_JA`](./ja_JA.json) | `203/205` (99%) | ─ |
+| ⚠ | [`pt_BR`](./pt_BR.json) | `203/205` (99%) | ─ |
+| ⚠ | [`zh_CN`](./zh_CN.json) | `203/205` (99%) | ─ |
 
 <sub>
 ✅ - Fully translated
@@ -49,58 +49,65 @@ This means to figure out which keys are untranslated, you will need to manually
 
 ### Missing keys:
 
-<details><summary><code>de_DE</code> - 1 missing key <i>(click to show)</i></summary><br>
+<details><summary><code>de_DE</code> - 2 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
 | `feature_requires_reload` | `Changing this feature requires a page reload` |
+| `feature_desc_thumbnailOverlayIndicatorOpacity` | `Opacity of the indicator in the bottom right corner` |
 
 <br></details>
 
-<details><summary><code>es_ES</code> - 1 missing key <i>(click to show)</i></summary><br>
+<details><summary><code>es_ES</code> - 2 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
 | `feature_requires_reload` | `Changing this feature requires a page reload` |
+| `feature_desc_thumbnailOverlayIndicatorOpacity` | `Opacity of the indicator in the bottom right corner` |
 
 <br></details>
 
-<details><summary><code>fr_FR</code> - 1 missing key <i>(click to show)</i></summary><br>
+<details><summary><code>fr_FR</code> - 2 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
 | `feature_requires_reload` | `Changing this feature requires a page reload` |
+| `feature_desc_thumbnailOverlayIndicatorOpacity` | `Opacity of the indicator in the bottom right corner` |
 
 <br></details>
 
-<details><summary><code>hi_IN</code> - 1 missing key <i>(click to show)</i></summary><br>
+<details><summary><code>hi_IN</code> - 2 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
 | `feature_requires_reload` | `Changing this feature requires a page reload` |
+| `feature_desc_thumbnailOverlayIndicatorOpacity` | `Opacity of the indicator in the bottom right corner` |
 
 <br></details>
 
-<details><summary><code>ja_JA</code> - 1 missing key <i>(click to show)</i></summary><br>
+<details><summary><code>ja_JA</code> - 2 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
 | `feature_requires_reload` | `Changing this feature requires a page reload` |
+| `feature_desc_thumbnailOverlayIndicatorOpacity` | `Opacity of the indicator in the bottom right corner` |
 
 <br></details>
 
-<details><summary><code>pt_BR</code> - 1 missing key <i>(click to show)</i></summary><br>
+<details><summary><code>pt_BR</code> - 2 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
 | `feature_requires_reload` | `Changing this feature requires a page reload` |
+| `feature_desc_thumbnailOverlayIndicatorOpacity` | `Opacity of the indicator in the bottom right corner` |
 
 <br></details>
 
-<details><summary><code>zh_CN</code> - 1 missing key <i>(click to show)</i></summary><br>
+<details><summary><code>zh_CN</code> - 2 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
 | `feature_requires_reload` | `Changing this feature requires a page reload` |
+| `feature_desc_thumbnailOverlayIndicatorOpacity` | `Opacity of the indicator in the bottom right corner` |
 
 <br></details>

+ 1 - 0
assets/translations/en_US.json

@@ -162,6 +162,7 @@
     "feature_desc_thumbnailOverlayToggleBtnShown": "Add a button to the media controls to manually toggle the thumbnail",
     "feature_helptext_thumbnailOverlayToggleBtnShown": "This button will allow you to manually toggle the thumbnail on and off. This is not affected if the thumbnail replacement option is set to \"never\".\nOnce a new video or song starts playing, the default state will be restored.\nHold shift while clicking or press the middle mouse button to open the thumbnail of the highest quality in a new tab.",
     "feature_desc_thumbnailOverlayShowIndicator": "Show an indicator in the bottom right corner of the thumbnail while it's active?",
+    "feature_desc_thumbnailOverlayIndicatorOpacity": "Opacity of the indicator in the bottom right corner",
     "feature_desc_thumbnailOverlayImageFit": "How to fit the thumbnail image over the video element",
     "feature_desc_hideCursorOnIdle": "Hide the cursor after a few seconds of inactivity over the video",
     "feature_desc_hideCursorOnIdleDelay": "How many seconds of inactivity before the cursor should be hidden?",

+ 2 - 2
src/config.ts

@@ -54,8 +54,8 @@ export const migrations: DataMigrationsDict = {
       "rememberSongTimeMinPlayTime", "volumeSharedBetweenTabs",
       "setInitialTabVolume", "initialTabVolumeLevel",
       "thumbnailOverlayBehavior", "thumbnailOverlayToggleBtnShown",
-      "thumbnailOverlayShowIndicator", "thumbnailOverlayImageFit",
-      "removeShareTrackingParamSites",
+      "thumbnailOverlayShowIndicator", "thumbnailOverlayIndicatorOpacity",
+      "thumbnailOverlayImageFit", "removeShareTrackingParamSites",
     ], oldData),
   }),
   // TODO: once advanced filtering is fully implemented, clear cache on migration to fv6

+ 3 - 1
src/index.ts

@@ -1,5 +1,5 @@
 import { compress, decompress, type Stringifiable } from "@sv443-network/userutils";
-import { addStyle, domLoaded, reserialize, warn } from "./utils";
+import { addStyle, domLoaded, reserialize, t, warn } from "./utils";
 import { clearConfig, defaultData as defaultFeatData, getFeatures, initConfig, setFeatures } from "./config";
 import { buildNumber, compressionFormat, defaultLogLevel, mode, scriptInfo } from "./constants";
 import { error, getDomain, info, getSessionId, log, setLogLevel, initTranslations, setLocale } from "./utils";
@@ -117,6 +117,8 @@ async function onDomLoad() {
   const features = getFeatures();
   const ftInit = [] as Promise<void>[];
 
+  console.log(">>>\n", Object.keys(features).map(k => ([k, t(`feature_desc_${k}`)]).join(" :: ")).reduce((a, c, i) => `${a}${i === 0 ? "" : "\n"}${c}`, ""));
+
   try {
     insertGlobalStyle();
 

+ 11 - 8
src/menu/menu_old.ts

@@ -282,9 +282,12 @@ async function addCfgMenu() {
     {} as Record<FeatureCategory, Record<FeatureKey, unknown>>,
     );
 
-  const fmtVal = (v: unknown) => {
+  const fmtVal = (v: unknown, key: FeatureKey) => {
     try {
-      return (typeof v === "object" ? JSON.stringify(v) : String(v)).trim();
+      // @ts-ignore
+      const renderValue = typeof featInfo?.[key]?.renderValue === "function" ? featInfo[key].renderValue : undefined;
+      const retVal = (typeof v === "object" ? JSON.stringify(v) : String(v)).trim();
+      return renderValue ? renderValue(retVal) : retVal;
     }
     catch(_e) {
       // because stringify throws on circular refs
@@ -304,7 +307,7 @@ async function addCfgMenu() {
     featuresCont.appendChild(catHeaderElem);
 
     for(const featKey in featObj) {
-      const ftInfo = featInfo[featKey as keyof typeof featureCfg] as FeatureInfo[keyof typeof featureCfg];
+      const ftInfo = featInfo[featKey as FeatureKey] as FeatureInfo[keyof typeof featureCfg];
 
       if(!ftInfo || ("hidden" in ftInfo && ftInfo.hidden === true))
         continue;
@@ -315,7 +318,7 @@ async function addCfgMenu() {
       const { type, default: ftDefault } = ftInfo;
 
       const step = "step" in ftInfo ? ftInfo.step : undefined;
-      const val = featureCfg[featKey as keyof typeof featureCfg];
+      const val = featureCfg[featKey as FeatureKey];
 
       const initialVal = val ?? ftDefault ?? undefined;
 
@@ -326,7 +329,7 @@ async function addCfgMenu() {
         const featLeftSideElem = document.createElement("div");
         featLeftSideElem.classList.add("bytm-ftitem-leftside");
         if(getFeatures().advancedMode) {
-          const defVal = fmtVal(ftDefault);
+          const defVal = fmtVal(ftDefault, featKey as FeatureKey);
           const extraTxts = [
             `default: ${defVal.length === 0 ? "(undefined)" : defVal}`,
           ];
@@ -508,11 +511,11 @@ async function addCfgMenu() {
           if(type === "slider") {
             labelElem = document.createElement("label");
             labelElem.classList.add("bytm-ftconf-label", "bytm-slider-label");
-            labelElem.textContent = `${fmtVal(initialVal)}${unitTxt}`;
+            labelElem.textContent = `${fmtVal(initialVal, featKey as FeatureKey)}${unitTxt}`;
 
             inputElem.addEventListener("input", () => {
               if(labelElem && lastDisplayedVal !== inputElem.value) {
-                labelElem.textContent = `${fmtVal(inputElem.value)}${unitTxt}`;
+                labelElem.textContent = `${fmtVal(inputElem.value, featKey as FeatureKey)}${unitTxt}`;
                 lastDisplayedVal = inputElem.value;
               }
             });
@@ -664,7 +667,7 @@ async function addCfgMenu() {
           )
       );
       if(ftInfo.type === "slider")
-        labelElem.textContent = `${fmtVal(Number(value))}${unitTxt}`;
+        labelElem.textContent = `${fmtVal(Number(value), ftKey as FeatureKey)}${unitTxt}`;
     }
     info("Rebuilt config menu");
   });

+ 4 - 0
src/types.ts

@@ -302,6 +302,8 @@ export type FeatureInfo = Record<
     helpText?: string | (() => string);
     /** Whether the value should be hidden in the config menu and from plugins */
     valueHidden?: boolean;
+    /** Transformation function called before the value is rendered in the config menu */
+    renderValue?: (value: string) => string | Promise<string>;
     /** HTML string that is appended to the end of a feature's text description */
     textAdornment?: () => (Promise<string | undefined> | string | undefined);
 
@@ -332,6 +334,8 @@ export interface FeatureConfig {
   thumbnailOverlayToggleBtnShown: boolean;
   /** Whether to show an indicator on the thumbnail overlay when it is active */
   thumbnailOverlayShowIndicator: boolean;
+  /** The opacity of the thumbnail overlay indicator element */
+  thumbnailOverlayIndicatorOpacity: number;
   /** How to fit the thumbnail overlay image */
   thumbnailOverlayImageFit: "cover" | "contain" | "fill";
   /** Hide the cursor when it's idling on the video element for a while */