Sven před 1 rokem
rodič
revize
292cd3516e
1 změnil soubory, kde provedl 110 přidání a 57 odebrání
  1. 110 57
      dist/BetterYTM.user.js

+ 110 - 57
dist/BetterYTM.user.js

@@ -17,7 +17,7 @@
 // @license           AGPL-3.0-only
 // @author            Sv443
 // @copyright         Sv443 (https://github.com/Sv443)
-// @icon              https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/logo/logo_48.png?b=2dc2045
+// @icon              https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/logo/logo_48.png?b=51dd3bb
 // @match             https://music.youtube.com/*
 // @match             https://www.youtube.com/*
 // @run-at            document-start
@@ -34,35 +34,35 @@
 // @grant             GM.xmlHttpRequest
 // @grant             unsafeWindow
 // @noframes
-// @resource          css-anchor_improvements https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/style/anchorImprovements.css?b=2dc2045
-// @resource          css-fix_spacing         https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/style/fixSpacing.css?b=2dc2045
-// @resource          doc-changelog           https://raw.githubusercontent.com/Sv443/BetterYTM/develop/changelog.md?b=2dc2045
-// @resource          icon-advanced_mode      https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/plus_circle_small.svg?b=2dc2045
-// @resource          icon-arrow_down         https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/arrow_down.svg?b=2dc2045
-// @resource          icon-delete             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/delete.svg?b=2dc2045
-// @resource          icon-error              https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/error.svg?b=2dc2045
-// @resource          icon-experimental       https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/beaker_small.svg?b=2dc2045
-// @resource          icon-globe              https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/globe.svg?b=2dc2045
-// @resource          icon-help               https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/help.svg?b=2dc2045
-// @resource          icon-lock               https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/lock.svg?b=2dc2045
-// @resource          icon-lyrics             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/lyrics.svg?b=2dc2045
-// @resource          icon-skip_to            https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/skip_to.svg?b=2dc2045
-// @resource          icon-spinner            https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/spinner.svg?b=2dc2045
-// @resource          img-logo                https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/logo/logo_48.png?b=2dc2045
-// @resource          img-close               https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/close.png?b=2dc2045
-// @resource          img-discord             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/external/discord.png?b=2dc2045
-// @resource          img-github              https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/external/github.png?b=2dc2045
-// @resource          img-greasyfork          https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/external/greasyfork.png?b=2dc2045
-// @resource          img-openuserjs          https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/external/openuserjs.png?b=2dc2045
-// @resource          trans-de_DE             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/de_DE.json?b=2dc2045
-// @resource          trans-en_US             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/en_US.json?b=2dc2045
-// @resource          trans-en_UK             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/en_UK.json?b=2dc2045
-// @resource          trans-es_ES             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/es_ES.json?b=2dc2045
-// @resource          trans-fr_FR             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/fr_FR.json?b=2dc2045
-// @resource          trans-hi_IN             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/hi_IN.json?b=2dc2045
-// @resource          trans-ja_JA             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/ja_JA.json?b=2dc2045
-// @resource          trans-pt_BR             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/pt_BR.json?b=2dc2045
-// @resource          trans-zh_CN             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/zh_CN.json?b=2dc2045
+// @resource          css-anchor_improvements https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/style/anchorImprovements.css?b=51dd3bb
+// @resource          css-fix_spacing         https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/style/fixSpacing.css?b=51dd3bb
+// @resource          doc-changelog           https://raw.githubusercontent.com/Sv443/BetterYTM/develop/changelog.md?b=51dd3bb
+// @resource          icon-advanced_mode      https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/plus_circle_small.svg?b=51dd3bb
+// @resource          icon-arrow_down         https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/arrow_down.svg?b=51dd3bb
+// @resource          icon-delete             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/delete.svg?b=51dd3bb
+// @resource          icon-error              https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/error.svg?b=51dd3bb
+// @resource          icon-experimental       https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/beaker_small.svg?b=51dd3bb
+// @resource          icon-globe              https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/globe.svg?b=51dd3bb
+// @resource          icon-help               https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/help.svg?b=51dd3bb
+// @resource          icon-lock               https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/lock.svg?b=51dd3bb
+// @resource          icon-lyrics             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/lyrics.svg?b=51dd3bb
+// @resource          icon-skip_to            https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/skip_to.svg?b=51dd3bb
+// @resource          icon-spinner            https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/icons/spinner.svg?b=51dd3bb
+// @resource          img-logo                https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/logo/logo_48.png?b=51dd3bb
+// @resource          img-close               https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/close.png?b=51dd3bb
+// @resource          img-discord             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/external/discord.png?b=51dd3bb
+// @resource          img-github              https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/external/github.png?b=51dd3bb
+// @resource          img-greasyfork          https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/external/greasyfork.png?b=51dd3bb
+// @resource          img-openuserjs          https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/images/external/openuserjs.png?b=51dd3bb
+// @resource          trans-de_DE             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/de_DE.json?b=51dd3bb
+// @resource          trans-en_US             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/en_US.json?b=51dd3bb
+// @resource          trans-en_UK             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/en_UK.json?b=51dd3bb
+// @resource          trans-es_ES             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/es_ES.json?b=51dd3bb
+// @resource          trans-fr_FR             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/fr_FR.json?b=51dd3bb
+// @resource          trans-hi_IN             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/hi_IN.json?b=51dd3bb
+// @resource          trans-ja_JA             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/ja_JA.json?b=51dd3bb
+// @resource          trans-pt_BR             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/pt_BR.json?b=51dd3bb
+// @resource          trans-zh_CN             https://raw.githubusercontent.com/Sv443/BetterYTM/develop/assets/translations/zh_CN.json?b=51dd3bb
 // @require           https://cdn.jsdelivr.net/npm/@sv443-network/[email protected]/dist/index.global.js
 // @require           https://cdn.jsdelivr.net/npm/[email protected]/dist/fuse.basic.js
 // @require           https://cdn.jsdelivr.net/npm/[email protected]/lib/marked.umd.js
@@ -239,7 +239,7 @@ var LogLevel;
 })(LogLevel || (LogLevel = {}));const modeRaw = "development";
 const branchRaw = "develop";
 const hostRaw = "github";
-const buildNumberRaw = "2dc2045";
+const buildNumberRaw = "51dd3bb";
 /** The mode in which the script was built (production or development) */
 const mode = (modeRaw.match(/^#{{.+}}$/) ? "production" : modeRaw);
 /** The branch to use in various URLs that point to the GitHub repo */
@@ -679,15 +679,18 @@ function getLyricsCacheEntry(artist, song, refreshEntry = true) {
         updateLyricsCacheEntry(artist, song);
     return entry;
 }
+/** Updates the "last viewed" timestamp of the cache entry for the passed artist and song */
 function updateLyricsCacheEntry(artist, song) {
     const { cache } = lyricsCacheMgr.getData();
     const idx = cache.findIndex(e => e.artist === artist && e.song === song);
     if (idx !== -1) {
         const newEntry = cache.splice(idx, 1)[0];
         newEntry.viewed = Date.now();
+        log("Updating cache entry for", artist, "-", song, "to", newEntry);
         lyricsCacheMgr.setData({ cache: [newEntry, ...cache] });
     }
 }
+/** Deletes the cache entry for the passed artist and song */
 function deleteLyricsCacheEntry(artist, song) {
     const { cache } = lyricsCacheMgr.getData();
     const idx = cache.findIndex(e => e.artist === artist && e.song === song);
@@ -705,6 +708,27 @@ function clearLyricsCache() {
 function getLyricsCache() {
     return lyricsCacheMgr.getData().cache;
 }
+/**
+ * Adds the provided "best" (non-penalized) entry into the lyrics URL cache, synchronously to RAM and asynchronously to GM storage
+ * {@linkcode artist} and {@linkcode song} need to be sanitized first!
+ */
+function addLyricsCacheEntryBest(artist, song, url) {
+    // refresh entry if it exists and don't overwrite / duplicate it
+    const cachedEntry = getLyricsCacheEntry(artist, song, true);
+    if (cachedEntry)
+        return;
+    const { cache } = lyricsCacheMgr.getData();
+    const entry = {
+        artist, song, url, viewed: Date.now(), added: Date.now(),
+    };
+    cache.push(entry);
+    cache.sort((a, b) => b.viewed - a.viewed);
+    if (cache.length > getFeatures().lyricsCacheMaxSize)
+        cache.pop();
+    log("Added cache entry for best result", artist, "-", song, "\n", entry);
+    emitInterface("bytm:lyricsCacheEntryAdded", { entry, type: "best" });
+    return lyricsCacheMgr.setData({ cache });
+}
 /**
  * Adds the provided entry into the lyrics URL cache, synchronously to RAM and asynchronously to GM storage
  * Also adds a penalty to the viewed timestamp and added timestamp to decrease entry's lifespan in cache
@@ -713,6 +737,10 @@ function getLyricsCache() {
  * @param penaltyFr Fraction to remove from the timestamp values - has to be between 0 and 1 - default is 0 (no penalty) - (0.25 = only penalized by a quarter of the predefined max penalty)
  */
 function addLyricsCacheEntryPenalized(artist, song, url, penaltyFr = 0) {
+    // refresh entry if it exists and don't overwrite / duplicate it
+    const cachedEntry = getLyricsCacheEntry(artist, song, true);
+    if (cachedEntry)
+        return;
     const { cache } = lyricsCacheMgr.getData();
     penaltyFr = UserUtils.clamp(penaltyFr, 0, 1);
     const viewedPenalty = maxViewedPenalty * penaltyFr;
@@ -728,6 +756,7 @@ function addLyricsCacheEntryPenalized(artist, song, url, penaltyFr = 0) {
     cache.sort((a, b) => b.viewed - a.viewed);
     if (cache.length > getFeatures().lyricsCacheMaxSize)
         cache.pop();
+    log("Added penalized cache entry for", artist, "-", song, "with penalty fraction", penaltyFr, "\n", entry);
     emitInterface("bytm:lyricsCacheEntryAdded", { entry, type: "penalized" });
     return lyricsCacheMgr.setData({ cache });
 }let createNanoEvents = () => ({
@@ -2144,7 +2173,7 @@ function addCfgMenu() {
         versionEl.role = "button";
         versionEl.tabIndex = 0;
         versionEl.ariaLabel = versionEl.title = t("version_tooltip", scriptInfo.version, buildNumber);
-        versionEl.textContent = `v${scriptInfo.version} (${buildNumber})${mode === "development" ? " [dev build]" : ""}`;
+        versionEl.textContent = `v${scriptInfo.version} (${buildNumber})${mode === "development" ? " [DEV]" : ""}`;
         const versionElemClicked = (e) => __awaiter(this, void 0, void 0, function* () {
             e.preventDefault();
             e.stopPropagation();
@@ -3234,7 +3263,8 @@ function addScrollToActiveBtn() {
             }),
         });
     });
-}let features$1;
+}const inputIgnoreTagNames = ["INPUT", "TEXTAREA", "SELECT", "BUTTON", "A"];
+let features$1;
 function setInputConfig(feats) {
     features$1 = feats;
 }
@@ -3246,7 +3276,7 @@ function initArrowKeySkip() {
             if (!["ArrowLeft", "ArrowRight"].includes(evt.code))
                 return;
             // discard the event when a (text) input is currently active, like when editing a playlist
-            if (["INPUT", "TEXTAREA", "SELECT"].includes((_b = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.tagName) !== null && _b !== void 0 ? _b : "_"))
+            if (inputIgnoreTagNames.includes((_b = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.tagName) !== null && _b !== void 0 ? _b : ""))
                 return info(`Captured valid key to skip forward or backward but the current active element is <${(_c = document.activeElement) === null || _c === void 0 ? void 0 : _c.tagName.toLowerCase()}>, so the keypress is ignored`);
             evt.preventDefault();
             evt.stopImmediatePropagation();
@@ -3316,6 +3346,8 @@ function switchSite(newDomain) {
     });
 }
 //#MARKER number keys skip to time
+const numKeysIgnoreTagNames = [...inputIgnoreTagNames, "TP-YT-PAPER-TAB"];
+const numKeysIgnoreIds = ["progress-bar", "song-media-window"];
 /** Adds the ability to skip to a certain time in the video by pressing a number key (0-9) */
 function initNumKeysSkip() {
     return __awaiter(this, void 0, void 0, function* () {
@@ -3325,11 +3357,12 @@ function initNumKeysSkip() {
                 return;
             if (isCfgMenuOpen)
                 return;
-            // discard the event when a (text) input is currently active, like when editing a playlist or when the search bar is focused
-            if (document.activeElement !== document.body
-                && !["progress-bar"].includes((_b = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : "_")
-                && !["BUTTON", "A"].includes((_d = (_c = document.activeElement) === null || _c === void 0 ? void 0 : _c.tagName) !== null && _d !== void 0 ? _d : "_"))
-                return info("Captured valid key to skip video to but an unexpected element is focused, so the keypress is ignored");
+            // discard the event when an unexpected element is currently active or in focus, like when editing a playlist or when the search bar is focused
+            if (document.activeElement !== document.body // short-circuit if nothing is active
+                && !numKeysIgnoreIds.includes((_b = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : "") // video element or player bar active
+                && !numKeysIgnoreTagNames.includes((_d = (_c = document.activeElement) === null || _c === void 0 ? void 0 : _c.tagName) !== null && _d !== void 0 ? _d : "") // other element active
+            )
+                return info("Captured valid key to skip video to, but ignored it since an unexpected element is active:", document.activeElement);
             const vidElem = document.querySelector(videoSelector);
             if (!vidElem)
                 return warn("Could not find video element, so the keypress is ignored");
@@ -3568,12 +3601,15 @@ function fetchLyricsUrls(artist, song) {
                     url,
                 });
             });
-            if (!getFeatures().advancedLyricsFilter)
+            if (!getFeatures().advancedLyricsFilter) {
+                const topRes = allResultsSan[0];
+                topRes && addLyricsCacheEntryBest(topRes.meta.artists, topRes.meta.title, topRes.url);
                 return allResultsSan.map(r => ({
                     artist: r.meta.primaryArtist.name,
                     song: r.meta.title,
                     url: r.url,
                 }));
+            }
             const exactish = (input) => input.toLowerCase()
                 .replace(/[\s\-_&,.()[\]]+/gm, "");
             // exact-ish matches, best matching one first
@@ -3618,7 +3654,7 @@ function fetchLyricsUrls(artist, song) {
             ].slice(0, 5);
             // add top 3 results to the cache with a penalty to their time to live
             // so every entry is deleted faster if it's not considered as relevant
-            finalResults.slice(1, 3).forEach(({ meta: { artists, title }, url }, i) => {
+            finalResults.slice(0, 3).forEach(({ meta: { artists, title }, url }, i) => {
                 const penaltyFraction = hasExactMatch
                     // if there's an exact match, give it 0 penalty and penalize all other results with the full value
                     ? i === 0 ? 0 : 1
@@ -3914,17 +3950,20 @@ const adornments = {
  * **Optional props:**
  * | Property | Description |
  * | :-- | :-- |
- * | `disable(newValue: any)`                    | for type `toggle` only - function that will be called when the feature is disabled - can be a synchronous or asynchronous function |
- * | `change(prevValue: any, newValue: any)`     | for types `number`, `select`, `slider` and `hotkey` only - function that will be called when the value is changed |
- * | `click: () => void`                         | for type `button` only - function that will be called when the button is clicked |
- * | `helpText(): string / () => string`         | function that returns an HTML string or the literal string itself that will be the help text for this feature - writing as function is useful for pluralizing or inserting values into the translation at runtime - if not set, translation with key `feature_helptext_featureKey` will be used instead, if available |
- * | `textAdornment(): string / Promise<string>` | function that returns an HTML string that will be appended to the text in the config menu as an adornment element - TODO: to be replaced in the big menu rework |
- * | `advanced`                                  | if true, the feature will only be shown if the advanced mode feature has been turned on |
- * | `hidden`                                    | if true, the feature will not be shown in the settings - default is undefined (false) |
- * | `min`                                       | Only if type is `number` or `slider` - Overwrites the default of the `min` property of the HTML input element |
- * | `max`                                       | Only if type is `number` or `slider` - Overwrites the default of the `max` property of the HTML input element |
- * | `step`                                      | Only if type is `number` or `slider` - Overwrites the default of the `step` property of the HTML input element |
- * | `unit: string / (val: number) => string`    | Only if type is `number` or `slider` - The unit text that is displayed next to the input element, i.e. "px" |
+ * | `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 |
+ * | `change: (prevValue: any, newValue: any)` => void | for types `number`, `select`, `slider` and `hotkey` only - function that will be called when the value is changed |
+ * | `click: () => void`                               | for type `button` only - function that will be called when the button is clicked |
+ * | `helpText: string / () => string`                 | function that returns an HTML string or the literal string itself that will be the help text for this feature - writing as function is useful for pluralizing or inserting values into the translation at runtime - if not set, translation with key `feature_helptext_featureKey` will be used instead, if available |
+ * | `textAdornment: () => string / Promise<string>`   | function that returns an HTML string that will be appended to the text in the config menu as an adornment element - TODO: to be replaced in the big menu rework |
+ * | `unit: string / (val: number) => string`          | Only if type is `number` or `slider` - The unit text that is displayed next to the input element, i.e. "px" |
+ * | `min: number`                                     | Only if type is `number` or `slider` - Overwrites the default of the `min` property of the HTML input element |
+ * | `max: number`                                     | Only if type is `number` or `slider` - Overwrites the default of the `max` property of the HTML input element |
+ * | `step: number`                                    | Only if type is `number` or `slider` - Overwrites the default of the `step` property of the HTML input element |
+ * | `options: SelectOption[] / () => SelectOption[]`  | Only if type is `select` - function that returns an array of objects with `value` and `label` properties |
+ * | `advanced: boolean`                               | if true, the feature will only be shown if the advanced mode feature has been turned on |
+ * | `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 |
  *
  * **Notes:**
  * - If no `disable()` or `change()` function is present, the page needs to be reloaded for the changes to take effect
@@ -4570,9 +4609,9 @@ function resourceToHTMLString(resource) {
         }
     });
 }
-/** Parses a markdown string and turns it into an HTML string - doesn't sanitize against XSS! */
-function parseMarkdown(md) {
-    return marked.marked.parse(md, {
+/** Parses a markdown string using marked and turns it into an HTML string with default settings - doesn't sanitize against XSS! */
+function parseMarkdown(mdString) {
+    return marked.marked.parse(mdString, {
         async: true,
         gfm: true,
     });
@@ -4603,7 +4642,7 @@ function getChangelogHtmlWithDetails() {
             return changelogHtml;
         }
         catch (err) {
-            return `Error: ${err}`;
+            return `Error while preparing changelog: ${err}`;
         }
     });
 }const selectorMap = new Map();
@@ -5728,7 +5767,7 @@ hr {
 }
 
 #bytm-cfg-menu-bg .bytm-menu-title {
-  transform: translate(0px, -5px);
+  transform: translate(0px, -6px);
 }
 
 #bytm-menu-subtitle-cont {
@@ -6545,6 +6584,20 @@ function registerMenuCommands() {
             }
             console.log(`Showing currently active listeners for ${Object.keys(observers$1).length} observers with ${listenersAmt} total listeners:\n${lines.join("\n")}`);
         }), "s");
+        GM.registerMenuCommand("Compress value", () => __awaiter(this, void 0, void 0, function* () {
+            const input = prompt("Enter the value to compress.\nSee console for output.");
+            if (input && input.length > 0) {
+                const compressed = yield UserUtils.compress(input, compressionFormat);
+                console.log(`Compression result (${input.length} chars -> ${compressed.length} chars)\nValue: ${compressed}`);
+            }
+        }));
+        GM.registerMenuCommand("Decompress value", () => __awaiter(this, void 0, void 0, function* () {
+            const input = prompt("Enter the value to decompress.\nSee console for output.");
+            if (input && input.length > 0) {
+                const decompressed = yield UserUtils.decompress(input, compressionFormat);
+                console.log(`Decompresion result (${input.length} chars -> ${decompressed.length} chars)\nValue: ${decompressed}`);
+            }
+        }));
     }
 }
 preInit();})(UserUtils,marked,Fuse);//# sourceMappingURL=http://localhost:8710/BetterYTM.user.js.map