tiny-essentials 1.28.4 → 1.28.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +18 -1
  2. package/changelog/1/28/5.md +31 -0
  3. package/changelog/1/28/6.md +11 -0
  4. package/dist/v1/TinyAdvancedRaffle.min.js +1 -1
  5. package/dist/v1/TinyBasicsEs.min.js +1 -1
  6. package/dist/v1/TinyEssentials.min.js +1 -1
  7. package/dist/v1/TinyIframeEvents.min.js +1 -1
  8. package/dist/v1/TinyLocalStorage.min.js +1 -1
  9. package/dist/v1/TinyMediaPlayer.min.js +1 -1
  10. package/dist/v1/TinyNewWinEvents.min.js +1 -1
  11. package/dist/v1/TinyRadioFm.min.js +1 -1
  12. package/dist/v1/TinySmartScroller.min.js +1 -1
  13. package/dist/v1/TinyTimeout.min.js +1 -1
  14. package/dist/v1/TinyUploadClicker.min.js +1 -1
  15. package/dist/v1/basics/index.cjs +4 -0
  16. package/dist/v1/basics/index.d.mts +3 -2
  17. package/dist/v1/basics/index.mjs +3 -2
  18. package/dist/v1/basics/mediaContent.cjs +1 -0
  19. package/dist/v1/basics/mediaContent.d.mts +4 -0
  20. package/dist/v1/basics/mediaContent.mjs +1 -0
  21. package/dist/v1/basics/objChecker.cjs +16 -0
  22. package/dist/v1/basics/objChecker.d.mts +12 -0
  23. package/dist/v1/basics/objChecker.mjs +14 -0
  24. package/dist/v1/basics/objFilter.cjs +0 -2
  25. package/dist/v1/basics/objFilter.d.mts +0 -2
  26. package/dist/v1/basics/objFilter.mjs +1 -2
  27. package/dist/v1/basics/promiseUtils.cjs +101 -0
  28. package/dist/v1/basics/promiseUtils.d.mts +31 -0
  29. package/dist/v1/basics/promiseUtils.mjs +89 -0
  30. package/dist/v1/css/TinyLoadingScreen.min.css +1 -1
  31. package/dist/v1/index.cjs +4 -0
  32. package/dist/v1/index.d.mts +3 -2
  33. package/dist/v1/index.mjs +3 -2
  34. package/dist/v1/libs/TinyMediaPlayer/HtmlAudio.cjs +318 -0
  35. package/dist/v1/libs/TinyMediaPlayer/HtmlAudio.d.mts +143 -0
  36. package/dist/v1/libs/TinyMediaPlayer/HtmlAudio.mjs +283 -0
  37. package/dist/v1/libs/TinyMediaPlayer/HtmlVideo.cjs +315 -0
  38. package/dist/v1/libs/TinyMediaPlayer/HtmlVideo.d.mts +143 -0
  39. package/dist/v1/libs/TinyMediaPlayer/HtmlVideo.mjs +280 -0
  40. package/dist/v1/libs/TinyMediaPlayer/SoundCloud.cjs +792 -0
  41. package/dist/v1/libs/TinyMediaPlayer/SoundCloud.d.mts +300 -0
  42. package/dist/v1/libs/TinyMediaPlayer/SoundCloud.mjs +697 -0
  43. package/dist/v1/libs/TinyMediaPlayer/Youtube.cjs +783 -0
  44. package/dist/v1/libs/TinyMediaPlayer/Youtube.d.mts +355 -0
  45. package/dist/v1/libs/TinyMediaPlayer/Youtube.mjs +694 -0
  46. package/dist/v1/libs/TinyMediaPlayer/docs/SoundCloudWidget.cjs +381 -0
  47. package/dist/v1/libs/TinyMediaPlayer/docs/SoundCloudWidget.d.mts +704 -0
  48. package/dist/v1/libs/TinyMediaPlayer/docs/SoundCloudWidget.mjs +343 -0
  49. package/dist/v1/libs/TinyMediaPlayer/docs/YouTubePlayer.cjs +546 -0
  50. package/dist/v1/libs/TinyMediaPlayer/docs/YouTubePlayer.d.mts +657 -0
  51. package/dist/v1/libs/TinyMediaPlayer/docs/YouTubePlayer.mjs +480 -0
  52. package/dist/v1/libs/TinyMediaPlayer/index.cjs +216 -0
  53. package/dist/v1/libs/TinyMediaPlayer/index.d.mts +162 -0
  54. package/dist/v1/libs/TinyMediaPlayer/index.mjs +190 -0
  55. package/dist/v1/libs/TinyMediaPlayer.cjs +627 -103
  56. package/dist/v1/libs/TinyMediaPlayer.d.mts +163 -65
  57. package/dist/v1/libs/TinyMediaPlayer.mjs +573 -93
  58. package/dist/v1/libs/TinyTimeout.cjs +4 -14
  59. package/dist/v1/libs/TinyTimeout.d.mts +1 -0
  60. package/dist/v1/libs/TinyTimeout.mjs +4 -13
  61. package/docs/v1/basics/mediaContent.md +1 -1
  62. package/docs/v1/basics/objChecker.md +13 -0
  63. package/docs/v1/basics/promiseUtils.md +32 -0
  64. package/docs/v1/libs/TinyMediaPlayer.md +268 -39
  65. package/docs/v1/libs/TinyTimeout.md +1 -14
  66. package/package.json +71 -10
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var promiseUtils = require('../basics/promiseUtils.cjs');
3
4
  var utils = require('./utils.cjs');
4
5
 
5
6
  const checkDestroy = utils.createCheckDestroyed('TinyTimeout');
@@ -152,21 +153,10 @@ class TinyTimeout {
152
153
  * @param {number} [checkInterval=100] - How often (in ms) to check the condition.
153
154
  * @returns {Promise<void>} Resolves when the condition is met.
154
155
  * @throws {TypeError} If arguments are invalid.
156
+ * @deprecated Script migrated to `src/v1/basics/promiseUtils.mjs`.
155
157
  */
156
158
  static waitForTrue(getValue, checkInterval = 100) {
157
- if (typeof getValue !== 'function')
158
- throw new TypeError(`Expected 'getValue' to be a function.`);
159
- if (!Number.isFinite(checkInterval) || checkInterval <= 0)
160
- throw new TypeError(`Expected 'checkInterval' to be a positive number.`);
161
-
162
- return new Promise((resolve) => {
163
- const interval = setInterval(() => {
164
- if (getValue()) {
165
- clearInterval(interval);
166
- resolve();
167
- }
168
- }, checkInterval);
169
- });
159
+ return promiseUtils.waitForTrue(getValue, checkInterval);
170
160
  }
171
161
 
172
162
  /**
@@ -185,7 +175,7 @@ class TinyTimeout {
185
175
  throw new TypeError(`Expected 'getValue' to be a function.`);
186
176
  if (checkInterval !== null && (!Number.isFinite(checkInterval) || checkInterval <= 0))
187
177
  throw new TypeError(`Expected 'checkInterval' to be null or a positive number.`);
188
- return TinyTimeout.waitForTrue(getValue, checkInterval ?? this.#cooldownWatcherTime);
178
+ return promiseUtils.waitForTrue(getValue, checkInterval ?? this.#cooldownWatcherTime);
189
179
  }
190
180
 
191
181
  /**
@@ -67,6 +67,7 @@ declare class TinyTimeout {
67
67
  * @param {number} [checkInterval=100] - How often (in ms) to check the condition.
68
68
  * @returns {Promise<void>} Resolves when the condition is met.
69
69
  * @throws {TypeError} If arguments are invalid.
70
+ * @deprecated Script migrated to `src/v1/basics/promiseUtils.mjs`.
70
71
  */
71
72
  static waitForTrue(getValue: () => boolean, checkInterval?: number): Promise<void>;
72
73
  /**
@@ -1,3 +1,4 @@
1
+ import { waitForTrue } from '../basics/promiseUtils.mjs';
1
2
  import { createCheckDestroyed } from './utils.mjs';
2
3
  const checkDestroy = createCheckDestroyed('TinyTimeout');
3
4
  /**
@@ -136,20 +137,10 @@ class TinyTimeout {
136
137
  * @param {number} [checkInterval=100] - How often (in ms) to check the condition.
137
138
  * @returns {Promise<void>} Resolves when the condition is met.
138
139
  * @throws {TypeError} If arguments are invalid.
140
+ * @deprecated Script migrated to `src/v1/basics/promiseUtils.mjs`.
139
141
  */
140
142
  static waitForTrue(getValue, checkInterval = 100) {
141
- if (typeof getValue !== 'function')
142
- throw new TypeError(`Expected 'getValue' to be a function.`);
143
- if (!Number.isFinite(checkInterval) || checkInterval <= 0)
144
- throw new TypeError(`Expected 'checkInterval' to be a positive number.`);
145
- return new Promise((resolve) => {
146
- const interval = setInterval(() => {
147
- if (getValue()) {
148
- clearInterval(interval);
149
- resolve();
150
- }
151
- }, checkInterval);
152
- });
143
+ return waitForTrue(getValue, checkInterval);
153
144
  }
154
145
  /**
155
146
  * Instance version of `waitForTrue`, which defaults to using the instance's
@@ -168,7 +159,7 @@ class TinyTimeout {
168
159
  throw new TypeError(`Expected 'getValue' to be a function.`);
169
160
  if (checkInterval !== null && (!Number.isFinite(checkInterval) || checkInterval <= 0))
170
161
  throw new TypeError(`Expected 'checkInterval' to be null or a positive number.`);
171
- return TinyTimeout.waitForTrue(getValue, checkInterval ?? this.#cooldownWatcherTime);
162
+ return waitForTrue(getValue, checkInterval ?? this.#cooldownWatcherTime);
172
163
  }
173
164
  /**
174
165
  * Cleans up all internal references and stops the cooldown watcher.
@@ -13,7 +13,7 @@ These definitions ensure type safety and provide a clear blueprint for how media
13
13
  | Type | Description |
14
14
  | :--- | :--- |
15
15
  | `MediaContent` | **The Final Object.** A combination of `MediaContentBase` and `MediaContentMetadata`. This is what the system uses for playback. |
16
- | `MediaContentBase` | The essential properties: `id`, `title`, `artist`, `duration`, `url`, and `weight`. |
16
+ | `MediaContentBase` | The essential properties: `id`, `title`, `artist`, `duration`, `url`, `weight`, and an optional `mediaType` (e.g., 'audio', 'video') to facilitate content filtering when using both `HtmlAudioAdapter` and `HtmlVideoAdapter` within a `TinyMediaPlayer`. |
17
17
  | `MediaContentMetadata` | Rich metadata modeled after `music-metadata`. Includes `album`, `genre`, `year`, `track` info, etc. |
18
18
  | `MediaNumber` | A structure for indexing: `{ no: number \| null, of: number \| null }`. |
19
19
  | `UnknownArtistGetter` | A type that can be a `string` or a function returning a `string`. |
@@ -20,6 +20,19 @@ countObj('hi'); // Throws TypeError
20
20
 
21
21
  ---
22
22
 
23
+ ### 🧼 `isValidObj(value)`
24
+
25
+ Check if a value is a **JSON-compatible object** — meaning it's **not** a Array.
26
+
27
+ 🔒 This function ensures the object:
28
+
29
+ * is not `null`
30
+ * has `typeof === 'object'`
31
+
32
+ Use this when you need to strictly validate a JSON object.
33
+
34
+ ---
35
+
23
36
  ### 🧼 `isJsonObject(value)`
24
37
 
25
38
  Check if a value is a **plain JSON-compatible object** — meaning it's created via `{}` or `new Object()`, with a prototype of `Object.prototype`, and **not** a special object like `Date`, `Map`, `Array`, etc.
@@ -0,0 +1,32 @@
1
+ ### 🔁 `waitForTrue(getValue, checkInterval = 100)`
2
+
3
+ Waits until a provided function returns `true`, polling periodically.
4
+
5
+ ```ts
6
+ static waitForTrue(getValue: () => boolean, checkInterval?: number): Promise<void>
7
+ ```
8
+
9
+ * `getValue`: Function that returns `true` when the wait should end.
10
+ * `checkInterval`: Polling interval in milliseconds.
11
+
12
+ ---
13
+
14
+ ### 🔒 `createSingletonTask(baseFunction)`
15
+
16
+ Creates a controller object that ensures an asynchronous function is only executed once at a time. If a task is already in progress, subsequent calls to `callback` will wait for the existing promise to resolve.
17
+
18
+ ```ts
19
+ createSingletonTask<T, A extends any[]>(
20
+ baseFunction: (...args: A) => Promise<T>
21
+ ): {
22
+ callback: (...args: A) => Promise<T>;
23
+ getActivePromise: () => Promise<T> | null;
24
+ resetActivePromise: () => void;
25
+ }
26
+ ```
27
+
28
+ * `callback`: The wrapped function that manages execution state.
29
+ * `getActivePromise`: Returns the current active promise, or `null` if no task is running.
30
+ * `resetActivePromise`: Forces the state to reset, allowing the next call to start a new execution.
31
+
32
+ > **Note:** This utility is designed for **request collapsing** (all callers receive the same result). If you need to execute multiple independent tasks sequentially where each call returns its own unique result, please refer to the documentation for `TinyPromiseQueue.mjs`.
@@ -9,17 +9,158 @@
9
9
  To support different media platforms, `TinyMediaPlayer` relies on **Adapters**. You must create a class that extends `BaseMediaAdapter` for every new service you wish to support.
10
10
 
11
11
  ### 🛠️ `BaseMediaAdapter` (Abstract Class)
12
- *This class cannot be instantiated directly. It serves as an interface.*
12
+ *This class cannot be instantiated directly. It serves as an interface that all specific API wrappers must extend and implement.*
13
13
 
14
+ #### Properties
15
+ | Property | Type | Description |
16
+ | :--- | :--- | :--- |
17
+ | `destroyed` | `boolean` | Indicates if the adapter instance has been destroyed. |
18
+
19
+ #### Methods
14
20
  | Method | Description | Parameters | Returns |
15
21
  | :--- | :--- | :--- | :--- |
16
- | `canHandle` | Checks if the adapter supports a specific content item. | `content: MediaContent` | `boolean` |
17
- | `play` | Starts or resumes playback. | `content: MediaContent` | `Promise<void>` |
22
+ | `canHandle` | Determines if the adapter can play the provided content. | `content: MediaContent` | `boolean` |
23
+ | `play` | Starts or resumes playback of the provided content. | `content: MediaContent` | `Promise<void>` |
18
24
  | `pause` | Pauses the current playback. | None | `Promise<void>` |
19
- | `stop` | Stops playback and resets the platform state. | None | `Promise<void>` |
20
- | `seek` | Jumps to a specific time. | `timeMs: number` | `Promise<void>` |
21
- | `getCurrentTime` | Gets the current playback position. | None | `number` (ms) |
22
- | `setVolume` | Sets the volume level. | `volume: number` (0.0 to 1.0) | `void` |
25
+ | `stop` | Stops the playback completely and resets the platform state. | None | `Promise<void>` |
26
+ | `seek` | Seeks to a specific time in the media timeline. | `timeMs: number` | `Promise<void>` |
27
+ | `getCurrentTime` | Retrieves the current playback position. | None | `number` (ms) |
28
+ | `getTotalDuration` | Gets the total duration of the content. | None | `number` (ms) |
29
+ | `getRemainingTime` | Gets the remaining time until the content ends. | None | `number` (ms) |
30
+ | `getPlaybackPercentage` | Gets the percentage of the content that has been played. | None | `number` (0 to 100) |
31
+ | `getTimeData` | Retrieves a consolidated object containing all time-related metrics. | None | `ContentTimeData` |
32
+ | `setVolume` | Sets the playback volume for the underlying API. | `volume: number` (0.0 to 1.0) | `void` |
33
+ | `getVolume` | Gets the current playback volume. | None | `number` (0.0 to 1.0) |
34
+ | `destroy` | Cleans up the instance, removes listeners, and marks it as destroyed. | None | `void` |
35
+
36
+ ---
37
+
38
+ ### 🚀 Implementation Guide
39
+
40
+ You can integrate `TinyMediaPlayer` into your project using two methods: using the ready-to-use adapters provided in the library, or creating your own custom adapters for unique services.
41
+
42
+ #### 📦 Option 1: Using Pre-built Adapters
43
+ The library provides several optimized adapters for common media sources. You can import them and register them directly with your player instance.
44
+
45
+ **Available Adapters:**
46
+ * `YoutubeMediaAdapter` from `tiny-essentials/libs/TinyMediaPlayer/Youtube` (https://www.youtube.com/watch?v=XXXXXXXXXXX)
47
+ * `SoundCloudMediaAdapter` from `tiny-essentials/libs/TinyMediaPlayer/SoundCloud` (https://api.soundcloud.com/tracks/XXXXXXXXX (From SoundCloud Embed))
48
+ * `HtmlAudioAdapter` from `tiny-essentials/libs/TinyMediaPlayer/HtmlAudio`
49
+ * `HtmlVideoAdapter` from `tiny-essentials/libs/TinyMediaPlayer/HtmlVideo`
50
+
51
+ **Example Usage:**
52
+ ```javascript
53
+ import TinyMediaPlayer from 'tiny-essentials/libs/TinyMediaPlayer';
54
+ import { YoutubeMediaAdapter } from 'tiny-essentials/libs/TinyMediaPlayer/Youtube';
55
+ import { HtmlAudioAdapter } from 'tiny-essentials/libs/TinyMediaPlayer/HtmlAudio';
56
+
57
+ const player = new TinyMediaPlayer({
58
+ persistVolume: true
59
+ });
60
+
61
+ YoutubeMediaAdapter.defaultContainer = YoutubeMediaAdapter.createIframeContainer({
62
+ videoId: 'fzKvGbQ9SgY',
63
+ hidden: true,
64
+ autoplay: false,
65
+ });
66
+
67
+ // Register the ready-made adapters
68
+ player.registerAdapter(new YoutubeMediaAdapter());
69
+ player.registerAdapter(new HtmlAudioAdapter());
70
+
71
+ // The player will now automatically select the correct adapter
72
+ // based on the content provided.
73
+ ```
74
+
75
+ #### 🛠️ Option 2: Creating Custom Adapters
76
+ If you need to support a service not covered by the pre-built adapters, you can create a custom class by extending the `BaseMediaAdapter`.
77
+
78
+ **Example Implementation:**
79
+ ```javascript
80
+ import { BaseMediaAdapter } from 'tiny-essentials/libs/TinyMediaPlayer/Base';
81
+
82
+ /**
83
+ * A custom adapter for a hypothetical streaming service.
84
+ * @extends BaseMediaAdapter
85
+ */
86
+ class MyCustomServiceAdapter extends BaseMediaAdapter {
87
+ /**
88
+ * Determines if this adapter can play the given content.
89
+ * @param {MediaContent} content - The media content to check.
90
+ * @returns {boolean} - True if the URL matches the service.
91
+ */
92
+ static canHandle(content) {
93
+ return content.url.startsWith('https://example.com/');
94
+ }
95
+
96
+ /**
97
+ * Determines if this adapter can play the given content.
98
+ * @param {MediaContent} content - The media content to check.
99
+ * @returns {boolean} - True if the URL matches the service.
100
+ */
101
+ canHandle(content) {
102
+ return MyCustomServiceAdapter.canHandle(content);
103
+ }
104
+
105
+ /**
106
+ * Starts playback for the provided content.
107
+ * @param {MediaContent} content - The content to play.
108
+ * @returns {Promise<void>}
109
+ */
110
+ async play(content) {
111
+ console.log(`Starting playback for: ${content.title}`);
112
+ // Logic to interface with the custom service API goes here
113
+ }
114
+
115
+ async pause() {
116
+ // Logic to pause custom service playback
117
+ }
118
+
119
+ async stop() {
120
+ // Logic to stop custom service playback
121
+ }
122
+
123
+ async seek(timeMs) {
124
+ // Logic to seek in custom service playback
125
+ }
126
+
127
+ getCurrentTime() {
128
+ // Logic to return current time from custom service
129
+ return 0;
130
+ }
131
+
132
+ setVolume(volume) {
133
+ // Logic to set volume on custom service
134
+ console.log(`Volume set to: ${volume}`);
135
+ }
136
+ }
137
+
138
+ // Registering the custom adapter
139
+ const player = new TinyMediaPlayer();
140
+ player.registerAdapter(new MyCustomServiceAdapter());
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 📊 Data Types
146
+
147
+ ### `ContentTimeData`
148
+ This object is emitted during the `timeupdate` event and provides real-time playback information.
149
+
150
+ | Property | Type | Description |
151
+ | :--- | :--- | :--- |
152
+ | `total` | `number` | The total duration of the media in milliseconds. |
153
+ | `current` | `number` | The current playback position in milliseconds. |
154
+ | `remaining` | `number` | The remaining time until the media ends in milliseconds. |
155
+ | `playbackPercentage` | `number` | The percentage of the media that has been played (0 to 100). |
156
+
157
+ ### `SearchResult`
158
+ Returned by the `searchTrack` method.
159
+
160
+ | Property | Type | Description |
161
+ | :--- | :--- | :--- |
162
+ | `track` | `MediaContent` | The matched media content object. |
163
+ | `index` | `number` | The current index of the track in the playlist. |
23
164
 
24
165
  ---
25
166
 
@@ -28,29 +169,43 @@ To support different media platforms, `TinyMediaPlayer` relies on **Adapters**.
28
169
  The main controller for managing playlists, playback state, and adapters.
29
170
 
30
171
  ### ⚙️ Configuration (Constructor Options)
31
- When initializing `new TinyMediaPlayer(options)`, you can pass the following:
172
+ When initializing `new TinyMediaPlayer(options)`, you can pass the following `TinyMediaPlayerOptions`:
32
173
 
33
- * **`persistVolume`** (`boolean`): If `true`, the volume level is automatically saved to and loaded from `localStorage`. (Default: `false`).
34
- * **`volumeStorageKey`** (`string`): The key name used in `localStorage` to store the volume. (Default: `'tiny_media_player_volume'`).
174
+ * **`persistVolume`** (`boolean`): If `true`, the volume level is automatically saved to and loaded from `localStorage`. (Default: `false`).
175
+ * **`volumeStorageKey`** (`string`): The key name used in `localStorage` to store the volume. (Default: `'tiny_media_player_volume'`).
176
+ * **`repeatCurrentOnPrev`** (`boolean`): If `true`, clicking 'previous' repeats the current track on the first click. (Default: `false`).
177
+ * **`smoothPlayPauseVolume`** (`boolean`): If `true`, volume fades smoothly during play/pause transitions. (Default: `false`).
178
+ * **`smoothStopVolume`** (`boolean`): If `true`, volume fades smoothly to zero when stopping. (Default: `false`).
35
179
 
36
180
  ---
37
181
 
38
182
  ### 🏗️ Static Members
39
183
 
40
184
  #### Properties
41
- * **`unknownArtist`**: A global setting for when an artist's name is unavailable.
42
- * **Type**: `string` | `function` (returns a string).
43
- * **Getter/Setter**: Allows you to define a custom string or a logic-based function.
185
+ * **`BaseMediaAdapter`**: A reference to the `BaseMediaAdapter` class (useful for `instanceof` checks).
186
+ * **`unknownArtist`**: A global setting for when an artist's name is unavailable.
187
+ * **Type**: `string` | `function` (returns a string).
188
+ * **Getter/Setter**: Allows you to define a custom string or a logic-based function.
189
+ * **`defaultAdapterEventNames`**: An array of strings representing the events the player listens to by default on all registered adapters.
190
+ * **Type**: `string[]` (e.g., `['timeupdate', 'ended']`).
191
+ * **Getter/Setter**: Allows customization of the default event subscription list.
44
192
 
45
193
  #### Methods
46
- * **`parseContent(source, defaultMetadata, metadata, parseFile, callbacks)`**:
47
- * A static factory method to prepare a `MediaContent` object by extracting metadata from a URL or HTMLMediaElement.
48
- * **Returns**: `Promise<MediaContent>`.
194
+ * **`parseContent(source, defaultMetadata, metadata, parseFile, callbacks)`**:
195
+ * A static factory method to prepare a `MediaContent` object by extracting metadata from a URL or HTMLMediaElement.
196
+ * **Parameters**:
197
+ * `source`: `string | HTMLMediaElement`
198
+ * `defaultMetadata`: `Partial<MediaContentBase & MediaContentMetadata>`
199
+ * `metadata`: `Partial<MediaContentBase & MediaContentMetadata>`
200
+ * `parseFile`: `ParseMediaContentMetadata`
201
+ * `callbacks`: `Object` (containing `onProgress` and `onError`)
202
+ * **Returns**: `Promise<MediaContent>`.
49
203
 
50
204
  ---
51
205
 
52
206
  ### 📊 Instance Properties (Getters & Setters)
53
207
 
208
+ #### 🔄 State & Playback
54
209
  | Property | Type | Description |
55
210
  | :--- | :--- | :--- |
56
211
  | `playlist` | `MediaContent[]` | Returns a shallow copy of the current playlist. |
@@ -58,43 +213,117 @@ When initializing `new TinyMediaPlayer(options)`, you can pass the following:
58
213
  | `loopMode` | `'NONE' \| 'TRACK' \| 'PLAYLIST'` | Defines how the player behaves at the end of a track. |
59
214
  | `isRandom` | `boolean` | Enables or disables shuffle mode. |
60
215
  | `isPlaying` | `boolean` | Indicates if media is currently playing. |
61
- | `volume` | `number` | The current volume (constrained between `0.0` and `1.0`). |
216
+ | `volume` | `number` | The current volume level (strictly between `0.0` and `1.0`). |
217
+
218
+ #### 🎨 UX & Customization
219
+ | Property | Type | Description |
220
+ | :--- | :--- | :--- |
221
+ | `repeatCurrentOnPrev` | `boolean` | Whether clicking 'previous' repeats the current track on first click. |
222
+ | `smoothPlayPauseVolume`| `boolean` | Enables smooth volume fading during play/pause. |
223
+ | `smoothStopVolume` | `boolean` | Enables smooth volume fading when stopping. |
224
+ | `fadeVolumeSpeed` | `number` | The duration (ms) of the volume fade transition (must be non-negative). |
225
+ | `prevClickTimeoutDuration`| `number` | The duration (ms) before the "repeat on prev" state resets (must be non-negative). |
62
226
  | `persistVolume` | `boolean` | Enables/disables volume saving to `localStorage`. |
63
- | `volumeStorageKey`| `string` | The key used for volume persistence. |
227
+ | `volumeStorageKey` | `string` | The key used for volume persistence (cannot be empty). |
228
+
229
+ #### 🛠️ Utility & Lifecycle
230
+ | Property | Type | Description |
231
+ | :--- | :--- | :--- |
232
+ | `destroyed` | `boolean` | Indicates if the instance has been destroyed. |
233
+ | `adapters` | `BaseMediaAdapter[]` | Returns an array of all registered adapters. |
234
+ | `adaptersSize` | `number` | The number of currently registered adapters. |
64
235
 
65
236
  ---
66
237
 
67
238
  ### 🕹️ Methods
68
239
 
69
240
  #### 🔌 Adapter Management
70
- * **`registerAdapter(id, adapter)`**: Registers a new provider.
71
- * `id`: A unique string (e.g., `'youtube'`).
72
- * `adapter`: An instance of a class extending `BaseMediaAdapter`.
241
+ * **`registerAdapter(adapter)`**: Registers a new provider.
242
+ * `adapter`: An instance of a class extending `BaseMediaAdapter`.
243
+ * **`removeAdapter(adapter)`**: Removes a specific registered adapter.
244
+ * **`destroyAdapter(adapter)`**: Destroys and removes a specific registered adapter.
245
+ * **`hasAdapter(adapter)`**: Checks if a specific adapter is registered.
246
+ * **`clearAdapters()`**: Clears the list of adapters (does not call `destroy` on them).
247
+ * **`destroyAllAdapters()`**: Destroys and removes all registered media adapters.
248
+ * **`getMediaAdapter(content)`**: Finds the compatible adapter for the provided content.
249
+
250
+ #### 📡 Event Management (Controlled)
251
+ *Use these methods to manage which events from the underlying adapters are proxied to the `TinyMediaPlayer` instance.*
252
+
253
+ * **`addAdapterEvent(eventName)`**: Subscribes the player to a new event type from all registered adapters.
254
+ * `eventName`: `string`.
255
+ * **`removeAdapterEvent(eventName)`**: Unsubscribes the player from a specific event type from all registered adapters.
256
+ * `eventName`: `string`.
257
+ * **`resetAdapterEvents()`**: Restores the event listener list to the default state defined by `TinyMediaPlayer.defaultAdapterEventNames`.
73
258
 
74
259
  #### 📋 Playlist Management
75
- * **`addTrack(content)`**: Adds a new `MediaContent` object to the end of the playlist.
76
- * **`existsTrack(index)`**: Returns `true` if a track exists at the given index.
77
- * **`getTrack(index)`**: Retrieves the track at the specified index.
78
- * **`removeTrack(index)`**: Removes a track. If the current track is removed, playback stops or adjusts.
79
- * **`searchTrack(query)`**: Searches the playlist.
80
- * `query`: A `string` (searches title, artist, or album) or a `function` (custom logic).
81
- * **Returns**: `SearchResult[]` (array of objects containing the track and its index).
82
- * **`clearPlaylist()`**: Stops playback and empties the playlist.
260
+ * **`addTrack(content)`**: Adds a new `MediaContent` object to the end of the playlist.
261
+ * **Returns**: `number` (the new length of the playlist).
262
+ * **`existsTrack(index)`**: Returns `true` if the track exists at the given index.
263
+ * **`getTrack(index)`**: Retrieves the track at the specified index.
264
+ * **`removeTrack(index)`**: **(Async)** Removes a track and adjusts the current index/playback accordingly.
265
+ * **`searchTrack(query)`**: Searches the playlist.
266
+ * `query`: A `string` (searches title, artist, or album) or a `function` (custom logic).
267
+ * **Returns**: `SearchResult[]` (array of objects containing the track and their corresponding indices).
268
+ * **`clearPlaylist()`**: **(Async)** Stops playback and empties the entire playlist.
83
269
 
84
270
  #### ⏯️ Playback Controls
85
- * **`play()`**: Starts playback of the current track.
86
- * **`pause()`**: Pauses the current track.
87
- * **`stop()`**: Stops the current track completely.
88
- * **`next()`**: Advances to the next track (respects `loopMode` and `isRandom`).
89
- * **`prev()`**: Returns to the previous track (respects `loopMode` and `isRandom`).
90
- * **`seek(timeMs)`**: Jumps to a specific millisecond in the current track.
91
- * **`step(stepMs)`**: Moves the timeline forward (positive) or backward (negative) by a specific amount.
271
+ * **`play()`**: **(Async)** Starts playback of the current track.
272
+ * **`pause()`**: **(Async)** Pauses the current track.
273
+ * **`stop()`**: **(Async)** Stops the current track completely.
274
+ * **`next()`**: **(Async)** Advances to the next track (respects `loopMode` and `isRandom`).
275
+ * **`prev()`**: **(Async)** Returns to the previous track (respects `loopMode` and `isRandom`).
276
+ * **`seek(timeMs)`**: **(Async)** Jumps to a specific millisecond in the current track.
277
+ * **`step(stepMs)`**: **(Async)** Moves the timeline forward (positive) or backward (negative) by a specified amount.
278
+
279
+ #### ⏳ Time Utilities
280
+ * **`getCurrentTime()`**: Gets the current playback time in milliseconds.
281
+ * **`getTotalDuration()`**: Gets the total duration of the current track in milliseconds.
282
+ * **`getRemainingTime()`**: Gets the remaining time until the current track ends in milliseconds.
283
+ * **`getPlaybackPercentage()`**: Gets the percentage of the current track that has been played (0-100).
284
+
285
+ #### ♻️ Lifecycle
286
+ * **`destroy()`**: **(Async)** Safely stops playback, clears state, removes adapters, and detaches all listeners to prevent memory leaks.
287
+
288
+ ---
289
+
290
+ ## 📡 Emitted Events
291
+
292
+ `TinyMediaPlayer` extends `EventEmitter`. You can listen to the following events.
293
+
294
+ ### 🎶 Playback Events
295
+ | Event | Data Type | Description |
296
+ | :--- | :--- | :--- |
297
+ | `play` | `number` | Emitted when playback starts. Returns the `currentIndex`. |
298
+ | `pause` | `number` | Emitted when playback is paused. Returns the `currentIndex`. |
299
+ | `stop` | `number` | Emitted when playback is stopped. Returns the `currentIndex`. |
300
+ | `seek` | `number` | Emitted when the timeline is jumped to a new time (in ms). |
301
+ | `timeupdate` | `ContentTimeData` | Emitted by the adapter every time the playback position changes (in ms). |
302
+
303
+ ### 🔄 State & Configuration Events
304
+ | Event | Data Type | Description |
305
+ | :--- | :--- | :--- |
306
+ | `playlistUpdate` | `MediaContent[]` | Emitted when the playlist is modified. |
307
+ | `trackChange` | `number` | Emitted when the `currentIndex` changes. |
308
+ | `volumeChange` | `number` | Emitted when the volume is updated (0.0 to 1.0). |
309
+ | `isRandomChange` | `boolean` | Emitted when the random mode is toggled. |
310
+ | `loopModeChange` | `LoopModeType` | Emitted when the loop mode is changed. |
311
+ | `repeatCurrentOnPrevChange` | `boolean` | Emitted when the "repeat on prev" setting is toggled. |
312
+ | `smoothPlayPauseVolumeChange` | `boolean` | Emitted when the smooth play/pause volume setting is toggled. |
313
+ | `smoothStopVolumeChange` | `boolean` | Emitted when the smooth stop volume setting is toggled. |
314
+ | `fadeVolumeSpeedChange` | `number` | Emitted when the volume fade speed is updated. |
315
+ | `prevClickTimeoutDurationChange` | `number` | Emitted when the "repeat on prev" timeout duration is updated. |
316
+
317
+ ### 💀 Lifecycle Events
318
+ | Event | Data Type | Description |
319
+ | :--- | :--- | :--- |
320
+ | `destroyed` | `void` | Emitted when the `destroy()` method has finished executing. |
92
321
 
93
322
  ---
94
323
 
95
324
  ## ⚠️ Error Handling
96
325
 
97
326
  The class uses strict validation. The following errors may be thrown:
98
- * **`TypeError`**: Thrown when an argument is of the wrong type (e.g., passing a string to `volume`).
99
- * **`RangeError`**: Thrown when a number is out of allowed bounds (e.g., an index that doesn't exist or volume > 1.0).
100
- * **`Error`**: Thrown if no compatible adapter is found for the current content.
327
+ * **`TypeError`**: Thrown when an argument is of the wrong type (e.g., invalid index type, non-boolean options, invalid adapter instance, or empty storage key).
328
+ * **`RangeError`**: Thrown when a number is out of allowed bounds (e.g., negative time, volume outside `0.0`-`1.0`, negative durations, or index out of playlist bounds).
329
+ * **`Error`**: Thrown if no compatible adapter is found for the current content.
@@ -78,20 +78,7 @@ A numeric ID returned by `setTimeout`, which can be manually canceled later usin
78
78
 
79
79
  ---
80
80
 
81
- ### 🔁 `waitForTrue(getValue, checkInterval = 100)`
82
-
83
- Waits until a provided function returns `true`, polling periodically.
84
-
85
- ```ts
86
- static waitForTrue(getValue: () => boolean, checkInterval?: number): Promise<void>
87
- ```
88
-
89
- * `getValue`: Function that returns `true` when the wait should end.
90
- * `checkInterval`: Polling interval in milliseconds.
91
-
92
- ---
93
-
94
- ### 🧩 `waitForTrue(getValue, checkInterval?)` *(instance version)*
81
+ ### 🧩 `waitForTrue(getValue, checkInterval?)`
95
82
 
96
83
  Same as `waitForTrue`, but uses the instance's `cooldownWatcherTime` as the default if `checkInterval` is `null`.
97
84
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-essentials",
3
- "version": "1.28.4",
3
+ "version": "1.28.6",
4
4
  "description": "Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.",
5
5
  "bin": {
6
6
  "tiny-essentials-fork": "./TinyFork.mjs"
@@ -108,6 +108,10 @@
108
108
  "require": "./dist/v1/basics/text.cjs",
109
109
  "import": "./dist/v1/basics/text.mjs"
110
110
  },
111
+ "./basics/promiseUtils": {
112
+ "require": "./dist/v1/basics/promiseUtils.cjs",
113
+ "import": "./dist/v1/basics/promiseUtils.mjs"
114
+ },
111
115
  "./fileManager": {
112
116
  "require": "./dist/v1/fileManager/index.cjs",
113
117
  "import": "./dist/v1/fileManager/index.mjs"
@@ -132,6 +136,30 @@
132
136
  "require": "./dist/v1/libs/TinyMediaPlayer.cjs",
133
137
  "import": "./dist/v1/libs/TinyMediaPlayer.mjs"
134
138
  },
139
+ "./libs/TinyMediaPlayer/Base": {
140
+ "require": "./dist/v1/libs/TinyMediaPlayer/index.cjs",
141
+ "import": "./dist/v1/libs/TinyMediaPlayer/index.mjs"
142
+ },
143
+ "./libs/TinyMediaPlayer/Youtube": {
144
+ "require": "./dist/v1/libs/TinyMediaPlayer/Youtube.cjs",
145
+ "import": "./dist/v1/libs/TinyMediaPlayer/Youtube.mjs"
146
+ },
147
+ "./libs/TinyMediaPlayer/SoundCloud": {
148
+ "require": "./dist/v1/libs/TinyMediaPlayer/SoundCloud.cjs",
149
+ "import": "./dist/v1/libs/TinyMediaPlayer/SoundCloud.mjs"
150
+ },
151
+ "./libs/TinyMediaPlayer/HtmlAudio": {
152
+ "require": "./dist/v1/libs/TinyMediaPlayer/HtmlAudio.cjs",
153
+ "import": "./dist/v1/libs/TinyMediaPlayer/HtmlAudio.mjs"
154
+ },
155
+ "./libs/TinyMediaPlayer/HtmlVideo": {
156
+ "require": "./dist/v1/libs/TinyMediaPlayer/HtmlVideo.cjs",
157
+ "import": "./dist/v1/libs/TinyMediaPlayer/HtmlVideo.mjs"
158
+ },
159
+ "./libs/TinyMediaPlayer/docs/YouTubePlayer": {
160
+ "require": "./dist/v1/libs/TinyMediaPlayer/docs/YouTubePlayer.cjs",
161
+ "import": "./dist/v1/libs/TinyMediaPlayer/docs/YouTubePlayer.mjs"
162
+ },
135
163
  "./libs/TinyRadioFm": {
136
164
  "require": "./dist/v1/libs/TinyRadioFm.cjs",
137
165
  "import": "./dist/v1/libs/TinyRadioFm.mjs"
@@ -483,23 +511,16 @@
483
511
  },
484
512
  "keywords": [
485
513
  "tiny-essentials",
486
- "timeout",
514
+ "utility-library",
487
515
  "storage",
488
516
  "text-editor",
489
517
  "color-converter",
490
518
  "clock",
491
519
  "time",
492
- "text",
493
- "text-range",
494
- "input-editor",
495
- "string-utils",
496
520
  "string-manipulation",
497
521
  "obj-type",
498
522
  "type-checker",
499
- "simple-math",
500
- "math-utils",
501
523
  "shuffle-array",
502
- "array-utils",
503
524
  "json",
504
525
  "json-utils",
505
526
  "json-color",
@@ -516,7 +537,47 @@
516
537
  "toolkit",
517
538
  "frontend-utils",
518
539
  "backend-utils",
519
- "nodejs-utils"
540
+ "nodejs-utils",
541
+ "array-utils",
542
+ "object-utils",
543
+ "string-utils",
544
+ "math-utils",
545
+ "dom-utils",
546
+ "html-utils",
547
+ "css-utils",
548
+ "modular-scripts",
549
+ "type-validation",
550
+ "text-manipulation",
551
+ "text-formatting",
552
+ "color-management",
553
+ "color-conversion",
554
+ "color-validation",
555
+ "drag-and-drop",
556
+ "scroll-management",
557
+ "clipboard-management",
558
+ "notifications",
559
+ "toast-notifications",
560
+ "loading-screen",
561
+ "cookie-consent",
562
+ "i18n",
563
+ "iframe-communication",
564
+ "window-communication",
565
+ "media-playback",
566
+ "audio-processing",
567
+ "gamepad-api",
568
+ "input-handling",
569
+ "file-upload",
570
+ "inventory-management",
571
+ "level-up-system",
572
+ "raffle-system",
573
+ "day-night-cycle",
574
+ "rate-limiting",
575
+ "promise-queue",
576
+ "file-management",
577
+ "terminal-ui",
578
+ "json-formatting",
579
+ "fuzzy-logic",
580
+ "text-range-editor"
520
581
  ],
521
582
  "author": "Yasmin Seidel (Jasmin Dreasond)",
522
583
  "license": "LGPL-3.0-only",