Sv443 11 месяцев назад
Родитель
Сommit
3b0d208353
8 измененных файлов с 147 добавлено и 65 удалено
  1. 51 30
      assets/translations/README.md
  2. 5 2
      assets/translations/en_US.json
  3. 1 1
      contributing.md
  4. 11 3
      src/dialogs/autoLikeChannels.ts
  5. 11 0
      src/features/index.ts
  6. 21 11
      src/index.ts
  7. 45 18
      src/interface.ts
  8. 2 0
      src/types.ts

+ 51 - 30
assets/translations/README.md

@@ -16,15 +16,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) | 231 (default locale) |  |
-| ‼️ | [`de_DE`](./de_DE.json) | `214/231` (92.6%) | ─ |
-| ─ | [`en_UK`](./en_UK.json) | `231/231` (100%) | `en_US` |
-| ‼️ | [`es_ES`](./es_ES.json) | `214/231` (92.6%) | ─ |
-| ‼️ | [`fr_FR`](./fr_FR.json) | `214/231` (92.6%) | ─ |
-| ‼️ | [`hi_IN`](./hi_IN.json) | `214/231` (92.6%) | ─ |
-| ‼️ | [`ja_JA`](./ja_JA.json) | `214/231` (92.6%) | ─ |
-| ‼️ | [`pt_BR`](./pt_BR.json) | `214/231` (92.6%) | ─ |
-| ‼️ | [`zh_CN`](./zh_CN.json) | `214/231` (92.6%) | ─ |
+| ─ | [`en_US`](./en_US.json) | 234 (default locale) |  |
+| ‼️ | [`de_DE`](./de_DE.json) | `214/234` (91.5%) | ─ |
+| ─ | [`en_UK`](./en_UK.json) | `234/234` (100%) | `en_US` |
+| ‼️ | [`es_ES`](./es_ES.json) | `214/234` (91.5%) | ─ |
+| ‼️ | [`fr_FR`](./fr_FR.json) | `214/234` (91.5%) | ─ |
+| ‼️ | [`hi_IN`](./hi_IN.json) | `214/234` (91.5%) | ─ |
+| ‼️ | [`ja_JA`](./ja_JA.json) | `214/234` (91.5%) | ─ |
+| ‼️ | [`pt_BR`](./pt_BR.json) | `214/234` (91.5%) | ─ |
+| ‼️ | [`zh_CN`](./zh_CN.json) | `214/234` (91.5%) | ─ |
 
 <sub>
 ✅ - Fully translated
@@ -45,7 +45,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 ### Missing keys:
 
-<details><summary><code>de_DE</code> - 17 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>de_DE</code> - 20 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -56,20 +56,23 @@ This means to figure out which keys are untranslated, you will need to manually
 | `auto_like` | `Auto-like` |
 | `auto_like_button_tooltip_enabled` | `Click to disable auto-liking. Shift-click to open the management dialog.` |
 | `auto_like_button_tooltip_disabled` | `Click to enable auto-liking. Shift-click to open the management dialog.` |
-| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
-| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "/channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_invalid_id` | `The entered channel ID is invalid.\nPlease make sure you copy only the part *after* "/channel/" in the URL, excluding the slash.` |
 | `add_auto_like_channel_already_exists_prompt_new_name` | `A channel with that ID is already in the list.\nDo you instead want to change its name?` |
+| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
 | `feature_desc_autoLikeChannels` | `Automatically like all songs and videos of certain channels` |
 | `feature_helpText_autoLikeChannels` | `Once enabled, you can enable this feature for certain channels by opening their page and clicking the toggle button. Afterwards, any song you play of that channel will be liked automatically.\nUse the option below to open a dialog to manage the channels.` |
 | `feature_desc_openAutoLikeChannelsDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_openAutoLikeChannelsDialog` | `Open dialog` |
 | `feature_btn_openAutoLikeChannelsDialog_running` | `Opening...` |
+| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
 | `plugin_validation_error_invalid_property-1` | `Property '%1' with value '%2' is invalid. Example value: %3` |
 | `plugin_validation_error_invalid_property-n` | `Property '%1' with value '%2' is invalid. Example values: %3` |
 
 <br></details>
 
-<details><summary><code>es_ES</code> - 17 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>es_ES</code> - 20 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -80,20 +83,23 @@ This means to figure out which keys are untranslated, you will need to manually
 | `auto_like` | `Auto-like` |
 | `auto_like_button_tooltip_enabled` | `Click to disable auto-liking. Shift-click to open the management dialog.` |
 | `auto_like_button_tooltip_disabled` | `Click to enable auto-liking. Shift-click to open the management dialog.` |
-| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
-| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "/channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_invalid_id` | `The entered channel ID is invalid.\nPlease make sure you copy only the part *after* "/channel/" in the URL, excluding the slash.` |
 | `add_auto_like_channel_already_exists_prompt_new_name` | `A channel with that ID is already in the list.\nDo you instead want to change its name?` |
+| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
 | `feature_desc_autoLikeChannels` | `Automatically like all songs and videos of certain channels` |
 | `feature_helpText_autoLikeChannels` | `Once enabled, you can enable this feature for certain channels by opening their page and clicking the toggle button. Afterwards, any song you play of that channel will be liked automatically.\nUse the option below to open a dialog to manage the channels.` |
 | `feature_desc_openAutoLikeChannelsDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_openAutoLikeChannelsDialog` | `Open dialog` |
 | `feature_btn_openAutoLikeChannelsDialog_running` | `Opening...` |
+| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
 | `plugin_validation_error_invalid_property-1` | `Property '%1' with value '%2' is invalid. Example value: %3` |
 | `plugin_validation_error_invalid_property-n` | `Property '%1' with value '%2' is invalid. Example values: %3` |
 
 <br></details>
 
-<details><summary><code>fr_FR</code> - 17 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>fr_FR</code> - 20 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -104,20 +110,23 @@ This means to figure out which keys are untranslated, you will need to manually
 | `auto_like` | `Auto-like` |
 | `auto_like_button_tooltip_enabled` | `Click to disable auto-liking. Shift-click to open the management dialog.` |
 | `auto_like_button_tooltip_disabled` | `Click to enable auto-liking. Shift-click to open the management dialog.` |
-| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
-| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "/channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_invalid_id` | `The entered channel ID is invalid.\nPlease make sure you copy only the part *after* "/channel/" in the URL, excluding the slash.` |
 | `add_auto_like_channel_already_exists_prompt_new_name` | `A channel with that ID is already in the list.\nDo you instead want to change its name?` |
+| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
 | `feature_desc_autoLikeChannels` | `Automatically like all songs and videos of certain channels` |
 | `feature_helpText_autoLikeChannels` | `Once enabled, you can enable this feature for certain channels by opening their page and clicking the toggle button. Afterwards, any song you play of that channel will be liked automatically.\nUse the option below to open a dialog to manage the channels.` |
 | `feature_desc_openAutoLikeChannelsDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_openAutoLikeChannelsDialog` | `Open dialog` |
 | `feature_btn_openAutoLikeChannelsDialog_running` | `Opening...` |
+| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
 | `plugin_validation_error_invalid_property-1` | `Property '%1' with value '%2' is invalid. Example value: %3` |
 | `plugin_validation_error_invalid_property-n` | `Property '%1' with value '%2' is invalid. Example values: %3` |
 
 <br></details>
 
-<details><summary><code>hi_IN</code> - 17 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>hi_IN</code> - 20 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -128,20 +137,23 @@ This means to figure out which keys are untranslated, you will need to manually
 | `auto_like` | `Auto-like` |
 | `auto_like_button_tooltip_enabled` | `Click to disable auto-liking. Shift-click to open the management dialog.` |
 | `auto_like_button_tooltip_disabled` | `Click to enable auto-liking. Shift-click to open the management dialog.` |
-| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
-| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "/channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_invalid_id` | `The entered channel ID is invalid.\nPlease make sure you copy only the part *after* "/channel/" in the URL, excluding the slash.` |
 | `add_auto_like_channel_already_exists_prompt_new_name` | `A channel with that ID is already in the list.\nDo you instead want to change its name?` |
+| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
 | `feature_desc_autoLikeChannels` | `Automatically like all songs and videos of certain channels` |
 | `feature_helpText_autoLikeChannels` | `Once enabled, you can enable this feature for certain channels by opening their page and clicking the toggle button. Afterwards, any song you play of that channel will be liked automatically.\nUse the option below to open a dialog to manage the channels.` |
 | `feature_desc_openAutoLikeChannelsDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_openAutoLikeChannelsDialog` | `Open dialog` |
 | `feature_btn_openAutoLikeChannelsDialog_running` | `Opening...` |
+| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
 | `plugin_validation_error_invalid_property-1` | `Property '%1' with value '%2' is invalid. Example value: %3` |
 | `plugin_validation_error_invalid_property-n` | `Property '%1' with value '%2' is invalid. Example values: %3` |
 
 <br></details>
 
-<details><summary><code>ja_JA</code> - 17 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>ja_JA</code> - 20 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -152,20 +164,23 @@ This means to figure out which keys are untranslated, you will need to manually
 | `auto_like` | `Auto-like` |
 | `auto_like_button_tooltip_enabled` | `Click to disable auto-liking. Shift-click to open the management dialog.` |
 | `auto_like_button_tooltip_disabled` | `Click to enable auto-liking. Shift-click to open the management dialog.` |
-| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
-| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "/channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_invalid_id` | `The entered channel ID is invalid.\nPlease make sure you copy only the part *after* "/channel/" in the URL, excluding the slash.` |
 | `add_auto_like_channel_already_exists_prompt_new_name` | `A channel with that ID is already in the list.\nDo you instead want to change its name?` |
+| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
 | `feature_desc_autoLikeChannels` | `Automatically like all songs and videos of certain channels` |
 | `feature_helpText_autoLikeChannels` | `Once enabled, you can enable this feature for certain channels by opening their page and clicking the toggle button. Afterwards, any song you play of that channel will be liked automatically.\nUse the option below to open a dialog to manage the channels.` |
 | `feature_desc_openAutoLikeChannelsDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_openAutoLikeChannelsDialog` | `Open dialog` |
 | `feature_btn_openAutoLikeChannelsDialog_running` | `Opening...` |
+| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
 | `plugin_validation_error_invalid_property-1` | `Property '%1' with value '%2' is invalid. Example value: %3` |
 | `plugin_validation_error_invalid_property-n` | `Property '%1' with value '%2' is invalid. Example values: %3` |
 
 <br></details>
 
-<details><summary><code>pt_BR</code> - 17 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>pt_BR</code> - 20 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -176,20 +191,23 @@ This means to figure out which keys are untranslated, you will need to manually
 | `auto_like` | `Auto-like` |
 | `auto_like_button_tooltip_enabled` | `Click to disable auto-liking. Shift-click to open the management dialog.` |
 | `auto_like_button_tooltip_disabled` | `Click to enable auto-liking. Shift-click to open the management dialog.` |
-| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
-| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "/channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_invalid_id` | `The entered channel ID is invalid.\nPlease make sure you copy only the part *after* "/channel/" in the URL, excluding the slash.` |
 | `add_auto_like_channel_already_exists_prompt_new_name` | `A channel with that ID is already in the list.\nDo you instead want to change its name?` |
+| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
 | `feature_desc_autoLikeChannels` | `Automatically like all songs and videos of certain channels` |
 | `feature_helpText_autoLikeChannels` | `Once enabled, you can enable this feature for certain channels by opening their page and clicking the toggle button. Afterwards, any song you play of that channel will be liked automatically.\nUse the option below to open a dialog to manage the channels.` |
 | `feature_desc_openAutoLikeChannelsDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_openAutoLikeChannelsDialog` | `Open dialog` |
 | `feature_btn_openAutoLikeChannelsDialog_running` | `Opening...` |
+| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
 | `plugin_validation_error_invalid_property-1` | `Property '%1' with value '%2' is invalid. Example value: %3` |
 | `plugin_validation_error_invalid_property-n` | `Property '%1' with value '%2' is invalid. Example values: %3` |
 
 <br></details>
 
-<details><summary><code>zh_CN</code> - 17 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>zh_CN</code> - 20 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -200,14 +218,17 @@ This means to figure out which keys are untranslated, you will need to manually
 | `auto_like` | `Auto-like` |
 | `auto_like_button_tooltip_enabled` | `Click to disable auto-liking. Shift-click to open the management dialog.` |
 | `auto_like_button_tooltip_disabled` | `Click to enable auto-liking. Shift-click to open the management dialog.` |
-| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
-| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_id_prompt` | `Enter the channel ID (the part after "/channel/" in the URL) of the channel you want to auto-like.\nPress "cancel" to exit.` |
+| `add_auto_like_channel_invalid_id` | `The entered channel ID is invalid.\nPlease make sure you copy only the part *after* "/channel/" in the URL, excluding the slash.` |
 | `add_auto_like_channel_already_exists_prompt_new_name` | `A channel with that ID is already in the list.\nDo you instead want to change its name?` |
+| `add_auto_like_channel_name_prompt` | `Enter the name of the channel.\nPress "cancel" to exit.` |
 | `feature_desc_autoLikeChannels` | `Automatically like all songs and videos of certain channels` |
 | `feature_helpText_autoLikeChannels` | `Once enabled, you can enable this feature for certain channels by opening their page and clicking the toggle button. Afterwards, any song you play of that channel will be liked automatically.\nUse the option below to open a dialog to manage the channels.` |
 | `feature_desc_openAutoLikeChannelsDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_openAutoLikeChannelsDialog` | `Open dialog` |
 | `feature_btn_openAutoLikeChannelsDialog_running` | `Opening...` |
+| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
 | `plugin_validation_error_invalid_property-1` | `Property '%1' with value '%2' is invalid. Example value: %3` |
 | `plugin_validation_error_invalid_property-n` | `Property '%1' with value '%2' is invalid. Example values: %3` |
 

+ 5 - 2
assets/translations/en_US.json

@@ -135,9 +135,10 @@
     "auto_like": "Auto-like",
     "auto_like_button_tooltip_enabled": "Click to disable auto-liking. Shift-click to open the management dialog.",
     "auto_like_button_tooltip_disabled": "Click to enable auto-liking. Shift-click to open the management dialog.",
-    "add_auto_like_channel_id_prompt": "Enter the channel ID (the part after \"channel/\" in the URL) of the channel you want to auto-like.\nPress \"cancel\" to exit.",
-    "add_auto_like_channel_name_prompt": "Enter the name of the channel.\nPress \"cancel\" to exit.",
+    "add_auto_like_channel_id_prompt": "Enter the channel ID (the part after \"/channel/\" in the URL) of the channel you want to auto-like.\nPress \"cancel\" to exit.",
+    "add_auto_like_channel_invalid_id": "The entered channel ID is invalid.\nPlease make sure you copy only the part *after* \"/channel/\" in the URL, excluding the slash.",
     "add_auto_like_channel_already_exists_prompt_new_name": "A channel with that ID is already in the list.\nDo you instead want to change its name?",
+    "add_auto_like_channel_name_prompt": "Enter the name of the channel.\nPress \"cancel\" to exit.",
 
     "unit_entries-1": "entry",
     "unit_entries-n": "entries",
@@ -244,6 +245,8 @@
     "feature_btn_checkVersionNow_running": "Checking...",
     "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_desc_initTimeout": "How long to wait for features to initialize before considering them to likely be in an errored state",
+    "feature_helptext_initTimeout": "This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.",
     "feature_desc_advancedMode": "Show advanced settings (reloads the menu)",
     "feature_helptext_advancedMode": "After enabling this, the menu will reload and show advanced settings that are hidden by default.\nThis is useful if you want to more deeply customize the script's behavior and don't care about an overcrowded menu.",
 

+ 1 - 1
contributing.md

@@ -389,7 +389,7 @@ The usage and example blocks on each are written in TypeScript but can be used i
 >   return authToken;
 > }
 > 
-> unsafeWindow.addEventListener("bytm:initPlugins", () => {
+> unsafeWindow.addEventListener("bytm:registerPlugins", () => {
 >   // register the plugin
 >   const { token, events } = unsafeWindow.BYTM.registerPlugin(pluginDef);
 >   // listen for the pluginRegistered event

+ 11 - 3
src/dialogs/autoLikeChannels.ts

@@ -16,6 +16,7 @@ export async function getAutoLikeChannelsDialog() {
       closeBtnEnabled: true,
       closeOnBgClick: true,
       closeOnEscPress: true,
+      destroyOnClose: true,
       small: true,
       renderHeader,
       renderBody,
@@ -54,18 +55,25 @@ async function renderBody() {
 
   contElem.appendChild(descriptionEl);
 
-  const addNewEl = document.createElement("div");
+  const addNewWrapper = document.createElement("div");
+
+  const addNewEl = document.createElement("span");
   addNewEl.id = "bytm-auto-like-channels-add-new";
   addNewEl.role = "button";
   addNewEl.tabIndex = 0;
   addNewEl.textContent = `+ ${t("create_new_entry")}`;
   addNewEl.classList.add("bytm-link", "bytm-no-select");
 
+  addNewWrapper.appendChild(addNewEl);
+
   onInteraction(addNewEl, async () => {
     const id = prompt(t("add_auto_like_channel_id_prompt"))?.trim();
-    if(!id || !id.match(/^[a-zA-Z0-9_-]{20,}$/))
+    if(!id)
       return;
 
+    if(!id.match(/^[a-zA-Z0-9_-]{20,}$/))
+      return alert(t("add_auto_like_channel_invalid_id"));
+
     let overwriteName = false;
 
     if(autoLikeChannelsStore.getData().channels.some((ch) => ch.id === id)) {
@@ -100,7 +108,7 @@ async function renderBody() {
     autoLikeChannelsDialog?.unmount();
   });
 
-  contElem.appendChild(addNewEl);
+  contElem.appendChild(addNewWrapper);
 
   const channelListCont = document.createElement("div");
   channelListCont.id = "bytm-auto-like-channels-list";

+ 11 - 0
src/features/index.ts

@@ -577,6 +577,17 @@ export const featInfo = {
     default: 1,
     textAdornment: adornments.reloadRequired,
   },
+  initTimeout: {
+    type: "number",
+    category: "general",
+    min: 1,
+    max: 30,
+    default: 8,
+    step: 0.1,
+    unit: "s",
+    advanced: true,
+    textAdornment: () => combineAdornments([adornments.advanced, adornments.reloadRequired]),
+  },
   advancedMode: {
     type: "toggle",
     category: "general",

+ 21 - 11
src/index.ts

@@ -89,7 +89,7 @@ async function init() {
     await initTranslations(features.locale ?? "en_US");
     setLocale(features.locale ?? "en_US");
 
-    emitInterface("bytm:initPlugins");
+    emitInterface("bytm:registerPlugins");
 
     if(features.disableBeforeUnloadPopup && domain === "ytm")
       disableBeforeUnload();
@@ -231,16 +231,7 @@ async function onDomLoad() {
         ftInit.push(["initAutoLikeChannels", initAutoLikeChannels()]);
     }
 
-    const initStartTs = Date.now();
-
-    // wait for feature init or timeout (in case an init function is hung up on a promise)
-    await Promise.race([
-      pauseFor(10_000),
-      Promise.allSettled(ftInit.map(([, p]) => p)),
-    ]);
-
-    emitInterface("bytm:ready");
-    info(`Done initializing all ${ftInit.length} features after ${Math.floor(Date.now() - initStartTs)}ms`);
+    emitInterface("bytm:featureInitStarted");
 
     try {
       initPlugins();
@@ -250,6 +241,25 @@ async function onDomLoad() {
       emitInterface("bytm:fatalError", "Error while loading plugins");
     }
 
+    const initStartTs = Date.now();
+
+    // wait for feature init or timeout (in case an init function is hung up on a promise)
+    await Promise.race([
+      pauseFor(getFeatures().initTimeout > 0 ? getFeatures().initTimeout * 1000 : 8_000),
+      Promise.allSettled(
+        ftInit.map(([name, prom]) =>
+          new Promise(async (res) => {
+            const v = await prom;
+            emitInterface("bytm:featureInitialized", name);
+            res(v);
+          })
+        )
+      ),
+    ]);
+
+    emitInterface("bytm:ready");
+    info(`Done initializing all ${ftInit.length} features after ${Math.floor(Date.now() - initStartTs)}ms`);
+
     try {
       registerDevMenuCommands();
     }

+ 45 - 18
src/interface.ts

@@ -21,24 +21,50 @@ export type InterfaceEventsMap = {
 
 /** All events that can be emitted on the BYTM interface and the data they provide */
 export type InterfaceEvents = {
-  /** Emitted whenever the plugins should be registered using `unsafeWindow.BYTM.registerPlugin()` */
-  "bytm:initPlugins": undefined;
-  /** Emitted whenever all plugins have been loaded */
-  "bytm:pluginsRegistered": undefined;
-  /** Emitted when BYTM has finished initializing all features */
-  "bytm:ready": undefined;
-  /** Emitted when a fatal error occurs and the script can't continue to run. Returns a short error description (not really meant to be displayed to the user). */
-  "bytm:fatalError": string;
-  /**
-   * Emitted whenever the SelectorObserver instances have been initialized  
-   * Use `unsafeWindow.BYTM.addObserverListener()` to add custom listener functions to the observers
-   */
-  "bytm:observersReady": undefined;
+  //#region startup events
+  // (sorted in order of execution)
+
   /** Emitted as soon as the feature config has finished loading and can be accessed via `unsafeWindow.BYTM.getFeatures(token)` */
   "bytm:configReady": undefined;
-
+  /** Emitted when the lyrics cache has been loaded */
+  "bytm:lyricsCacheReady": undefined;
   /** Emitted whenever the locale is changed */
   "bytm:setLocale": { locale: TrLocale, pluginId?: string };
+  /**
+   * When this is emitted, this is your call to register your plugin using `unsafeWindow.BYTM.registerPlugin()`  
+   * To be safe, you should wait for this event before doing anything else in your plugin script.
+   */
+  "bytm:registerPlugins": undefined;
+  /**
+   * Emitted whenever the SelectorObserver instances have been initialized and can be used to listen for DOM changes and wait for elements to be available.  
+   * Use `unsafeWindow.BYTM.addObserverListener(name, selector, opts)` to add custom listener functions to the observers (see contributing guide).
+   */
+  "bytm:observersReady": undefined;
+  /**
+   * Emitted when the feature initialization has started.  
+   * This is the last event that is emitted before the `bytm:ready` event.  
+   * As soon as this is emitted, you cannot register any more plugins.
+   */
+  "bytm:featureInitStarted": undefined;
+  /**
+   * Emitted whenever all plugins have been registered and are allowed to call token-authenticated functions.  
+   * All parts of your plugin that require those functions should wait for this event to be emitted.
+   */
+  "bytm:pluginsRegistered": undefined;
+  /** Emitted when a feature has been initialized. The data is the feature's key as seen in `onDomLoad()` of `src/index.ts` */
+  "bytm:featureInitialized": string;
+  /** Emitted when BYTM has finished initializing all features or has reached the init timeout and has entered an idle state. */
+  "bytm:ready": undefined;
+
+  //#region additional events
+  // (not sorted)
+
+  /**
+   * Emitted when a fatal error occurs and the script can't continue to run.  
+   * Returns a short error description that's not really meant to be displayed to the user (console is fine).  
+   * But may be helpful in plugin development if the plugin causes an internal error.
+   */
+  "bytm:fatalError": string;
 
   /** Emitted when a dialog was opened - returns the dialog's instance */
   "bytm:dialogOpened": BytmDialog;
@@ -47,21 +73,22 @@ export type InterfaceEvents = {
 
   /** Emitted whenever the lyrics URL for a song is loaded */
   "bytm:lyricsLoaded": { type: "current" | "queue", artists: string, title: string, url: string };
-  /** Emitted when the lyrics cache has been loaded */
-  "bytm:lyricsCacheReady": undefined;
   /** Emitted when the lyrics cache has been cleared */
   "bytm:lyricsCacheCleared": undefined;
   /** Emitted when an entry is added to the lyrics cache - "penalized" entries get removed from cache faster because they were less related in lyrics lookups, opposite to the "best" entries */
   "bytm:lyricsCacheEntryAdded": { type: "best" | "penalized", entry: LyricsCacheEntry };
 
-  // additionally all events from SiteEventsMap in `src/siteEvents.ts`
+  // NOTE:
+  // Additionally, all events from `SiteEventsMap` in `src/siteEvents.ts`
   // are emitted in this format: "bytm:siteEvent:nameOfSiteEvent"
 };
 
+/** Array of all events emittable on the interface (excluding plugin-specific, private events) */
 export const allInterfaceEvents = [
-  "bytm:initPlugins",
+  "bytm:registerPlugins",
   "bytm:pluginsRegistered",
   "bytm:ready",
+  "bytm:featureInitfeatureInitStarted",
   "bytm:fatalError",
   "bytm:observersReady",
   "bytm:configReady",

+ 2 - 0
src/types.ts

@@ -453,6 +453,8 @@ export interface FeatureConfig {
   checkVersionNow: undefined;
   /** The console log level - 0 = Debug, 1 = Info */
   logLevel: LogLevel;
+  /** Amount of seconds until the feature initialization times out */
+  initTimeout: number;
   /** Whether to show advanced settings in the config menu */
   advancedMode: boolean;
 }