vidply 1.2.0 → 1.2.1

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 (164) hide show
  1. package/README.md +946 -946
  2. package/dist/dev/{vidply.AudioDescriptionManager-R47Q4YR4.js → vidply.AudioDescriptionManager-6RFVF27Z.js} +275 -19
  3. package/dist/dev/vidply.AudioDescriptionManager-6RFVF27Z.js.map +7 -0
  4. package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js → vidply.CaptionStyleMenu-R2SCQ6VP.js} +4 -4
  5. package/dist/dev/{vidply.DASHRenderer-PWEMC3BT.js → vidply.DASHRenderer-EOVEW73H.js} +3 -3
  6. package/dist/dev/vidply.DASHRenderer-EOVEW73H.js.map +7 -0
  7. package/dist/dev/{vidply.FloatingPlayerManager-PKNNNAS2.js → vidply.FloatingPlayerManager-V5XQWS75.js} +5 -5
  8. package/dist/dev/vidply.FloatingPlayerManager-V5XQWS75.js.map +7 -0
  9. package/dist/dev/{vidply.HLSRenderer-E7RQ74HI.js → vidply.HLSRenderer-ZBEFVH5W.js} +4 -4
  10. package/dist/dev/vidply.HLSRenderer-ZBEFVH5W.js.map +7 -0
  11. package/dist/dev/vidply.HTML5Renderer-P7ICKYU4.js +12 -0
  12. package/dist/dev/{vidply.SignLanguageManager-FET5FQZ7.js → vidply.SignLanguageManager-7IAJOVF6.js} +8 -8
  13. package/dist/dev/vidply.SignLanguageManager-7IAJOVF6.js.map +7 -0
  14. package/dist/dev/{vidply.SoundCloudRenderer-RVSJZODO.js → vidply.SoundCloudRenderer-OA7QQYGN.js} +3 -3
  15. package/dist/dev/vidply.SoundCloudRenderer-OA7QQYGN.js.map +7 -0
  16. package/dist/dev/{vidply.TranscriptManager-5GXOQCLX.js → vidply.TranscriptManager-BPM3T23L.js} +10 -10
  17. package/dist/dev/vidply.TranscriptManager-BPM3T23L.js.map +7 -0
  18. package/dist/dev/{vidply.VimeoRenderer-ER2LSBBW.js → vidply.VimeoRenderer-BRHFYPNJ.js} +3 -3
  19. package/dist/dev/vidply.VimeoRenderer-BRHFYPNJ.js.map +7 -0
  20. package/dist/dev/{vidply.YouTubeRenderer-NFTOWJAB.js → vidply.YouTubeRenderer-HRTN4EJ5.js} +3 -3
  21. package/dist/dev/vidply.YouTubeRenderer-HRTN4EJ5.js.map +7 -0
  22. package/dist/dev/{vidply.chunk-6RQA4ROD.js → vidply.chunk-5IK3IC5V.js} +2 -2
  23. package/dist/dev/{vidply.chunk-JJ47NO24.js → vidply.chunk-C55OBT5H.js} +2 -2
  24. package/dist/dev/vidply.chunk-C55OBT5H.js.map +7 -0
  25. package/dist/dev/{vidply.chunk-DZSDO3B7.js → vidply.chunk-HOYEMJSD.js} +2 -2
  26. package/dist/dev/{vidply.chunk-VMSQAZM7.js → vidply.chunk-JAKZNGOR.js} +2 -2
  27. package/dist/dev/{vidply.chunk-64WXMTGL.js → vidply.chunk-LDVFAFGC.js} +5 -5
  28. package/dist/dev/vidply.chunk-LDVFAFGC.js.map +7 -0
  29. package/dist/dev/{vidply.chunk-RZWZGDV7.js → vidply.chunk-NSMAZCMB.js} +6 -6
  30. package/dist/dev/vidply.chunk-NSMAZCMB.js.map +7 -0
  31. package/dist/dev/{vidply.chunk-KI7C3QVL.js → vidply.chunk-RQG3MA7W.js} +2 -2
  32. package/dist/dev/vidply.chunk-RQG3MA7W.js.map +7 -0
  33. package/dist/dev/{vidply.chunk-BNFIUL2Z.js → vidply.chunk-UHMVDBDB.js} +3 -3
  34. package/dist/dev/vidply.chunk-UHMVDBDB.js.map +7 -0
  35. package/dist/dev/{vidply.chunk-NQPURMQY.js → vidply.chunk-W5BR65JY.js} +6 -6
  36. package/dist/dev/vidply.chunk-W5BR65JY.js.map +7 -0
  37. package/dist/dev/{vidply.chunk-W25HUCHS.js → vidply.chunk-XAK3DPTO.js} +2 -2
  38. package/dist/dev/vidply.chunk-XAK3DPTO.js.map +7 -0
  39. package/dist/dev/{vidply.chunk-SK4V2DAU.js → vidply.chunk-YVCYQZJI.js} +3 -3
  40. package/dist/dev/{vidply.de-4YAT7FFM.js → vidply.de-5W5LBFSJ.js} +2 -2
  41. package/dist/dev/vidply.de-5W5LBFSJ.js.map +7 -0
  42. package/dist/dev/{vidply.es-LEWIRUBH.js → vidply.es-SHDAT6L6.js} +2 -2
  43. package/dist/dev/vidply.es-SHDAT6L6.js.map +7 -0
  44. package/dist/dev/vidply.esm.js +73 -34
  45. package/dist/dev/vidply.esm.js.map +2 -2
  46. package/dist/dev/{vidply.fr-Q4GV2NOE.js → vidply.fr-2JANOMNB.js} +2 -2
  47. package/dist/dev/vidply.fr-2JANOMNB.js.map +7 -0
  48. package/dist/dev/{vidply.ja-S6ITA6WU.js → vidply.ja-WWMSTEJH.js} +2 -2
  49. package/dist/dev/vidply.ja-WWMSTEJH.js.map +7 -0
  50. package/dist/legacy/vidply.js +345 -32
  51. package/dist/legacy/vidply.js.map +3 -3
  52. package/dist/legacy/vidply.min.js +2 -2
  53. package/dist/legacy/vidply.min.meta.json +66 -47
  54. package/dist/prod/vidply.AudioDescriptionManager-YTDVDQBO.min.js +6 -0
  55. package/dist/prod/{vidply.CaptionStyleMenu-M3KVQWB5.min.js → vidply.CaptionStyleMenu-2AFF3HF2.min.js} +2 -2
  56. package/dist/prod/{vidply.DASHRenderer-DN3S27AV.min.js → vidply.DASHRenderer-URDOTOKS.min.js} +2 -2
  57. package/dist/prod/{vidply.FloatingPlayerManager-SKAZ4J43.min.js → vidply.FloatingPlayerManager-QUBFK7CQ.min.js} +2 -2
  58. package/dist/prod/{vidply.HLSRenderer-62HH4YTK.min.js → vidply.HLSRenderer-46KNUVAB.min.js} +2 -2
  59. package/dist/prod/vidply.HTML5Renderer-7TQDMIGY.min.js +6 -0
  60. package/dist/prod/{vidply.SignLanguageManager-V3OBTSSF.min.js → vidply.SignLanguageManager-H4C36EVL.min.js} +2 -2
  61. package/dist/prod/{vidply.SoundCloudRenderer-CXRVZIAJ.min.js → vidply.SoundCloudRenderer-OYSWMW7D.min.js} +2 -2
  62. package/dist/prod/{vidply.TranscriptManager-SYM3DFUY.min.js → vidply.TranscriptManager-BA3DAS63.min.js} +2 -2
  63. package/dist/prod/{vidply.VimeoRenderer-72TWRYFQ.min.js → vidply.VimeoRenderer-NF3COTHU.min.js} +2 -2
  64. package/dist/prod/{vidply.YouTubeRenderer-UMHEV3KD.min.js → vidply.YouTubeRenderer-UCQKYIJ4.min.js} +2 -2
  65. package/dist/prod/{vidply.chunk-Z3YDSA7O.min.js → vidply.chunk-2HNCP64N.min.js} +1 -1
  66. package/dist/prod/{vidply.chunk-EKEYJWMG.min.js → vidply.chunk-6ECBIYVI.min.js} +2 -2
  67. package/dist/prod/{vidply.chunk-YEENJS3Q.min.js → vidply.chunk-7S5AFTST.min.js} +2 -2
  68. package/dist/prod/{vidply.chunk-P4UXOHWA.min.js → vidply.chunk-EUOA2DJK.min.js} +1 -1
  69. package/dist/prod/{vidply.chunk-2TB6MUHO.min.js → vidply.chunk-G6KGXNEW.min.js} +1 -1
  70. package/dist/prod/{vidply.chunk-ABPXVDLZ.min.js → vidply.chunk-JPMAK3NS.min.js} +1 -1
  71. package/dist/prod/{vidply.chunk-P3PQBY7N.min.js → vidply.chunk-L4O44K63.min.js} +1 -1
  72. package/dist/prod/{vidply.chunk-WX3MVEAL.min.js → vidply.chunk-M76ABMKB.min.js} +1 -1
  73. package/dist/prod/{vidply.chunk-TM6AXJVD.min.js → vidply.chunk-WRVDVD33.min.js} +2 -2
  74. package/dist/prod/{vidply.chunk-RI3X7WHK.min.js → vidply.chunk-X2FQEQYR.min.js} +2 -2
  75. package/dist/prod/{vidply.chunk-UK7YGOB5.min.js → vidply.chunk-XXUH7ADU.min.js} +2 -2
  76. package/dist/prod/{vidply.de-BCHXRQ53.min.js → vidply.de-JMCATTKZ.min.js} +1 -1
  77. package/dist/prod/{vidply.es-PICAKMZD.min.js → vidply.es-YVG37V7Z.min.js} +1 -1
  78. package/dist/prod/vidply.esm.min.js +2 -2
  79. package/dist/prod/{vidply.fr-ZILI7CDR.min.js → vidply.fr-OGKGN2R4.min.js} +1 -1
  80. package/dist/prod/{vidply.ja-5WQ4OK4J.min.js → vidply.ja-Z6DS7QLS.min.js} +1 -1
  81. package/dist/vidply.css +5796 -5796
  82. package/dist/vidply.esm.min.meta.json +148 -135
  83. package/package.json +7 -7
  84. package/src/controls/CaptionManager.ts +598 -598
  85. package/src/controls/ControlBar.ts +4159 -4159
  86. package/src/controls/KeyboardManager.ts +383 -383
  87. package/src/controls/SettingsDialog.ts +488 -488
  88. package/src/controls/TranscriptManager.ts +2426 -2426
  89. package/src/core/AudioDescriptionManager.ts +863 -774
  90. package/src/core/DescriptionSpeechManager.ts +232 -0
  91. package/src/core/FloatingPlayerManager.ts +674 -674
  92. package/src/core/LazyInit.ts +80 -80
  93. package/src/core/MetadataAlertsManager.ts +514 -514
  94. package/src/core/Player.ts +2915 -2872
  95. package/src/core/PosterManager.ts +169 -169
  96. package/src/core/PseudoFullscreen.ts +179 -179
  97. package/src/core/ResponsiveManager.ts +231 -231
  98. package/src/core/ResumeManager.ts +236 -236
  99. package/src/core/SignLanguageManager.ts +1308 -1308
  100. package/src/core/ThemeManager.ts +157 -157
  101. package/src/features/PlaylistManager.ts +1838 -1827
  102. package/src/i18n/i18n.ts +223 -223
  103. package/src/i18n/languages/de.ts +217 -217
  104. package/src/i18n/languages/en.ts +218 -218
  105. package/src/i18n/languages/es.ts +214 -214
  106. package/src/i18n/languages/fr.ts +214 -214
  107. package/src/i18n/languages/ja.ts +214 -214
  108. package/src/icons/Icons.ts +167 -167
  109. package/src/index.ts +196 -193
  110. package/src/renderers/DASHRenderer.ts +1077 -1077
  111. package/src/renderers/HLSRenderer.ts +944 -944
  112. package/src/renderers/HTML5Renderer.ts +389 -389
  113. package/src/renderers/SoundCloudRenderer.ts +437 -437
  114. package/src/renderers/VimeoRenderer.ts +298 -298
  115. package/src/renderers/YouTubeRenderer.ts +290 -290
  116. package/src/styles/vidply.css +5796 -5796
  117. package/src/types/events.ts +124 -122
  118. package/src/types/globals.d.ts +313 -313
  119. package/src/types/options.ts +185 -182
  120. package/src/types/renderer.ts +58 -58
  121. package/src/utils/DOMUtils.ts +281 -281
  122. package/src/utils/DownloadInfo.ts +171 -171
  123. package/src/utils/DraggablePanel.ts +539 -539
  124. package/src/utils/DraggablePanelMenu.ts +195 -195
  125. package/src/utils/DraggableResizable.ts +997 -997
  126. package/src/utils/EventEmitter.ts +59 -59
  127. package/src/utils/FormUtils.ts +95 -95
  128. package/src/utils/MenuFactory.ts +483 -483
  129. package/src/utils/Sanitize.ts +70 -70
  130. package/src/utils/SettingsMenuFactory.ts +289 -289
  131. package/src/utils/StorageManager.ts +287 -287
  132. package/src/utils/TrackLabelUtils.ts +52 -52
  133. package/src/utils/UrlSafe.ts +69 -69
  134. package/src/utils/VideoFrameCapture.ts +114 -114
  135. package/src/utils/WindowComponents.ts +250 -250
  136. package/dist/dev/vidply.AudioDescriptionManager-R47Q4YR4.js.map +0 -7
  137. package/dist/dev/vidply.DASHRenderer-PWEMC3BT.js.map +0 -7
  138. package/dist/dev/vidply.FloatingPlayerManager-PKNNNAS2.js.map +0 -7
  139. package/dist/dev/vidply.HLSRenderer-E7RQ74HI.js.map +0 -7
  140. package/dist/dev/vidply.HTML5Renderer-BU4QJJJY.js +0 -12
  141. package/dist/dev/vidply.SignLanguageManager-FET5FQZ7.js.map +0 -7
  142. package/dist/dev/vidply.SoundCloudRenderer-RVSJZODO.js.map +0 -7
  143. package/dist/dev/vidply.TranscriptManager-5GXOQCLX.js.map +0 -7
  144. package/dist/dev/vidply.VimeoRenderer-ER2LSBBW.js.map +0 -7
  145. package/dist/dev/vidply.YouTubeRenderer-NFTOWJAB.js.map +0 -7
  146. package/dist/dev/vidply.chunk-64WXMTGL.js.map +0 -7
  147. package/dist/dev/vidply.chunk-BNFIUL2Z.js.map +0 -7
  148. package/dist/dev/vidply.chunk-JJ47NO24.js.map +0 -7
  149. package/dist/dev/vidply.chunk-KI7C3QVL.js.map +0 -7
  150. package/dist/dev/vidply.chunk-NQPURMQY.js.map +0 -7
  151. package/dist/dev/vidply.chunk-RZWZGDV7.js.map +0 -7
  152. package/dist/dev/vidply.chunk-W25HUCHS.js.map +0 -7
  153. package/dist/dev/vidply.de-4YAT7FFM.js.map +0 -7
  154. package/dist/dev/vidply.es-LEWIRUBH.js.map +0 -7
  155. package/dist/dev/vidply.fr-Q4GV2NOE.js.map +0 -7
  156. package/dist/dev/vidply.ja-S6ITA6WU.js.map +0 -7
  157. package/dist/prod/vidply.AudioDescriptionManager-RHLIJW5C.min.js +0 -6
  158. package/dist/prod/vidply.HTML5Renderer-IU5T3WEW.min.js +0 -6
  159. /package/dist/dev/{vidply.CaptionStyleMenu-7XHRBWUM.js.map → vidply.CaptionStyleMenu-R2SCQ6VP.js.map} +0 -0
  160. /package/dist/dev/{vidply.HTML5Renderer-BU4QJJJY.js.map → vidply.HTML5Renderer-P7ICKYU4.js.map} +0 -0
  161. /package/dist/dev/{vidply.chunk-6RQA4ROD.js.map → vidply.chunk-5IK3IC5V.js.map} +0 -0
  162. /package/dist/dev/{vidply.chunk-DZSDO3B7.js.map → vidply.chunk-HOYEMJSD.js.map} +0 -0
  163. /package/dist/dev/{vidply.chunk-VMSQAZM7.js.map → vidply.chunk-JAKZNGOR.js.map} +0 -0
  164. /package/dist/dev/{vidply.chunk-SK4V2DAU.js.map → vidply.chunk-YVCYQZJI.js.map} +0 -0
package/src/index.ts CHANGED
@@ -1,193 +1,196 @@
1
- /**
2
- * VidPly - Universal Video Player
3
- * Main Entry Point
4
- */
5
-
6
- import { Player } from './core/Player.js';
7
- import { observeForLazyInit } from './core/LazyInit.js';
8
- import { PlaylistManager } from './features/PlaylistManager.js';
9
- import { isForbiddenKey } from './utils/Sanitize.js';
10
- import type { PlayerOptions } from './types/options.js';
11
-
12
- // Re-export so existing consumers of `import { LazyHandle } from 'vidply'`
13
- // keep working; the canonical definition now lives in core/LazyInit.
14
- export type { LazyHandle } from './core/LazyInit.js';
15
-
16
- /**
17
- * Filter `__proto__` / `constructor` / `prototype` keys from an attacker-
18
- * influenced JSON object before merging it into the player options. This
19
- * avoids prototype-pollution turning a malformed `data-vidply-options`
20
- * attribute into a global gadget.
21
- */
22
- function sanitizeOptionsObject(input: unknown): Partial<PlayerOptions> {
23
- if (!input || typeof input !== 'object' || Array.isArray(input)) {
24
- return {};
25
- }
26
- const out: Record<string, unknown> = Object.create(null);
27
- for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
28
- if (isForbiddenKey(key)) continue;
29
- out[key] = value;
30
- }
31
- return out as Partial<PlayerOptions>;
32
- }
33
-
34
- /**
35
- * Parse a `data-vidply-options` JSON string. Robust against malformed input
36
- * — a single broken attribute on one element no longer aborts the auto-init
37
- * loop for every other player on the page.
38
- */
39
- function parseInlineOptions(element: HTMLElement): Partial<PlayerOptions> {
40
- const raw = element.dataset.vidplyOptions;
41
- if (!raw) return {};
42
- try {
43
- const parsed: unknown = JSON.parse(raw);
44
- return sanitizeOptionsObject(parsed);
45
- } catch (err) {
46
- console.warn('[VidPly] Ignored malformed data-vidply-options:', err);
47
- return {};
48
- }
49
- }
50
-
51
- function initializePlayers(): void {
52
- const elements = document.querySelectorAll<HTMLElement>('[data-vidply]');
53
-
54
- elements.forEach((element) => {
55
- const options = parseInlineOptions(element);
56
- const dataOptions = parseDataAttributes(element.dataset);
57
- const mergedOptions: Partial<PlayerOptions> = { ...dataOptions, ...options };
58
-
59
- const lazyInit =
60
- element.dataset.vidplyLazy !== 'false' && mergedOptions.lazyInit !== false;
61
- const lazyMargin =
62
- element.dataset.vidplyLazyMargin || (mergedOptions.lazyMargin as string) || '500px';
63
-
64
- if (lazyInit && 'IntersectionObserver' in window) {
65
- observeForLazyInit<Partial<PlayerOptions>>(
66
- element,
67
- mergedOptions,
68
- lazyMargin,
69
- (target, opts) => { new Player(target, opts); }
70
- );
71
- } else {
72
- new Player(element, mergedOptions);
73
- }
74
- });
75
- }
76
-
77
- function parseDataAttributes(dataset: DOMStringMap): Partial<PlayerOptions> {
78
- const options: Record<string, unknown> = Object.create(null);
79
-
80
- const attributeMap: Record<string, keyof PlayerOptions> = {
81
- signLanguageSrc: 'signLanguageSrc',
82
- signLanguageButton: 'signLanguageButton',
83
- signLanguagePosition: 'signLanguagePosition',
84
- signLanguageDisplayMode: 'signLanguageDisplayMode',
85
- audioDescriptionSrc: 'audioDescriptionSrc',
86
- audioDescriptionButton: 'audioDescriptionButton',
87
- autoplay: 'autoplay',
88
- loop: 'loop',
89
- muted: 'muted',
90
- controls: 'controls',
91
- poster: 'poster',
92
- width: 'width',
93
- height: 'height',
94
- language: 'language',
95
- captions: 'captions',
96
- captionsDefault: 'captionsDefault',
97
- transcript: 'transcript',
98
- transcriptButton: 'transcriptButton',
99
- keyboard: 'keyboard',
100
- responsive: 'responsive',
101
- pipButton: 'pipButton',
102
- fullscreenButton: 'fullscreenButton',
103
- floating: 'floating',
104
- floatingPosition: 'floatingPosition',
105
- floatingMinViewportWidth: 'floatingMinViewportWidth',
106
- lazyInit: 'lazyInit',
107
- lazyMargin: 'lazyMargin',
108
- theme: 'theme'
109
- };
110
-
111
- for (const [dataKey, optionKey] of Object.entries(attributeMap)) {
112
- if (isForbiddenKey(optionKey)) continue;
113
- const value = dataset[dataKey];
114
- if (value === undefined) continue;
115
- if (value === 'true') {
116
- options[optionKey] = true;
117
- } else if (value === 'false') {
118
- options[optionKey] = false;
119
- } else if (value !== '' && !Number.isNaN(Number(value))) {
120
- options[optionKey] = Number(value);
121
- } else {
122
- options[optionKey] = value;
123
- }
124
- }
125
-
126
- const signLanguageSources: Record<string, string> = Object.create(null);
127
- for (const key of Object.keys(dataset)) {
128
- if (key.startsWith('signLanguageSrc') && key !== 'signLanguageSrc') {
129
- const langMatch = key.match(/^signLanguageSrc([A-Z][a-z]*)$/);
130
- if (langMatch && langMatch[1]) {
131
- const langCode = langMatch[1].toLowerCase();
132
- const value = dataset[key];
133
- if (value !== undefined) {
134
- signLanguageSources[langCode] = value;
135
- }
136
- }
137
- }
138
- }
139
-
140
- if (Object.keys(signLanguageSources).length > 0) {
141
- options.signLanguageSources = signLanguageSources;
142
- if (dataset.signLanguageSrc && !options.signLanguageSrc) {
143
- options.signLanguageSrc = dataset.signLanguageSrc;
144
- }
145
- }
146
-
147
- if (dataset.vidplyLanguageFiles) {
148
- try {
149
- const parsed = JSON.parse(dataset.vidplyLanguageFiles);
150
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
151
- options.languageFiles = sanitizeOptionsObject(parsed) as Record<string, string>;
152
- }
153
- } catch (e) {
154
- console.warn('Invalid JSON in data-vidply-language-files:', e);
155
- }
156
- }
157
-
158
- if (dataset.vidplyLanguageFile) {
159
- try {
160
- const parsed = JSON.parse(dataset.vidplyLanguageFile);
161
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
162
- options.languageFiles = sanitizeOptionsObject(parsed) as Record<string, string>;
163
- }
164
- } catch {
165
- if (dataset.vidplyLanguageFileCode && dataset.vidplyLanguageFileUrl) {
166
- options.languageFile = dataset.vidplyLanguageFileCode;
167
- options.languageFileUrl = dataset.vidplyLanguageFileUrl;
168
- }
169
- }
170
- } else if (dataset.vidplyLanguageFileCode && dataset.vidplyLanguageFileUrl) {
171
- options.languageFile = dataset.vidplyLanguageFileCode;
172
- options.languageFileUrl = dataset.vidplyLanguageFileUrl;
173
- }
174
-
175
- return options as Partial<PlayerOptions>;
176
- }
177
-
178
- if (document.readyState === 'loading') {
179
- document.addEventListener('DOMContentLoaded', initializePlayers);
180
- } else {
181
- initializePlayers();
182
- }
183
-
184
- export { Player, PlaylistManager };
185
- export type { PlayerOptions } from './types/options.js';
186
- export type {
187
- PlayerEventMap,
188
- PlaylistTrack,
189
- FloatingChangeDetail
190
- } from './types/events.js';
191
- export type { PlayerState } from './types/state.js';
192
- export type { Renderer, QualityLevel } from './types/renderer.js';
193
- export default Player;
1
+ /**
2
+ * VidPly - Universal Video Player
3
+ * Main Entry Point
4
+ */
5
+
6
+ import { Player } from './core/Player.js';
7
+ import { observeForLazyInit } from './core/LazyInit.js';
8
+ import { PlaylistManager } from './features/PlaylistManager.js';
9
+ import { isForbiddenKey } from './utils/Sanitize.js';
10
+ import type { PlayerOptions } from './types/options.js';
11
+
12
+ // Re-export so existing consumers of `import { LazyHandle } from 'vidply'`
13
+ // keep working; the canonical definition now lives in core/LazyInit.
14
+ export type { LazyHandle } from './core/LazyInit.js';
15
+
16
+ /**
17
+ * Filter `__proto__` / `constructor` / `prototype` keys from an attacker-
18
+ * influenced JSON object before merging it into the player options. This
19
+ * avoids prototype-pollution turning a malformed `data-vidply-options`
20
+ * attribute into a global gadget.
21
+ */
22
+ function sanitizeOptionsObject(input: unknown): Partial<PlayerOptions> {
23
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
24
+ return {};
25
+ }
26
+ const out: Record<string, unknown> = Object.create(null);
27
+ for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
28
+ if (isForbiddenKey(key)) continue;
29
+ out[key] = value;
30
+ }
31
+ return out as Partial<PlayerOptions>;
32
+ }
33
+
34
+ /**
35
+ * Parse a `data-vidply-options` JSON string. Robust against malformed input
36
+ * — a single broken attribute on one element no longer aborts the auto-init
37
+ * loop for every other player on the page.
38
+ */
39
+ function parseInlineOptions(element: HTMLElement): Partial<PlayerOptions> {
40
+ const raw = element.dataset.vidplyOptions;
41
+ if (!raw) return {};
42
+ try {
43
+ const parsed: unknown = JSON.parse(raw);
44
+ return sanitizeOptionsObject(parsed);
45
+ } catch (err) {
46
+ console.warn('[VidPly] Ignored malformed data-vidply-options:', err);
47
+ return {};
48
+ }
49
+ }
50
+
51
+ function initializePlayers(): void {
52
+ const elements = document.querySelectorAll<HTMLElement>('[data-vidply]');
53
+
54
+ elements.forEach((element) => {
55
+ const options = parseInlineOptions(element);
56
+ const dataOptions = parseDataAttributes(element.dataset);
57
+ const mergedOptions: Partial<PlayerOptions> = { ...dataOptions, ...options };
58
+
59
+ const lazyInit =
60
+ element.dataset.vidplyLazy !== 'false' && mergedOptions.lazyInit !== false;
61
+ const lazyMargin =
62
+ element.dataset.vidplyLazyMargin || (mergedOptions.lazyMargin as string) || '500px';
63
+
64
+ if (lazyInit && 'IntersectionObserver' in window) {
65
+ observeForLazyInit<Partial<PlayerOptions>>(
66
+ element,
67
+ mergedOptions,
68
+ lazyMargin,
69
+ (target, opts) => { new Player(target, opts); }
70
+ );
71
+ } else {
72
+ new Player(element, mergedOptions);
73
+ }
74
+ });
75
+ }
76
+
77
+ function parseDataAttributes(dataset: DOMStringMap): Partial<PlayerOptions> {
78
+ const options: Record<string, unknown> = Object.create(null);
79
+
80
+ const attributeMap: Record<string, keyof PlayerOptions> = {
81
+ signLanguageSrc: 'signLanguageSrc',
82
+ signLanguageButton: 'signLanguageButton',
83
+ signLanguagePosition: 'signLanguagePosition',
84
+ signLanguageDisplayMode: 'signLanguageDisplayMode',
85
+ audioDescriptionSrc: 'audioDescriptionSrc',
86
+ audioDescriptionButton: 'audioDescriptionButton',
87
+ audioDescriptionMode: 'audioDescriptionMode',
88
+ audioDescriptionSpeech: 'audioDescriptionSpeech',
89
+ audioDescriptionExtended: 'audioDescriptionExtended',
90
+ autoplay: 'autoplay',
91
+ loop: 'loop',
92
+ muted: 'muted',
93
+ controls: 'controls',
94
+ poster: 'poster',
95
+ width: 'width',
96
+ height: 'height',
97
+ language: 'language',
98
+ captions: 'captions',
99
+ captionsDefault: 'captionsDefault',
100
+ transcript: 'transcript',
101
+ transcriptButton: 'transcriptButton',
102
+ keyboard: 'keyboard',
103
+ responsive: 'responsive',
104
+ pipButton: 'pipButton',
105
+ fullscreenButton: 'fullscreenButton',
106
+ floating: 'floating',
107
+ floatingPosition: 'floatingPosition',
108
+ floatingMinViewportWidth: 'floatingMinViewportWidth',
109
+ lazyInit: 'lazyInit',
110
+ lazyMargin: 'lazyMargin',
111
+ theme: 'theme'
112
+ };
113
+
114
+ for (const [dataKey, optionKey] of Object.entries(attributeMap)) {
115
+ if (isForbiddenKey(optionKey)) continue;
116
+ const value = dataset[dataKey];
117
+ if (value === undefined) continue;
118
+ if (value === 'true') {
119
+ options[optionKey] = true;
120
+ } else if (value === 'false') {
121
+ options[optionKey] = false;
122
+ } else if (value !== '' && !Number.isNaN(Number(value))) {
123
+ options[optionKey] = Number(value);
124
+ } else {
125
+ options[optionKey] = value;
126
+ }
127
+ }
128
+
129
+ const signLanguageSources: Record<string, string> = Object.create(null);
130
+ for (const key of Object.keys(dataset)) {
131
+ if (key.startsWith('signLanguageSrc') && key !== 'signLanguageSrc') {
132
+ const langMatch = key.match(/^signLanguageSrc([A-Z][a-z]*)$/);
133
+ if (langMatch && langMatch[1]) {
134
+ const langCode = langMatch[1].toLowerCase();
135
+ const value = dataset[key];
136
+ if (value !== undefined) {
137
+ signLanguageSources[langCode] = value;
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ if (Object.keys(signLanguageSources).length > 0) {
144
+ options.signLanguageSources = signLanguageSources;
145
+ if (dataset.signLanguageSrc && !options.signLanguageSrc) {
146
+ options.signLanguageSrc = dataset.signLanguageSrc;
147
+ }
148
+ }
149
+
150
+ if (dataset.vidplyLanguageFiles) {
151
+ try {
152
+ const parsed = JSON.parse(dataset.vidplyLanguageFiles);
153
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
154
+ options.languageFiles = sanitizeOptionsObject(parsed) as Record<string, string>;
155
+ }
156
+ } catch (e) {
157
+ console.warn('Invalid JSON in data-vidply-language-files:', e);
158
+ }
159
+ }
160
+
161
+ if (dataset.vidplyLanguageFile) {
162
+ try {
163
+ const parsed = JSON.parse(dataset.vidplyLanguageFile);
164
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
165
+ options.languageFiles = sanitizeOptionsObject(parsed) as Record<string, string>;
166
+ }
167
+ } catch {
168
+ if (dataset.vidplyLanguageFileCode && dataset.vidplyLanguageFileUrl) {
169
+ options.languageFile = dataset.vidplyLanguageFileCode;
170
+ options.languageFileUrl = dataset.vidplyLanguageFileUrl;
171
+ }
172
+ }
173
+ } else if (dataset.vidplyLanguageFileCode && dataset.vidplyLanguageFileUrl) {
174
+ options.languageFile = dataset.vidplyLanguageFileCode;
175
+ options.languageFileUrl = dataset.vidplyLanguageFileUrl;
176
+ }
177
+
178
+ return options as Partial<PlayerOptions>;
179
+ }
180
+
181
+ if (document.readyState === 'loading') {
182
+ document.addEventListener('DOMContentLoaded', initializePlayers);
183
+ } else {
184
+ initializePlayers();
185
+ }
186
+
187
+ export { Player, PlaylistManager };
188
+ export type { PlayerOptions } from './types/options.js';
189
+ export type {
190
+ PlayerEventMap,
191
+ PlaylistTrack,
192
+ FloatingChangeDetail
193
+ } from './types/events.js';
194
+ export type { PlayerState } from './types/state.js';
195
+ export type { Renderer, QualityLevel } from './types/renderer.js';
196
+ export default Player;