Răsfoiți Sursa

feat: add advanced settings

Sv443 1 an în urmă
părinte
comite
ba81557a97
8 a modificat fișierele cu 246 adăugiri și 72 ștergeri
  1. 114 16
      assets/translations/README.md
  2. 17 2
      assets/translations/en_US.json
  3. 2 0
      src/config.ts
  4. 27 3
      src/features/index.ts
  5. 22 12
      src/features/lyrics.ts
  6. 6 5
      src/index.ts
  7. 16 2
      src/menu/menu_old.ts
  8. 42 32
      src/types.ts

+ 114 - 16
assets/translations/README.md

@@ -6,15 +6,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) | 137 (default locale) |  |
-| [`de_DE`](./de_DE.json) | 🚫 `125/137` (91.2%) | ─ |
-| [`en_UK`](./en_UK.json) | ✅ `137/137` (100.0%) | `en_US` |
-| [`es_ES`](./es_ES.json) | 🚫 `125/137` (91.2%) | ─ |
-| [`fr_FR`](./fr_FR.json) | 🚫 `125/137` (91.2%) | ─ |
-| [`hi_IN`](./hi_IN.json) | 🚫 `125/137` (91.2%) | ─ |
-| [`ja_JA`](./ja_JA.json) | 🚫 `125/137` (91.2%) | ─ |
-| [`pt_BR`](./pt_BR.json) | 🚫 `125/137` (91.2%) | ─ |
-| [`zh_CN`](./zh_CN.json) | 🚫 `125/137` (91.2%) | ─ |
+| [`en_US`](./en_US.json) | 151 (default locale) |  |
+| [`de_DE`](./de_DE.json) | 🚫 `125/151` (82.8%) | ─ |
+| [`en_UK`](./en_UK.json) | ✅ `151/151` (100.0%) | `en_US` |
+| [`es_ES`](./es_ES.json) | 🚫 `125/151` (82.8%) | ─ |
+| [`fr_FR`](./fr_FR.json) | 🚫 `125/151` (82.8%) | ─ |
+| [`hi_IN`](./hi_IN.json) | 🚫 `125/151` (82.8%) | ─ |
+| [`ja_JA`](./ja_JA.json) | 🚫 `125/151` (82.8%) | ─ |
+| [`pt_BR`](./pt_BR.json) | 🚫 `125/151` (82.8%) | ─ |
+| [`zh_CN`](./zh_CN.json) | 🚫 `125/151` (82.8%) | ─ |
 
 <br>
 
@@ -25,10 +25,14 @@ This means you need to manually check against the base translations for missing
 
 ### Missing keys:
 
-<details><summary><code>de_DE</code> - 12 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>de_DE</code> - 26 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `trigger_btn_action` | `Trigger` |
+| `lyrics_clear_cache_confirm_prompt-1` | `The lyrics cache currently has %1 entry.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_confirm_prompt-n` | `The lyrics cache currently has %1 entries.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_success` | `Lyrics cache was cleared successfully.` |
 | `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
@@ -41,13 +45,27 @@ This means you need to manually check against the base translations for missing
 | `unit_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
+| `advanced_feature_desc_template` | `[Advanced] %1` |
+| `feature_desc_lyricsCacheMaxSize` | `Maximum amount of lyrics to keep in the cache` |
+| `feature_helptext_lyricsCacheMaxSize` | `The lyrics of songs you listen to are stored in a cache to reduce the amount of requests to the lyrics provider.\nThis feature allows you to set the maximum amount of lyrics to keep in the cache.\nWhen the limit is reached, the entry that was used last will be removed to make space for any new ones.` |
+| `feature_desc_lyricsCacheTTL` | `Max amount of days to keep a lyrics entry in the cache` |
+| `feature_helptext_lyricsCacheTTL` | `The cache that lyrics are stored in will automatically delete them after this amount of time to ensure that updates to the source are being fetched sooner or later.\nIf you wanna make sure that you always have the most recent lyrics, set this to a low value like 4 days.` |
+| `feature_desc_clearLyricsCache` | `Clear the lyrics cache manually` |
+| `feature_helptext_clearLyricsCache` | `If the lyrics that are in the local cache are outdated or you just want to free up some space, you can clear the cache manually by pressing this button.` |
+| `feature_btn_clearLyricsCache` | `Clear cache` |
+| `feature_desc_advancedMode` | `Show advanced settings (after reload)` |
+| `feature_helptext_advancedMode` | `Show advanced settings in the configuration menu after reloading the page.\nThis is useful if you want to more deeply customize the script's behavior.` |
 
 <br></details>
 
-<details><summary><code>es_ES</code> - 12 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>es_ES</code> - 26 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `trigger_btn_action` | `Trigger` |
+| `lyrics_clear_cache_confirm_prompt-1` | `The lyrics cache currently has %1 entry.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_confirm_prompt-n` | `The lyrics cache currently has %1 entries.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_success` | `Lyrics cache was cleared successfully.` |
 | `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
@@ -60,13 +78,27 @@ This means you need to manually check against the base translations for missing
 | `unit_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
+| `advanced_feature_desc_template` | `[Advanced] %1` |
+| `feature_desc_lyricsCacheMaxSize` | `Maximum amount of lyrics to keep in the cache` |
+| `feature_helptext_lyricsCacheMaxSize` | `The lyrics of songs you listen to are stored in a cache to reduce the amount of requests to the lyrics provider.\nThis feature allows you to set the maximum amount of lyrics to keep in the cache.\nWhen the limit is reached, the entry that was used last will be removed to make space for any new ones.` |
+| `feature_desc_lyricsCacheTTL` | `Max amount of days to keep a lyrics entry in the cache` |
+| `feature_helptext_lyricsCacheTTL` | `The cache that lyrics are stored in will automatically delete them after this amount of time to ensure that updates to the source are being fetched sooner or later.\nIf you wanna make sure that you always have the most recent lyrics, set this to a low value like 4 days.` |
+| `feature_desc_clearLyricsCache` | `Clear the lyrics cache manually` |
+| `feature_helptext_clearLyricsCache` | `If the lyrics that are in the local cache are outdated or you just want to free up some space, you can clear the cache manually by pressing this button.` |
+| `feature_btn_clearLyricsCache` | `Clear cache` |
+| `feature_desc_advancedMode` | `Show advanced settings (after reload)` |
+| `feature_helptext_advancedMode` | `Show advanced settings in the configuration menu after reloading the page.\nThis is useful if you want to more deeply customize the script's behavior.` |
 
 <br></details>
 
-<details><summary><code>fr_FR</code> - 12 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>fr_FR</code> - 26 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `trigger_btn_action` | `Trigger` |
+| `lyrics_clear_cache_confirm_prompt-1` | `The lyrics cache currently has %1 entry.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_confirm_prompt-n` | `The lyrics cache currently has %1 entries.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_success` | `Lyrics cache was cleared successfully.` |
 | `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
@@ -79,13 +111,27 @@ This means you need to manually check against the base translations for missing
 | `unit_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
+| `advanced_feature_desc_template` | `[Advanced] %1` |
+| `feature_desc_lyricsCacheMaxSize` | `Maximum amount of lyrics to keep in the cache` |
+| `feature_helptext_lyricsCacheMaxSize` | `The lyrics of songs you listen to are stored in a cache to reduce the amount of requests to the lyrics provider.\nThis feature allows you to set the maximum amount of lyrics to keep in the cache.\nWhen the limit is reached, the entry that was used last will be removed to make space for any new ones.` |
+| `feature_desc_lyricsCacheTTL` | `Max amount of days to keep a lyrics entry in the cache` |
+| `feature_helptext_lyricsCacheTTL` | `The cache that lyrics are stored in will automatically delete them after this amount of time to ensure that updates to the source are being fetched sooner or later.\nIf you wanna make sure that you always have the most recent lyrics, set this to a low value like 4 days.` |
+| `feature_desc_clearLyricsCache` | `Clear the lyrics cache manually` |
+| `feature_helptext_clearLyricsCache` | `If the lyrics that are in the local cache are outdated or you just want to free up some space, you can clear the cache manually by pressing this button.` |
+| `feature_btn_clearLyricsCache` | `Clear cache` |
+| `feature_desc_advancedMode` | `Show advanced settings (after reload)` |
+| `feature_helptext_advancedMode` | `Show advanced settings in the configuration menu after reloading the page.\nThis is useful if you want to more deeply customize the script's behavior.` |
 
 <br></details>
 
-<details><summary><code>hi_IN</code> - 12 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>hi_IN</code> - 26 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `trigger_btn_action` | `Trigger` |
+| `lyrics_clear_cache_confirm_prompt-1` | `The lyrics cache currently has %1 entry.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_confirm_prompt-n` | `The lyrics cache currently has %1 entries.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_success` | `Lyrics cache was cleared successfully.` |
 | `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
@@ -98,13 +144,27 @@ This means you need to manually check against the base translations for missing
 | `unit_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
+| `advanced_feature_desc_template` | `[Advanced] %1` |
+| `feature_desc_lyricsCacheMaxSize` | `Maximum amount of lyrics to keep in the cache` |
+| `feature_helptext_lyricsCacheMaxSize` | `The lyrics of songs you listen to are stored in a cache to reduce the amount of requests to the lyrics provider.\nThis feature allows you to set the maximum amount of lyrics to keep in the cache.\nWhen the limit is reached, the entry that was used last will be removed to make space for any new ones.` |
+| `feature_desc_lyricsCacheTTL` | `Max amount of days to keep a lyrics entry in the cache` |
+| `feature_helptext_lyricsCacheTTL` | `The cache that lyrics are stored in will automatically delete them after this amount of time to ensure that updates to the source are being fetched sooner or later.\nIf you wanna make sure that you always have the most recent lyrics, set this to a low value like 4 days.` |
+| `feature_desc_clearLyricsCache` | `Clear the lyrics cache manually` |
+| `feature_helptext_clearLyricsCache` | `If the lyrics that are in the local cache are outdated or you just want to free up some space, you can clear the cache manually by pressing this button.` |
+| `feature_btn_clearLyricsCache` | `Clear cache` |
+| `feature_desc_advancedMode` | `Show advanced settings (after reload)` |
+| `feature_helptext_advancedMode` | `Show advanced settings in the configuration menu after reloading the page.\nThis is useful if you want to more deeply customize the script's behavior.` |
 
 <br></details>
 
-<details><summary><code>ja_JA</code> - 12 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>ja_JA</code> - 26 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `trigger_btn_action` | `Trigger` |
+| `lyrics_clear_cache_confirm_prompt-1` | `The lyrics cache currently has %1 entry.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_confirm_prompt-n` | `The lyrics cache currently has %1 entries.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_success` | `Lyrics cache was cleared successfully.` |
 | `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
@@ -117,13 +177,27 @@ This means you need to manually check against the base translations for missing
 | `unit_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
+| `advanced_feature_desc_template` | `[Advanced] %1` |
+| `feature_desc_lyricsCacheMaxSize` | `Maximum amount of lyrics to keep in the cache` |
+| `feature_helptext_lyricsCacheMaxSize` | `The lyrics of songs you listen to are stored in a cache to reduce the amount of requests to the lyrics provider.\nThis feature allows you to set the maximum amount of lyrics to keep in the cache.\nWhen the limit is reached, the entry that was used last will be removed to make space for any new ones.` |
+| `feature_desc_lyricsCacheTTL` | `Max amount of days to keep a lyrics entry in the cache` |
+| `feature_helptext_lyricsCacheTTL` | `The cache that lyrics are stored in will automatically delete them after this amount of time to ensure that updates to the source are being fetched sooner or later.\nIf you wanna make sure that you always have the most recent lyrics, set this to a low value like 4 days.` |
+| `feature_desc_clearLyricsCache` | `Clear the lyrics cache manually` |
+| `feature_helptext_clearLyricsCache` | `If the lyrics that are in the local cache are outdated or you just want to free up some space, you can clear the cache manually by pressing this button.` |
+| `feature_btn_clearLyricsCache` | `Clear cache` |
+| `feature_desc_advancedMode` | `Show advanced settings (after reload)` |
+| `feature_helptext_advancedMode` | `Show advanced settings in the configuration menu after reloading the page.\nThis is useful if you want to more deeply customize the script's behavior.` |
 
 <br></details>
 
-<details><summary><code>pt_BR</code> - 12 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>pt_BR</code> - 26 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `trigger_btn_action` | `Trigger` |
+| `lyrics_clear_cache_confirm_prompt-1` | `The lyrics cache currently has %1 entry.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_confirm_prompt-n` | `The lyrics cache currently has %1 entries.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_success` | `Lyrics cache was cleared successfully.` |
 | `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
@@ -136,13 +210,27 @@ This means you need to manually check against the base translations for missing
 | `unit_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
+| `advanced_feature_desc_template` | `[Advanced] %1` |
+| `feature_desc_lyricsCacheMaxSize` | `Maximum amount of lyrics to keep in the cache` |
+| `feature_helptext_lyricsCacheMaxSize` | `The lyrics of songs you listen to are stored in a cache to reduce the amount of requests to the lyrics provider.\nThis feature allows you to set the maximum amount of lyrics to keep in the cache.\nWhen the limit is reached, the entry that was used last will be removed to make space for any new ones.` |
+| `feature_desc_lyricsCacheTTL` | `Max amount of days to keep a lyrics entry in the cache` |
+| `feature_helptext_lyricsCacheTTL` | `The cache that lyrics are stored in will automatically delete them after this amount of time to ensure that updates to the source are being fetched sooner or later.\nIf you wanna make sure that you always have the most recent lyrics, set this to a low value like 4 days.` |
+| `feature_desc_clearLyricsCache` | `Clear the lyrics cache manually` |
+| `feature_helptext_clearLyricsCache` | `If the lyrics that are in the local cache are outdated or you just want to free up some space, you can clear the cache manually by pressing this button.` |
+| `feature_btn_clearLyricsCache` | `Clear cache` |
+| `feature_desc_advancedMode` | `Show advanced settings (after reload)` |
+| `feature_helptext_advancedMode` | `Show advanced settings in the configuration menu after reloading the page.\nThis is useful if you want to more deeply customize the script's behavior.` |
 
 <br></details>
 
-<details><summary><code>zh_CN</code> - 12 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>zh_CN</code> - 26 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `trigger_btn_action` | `Trigger` |
+| `lyrics_clear_cache_confirm_prompt-1` | `The lyrics cache currently has %1 entry.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_confirm_prompt-n` | `The lyrics cache currently has %1 entries.\nDo you really want to delete them?` |
+| `lyrics_clear_cache_success` | `Lyrics cache was cleared successfully.` |
 | `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
@@ -155,5 +243,15 @@ This means you need to manually check against the base translations for missing
 | `unit_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
+| `advanced_feature_desc_template` | `[Advanced] %1` |
+| `feature_desc_lyricsCacheMaxSize` | `Maximum amount of lyrics to keep in the cache` |
+| `feature_helptext_lyricsCacheMaxSize` | `The lyrics of songs you listen to are stored in a cache to reduce the amount of requests to the lyrics provider.\nThis feature allows you to set the maximum amount of lyrics to keep in the cache.\nWhen the limit is reached, the entry that was used last will be removed to make space for any new ones.` |
+| `feature_desc_lyricsCacheTTL` | `Max amount of days to keep a lyrics entry in the cache` |
+| `feature_helptext_lyricsCacheTTL` | `The cache that lyrics are stored in will automatically delete them after this amount of time to ensure that updates to the source are being fetched sooner or later.\nIf you wanna make sure that you always have the most recent lyrics, set this to a low value like 4 days.` |
+| `feature_desc_clearLyricsCache` | `Clear the lyrics cache manually` |
+| `feature_helptext_clearLyricsCache` | `If the lyrics that are in the local cache are outdated or you just want to free up some space, you can clear the cache manually by pressing this button.` |
+| `feature_btn_clearLyricsCache` | `Clear cache` |
+| `feature_desc_advancedMode` | `Show advanced settings (after reload)` |
+| `feature_helptext_advancedMode` | `Show advanced settings in the configuration menu after reloading the page.\nThis is useful if you want to more deeply customize the script's behavior.` |
 
 <br></details>

+ 17 - 2
assets/translations/en_US.json

@@ -40,6 +40,7 @@
     "log_level_info": "Info (only important)",
     "toggled_on": "On",
     "toggled_off": "Off",
+    "trigger_btn_action": "Trigger",
     "remove_from_queue": "Remove this song from the queue",
     "delete_from_list": "Delete this song from the list",
     "couldnt_remove_from_queue": "Couldn't remove this song from the queue",
@@ -58,6 +59,9 @@
     "lyrics_rate_limited-n": "You are being rate limited.\nPlease wait %1 seconds before requesting more lyrics.",
     "lyrics_not_found_confirm_open_search": "Couldn't find a lyrics page for this song.\nDo you want to open genius.com to manually search for it?",
     "lyrics_not_found_click_open_search": "Couldn't find lyrics URL - click to open the manual lyrics search",
+    "lyrics_clear_cache_confirm_prompt-1": "The lyrics cache currently has %1 entry.\nDo you really want to delete them?",
+    "lyrics_clear_cache_confirm_prompt-n": "The lyrics cache currently has %1 entries.\nDo you really want to delete them?",
+    "lyrics_clear_cache_success": "Lyrics cache was cleared successfully.",
 
     "hotkey_input_click_to_change": "Click to change",
     "hotkey_input_click_to_change_tooltip": "Click, then press the desired key combination",
@@ -100,6 +104,8 @@
     "unit_days-1": "day",
     "unit_days-n": "days",
 
+    "advanced_feature_desc_template": "[Advanced] %1",
+
     "feature_category_layout": "Layout",
     "feature_category_songLists": "Song Lists",
     "feature_category_behavior": "Behavior",
@@ -146,11 +152,20 @@
     "feature_helptext_anchorImprovements": "Some elements on the page are only clickable with the left mouse button, which means you can't open them in a new tab by middle-clicking or through the context menu using shift + right-click. This feature adds links to a lot of them or enlarges existing ones to make clicking easier.",
 
     "feature_desc_geniusLyrics": "Add a button to the media controls of the currently playing song to open its lyrics on genius.com",
+    "feature_desc_lyricsCacheMaxSize": "Maximum amount of lyrics to keep in the cache",
+    "feature_helptext_lyricsCacheMaxSize": "The lyrics of songs you listen to are stored in a cache to reduce the amount of requests to the lyrics provider.\nThis feature allows you to set the maximum amount of lyrics to keep in the cache.\nWhen the limit is reached, the entry that was used last will be removed to make space for any new ones.",
+    "feature_desc_lyricsCacheTTL": "Max amount of days to keep a lyrics entry in the cache",
+    "feature_helptext_lyricsCacheTTL": "The cache that lyrics are stored in will automatically delete them after this amount of time to ensure that updates to the source are being fetched sooner or later.\nIf you wanna make sure that you always have the most recent lyrics, set this to a low value like 4 days.",
+    "feature_desc_clearLyricsCache": "Clear the lyrics cache manually",
+    "feature_helptext_clearLyricsCache": "If the lyrics that are in the local cache are outdated or you just want to free up some space, you can clear the cache manually by pressing this button.",
+    "feature_btn_clearLyricsCache": "Clear cache",
 
     "feature_desc_locale": "Language",
     "feature_desc_versionCheck": "Check for updates every 24 hours",
     "feature_helptext_versionCheck": "This feature checks for updates every 24 hours, notifies you if a new version is available and allows you to update the script manually.\nIf your userscript manager extension updates scripts automatically, you can disable this feature.",
     "feature_desc_logLevel": "How much information to log to the console",
-    "feature_helptext_logLevel": "Changing this is really only needed for debugging purposes as a result of experiencing a problem.\nShould you have one, you can increase the log level here, open your browser's JavaScript console (usually with Ctrl + Shift + K) and attach screenshots of that log in a GitHub issue."
+    "feature_helptext_logLevel": "Changing this is really only needed for debugging purposes as a result of experiencing a problem.\nShould you have one, you can increase the log level here, open your browser's JavaScript console (usually with Ctrl + Shift + K) and attach screenshots of that log in a GitHub issue.",
+    "feature_desc_advancedMode": "Show advanced settings (after reload)",
+    "feature_helptext_advancedMode": "Show advanced settings in the configuration menu after reloading the page.\nThis is useful if you want to more deeply customize the script's behavior."
   }
-}
+}

+ 2 - 0
src/config.ts

@@ -54,6 +54,8 @@ export const migrations: ConfigMigrationsDict = {
       ...oldData,
       lyricsCacheMaxSize: getFeatureDefault("lyricsCacheMaxSize"),
       lyricsCacheTTL: getFeatureDefault("lyricsCacheTTL"),
+      clearLyricsCache: undefined,
+      advancedMode: getFeatureDefault("advancedMode"),
     };
   },
 };

+ 27 - 3
src/features/index.ts

@@ -1,6 +1,7 @@
 import { getPreferredLocale, resourceToHTMLString, t, tp } from "../utils";
 import langMapping from "../../assets/locales.json" assert { type: "json" };
 import { remSongMinPlayTime } from "./behavior";
+import { clearLyricsCache, getLyricsCache } from "./lyrics";
 import { FeatureInfo } from "../types";
 
 export * from "./layout";
@@ -40,13 +41,14 @@ const localeOptions = Object.entries(langMapping).reduce((a, [locale, { name }])
  * | :-- | :-- |
  * | `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 |
  * | `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`                                      | Only if type is `number` or `slider` - The unit text that is displayed next to the input element, i.e. "px" |
+ * | `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" |
  *   
  * **Notes:**
  * - If no `disable()` or `change()` function is present, the page needs to be reloaded for the changes to take effect
@@ -256,23 +258,38 @@ export const featInfo = {
     type: "slider",
     category: "lyrics",
     default: 500,
-    min: 0,
+    min: 50,
     max: 2000,
     step: 50,
     unit: (val: number) => tp("unit_entries", val),
     enable: () => void "TODO",
     change: () => void "TODO",
+    advanced: true,
   },
   lyricsCacheTTL: {
     type: "slider",
     category: "lyrics",
     default: 21,
-    min: 1,
+    min: 3,
     max: 100,
     step: 1,
     unit: (val: number) => tp("unit_days", val),
     enable: () => void "TODO",
     change: () => void "TODO",
+    advanced: true,
+  },
+  clearLyricsCache: {
+    type: "button",
+    category: "lyrics",
+    default: undefined,
+    click() {
+      const entries = getLyricsCache().length;
+      if(confirm(tp("lyrics_clear_cache_confirm_prompt", entries, entries))) {
+        clearLyricsCache();
+        alert(t("lyrics_clear_cache_success"));
+      }
+    },
+    advanced: true,
   },
 
   //#SECTION general
@@ -302,4 +319,11 @@ export const featInfo = {
     default: 1,
     enable: () => void "TODO",
   },
+  advancedMode: {
+    type: "toggle",
+    category: "general",
+    default: false,
+    enable: () => void "TODO",
+    disable: () => void "TODO",
+  },
 } as const satisfies FeatureInfo;

+ 22 - 12
src/features/lyrics.ts

@@ -21,7 +21,7 @@ export type LyricsCache = {
 
 let canCompress = true;
 
-const lyricsCache = new ConfigManager<LyricsCache>({
+const lyricsCacheMgr = new ConfigManager<LyricsCache>({
   id: "bytm-lyrics-cache",
   defaultConfig: {
     cache: [],
@@ -33,7 +33,7 @@ const lyricsCache = new ConfigManager<LyricsCache>({
 
 export async function initLyricsCache() {
   canCompress = await compressionSupported();
-  const data = await lyricsCache.loadData();
+  const data = await lyricsCacheMgr.loadData();
   log(`Loaded lyrics cache (${data.cache.length} entries):`, data);
   return data;
 }
@@ -44,7 +44,7 @@ export async function initLyricsCache() {
  * @param refreshEntry If true, the timestamp of the entry will be set to the current time
  */
 export function getLyricsCacheEntry(artist: string, song: string, refreshEntry = true) {
-  const { cache } = lyricsCache.getData();
+  const { cache } = lyricsCacheMgr.getData();
   const entry = cache.find(e => e.artist === artist && e.song === song);
   if(entry && Date.now() - entry?.added > getFeatures().lyricsCacheTTL * 1000 * 60 * 60 * 24) {
     deleteLyricsCacheEntry(artist, song);
@@ -58,27 +58,37 @@ export function getLyricsCacheEntry(artist: string, song: string, refreshEntry =
 }
 
 function updateLyricsCacheEntry(artist: string, song: string) {
-  const { cache } = lyricsCache.getData();
+  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();
-    lyricsCache.setData({ cache: [ newEntry, ...cache ] });
+    lyricsCacheMgr.setData({ cache: [ newEntry, ...cache ] });
   }
 }
 
 function deleteLyricsCacheEntry(artist: string, song: string) {
-  const { cache } = lyricsCache.getData();
+  const { cache } = lyricsCacheMgr.getData();
   const idx = cache.findIndex(e => e.artist === artist && e.song === song);
   if(idx !== -1) {
     cache.splice(idx, 1);
-    lyricsCache.setData({ cache });
+    lyricsCacheMgr.setData({ cache });
   }
 }
 
+/** Clears the lyrics cache locally and deletes it from persistent storage - the window should be reloaded right after! */
+export function deleteLyricsCache() {
+  return lyricsCacheMgr.deleteConfig();
+}
+
+/** Clears the lyrics cache locally and clears it in persistent storage */
+export function clearLyricsCache() {
+  return lyricsCacheMgr.setData({ cache: [] });
+}
+
 /** Returns the full lyrics cache array */
 export function getLyricsCache() {
-  return lyricsCache.getData().cache;
+  return lyricsCacheMgr.getData().cache;
 }
 
 /**
@@ -86,14 +96,14 @@ export function getLyricsCache() {
  * {@linkcode artist} and {@linkcode song} need to be sanitized first!
  */
 export function addLyricsCacheEntry(artist: string, song: string, url: string) {
-  const { cache } = lyricsCache.getData();
+  const { cache } = lyricsCacheMgr.getData();
   cache.push({
     artist, song, url, viewed: Date.now(), added: Date.now(),
   } satisfies LyricsCacheEntry);
   cache.sort((a, b) => b.viewed - a.viewed);
   if(cache.length > getFeatures().lyricsCacheMaxSize)
     cache.pop();
-  return lyricsCache.setData({ cache });
+  return lyricsCacheMgr.setData({ cache });
 }
 
 /**
@@ -104,7 +114,7 @@ export function addLyricsCacheEntry(artist: string, song: string, url: string) {
  * @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)
  */
 export function addLyricsCacheEntryPenalized(artist: string, song: string, url: string, penaltyFr = 0) {
-  const { cache } = lyricsCache.getData();
+  const { cache } = lyricsCacheMgr.getData();
 
   penaltyFr = clamp(penaltyFr, 0, 1);
 
@@ -122,7 +132,7 @@ export function addLyricsCacheEntryPenalized(artist: string, song: string, url:
   if(cache.length > getFeatures().lyricsCacheMaxSize)
     cache.pop();
 
-  return lyricsCache.setData({ cache });
+  return lyricsCacheMgr.setData({ cache });
 }
 
 //#MARKER media control bar

+ 6 - 5
src/index.ts

@@ -219,7 +219,8 @@ async function initFeatures() {
 
   for(const [ftKey, ftInfo] of Object.entries(featInfo)) {
     try {
-      const res = ftInfo.enable() as void | Promise<void>;
+      // @ts-ignore
+      const res = ftInfo?.enable?.() as undefined | Promise<void>;
       if(res instanceof Promise)
         ftInit.push(res);
       else
@@ -241,10 +242,10 @@ async function initFeatures() {
       else if(featInfo[ftKey].disable) {
         // @ts-ignore
         const disableRes = featInfo[ftKey].disable();
-        if(disableRes instanceof Promise)
-          disableRes.then(() => featInfo[ftKey].enable());
-        else
-          featInfo[ftKey].enable();
+        if(disableRes instanceof Promise) // @ts-ignore
+          disableRes.then(() => featInfo[ftKey]?.enable?.());
+        else // @ts-ignore
+          featInfo[ftKey]?.enable?.();
       }
       else {
         // TODO: set "page reload required" flag in new menu

+ 16 - 2
src/menu/menu_old.ts

@@ -261,6 +261,9 @@ async function addCfgMenu() {
       if(!ftInfo || ftInfo.hidden === true)
         continue;
 
+      if(ftInfo.advanced && !featureCfg.advancedMode)
+        continue;
+
       const { type, default: ftDefault } = ftInfo;
 
       // @ts-ignore
@@ -277,7 +280,7 @@ async function addCfgMenu() {
         featLeftSideElem.classList.add("bytm-ftitem-leftside");
 
         const textElem = document.createElement("span");
-        textElem.textContent = t(`feature_desc_${featKey}`);
+        textElem.textContent = ftInfo.advanced ? t("advanced_feature_desc_template", t(`feature_desc_${featKey}`)) : t(`feature_desc_${featKey}`);
 
         let adornmentElem: undefined | HTMLElement;
 
@@ -349,6 +352,10 @@ async function addCfgMenu() {
           inputTag = undefined;
           inputType = undefined;
           break;
+        case "button":
+          inputTag = undefined;
+          inputType = undefined;
+          break;
         }
 
         const inputElemId = `bytm-ftconf-${featKey}-input`;
@@ -449,6 +456,12 @@ async function addCfgMenu() {
               labelPos: "left",
             });
             break;
+          case "button":
+            wrapperElem = document.createElement("button");
+            wrapperElem.tabIndex = 0;
+            wrapperElem.textContent = wrapperElem.ariaLabel = wrapperElem.title = hasKey(`feature_btn_${featKey}`) ? t(`feature_btn_${featKey}`) : t("trigger_btn_action");
+            wrapperElem.addEventListener("click", () => ftInfo.click());
+            break;
           }
 
           ctrlElem.appendChild(wrapperElem!);
@@ -717,7 +730,8 @@ async function openHelpDialog(featureKey: FeatureKey) {
     const featDescElem = menuBgElem.querySelector<HTMLElement>("#bytm-feat-help-menu-desc")!;
     const helpTextElem = menuBgElem.querySelector<HTMLElement>("#bytm-feat-help-menu-text")!;
 
-    featDescElem.textContent = t(`feature_desc_${featureKey}`);
+    // @ts-ignore
+    featDescElem.textContent = featInfo[featureKey].advanced ? t("advanced_feature_desc_template", t(`feature_desc_${featureKey}`)) : t(`feature_desc_${featureKey}`);
 
     // @ts-ignore
     const helpText: string | undefined = featInfo[featureKey]?.helpText?.();

+ 42 - 32
src/types.ts

@@ -117,40 +117,44 @@ export type FeatureCategory =
   | "general";
 
 type SelectOption = {
-  value: string | number,
-  label: string,
+  value: string | number;
+  label: string;
 };
 
-type FeatureTypeProps = 
+type FeatureTypeProps = ({
+    type: "toggle";
+    default: boolean;
+  } & FeatureFuncProps)
+  | ({
+    type: "number";
+    default: number;
+    min: number;
+    max?: number;
+    step?: number;
+    unit?: string | ((val: number) => string);
+  } & FeatureFuncProps)
+  | ({
+    type: "select";
+    default: string | number;
+    options: SelectOption[] | (() => SelectOption[]);
+  } & FeatureFuncProps)
+  | ({
+    type: "slider";
+    default: number;
+    min: number;
+    max: number;
+    step?: number;
+    unit?: string | ((val: number) => string);
+  } & FeatureFuncProps)
+  | ({
+    type: "hotkey";
+    default: HotkeyObj;
+  } & FeatureFuncProps)
   | {
-    type: "toggle",
-    default: boolean,
+    type: "button";
+    default: undefined;
+    click: () => void;
   }
-  | {
-    type: "number",
-    default: number,
-    min: number,
-    max?: number,
-    step?: number,
-    unit?: string | ((val: number) => string),
-  }
-  | {
-    type: "select",
-    default: string | number,
-    options: SelectOption[] | (() => SelectOption[]),
-  }
-  | {
-    type: "slider",
-    default: number,
-    min: number,
-    max: number,
-    step?: number,
-    unit?: string | ((val: number) => string),
-  }
-  | {
-    type: "hotkey",
-    default: HotkeyObj,
-  };
 
 type FeatureFuncProps = {
   /** Called to instantiate the feature on the page */
@@ -185,9 +189,11 @@ export type FeatureInfo = Record<
      * @deprecated TODO:FIXME: To be removed or changed in the big menu rework
      */
     textAdornment?: () => (Promise<string> | string);
+
+    /** Whether to only show this feature when advanced mode is activated (default false) */
+    advanced?: boolean;
   }
-    & FeatureTypeProps
-    & FeatureFuncProps
+  & FeatureTypeProps
 >;
 
 /** Feature configuration */
@@ -251,6 +257,8 @@ export interface FeatureConfig {
   lyricsCacheMaxSize: number;
   /** Max TTL of lyrics cache entries, in ms */
   lyricsCacheTTL: number;
+  /** Button to clear lyrics cache */
+  clearLyricsCache: undefined;
 
   //#SECTION misc
   /** The locale to use for translations */
@@ -259,4 +267,6 @@ export interface FeatureConfig {
   versionCheck: boolean;
   /** The console log level - 0 = Debug, 1 = Info */
   logLevel: LogLevel;
+  /** Whether to show advanced settings in the config menu */
+  advancedMode: boolean;
 }