Преглед изворни кода

feat: add advanced settings

Sv443 пре 1 година
родитељ
комит
9959d00b2d
8 измењених фајлова са 246 додато и 72 уклоњено
  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:
 ### Translation progress:
 | Locale | Translated keys | Based on |
 | 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>
 <br>
 
 
@@ -25,10 +25,14 @@ This means you need to manually check against the base translations for missing
 
 
 ### Missing keys:
 ### 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 |
 | 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` |
 | `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` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
 | `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_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
 | `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>
 <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 |
 | 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` |
 | `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` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
 | `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_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
 | `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>
 <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 |
 | 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` |
 | `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` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
 | `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_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
 | `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>
 <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 |
 | 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` |
 | `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` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
 | `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_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
 | `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>
 <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 |
 | 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` |
 | `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` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
 | `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_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
 | `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>
 <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 |
 | 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` |
 | `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` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
 | `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_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
 | `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>
 <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 |
 | 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` |
 | `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` |
 | `open_update_page_install_manually` | `Install on %1` |
 | `disable_update_check` | `Disable automatic update checks` |
 | `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_entries-n` | `entries` |
 | `unit_days-1` | `day` |
 | `unit_days-1` | `day` |
 | `unit_days-n` | `days` |
 | `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>
 <br></details>

+ 17 - 2
assets/translations/en_US.json

@@ -40,6 +40,7 @@
     "log_level_info": "Info (only important)",
     "log_level_info": "Info (only important)",
     "toggled_on": "On",
     "toggled_on": "On",
     "toggled_off": "Off",
     "toggled_off": "Off",
+    "trigger_btn_action": "Trigger",
     "remove_from_queue": "Remove this song from the queue",
     "remove_from_queue": "Remove this song from the queue",
     "delete_from_list": "Delete this song from the list",
     "delete_from_list": "Delete this song from the list",
     "couldnt_remove_from_queue": "Couldn't remove this song from the queue",
     "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_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_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_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": "Click to change",
     "hotkey_input_click_to_change_tooltip": "Click, then press the desired key combination",
     "hotkey_input_click_to_change_tooltip": "Click, then press the desired key combination",
@@ -100,6 +104,8 @@
     "unit_days-1": "day",
     "unit_days-1": "day",
     "unit_days-n": "days",
     "unit_days-n": "days",
 
 
+    "advanced_feature_desc_template": "[Advanced] %1",
+
     "feature_category_layout": "Layout",
     "feature_category_layout": "Layout",
     "feature_category_songLists": "Song Lists",
     "feature_category_songLists": "Song Lists",
     "feature_category_behavior": "Behavior",
     "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_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_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_locale": "Language",
     "feature_desc_versionCheck": "Check for updates every 24 hours",
     "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_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_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,
       ...oldData,
       lyricsCacheMaxSize: getFeatureDefault("lyricsCacheMaxSize"),
       lyricsCacheMaxSize: getFeatureDefault("lyricsCacheMaxSize"),
       lyricsCacheTTL: getFeatureDefault("lyricsCacheTTL"),
       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 { getPreferredLocale, resourceToHTMLString, t, tp } from "../utils";
 import langMapping from "../../assets/locales.json" assert { type: "json" };
 import langMapping from "../../assets/locales.json" assert { type: "json" };
 import { remSongMinPlayTime } from "./behavior";
 import { remSongMinPlayTime } from "./behavior";
+import { clearLyricsCache, getLyricsCache } from "./lyrics";
 import { FeatureInfo } from "../types";
 import { FeatureInfo } from "../types";
 
 
 export * from "./layout";
 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 |
  * | `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 |
  * | `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 |
  * | `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 |
  * | `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) |
  * | `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 |
  * | `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 |
  * | `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 |
  * | `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:**
  * **Notes:**
  * - If no `disable()` or `change()` function is present, the page needs to be reloaded for the changes to take effect
  * - 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",
     type: "slider",
     category: "lyrics",
     category: "lyrics",
     default: 500,
     default: 500,
-    min: 0,
+    min: 50,
     max: 2000,
     max: 2000,
     step: 50,
     step: 50,
     unit: (val: number) => tp("unit_entries", val),
     unit: (val: number) => tp("unit_entries", val),
     enable: () => void "TODO",
     enable: () => void "TODO",
     change: () => void "TODO",
     change: () => void "TODO",
+    advanced: true,
   },
   },
   lyricsCacheTTL: {
   lyricsCacheTTL: {
     type: "slider",
     type: "slider",
     category: "lyrics",
     category: "lyrics",
     default: 21,
     default: 21,
-    min: 1,
+    min: 3,
     max: 100,
     max: 100,
     step: 1,
     step: 1,
     unit: (val: number) => tp("unit_days", val),
     unit: (val: number) => tp("unit_days", val),
     enable: () => void "TODO",
     enable: () => void "TODO",
     change: () => 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
   //#SECTION general
@@ -302,4 +319,11 @@ export const featInfo = {
     default: 1,
     default: 1,
     enable: () => void "TODO",
     enable: () => void "TODO",
   },
   },
+  advancedMode: {
+    type: "toggle",
+    category: "general",
+    default: false,
+    enable: () => void "TODO",
+    disable: () => void "TODO",
+  },
 } as const satisfies FeatureInfo;
 } as const satisfies FeatureInfo;

+ 22 - 12
src/features/lyrics.ts

@@ -21,7 +21,7 @@ export type LyricsCache = {
 
 
 let canCompress = true;
 let canCompress = true;
 
 
-const lyricsCache = new ConfigManager<LyricsCache>({
+const lyricsCacheMgr = new ConfigManager<LyricsCache>({
   id: "bytm-lyrics-cache",
   id: "bytm-lyrics-cache",
   defaultConfig: {
   defaultConfig: {
     cache: [],
     cache: [],
@@ -33,7 +33,7 @@ const lyricsCache = new ConfigManager<LyricsCache>({
 
 
 export async function initLyricsCache() {
 export async function initLyricsCache() {
   canCompress = await compressionSupported();
   canCompress = await compressionSupported();
-  const data = await lyricsCache.loadData();
+  const data = await lyricsCacheMgr.loadData();
   log(`Loaded lyrics cache (${data.cache.length} entries):`, data);
   log(`Loaded lyrics cache (${data.cache.length} entries):`, data);
   return 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
  * @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) {
 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);
   const entry = cache.find(e => e.artist === artist && e.song === song);
   if(entry && Date.now() - entry?.added > getFeatures().lyricsCacheTTL * 1000 * 60 * 60 * 24) {
   if(entry && Date.now() - entry?.added > getFeatures().lyricsCacheTTL * 1000 * 60 * 60 * 24) {
     deleteLyricsCacheEntry(artist, song);
     deleteLyricsCacheEntry(artist, song);
@@ -58,27 +58,37 @@ export function getLyricsCacheEntry(artist: string, song: string, refreshEntry =
 }
 }
 
 
 function updateLyricsCacheEntry(artist: string, song: string) {
 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);
   const idx = cache.findIndex(e => e.artist === artist && e.song === song);
   if(idx !== -1) {
   if(idx !== -1) {
     const newEntry = cache.splice(idx, 1)[0]!;
     const newEntry = cache.splice(idx, 1)[0]!;
     newEntry.viewed = Date.now();
     newEntry.viewed = Date.now();
-    lyricsCache.setData({ cache: [ newEntry, ...cache ] });
+    lyricsCacheMgr.setData({ cache: [ newEntry, ...cache ] });
   }
   }
 }
 }
 
 
 function deleteLyricsCacheEntry(artist: string, song: string) {
 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);
   const idx = cache.findIndex(e => e.artist === artist && e.song === song);
   if(idx !== -1) {
   if(idx !== -1) {
     cache.splice(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 */
 /** Returns the full lyrics cache array */
 export function getLyricsCache() {
 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!
  * {@linkcode artist} and {@linkcode song} need to be sanitized first!
  */
  */
 export function addLyricsCacheEntry(artist: string, song: string, url: string) {
 export function addLyricsCacheEntry(artist: string, song: string, url: string) {
-  const { cache } = lyricsCache.getData();
+  const { cache } = lyricsCacheMgr.getData();
   cache.push({
   cache.push({
     artist, song, url, viewed: Date.now(), added: Date.now(),
     artist, song, url, viewed: Date.now(), added: Date.now(),
   } satisfies LyricsCacheEntry);
   } satisfies LyricsCacheEntry);
   cache.sort((a, b) => b.viewed - a.viewed);
   cache.sort((a, b) => b.viewed - a.viewed);
   if(cache.length > getFeatures().lyricsCacheMaxSize)
   if(cache.length > getFeatures().lyricsCacheMaxSize)
     cache.pop();
     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)
  * @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) {
 export function addLyricsCacheEntryPenalized(artist: string, song: string, url: string, penaltyFr = 0) {
-  const { cache } = lyricsCache.getData();
+  const { cache } = lyricsCacheMgr.getData();
 
 
   penaltyFr = clamp(penaltyFr, 0, 1);
   penaltyFr = clamp(penaltyFr, 0, 1);
 
 
@@ -122,7 +132,7 @@ export function addLyricsCacheEntryPenalized(artist: string, song: string, url:
   if(cache.length > getFeatures().lyricsCacheMaxSize)
   if(cache.length > getFeatures().lyricsCacheMaxSize)
     cache.pop();
     cache.pop();
 
 
-  return lyricsCache.setData({ cache });
+  return lyricsCacheMgr.setData({ cache });
 }
 }
 
 
 //#MARKER media control bar
 //#MARKER media control bar

+ 6 - 5
src/index.ts

@@ -219,7 +219,8 @@ async function initFeatures() {
 
 
   for(const [ftKey, ftInfo] of Object.entries(featInfo)) {
   for(const [ftKey, ftInfo] of Object.entries(featInfo)) {
     try {
     try {
-      const res = ftInfo.enable() as void | Promise<void>;
+      // @ts-ignore
+      const res = ftInfo?.enable?.() as undefined | Promise<void>;
       if(res instanceof Promise)
       if(res instanceof Promise)
         ftInit.push(res);
         ftInit.push(res);
       else
       else
@@ -241,10 +242,10 @@ async function initFeatures() {
       else if(featInfo[ftKey].disable) {
       else if(featInfo[ftKey].disable) {
         // @ts-ignore
         // @ts-ignore
         const disableRes = featInfo[ftKey].disable();
         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 {
       else {
         // TODO: set "page reload required" flag in new menu
         // 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)
       if(!ftInfo || ftInfo.hidden === true)
         continue;
         continue;
 
 
+      if(ftInfo.advanced && !featureCfg.advancedMode)
+        continue;
+
       const { type, default: ftDefault } = ftInfo;
       const { type, default: ftDefault } = ftInfo;
 
 
       // @ts-ignore
       // @ts-ignore
@@ -277,7 +280,7 @@ async function addCfgMenu() {
         featLeftSideElem.classList.add("bytm-ftitem-leftside");
         featLeftSideElem.classList.add("bytm-ftitem-leftside");
 
 
         const textElem = document.createElement("span");
         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;
         let adornmentElem: undefined | HTMLElement;
 
 
@@ -349,6 +352,10 @@ async function addCfgMenu() {
           inputTag = undefined;
           inputTag = undefined;
           inputType = undefined;
           inputType = undefined;
           break;
           break;
+        case "button":
+          inputTag = undefined;
+          inputType = undefined;
+          break;
         }
         }
 
 
         const inputElemId = `bytm-ftconf-${featKey}-input`;
         const inputElemId = `bytm-ftconf-${featKey}-input`;
@@ -449,6 +456,12 @@ async function addCfgMenu() {
               labelPos: "left",
               labelPos: "left",
             });
             });
             break;
             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!);
           ctrlElem.appendChild(wrapperElem!);
@@ -717,7 +730,8 @@ async function openHelpDialog(featureKey: FeatureKey) {
     const featDescElem = menuBgElem.querySelector<HTMLElement>("#bytm-feat-help-menu-desc")!;
     const featDescElem = menuBgElem.querySelector<HTMLElement>("#bytm-feat-help-menu-desc")!;
     const helpTextElem = menuBgElem.querySelector<HTMLElement>("#bytm-feat-help-menu-text")!;
     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
     // @ts-ignore
     const helpText: string | undefined = featInfo[featureKey]?.helpText?.();
     const helpText: string | undefined = featInfo[featureKey]?.helpText?.();

+ 42 - 32
src/types.ts

@@ -117,40 +117,44 @@ export type FeatureCategory =
   | "general";
   | "general";
 
 
 type SelectOption = {
 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 = {
 type FeatureFuncProps = {
   /** Called to instantiate the feature on the page */
   /** 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
      * @deprecated TODO:FIXME: To be removed or changed in the big menu rework
      */
      */
     textAdornment?: () => (Promise<string> | string);
     textAdornment?: () => (Promise<string> | string);
+
+    /** Whether to only show this feature when advanced mode is activated (default false) */
+    advanced?: boolean;
   }
   }
-    & FeatureTypeProps
-    & FeatureFuncProps
+  & FeatureTypeProps
 >;
 >;
 
 
 /** Feature configuration */
 /** Feature configuration */
@@ -251,6 +257,8 @@ export interface FeatureConfig {
   lyricsCacheMaxSize: number;
   lyricsCacheMaxSize: number;
   /** Max TTL of lyrics cache entries, in ms */
   /** Max TTL of lyrics cache entries, in ms */
   lyricsCacheTTL: number;
   lyricsCacheTTL: number;
+  /** Button to clear lyrics cache */
+  clearLyricsCache: undefined;
 
 
   //#SECTION misc
   //#SECTION misc
   /** The locale to use for translations */
   /** The locale to use for translations */
@@ -259,4 +267,6 @@ export interface FeatureConfig {
   versionCheck: boolean;
   versionCheck: boolean;
   /** The console log level - 0 = Debug, 1 = Info */
   /** The console log level - 0 = Debug, 1 = Info */
   logLevel: LogLevel;
   logLevel: LogLevel;
+  /** Whether to show advanced settings in the config menu */
+  advancedMode: boolean;
 }
 }