@aigamo/nostalgic-diva 0.0.1-alpha.69 → 0.0.1-alpha.71

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 (28) hide show
  1. package/dist/PlayerContainer-COjwHOhq.cjs.map +1 -1
  2. package/dist/PlayerContainer-VQ3YPGU_.js.map +1 -1
  3. package/dist/SpotifyPlayer-DUKJP7Jz.cjs +2 -0
  4. package/dist/SpotifyPlayer-DUKJP7Jz.cjs.map +1 -0
  5. package/dist/SpotifyPlayer-DbZNyvp-.js +38 -0
  6. package/dist/SpotifyPlayer-DbZNyvp-.js.map +1 -0
  7. package/dist/{TwitchPlayer-BeQUOIE3.js → TwitchPlayer-Bn8o_9f5.js} +1 -1
  8. package/dist/{TwitchPlayer-BeQUOIE3.js.map → TwitchPlayer-Bn8o_9f5.js.map} +1 -1
  9. package/dist/{TwitchPlayer-Doh6zF0n.cjs → TwitchPlayer-SK7o8pMq.cjs} +1 -1
  10. package/dist/{TwitchPlayer-Doh6zF0n.cjs.map → TwitchPlayer-SK7o8pMq.cjs.map} +1 -1
  11. package/dist/{VimeoPlayer-7MjNmmgs.cjs → VimeoPlayer-BySLiRru.cjs} +1 -1
  12. package/dist/{VimeoPlayer-7MjNmmgs.cjs.map → VimeoPlayer-BySLiRru.cjs.map} +1 -1
  13. package/dist/{VimeoPlayer-CgWujBXW.js → VimeoPlayer-Cz5hB9JG.js} +1 -1
  14. package/dist/{VimeoPlayer-CgWujBXW.js.map → VimeoPlayer-Cz5hB9JG.js.map} +1 -1
  15. package/dist/{YouTubePlayer-CkaOKK_g.js → YouTubePlayer-C_fmW0IS.js} +1 -1
  16. package/dist/{YouTubePlayer-CkaOKK_g.js.map → YouTubePlayer-C_fmW0IS.js.map} +1 -1
  17. package/dist/{YouTubePlayer-Clpmqsmv.cjs → YouTubePlayer-vLFVWfOz.cjs} +1 -1
  18. package/dist/{YouTubePlayer-Clpmqsmv.cjs.map → YouTubePlayer-vLFVWfOz.cjs.map} +1 -1
  19. package/dist/components/SpotifyPlayer.d.ts +4 -0
  20. package/dist/controllers/PlayerController.d.ts +1 -1
  21. package/dist/controllers/SpotifyPlayerController.d.ts +23 -0
  22. package/dist/controllers/index.d.ts +1 -0
  23. package/dist/index.cjs.js +1 -1
  24. package/dist/index.cjs.js.map +1 -1
  25. package/dist/index.es.js +102 -45
  26. package/dist/index.es.js.map +1 -1
  27. package/dist/services/SpotifyVideoService.d.ts +6 -0
  28. package/package.json +2 -1
package/dist/index.es.js CHANGED
@@ -102,61 +102,76 @@ var g = s(void 0), _ = ({ children: n, logger: i = r }) => {
102
102
  extractVideoId(e) {
103
103
  return e;
104
104
  }
105
- }, k = /(?:www\.|go\.)?twitch\.tv\/videos\/(\d+)($|\?)/, A = class extends y {
105
+ }, k = "track|episode|album|playlist|show|artist", A = RegExp(`^https?://open\\.spotify\\.com/(?:intl-[a-z]{2}/)?(${k})/([a-zA-Z0-9]+)`), j = RegExp(`^spotify:(${k}):([a-zA-Z0-9]+)$`), M = class extends y {
106
+ constructor() {
107
+ super("Spotify");
108
+ }
109
+ canPlay(e) {
110
+ return A.test(e) || j.test(e);
111
+ }
112
+ extractVideoId(e) {
113
+ let t = A.exec(e) ?? j.exec(e);
114
+ if (t === null) return;
115
+ let [, n, r] = t;
116
+ return `spotify:${n}:${r}`;
117
+ }
118
+ }, N = /(?:www\.|go\.)?twitch\.tv\/videos\/(\d+)($|\?)/, ee = class extends y {
106
119
  constructor() {
107
120
  super("Twitch");
108
121
  }
109
122
  canPlay(e) {
110
- return k.test(e);
123
+ return N.test(e);
111
124
  }
112
125
  extractVideoId(e) {
113
- return k.exec(e)?.[1];
126
+ return N.exec(e)?.[1];
114
127
  }
115
- }, j = /vimeo\.com\/(\d+)$/, M = class extends y {
128
+ }, P = /vimeo\.com\/(\d+)$/, F = class extends y {
116
129
  constructor() {
117
130
  super("Vimeo");
118
131
  }
119
132
  canPlay(e) {
120
- return j.test(e);
133
+ return P.test(e);
121
134
  }
122
135
  extractVideoId(e) {
123
- return j.exec(e)?.[1];
136
+ return P.exec(e)?.[1];
124
137
  }
125
- }, N = /(?:youtu\.be\/|youtube(?:-nocookie|education)?\.com\/(?:embed\/|v\/|watch\/|watch\?v=|watch\?.+&v=|shorts\/|live\/))((\w|-){11})|youtube\.com\/playlist\?list=|youtube\.com\/user\//, P = [
138
+ }, I = /(?:youtu\.be\/|youtube(?:-nocookie|education)?\.com\/(?:embed\/|v\/|watch\/|watch\?v=|watch\?.+&v=|shorts\/|live\/))((\w|-){11})|youtube\.com\/playlist\?list=|youtube\.com\/user\//, L = [
126
139
  new class extends y {
127
140
  constructor() {
128
141
  super("YouTube");
129
142
  }
130
143
  canPlay(e) {
131
- return N.test(e);
144
+ return I.test(e);
132
145
  }
133
146
  extractVideoId(e) {
134
- return N.exec(e)?.[1];
147
+ return I.exec(e)?.[1];
135
148
  }
136
149
  }(),
137
- new A(),
138
- new M(),
150
+ new ee(),
151
+ new F(),
139
152
  new w(),
140
153
  new O(),
154
+ new M(),
141
155
  new S(),
142
156
  new E()
143
157
  ];
144
- function F(e) {
145
- return P.find((t) => t.canPlay(e));
158
+ function R(e) {
159
+ return L.find((t) => t.canPlay(e));
146
160
  }
147
161
  //#endregion
148
162
  //#region src/components/NostalgicDiva.tsx
149
- var I = new Map(Object.entries({
163
+ var z = new Map(Object.entries({
150
164
  Audio: c(() => import("./AudioPlayer-7plDTn5w.js")),
151
165
  Dailymotion: c(() => import("./DailymotionPlayer-4LQmDDSf.js")),
152
166
  Niconico: c(() => import("./NiconicoPlayer-GFCXF5V7.js")),
153
167
  SoundCloud: c(() => import("./SoundCloudPlayer-Cqo5VU57.js")),
154
- Twitch: c(() => import("./TwitchPlayer-BeQUOIE3.js")),
155
- Vimeo: c(() => import("./VimeoPlayer-CgWujBXW.js")),
156
- YouTube: c(() => import("./YouTubePlayer-CkaOKK_g.js"))
168
+ Spotify: c(() => import("./SpotifyPlayer-DbZNyvp-.js")),
169
+ Twitch: c(() => import("./TwitchPlayer-Bn8o_9f5.js")),
170
+ Vimeo: c(() => import("./VimeoPlayer-Cz5hB9JG.js")),
171
+ YouTube: c(() => import("./YouTubePlayer-C_fmW0IS.js"))
157
172
  }));
158
- function L(e) {
159
- let t = F(e);
173
+ function B(e) {
174
+ let t = R(e);
160
175
  if (t === void 0) return;
161
176
  let { type: n, extractVideoId: r } = t, i = r(e);
162
177
  if (i !== void 0) return {
@@ -164,7 +179,7 @@ function L(e) {
164
179
  videoId: i
165
180
  };
166
181
  }
167
- var R = l(() => /* @__PURE__ */ m("div", {
182
+ var V = l(() => /* @__PURE__ */ m("div", {
168
183
  style: {
169
184
  width: "100%",
170
185
  height: "100%"
@@ -178,15 +193,15 @@ var R = l(() => /* @__PURE__ */ m("div", {
178
193
  border: 0
179
194
  }
180
195
  })
181
- })), z = l(({ src: t, options: n, onControllerChange: r }) => {
196
+ })), H = l(({ src: t, options: n, onControllerChange: r }) => {
182
197
  let i = v(), a = u((e) => {
183
198
  i.handleControllerChange(e), r?.(e);
184
199
  }, [i, r]);
185
200
  i.logger.log(e.Debug, "NostalgicDiva");
186
- let s = L(t);
187
- if (s === void 0) return i.logger.log(e.Warning, `Failed to extract type and videoId from src: "${t}". Returning EmptyPlayer.`), /* @__PURE__ */ m(R, {});
188
- let { type: c, videoId: l } = s, d = I.get(c);
189
- return d === void 0 ? (i.logger.log(e.Warning, `No player found for type "${c}" (videoId: "${l}"). Returning EmptyPlayer.`), /* @__PURE__ */ m(R, {})) : /* @__PURE__ */ m(o, {
201
+ let s = B(t);
202
+ if (s === void 0) return i.logger.log(e.Warning, `Failed to extract type and videoId from src: "${t}". Returning EmptyPlayer.`), /* @__PURE__ */ m(V, {});
203
+ let { type: c, videoId: l } = s, d = z.get(c);
204
+ return d === void 0 ? (i.logger.log(e.Warning, `No player found for type "${c}" (videoId: "${l}"). Returning EmptyPlayer.`), /* @__PURE__ */ m(V, {})) : /* @__PURE__ */ m(o, {
190
205
  fallback: null,
191
206
  children: /* @__PURE__ */ m(d, {
192
207
  logger: i.logger,
@@ -196,7 +211,7 @@ var R = l(() => /* @__PURE__ */ m("div", {
196
211
  options: n
197
212
  })
198
213
  });
199
- }), B = class extends HTMLElement {
214
+ }), U = class extends HTMLElement {
200
215
  static observedAttributes = ["src"];
201
216
  container;
202
217
  controller = t;
@@ -221,7 +236,7 @@ var R = l(() => /* @__PURE__ */ m("div", {
221
236
  console.debug("[@nostalgic-diva/web-components] handleControllerChange"), this.controller = e;
222
237
  };
223
238
  #n() {
224
- h.render(/* @__PURE__ */ m(_, { children: /* @__PURE__ */ m(z, {
239
+ h.render(/* @__PURE__ */ m(_, { children: /* @__PURE__ */ m(H, {
225
240
  src: this.src,
226
241
  options: this.#e,
227
242
  onControllerChange: this.#t
@@ -276,12 +291,12 @@ var R = l(() => /* @__PURE__ */ m("div", {
276
291
  return this.controller.supports(e);
277
292
  }
278
293
  };
279
- function V() {
280
- customElements.define("nostalgic-diva", B);
294
+ function W() {
295
+ customElements.define("nostalgic-diva", U);
281
296
  }
282
297
  //#endregion
283
298
  //#region src/controllers/AudioPlayerController.ts
284
- var H = class extends i {
299
+ var G = class extends i {
285
300
  async attach() {
286
301
  this.player.onerror = (e) => this.options?.onError?.(e), this.player.onloadeddata = () => this.options?.onLoaded?.({ id: this.player.src }), this.player.onplay = () => this.options?.onPlay?.(), this.player.onpause = () => this.options?.onPause?.(), this.player.onended = () => this.options?.onEnded?.(), this.player.ontimeupdate = () => {
287
302
  this.options?.onTimeUpdate?.({
@@ -330,7 +345,7 @@ var H = class extends i {
330
345
  async getPlaybackRate() {
331
346
  return this.player.playbackRate;
332
347
  }
333
- }, U = [
348
+ }, K = [
334
349
  "apiready",
335
350
  "seeked",
336
351
  "video_end",
@@ -338,7 +353,7 @@ var H = class extends i {
338
353
  "pause",
339
354
  "playing",
340
355
  "error"
341
- ], W = class extends i {
356
+ ], q = class extends i {
342
357
  handlePlayerEvents = (e) => {
343
358
  switch (e.type) {
344
359
  case "apiready":
@@ -367,10 +382,10 @@ var H = class extends i {
367
382
  }
368
383
  };
369
384
  async attach(e) {
370
- for (let e of U) this.player.addEventListener(e, this.handlePlayerEvents);
385
+ for (let e of K) this.player.addEventListener(e, this.handlePlayerEvents);
371
386
  }
372
387
  async detach() {
373
- for (let e of U) this.player.removeEventListener(e, this.handlePlayerEvents);
388
+ for (let e of K) this.player.removeEventListener(e, this.handlePlayerEvents);
374
389
  }
375
390
  async loadVideo(e) {
376
391
  this.player.load(e);
@@ -404,9 +419,9 @@ var H = class extends i {
404
419
  return this.player.muted;
405
420
  }
406
421
  getPlaybackRate = void 0;
407
- }, G = /* @__PURE__ */ function(e) {
422
+ }, J = /* @__PURE__ */ function(e) {
408
423
  return e[e.Play = 2] = "Play", e[e.Pause = 3] = "Pause", e[e.End = 4] = "End", e;
409
- }(G || {}), K = class t extends i {
424
+ }(J || {}), Y = class t extends i {
410
425
  static origin = "https://embed.nicovideo.jp";
411
426
  duration = 0;
412
427
  currentTime = 0;
@@ -417,10 +432,10 @@ var H = class extends i {
417
432
  let r = n.data;
418
433
  switch (r.eventName) {
419
434
  case "playerStatusChange":
420
- this.logger.log(e.Debug, `player status changed: ${G[r.data.playerStatus] ?? r.data.playerStatus}`);
435
+ this.logger.log(e.Debug, `player status changed: ${J[r.data.playerStatus] ?? r.data.playerStatus}`);
421
436
  break;
422
437
  case "statusChange":
423
- switch (this.logger.log(e.Debug, `status changed: ${G[r.data.playerStatus] ?? r.data.playerStatus}`), r.data.playerStatus) {
438
+ switch (this.logger.log(e.Debug, `status changed: ${J[r.data.playerStatus] ?? r.data.playerStatus}`), r.data.playerStatus) {
424
439
  case 2:
425
440
  this.options?.onPlay?.();
426
441
  break;
@@ -512,7 +527,7 @@ var H = class extends i {
512
527
  return this.muted;
513
528
  }
514
529
  getPlaybackRate = void 0;
515
- }, q = class e extends i {
530
+ }, X = class e extends i {
516
531
  getDurationCore() {
517
532
  return new Promise((e, t) => {
518
533
  this.player.getDuration(e);
@@ -581,7 +596,49 @@ var H = class extends i {
581
596
  }
582
597
  getMuted = void 0;
583
598
  getPlaybackRate = void 0;
584
- }, J = class extends i {
599
+ }, Z = class extends i {
600
+ duration = 0;
601
+ position = 0;
602
+ previousIsPaused = !0;
603
+ currentUri;
604
+ ended = !1;
605
+ handlePlaybackUpdate = (e) => {
606
+ let { position: t, duration: n, isPaused: r, playingURI: i } = e.data;
607
+ i !== this.currentUri && (this.currentUri = i, this.ended = !1), this.position = t, this.duration = n, this.options?.onTimeUpdate?.({
608
+ duration: n / 1e3,
609
+ percent: n > 0 ? t / n : 0,
610
+ seconds: t / 1e3
611
+ }), r !== this.previousIsPaused && (this.previousIsPaused = r, r ? this.options?.onPause?.() : this.options?.onPlay?.()), n > 0 && t >= n ? this.ended || (this.ended = !0, this.options?.onEnded?.()) : this.ended = !1;
612
+ };
613
+ async attach(e) {
614
+ this.player.addListener("ready", () => this.options?.onLoaded?.({ id: e })), this.player.addListener("playback_update", this.handlePlaybackUpdate);
615
+ }
616
+ async detach() {}
617
+ async loadVideo(e) {
618
+ this.duration = 0, this.position = 0, this.previousIsPaused = !0, this.player.loadUri(e), this.options?.onLoaded?.({ id: e });
619
+ }
620
+ async play() {
621
+ this.player.resume();
622
+ }
623
+ async pause() {
624
+ this.player.pause();
625
+ }
626
+ async setCurrentTime(e) {
627
+ e <= 0 ? this.player.restart() : this.player.seek(e);
628
+ }
629
+ setVolume = void 0;
630
+ setMuted = void 0;
631
+ setPlaybackRate = void 0;
632
+ async getDuration() {
633
+ return this.duration / 1e3;
634
+ }
635
+ async getCurrentTime() {
636
+ return this.position / 1e3;
637
+ }
638
+ getVolume = void 0;
639
+ getMuted = void 0;
640
+ getPlaybackRate = void 0;
641
+ }, Q = class extends i {
585
642
  handleReady = () => {
586
643
  this.options?.onLoaded?.({ id: this.player.getVideo() });
587
644
  };
@@ -637,7 +694,7 @@ var H = class extends i {
637
694
  return this.player.getMuted();
638
695
  }
639
696
  getPlaybackRate = void 0;
640
- }, Y = class extends i {
697
+ }, te = class extends i {
641
698
  async attach() {
642
699
  await this.player.ready(), this.player.on("error", (e) => this.options?.onError?.(e)), this.player.on("loaded", (e) => this.options?.onLoaded?.({ id: e.id.toString() })), this.player.on("play", () => this.options?.onPlay?.()), this.player.on("pause", () => this.options?.onPause?.()), this.player.on("ended", () => this.options?.onEnded?.()), this.player.on("timeupdate", (e) => {
643
700
  this.options?.onTimeUpdate?.({
@@ -686,9 +743,9 @@ var H = class extends i {
686
743
  async getPlaybackRate() {
687
744
  return this.player.getPlaybackRate();
688
745
  }
689
- }, X = /* @__PURE__ */ function(e) {
746
+ }, $ = /* @__PURE__ */ function(e) {
690
747
  return e[e.UNSTARTED = -1] = "UNSTARTED", e[e.ENDED = 0] = "ENDED", e[e.PLAYING = 1] = "PLAYING", e[e.PAUSED = 2] = "PAUSED", e[e.BUFFERING = 3] = "BUFFERING", e[e.CUED = 5] = "CUED", e;
691
- }(X || {}), Z = class extends i {
748
+ }($ || {}), ne = class extends i {
692
749
  previousTime;
693
750
  timeUpdateIntervalId;
694
751
  clearTimeUpdateInterval() {
@@ -711,7 +768,7 @@ var H = class extends i {
711
768
  return new Promise((n, r) => {
712
769
  this.player.addEventListener("onReady", async () => {
713
770
  this.player.addEventListener("onError", (e) => this.options?.onError?.(e.data)), this.player.addEventListener("onStateChange", (n) => {
714
- switch (this.logger.log(e.Debug, `state changed: ${X[n.data]}`), n.data) {
771
+ switch (this.logger.log(e.Debug, `state changed: ${$[n.data]}`), n.data) {
715
772
  case YT.PlayerState.CUED:
716
773
  this.options?.onLoaded?.({ id: t });
717
774
  break;
@@ -770,6 +827,6 @@ var H = class extends i {
770
827
  }
771
828
  };
772
829
  //#endregion
773
- export { H as AudioPlayerController, W as DailymotionPlayerController, e as LogLevel, K as NiconicoPlayerController, z as NostalgicDiva, B as NostalgicDivaElement, _ as NostalgicDivaProvider, a as PlayerContainer, n as PlayerController, i as PlayerControllerImpl, q as SoundCloudPlayerController, J as TwitchPlayerController, y as VideoService, Y as VimeoPlayerController, Z as YouTubePlayerController, r as defaultLogger, V as defineNostalgicDiva, F as findVideoService, t as nullPlayerController, I as players, v as useNostalgicDiva, P as videoServices };
830
+ export { G as AudioPlayerController, q as DailymotionPlayerController, e as LogLevel, Y as NiconicoPlayerController, H as NostalgicDiva, U as NostalgicDivaElement, _ as NostalgicDivaProvider, a as PlayerContainer, n as PlayerController, i as PlayerControllerImpl, X as SoundCloudPlayerController, Z as SpotifyPlayerController, Q as TwitchPlayerController, y as VideoService, te as VimeoPlayerController, ne as YouTubePlayerController, r as defaultLogger, W as defineNostalgicDiva, R as findVideoService, t as nullPlayerController, z as players, v as useNostalgicDiva, L as videoServices };
774
831
 
775
832
  //# sourceMappingURL=index.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","names":["#options","#handleControllerChange","#render"],"sources":["../src/components/NostalgicDivaProvider.tsx","../src/services/VideoService.ts","../src/services/AudioVideoService.ts","../src/services/DailymotionVideoService.ts","../src/services/NiconicoVideoService.ts","../src/services/SoundCloudVideoService.ts","../src/services/TwitchVideoService.ts","../src/services/VimeoVideoService.ts","../src/services/YouTubeVideoService.ts","../src/services/findVideoService.ts","../src/components/NostalgicDiva.tsx","../src/components/defineNostalgicDiva.tsx","../src/controllers/AudioPlayerController.ts","../src/controllers/DailymotionPlayerController.ts","../src/controllers/NiconicoPlayerController.ts","../src/controllers/SoundCloudPlayerController.ts","../src/controllers/TwitchPlayerController.ts","../src/controllers/VimeoPlayerController.ts","../src/controllers/YouTubePlayerController.ts"],"sourcesContent":["import { type ILogger, LogLevel, defaultLogger } from '@/controllers/Logger';\nimport { nullPlayerController } from '@/controllers/NullPlayerController';\nimport type {\n\tIPlayerCommands,\n\tIPlayerController,\n} from '@/controllers/PlayerController';\nimport {\n\ttype ReactElement,\n\ttype ReactNode,\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseMemo,\n\tuseRef,\n} from 'react';\n\ninterface NostalgicDivaContextProps extends IPlayerController {\n\tlogger: ILogger;\n\thandleControllerChange: (value: IPlayerController) => void;\n}\n\nconst NostalgicDivaContext = createContext<NostalgicDivaContextProps>(\n\tundefined!,\n);\n\nexport interface NostalgicDivaProviderProps {\n\tchildren?: ReactNode;\n\tlogger?: ILogger;\n}\n\nexport const NostalgicDivaProvider = ({\n\tchildren,\n\tlogger = defaultLogger,\n}: NostalgicDivaProviderProps): ReactElement => {\n\tconst controllerRef = useRef<IPlayerController>(nullPlayerController);\n\n\tconst handleControllerChange = useCallback(\n\t\t(value: IPlayerController): void => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.handleControllerChange',\n\t\t\t\tcontrollerRef.current,\n\t\t\t\tvalue,\n\t\t\t);\n\n\t\t\tcontrollerRef.current = value;\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst loadVideo = useCallback(\n\t\tasync (id: string): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.loadVideo',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.loadVideo(id);\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst play = useCallback(async (): Promise<void> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.play',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\tawait controllerRef.current.play();\n\t}, [logger]);\n\n\tconst pause = useCallback(async (): Promise<void> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.pause',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\tawait controllerRef.current.pause();\n\t}, [logger]);\n\n\tconst setCurrentTime = useCallback(\n\t\tasync (seconds: number): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.setCurrentTime',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.setCurrentTime(seconds);\n\t\t\tawait controllerRef.current.play();\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst setVolume = useCallback(\n\t\tasync (volume: number): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.setVolume',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.setVolume(volume);\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst setMuted = useCallback(\n\t\tasync (muted: boolean): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.setMuted',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.setMuted(muted);\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst setPlaybackRate = useCallback(\n\t\tasync (playbackRate: number): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.setPlaybackRate',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.setPlaybackRate(playbackRate);\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst getDuration = useCallback(async (): Promise<number> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getDuration',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getDuration();\n\t}, [logger]);\n\n\tconst getCurrentTime = useCallback(async (): Promise<number> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getCurrentTime',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getCurrentTime();\n\t}, [logger]);\n\n\tconst getVolume = useCallback(async (): Promise<number> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getVolume',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getVolume();\n\t}, [logger]);\n\n\tconst getMuted = useCallback(async (): Promise<boolean> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getMuted',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getMuted();\n\t}, [logger]);\n\n\tconst getPlaybackRate = useCallback(async (): Promise<number> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getPlaybackRate',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getPlaybackRate();\n\t}, [logger]);\n\n\tconst supports = useCallback(\n\t\t(command: keyof IPlayerCommands): boolean =>\n\t\t\tcontrollerRef.current.supports(command),\n\t\t[],\n\t);\n\n\tconst value = useMemo(\n\t\t(): NostalgicDivaContextProps => ({\n\t\t\tlogger,\n\t\t\thandleControllerChange,\n\t\t\tloadVideo,\n\t\t\tplay,\n\t\t\tpause,\n\t\t\tsetCurrentTime,\n\t\t\tsetVolume,\n\t\t\tsetMuted,\n\t\t\tsetPlaybackRate,\n\t\t\tgetDuration,\n\t\t\tgetCurrentTime,\n\t\t\tgetVolume,\n\t\t\tgetMuted,\n\t\t\tgetPlaybackRate,\n\t\t\tsupports,\n\t\t}),\n\t\t[\n\t\t\tlogger,\n\t\t\thandleControllerChange,\n\t\t\tloadVideo,\n\t\t\tplay,\n\t\t\tpause,\n\t\t\tsetCurrentTime,\n\t\t\tsetVolume,\n\t\t\tsetMuted,\n\t\t\tsetPlaybackRate,\n\t\t\tgetDuration,\n\t\t\tgetCurrentTime,\n\t\t\tgetVolume,\n\t\t\tgetMuted,\n\t\t\tgetPlaybackRate,\n\t\t\tsupports,\n\t\t],\n\t);\n\n\treturn (\n\t\t<NostalgicDivaContext.Provider value={value}>\n\t\t\t{children}\n\t\t</NostalgicDivaContext.Provider>\n\t);\n};\n\nexport const useNostalgicDiva = (): NostalgicDivaContextProps => {\n\treturn useContext(NostalgicDivaContext);\n};\n","import type { PlayerType } from '@/controllers/PlayerController';\n\nexport abstract class VideoService {\n\tprotected constructor(readonly type: PlayerType) {}\n\n\tabstract canPlay(url: string): boolean;\n\n\tabstract extractVideoId(url: string): string | undefined;\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst AUDIO_EXTENSIONS =\n\t/\\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3a|wav|weba|aac|oga|spx)($|\\?)/i;\nconst VIDEO_EXTENSIONS = /\\.(mp4|og[gv]|webm|mov|m4v)(#t=[,\\d+]+)?($|\\?)/i;\n\nexport class AudioVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Audio');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn AUDIO_EXTENSIONS.test(url) || VIDEO_EXTENSIONS.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\treturn url;\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_DAILYMOTION =\n\t/^(?:(?:https?):)?(?:\\/\\/)?(?:www\\.)?(?:(?:dailymotion\\.com(?:\\/embed)?\\/video)|dai\\.ly)\\/([a-zA-Z0-9]+)(?:_[\\w_-]+)?(?:[\\w.#_-]+)?/;\n\nexport class DailymotionVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Dailymotion');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_DAILYMOTION.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\tconst matches = MATCH_URL_DAILYMOTION.exec(url);\n\t\treturn matches?.[1];\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\nconst MATCH_URL_NICONICO = /(?:www\\.|)?nicovideo\\.jp\\/watch\\/(\\w+)$/;\n\nexport class NiconicoVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Niconico');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_NICONICO.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\tconst matches = MATCH_URL_NICONICO.exec(url);\n\t\treturn matches?.[1];\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_SOUNDCLOUD = /(?:soundcloud\\.com|snd\\.sc)\\/[^.]+$/;\n\nexport class SoundCloudVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('SoundCloud');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_SOUNDCLOUD.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\treturn url;\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_TWITCH_VIDEO = /(?:www\\.|go\\.)?twitch\\.tv\\/videos\\/(\\d+)($|\\?)/;\n\nexport class TwitchVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Twitch');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_TWITCH_VIDEO.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\tconst matches = MATCH_URL_TWITCH_VIDEO.exec(url);\n\t\treturn matches?.[1];\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_VIMEO = /vimeo\\.com\\/(\\d+)$/;\n\nexport class VimeoVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Vimeo');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_VIMEO.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\treturn MATCH_URL_VIMEO.exec(url)?.[1];\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_YOUTUBE =\n\t/(?:youtu\\.be\\/|youtube(?:-nocookie|education)?\\.com\\/(?:embed\\/|v\\/|watch\\/|watch\\?v=|watch\\?.+&v=|shorts\\/|live\\/))((\\w|-){11})|youtube\\.com\\/playlist\\?list=|youtube\\.com\\/user\\//;\n\nexport class YouTubeVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('YouTube');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_YOUTUBE.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\tconst matches = MATCH_URL_YOUTUBE.exec(url);\n\t\treturn matches?.[1];\n\t}\n}\n","import { AudioVideoService } from '@/services/AudioVideoService';\nimport { DailymotionVideoService } from '@/services/DailymotionVideoService';\nimport { NiconicoVideoService } from '@/services/NiconicoVideoService';\nimport { SoundCloudVideoService } from '@/services/SoundCloudVideoService';\nimport { TwitchVideoService } from '@/services/TwitchVideoService';\nimport type { VideoService } from '@/services/VideoService';\nimport { VimeoVideoService } from '@/services/VimeoVideoService';\nimport { YouTubeVideoService } from '@/services/YouTubeVideoService';\n\nexport const videoServices: VideoService[] = [\n\tnew YouTubeVideoService(),\n\tnew TwitchVideoService(),\n\tnew VimeoVideoService(),\n\tnew DailymotionVideoService(),\n\tnew SoundCloudVideoService(),\n\tnew AudioVideoService(),\n\tnew NiconicoVideoService(),\n];\n\nexport function findVideoService(url: string): VideoService | undefined {\n\treturn videoServices.find((videoService) => videoService.canPlay(url));\n}\n","import { useNostalgicDiva } from '@/components/NostalgicDivaProvider';\nimport type { PlayerProps } from '@/components/PlayerContainer';\nimport { LogLevel } from '@/controllers/Logger';\nimport type {\n\tIPlayerController,\n\tPlayerOptions,\n\tPlayerType,\n} from '@/controllers/PlayerController';\nimport { findVideoService } from '@/services/findVideoService';\nimport {\n\ttype ElementType,\n\ttype ReactElement,\n\tSuspense,\n\tlazy,\n\tmemo,\n\tuseCallback,\n} from 'react';\n\nexport const players: Map<PlayerType, ElementType<PlayerProps>> = new Map(\n\tObject.entries({\n\t\tAudio: lazy(() => import('./AudioPlayer')),\n\t\tDailymotion: lazy(() => import('./DailymotionPlayer')),\n\t\tNiconico: lazy(() => import('./NiconicoPlayer')),\n\t\tSoundCloud: lazy(() => import('./SoundCloudPlayer')),\n\t\tTwitch: lazy(() => import('./TwitchPlayer')),\n\t\tVimeo: lazy(() => import('./VimeoPlayer')),\n\t\tYouTube: lazy(() => import('./YouTubePlayer')),\n\t}),\n);\n\nexport interface NostalgicDivaProps {\n\tsrc: string;\n\toptions?: PlayerOptions;\n\tonControllerChange?: (value: IPlayerController) => void;\n}\n\nfunction getTypeAndVideoId(\n\turl: string,\n): { type: PlayerType; videoId: string } | undefined {\n\tconst videoService = findVideoService(url);\n\tif (videoService === undefined) {\n\t\treturn undefined;\n\t}\n\n\tconst { type, extractVideoId } = videoService;\n\n\tconst videoId = extractVideoId(url);\n\tif (videoId === undefined) {\n\t\treturn undefined;\n\t}\n\n\treturn { type: type, videoId: videoId };\n}\n\nconst EmptyPlayer = memo((): ReactElement => {\n\treturn (\n\t\t<div style={{ width: '100%', height: '100%' }}>\n\t\t\t<iframe\n\t\t\t\tsrc=\"about:blank\"\n\t\t\t\ttitle=\"about:blank\"\n\t\t\t\tstyle={{\n\t\t\t\t\twidth: '100%',\n\t\t\t\t\theight: '100%',\n\t\t\t\t\tborder: 0,\n\t\t\t\t}}\n\t\t\t/>\n\t\t</div>\n\t);\n});\n\nexport const NostalgicDiva = memo(\n\t({\n\t\tsrc,\n\t\toptions,\n\t\tonControllerChange,\n\t}: NostalgicDivaProps): ReactElement => {\n\t\tconst diva = useNostalgicDiva();\n\n\t\tconst handleControllerChange = useCallback(\n\t\t\t(value: IPlayerController) => {\n\t\t\t\tdiva.handleControllerChange(value);\n\n\t\t\t\tonControllerChange?.(value);\n\t\t\t},\n\t\t\t[diva, onControllerChange],\n\t\t);\n\n\t\tdiva.logger.log(LogLevel.Debug, 'NostalgicDiva');\n\n\t\tconst typeAndVideoId = getTypeAndVideoId(src);\n\t\tif (typeAndVideoId === undefined) {\n\t\t\tdiva.logger.log(\n\t\t\t\tLogLevel.Warning,\n\t\t\t\t`Failed to extract type and videoId from src: \"${src}\". Returning EmptyPlayer.`,\n\t\t\t);\n\t\t\treturn <EmptyPlayer />;\n\t\t}\n\n\t\tconst { type, videoId } = typeAndVideoId;\n\n\t\tconst Player = players.get(type);\n\t\tif (Player === undefined) {\n\t\t\tdiva.logger.log(\n\t\t\t\tLogLevel.Warning,\n\t\t\t\t`No player found for type \"${type}\" (videoId: \"${videoId}\"). Returning EmptyPlayer.`,\n\t\t\t);\n\t\t\treturn <EmptyPlayer />;\n\t\t}\n\n\t\treturn (\n\t\t\t<Suspense fallback={null}>\n\t\t\t\t<Player\n\t\t\t\t\tlogger={diva.logger}\n\t\t\t\t\ttype={type}\n\t\t\t\t\tonControllerChange={handleControllerChange}\n\t\t\t\t\tvideoId={videoId}\n\t\t\t\t\toptions={options}\n\t\t\t\t/>\n\t\t\t</Suspense>\n\t\t);\n\t},\n);\n","import { NostalgicDiva } from '@/components/NostalgicDiva';\nimport { NostalgicDivaProvider } from '@/components/NostalgicDivaProvider';\nimport { nullPlayerController } from '@/controllers/NullPlayerController';\nimport type {\n\tIPlayerCommands,\n\tIPlayerController,\n\tPlayerOptions,\n} from '@/controllers/PlayerController';\nimport ReactDOM from 'react-dom';\n\nexport class NostalgicDivaElement\n\textends HTMLElement\n\timplements IPlayerController\n{\n\tstatic readonly observedAttributes = ['src'];\n\n\tcontainer: ShadowRoot;\n\tcontroller: IPlayerController = nullPlayerController;\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis.container = this.attachShadow({ mode: 'closed' });\n\t}\n\n\tget src(): string {\n\t\treturn this.getAttribute('src') ?? '';\n\t}\n\n\tset src(value: string) {\n\t\tthis.setAttribute('src', value);\n\t}\n\n\treadonly #options: PlayerOptions = {\n\t\tonError: (e) =>\n\t\t\tthis.dispatchEvent(new CustomEvent('error', { detail: e })),\n\t\tonLoaded: (e) =>\n\t\t\tthis.dispatchEvent(new CustomEvent('loaded', { detail: e })),\n\t\tonPlay: () => this.dispatchEvent(new CustomEvent('play')),\n\t\tonPause: () => this.dispatchEvent(new CustomEvent('pause')),\n\t\tonEnded: () => this.dispatchEvent(new CustomEvent('ended')),\n\t\tonTimeUpdate: (e) =>\n\t\t\tthis.dispatchEvent(new CustomEvent('timeupdate', { detail: e })),\n\t};\n\n\t#handleControllerChange = (value: IPlayerController): void => {\n\t\tconsole.debug(\n\t\t\t'[@nostalgic-diva/web-components] handleControllerChange',\n\t\t);\n\n\t\tthis.controller = value;\n\t};\n\n\t#render(): void {\n\t\tReactDOM.render(\n\t\t\t<NostalgicDivaProvider>\n\t\t\t\t<NostalgicDiva\n\t\t\t\t\tsrc={this.src}\n\t\t\t\t\toptions={this.#options}\n\t\t\t\t\tonControllerChange={this.#handleControllerChange}\n\t\t\t\t/>\n\t\t\t</NostalgicDivaProvider>,\n\t\t\tthis.container,\n\t\t);\n\t}\n\n\tconnectedCallback(): void {\n\t\tconsole.debug('[@nostalgic-diva/web-components] connectedCallback');\n\n\t\tthis.#render();\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tconsole.debug('[@nostalgic-diva/web-components] disconnectedCallback');\n\t}\n\n\tattributeChangedCallback(): void {\n\t\tconsole.debug(\n\t\t\t'[@nostalgic-diva/web-components] attributeChangedCallback',\n\t\t);\n\n\t\tthis.#render();\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tawait this.controller.loadVideo(id);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tawait this.controller.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tawait this.controller.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tawait this.controller.setCurrentTime(seconds);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tawait this.controller.setVolume(volume);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tawait this.controller.setMuted(muted);\n\t}\n\n\tasync setPlaybackRate(playbackRate: number): Promise<void> {\n\t\tawait this.controller.setPlaybackRate(playbackRate);\n\t}\n\n\tasync getDuration(): Promise<number> {\n\t\treturn await this.controller.getDuration();\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn await this.controller.getCurrentTime();\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn await this.controller.getVolume();\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn await this.controller.getMuted();\n\t}\n\n\tasync getPlaybackRate(): Promise<number> {\n\t\treturn await this.controller.getPlaybackRate();\n\t}\n\n\tsupports(command: keyof IPlayerCommands): boolean {\n\t\treturn this.controller.supports(command);\n\t}\n}\n\nexport function defineNostalgicDiva(): void {\n\tcustomElements.define('nostalgic-diva', NostalgicDivaElement);\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\n// https://github.com/VocaDB/vocadb/blob/61b8c54f3eca906a477101dab4fdd9b154be310e/VocaDbWeb/Scripts/ViewModels/PVs/PVPlayerFile.ts.\nexport class AudioPlayerController extends PlayerControllerImpl<HTMLAudioElement> {\n\tasync attach(): Promise<void> {\n\t\tthis.player.onerror = (event): void => this.options?.onError?.(event);\n\t\tthis.player.onloadeddata = (): void =>\n\t\t\tthis.options?.onLoaded?.({ id: this.player.src });\n\t\tthis.player.onplay = (): void => this.options?.onPlay?.();\n\t\tthis.player.onpause = (): void => this.options?.onPause?.();\n\t\tthis.player.onended = (): void => this.options?.onEnded?.();\n\t\tthis.player.ontimeupdate = (): void => {\n\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\tduration: this.player.duration,\n\t\t\t\tpercent: this.player.currentTime / this.player.duration,\n\t\t\t\tseconds: this.player.currentTime,\n\t\t\t});\n\t\t};\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tthis.player.onerror = null;\n\t\tthis.player.onloadeddata = null;\n\t\tthis.player.onplay = null;\n\t\tthis.player.onpause = null;\n\t\tthis.player.onended = null;\n\t\tthis.player.ontimeupdate = null;\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.player.src = id;\n\t}\n\n\tasync play(): Promise<void> {\n\t\tawait this.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.currentTime = seconds;\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.volume = volume;\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.player.muted = muted;\n\t}\n\n\tasync setPlaybackRate(playbackRate: number): Promise<void> {\n\t\tthis.player.playbackRate = playbackRate;\n\t}\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.duration;\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.currentTime;\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.volume;\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.player.muted;\n\t}\n\n\tasync getPlaybackRate(): Promise<number> {\n\t\treturn this.player.playbackRate;\n\t}\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\nconst events = [\n\t'apiready',\n\t'seeked',\n\t'video_end',\n\t'durationchange',\n\t'pause',\n\t'playing',\n\t'error',\n] satisfies DM.EventType[];\n\nexport class DailymotionPlayerController extends PlayerControllerImpl<DM.player> {\n\tprivate handlePlayerEvents = (e: { type: DM.EventType }): void => {\n\t\tswitch (e.type) {\n\t\t\tcase 'apiready':\n\t\t\t\tthis.options?.onLoaded?.({ id: this.player.video.videoId });\n\t\t\t\tbreak;\n\t\t\tcase 'seeked':\n\t\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\t\tduration: this.player.duration,\n\t\t\t\t\tpercent: this.player.currentTime / this.player.duration,\n\t\t\t\t\tseconds: this.player.currentTime,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase 'video_end':\n\t\t\t\tthis.options?.onEnded?.();\n\t\t\t\tbreak;\n\t\t\tcase 'durationchange':\n\t\t\t\tbreak;\n\t\t\tcase 'pause':\n\t\t\t\tthis.options?.onPause?.();\n\t\t\t\tbreak;\n\t\t\tcase 'playing':\n\t\t\t\tthis.options?.onPlay?.();\n\t\t\t\tbreak;\n\t\t\tcase 'error':\n\t\t\t\tthis.options?.onError?.(e);\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\tasync attach(_id: string): Promise<void> {\n\t\tfor (const event of events) {\n\t\t\tthis.player.addEventListener(event, this.handlePlayerEvents);\n\t\t}\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tfor (const event of events) {\n\t\t\tthis.player.removeEventListener(event, this.handlePlayerEvents);\n\t\t}\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.player.load(id);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.seek(seconds);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.setVolume(volume);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.player.setMuted(muted);\n\t}\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.duration;\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.currentTime;\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.volume;\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.player.muted;\n\t}\n\n\tgetPlaybackRate = undefined;\n}\n","import { LogLevel } from '@/controllers/Logger';\nimport { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\ndeclare global {\n\tinterface Window {\n\t\tonNicoPlayerFactoryReady: (callback: nico.NicoPlayerFactory) => void;\n\t}\n}\n\nenum PlayerStatus {\n\tPlay = 2,\n\tPause = 3,\n\tEnd = 4,\n}\n\n// https://github.com/VocaDB/vocadb/blob/a4b5f9d8186772d7e6f58f997bbcbb51509d2539/VocaDbWeb/Scripts/ViewModels/PVs/PVPlayerNico.ts.\nexport class NiconicoPlayerController extends PlayerControllerImpl<HTMLIFrameElement> {\n\tprivate static readonly origin = 'https://embed.nicovideo.jp';\n\n\tprivate duration = 0;\n\tprivate currentTime = 0;\n\tprivate volume = 0;\n\tprivate muted = false;\n\n\tprivate handleMessage = (e: nico.PlayerEvent): void => {\n\t\tif (e.origin !== NiconicoPlayerController.origin) return;\n\n\t\tconst data = e.data;\n\n\t\tswitch (data.eventName) {\n\t\t\tcase 'playerStatusChange':\n\t\t\t\tthis.logger.log(\n\t\t\t\t\tLogLevel.Debug,\n\t\t\t\t\t`player status changed: ${\n\t\t\t\t\t\tPlayerStatus[data.data.playerStatus] ??\n\t\t\t\t\t\tdata.data.playerStatus\n\t\t\t\t\t}`,\n\t\t\t\t);\n\t\t\t\tbreak;\n\n\t\t\tcase 'statusChange':\n\t\t\t\tthis.logger.log(\n\t\t\t\t\tLogLevel.Debug,\n\t\t\t\t\t`status changed: ${\n\t\t\t\t\t\tPlayerStatus[data.data.playerStatus] ??\n\t\t\t\t\t\tdata.data.playerStatus\n\t\t\t\t\t}`,\n\t\t\t\t);\n\n\t\t\t\tswitch (data.data.playerStatus) {\n\t\t\t\t\tcase PlayerStatus.Play:\n\t\t\t\t\t\tthis.options?.onPlay?.();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase PlayerStatus.Pause:\n\t\t\t\t\t\tthis.options?.onPause?.();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase PlayerStatus.End:\n\t\t\t\t\t\tthis.options?.onEnded?.();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'playerMetadataChange':\n\t\t\t\tif (data.data.duration !== undefined)\n\t\t\t\t\tthis.duration = data.data.duration / 1000;\n\n\t\t\t\tthis.currentTime =\n\t\t\t\t\tdata.data.currentTime === undefined\n\t\t\t\t\t\t? 0\n\t\t\t\t\t\t: data.data.currentTime / 1000;\n\n\t\t\t\tthis.volume = data.data.volume;\n\t\t\t\tthis.muted = data.data.muted;\n\n\t\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\t\tduration: this.duration,\n\t\t\t\t\tpercent:\n\t\t\t\t\t\tthis.currentTime !== 0 && this.duration !== 0\n\t\t\t\t\t\t\t? this.currentTime / this.duration\n\t\t\t\t\t\t\t: 0,\n\t\t\t\t\tseconds: this.currentTime,\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase 'loadComplete':\n\t\t\t\tthis.logger.log(LogLevel.Debug, 'load completed');\n\n\t\t\t\tthis.duration = data.data.videoInfo.lengthInSeconds;\n\n\t\t\t\tthis.options?.onLoaded?.({ id: data.data.videoInfo.watchId });\n\t\t\t\tbreak;\n\n\t\t\tcase 'error':\n\t\t\t\t// TODO: Implement.\n\n\t\t\t\tthis.options?.onError?.(data);\n\t\t\t\tbreak;\n\n\t\t\tcase 'player-error:video:play':\n\t\t\tcase 'player-error:video:seek':\n\t\t\t\tthis.options?.onError?.(data);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthis.logger.log(\n\t\t\t\t\tLogLevel.Debug,\n\t\t\t\t\t'message',\n\t\t\t\t\t(data as any).eventName,\n\t\t\t\t\t(data as any).data,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\tasync attach(): Promise<void> {\n\t\twindow.addEventListener('message', this.handleMessage);\n\t}\n\n\tasync detach(): Promise<void> {\n\t\twindow.removeEventListener('message', this.handleMessage);\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tthis.duration = 0;\n\t\t\tthis.currentTime = 0;\n\t\t\tthis.volume = 0;\n\t\t\tthis.muted = false;\n\n\t\t\t// Wait for iframe to load.\n\t\t\tthis.player.onload = (): void => {\n\t\t\t\tthis.player.onload = null;\n\t\t\t\tresolve();\n\t\t\t};\n\n\t\t\tthis.player.src = `https://embed.nicovideo.jp/watch/${id}?jsapi=1&playerId=1`;\n\t\t});\n\t}\n\n\t// https://blog.hayu.io/web/create/nicovideo-embed-player-api/.\n\tprivate postMessage(message: any): void {\n\t\tthis.player.contentWindow?.postMessage(\n\t\t\t{\n\t\t\t\t...message,\n\t\t\t\tplayerId: '1' /* Needs to be a string, not a number. */,\n\t\t\t\tsourceConnectorType: 1,\n\t\t\t},\n\t\t\tNiconicoPlayerController.origin,\n\t\t);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.postMessage({ eventName: 'play' });\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.postMessage({ eventName: 'pause' });\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.postMessage({ eventName: 'seek', data: { time: seconds * 1000 } });\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.postMessage({\n\t\t\teventName: 'volumeChange',\n\t\t\tdata: { volume: volume },\n\t\t});\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.postMessage({\n\t\t\teventName: 'mute',\n\t\t\tdata: { mute: muted },\n\t\t});\n\t}\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.duration;\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.currentTime;\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.volume;\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.muted;\n\t}\n\n\tgetPlaybackRate = undefined;\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\n// https://github.com/VocaDB/vocadb/blob/e147650a8f1f85c8fa865d0ab562126c278527ec/VocaDbWeb/Scripts/ViewModels/PVs/PVPlayerSoundCloud.ts.\nexport class SoundCloudPlayerController extends PlayerControllerImpl<SC.SoundCloudWidget> {\n\tprivate getDurationCore(): Promise<number> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tthis.player.getDuration(resolve);\n\t\t});\n\t}\n\n\tattach(id: string): Promise<void> {\n\t\treturn new Promise((resolve, _reject /* TODO: reject */) => {\n\t\t\tthis.player.bind(SC.Widget.Events.READY, () => {\n\t\t\t\tthis.player.bind(\n\t\t\t\t\tSC.Widget.Events.PLAY_PROGRESS,\n\t\t\t\t\tasync (event) => {\n\t\t\t\t\t\tconst duration = await this.getDurationCore();\n\n\t\t\t\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\t\t\t\tduration: duration / 1000,\n\t\t\t\t\t\t\tpercent: event.currentPosition / duration,\n\t\t\t\t\t\t\tseconds: event.currentPosition / 1000,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tthis.player.bind(SC.Widget.Events.ERROR, (event) =>\n\t\t\t\t\tthis.options?.onError?.(event),\n\t\t\t\t);\n\t\t\t\tthis.player.bind(SC.Widget.Events.PLAY, () =>\n\t\t\t\t\tthis.options?.onPlay?.(),\n\t\t\t\t);\n\t\t\t\tthis.player.bind(SC.Widget.Events.PAUSE, () =>\n\t\t\t\t\tthis.options?.onPause?.(),\n\t\t\t\t);\n\t\t\t\tthis.player.bind(SC.Widget.Events.FINISH, () =>\n\t\t\t\t\tthis.options?.onEnded?.(),\n\t\t\t\t);\n\n\t\t\t\tthis.options?.onLoaded?.({ id: id });\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tthis.player.unbind(SC.Widget.Events.READY);\n\t\tthis.player.unbind(SC.Widget.Events.PLAY_PROGRESS);\n\t\tthis.player.unbind(SC.Widget.Events.ERROR);\n\t\tthis.player.unbind(SC.Widget.Events.PLAY);\n\t\tthis.player.unbind(SC.Widget.Events.PAUSE);\n\t\tthis.player.unbind(SC.Widget.Events.FINISH);\n\t}\n\n\tprivate static playerLoadAsync(\n\t\tplayer: SC.SoundCloudWidget,\n\t\turl: string,\n\t\toptions: Omit<SC.SoundCloudLoadOptions, 'callback'>,\n\t): Promise<void> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tplayer.load(url, { ...options, callback: resolve });\n\t\t});\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tawait SoundCloudPlayerController.playerLoadAsync(this.player, id, {\n\t\t\tauto_play: true,\n\t\t});\n\n\t\tthis.options?.onLoaded?.({ id: id });\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.seekTo(seconds * 1000);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.setVolume(volume * 100);\n\t}\n\n\tsetMuted = undefined;\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\tconst duration = await this.getDurationCore();\n\t\treturn duration / 1000;\n\t}\n\n\tprivate getCurrentTimeCore(): Promise<number> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tthis.player.getPosition(resolve);\n\t\t});\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\tconst position = await this.getCurrentTimeCore();\n\t\treturn position / 1000;\n\t}\n\n\tprivate getVolumeCore(): Promise<number> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tthis.player.getVolume(resolve);\n\t\t});\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\tconst volume = await this.getVolumeCore();\n\t\treturn volume / 100;\n\t}\n\n\tgetMuted = undefined;\n\n\tgetPlaybackRate = undefined;\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\nexport class TwitchPlayerController extends PlayerControllerImpl<Twitch.Player> {\n\tprivate handleReady = (): void => {\n\t\tthis.options?.onLoaded?.({ id: this.player.getVideo() });\n\t};\n\n\tprivate handlePlay = (): void => {\n\t\tthis.options?.onPlay?.();\n\t};\n\n\tprivate handlePause = (): void => {\n\t\tthis.options?.onPause?.();\n\t};\n\n\tprivate handleEnded = (): void => {\n\t\tthis.options?.onEnded?.();\n\t};\n\n\tprivate handleSeek = (): void => {\n\t\tthis.options?.onTimeUpdate?.({\n\t\t\tduration: 0,\n\t\t\tpercent: 0,\n\t\t\tseconds: 0,\n\t\t});\n\t};\n\n\tasync attach(_id: string): Promise<void> {\n\t\tthis.player.addEventListener(Twitch.Player.READY, this.handleReady);\n\t\tthis.player.addEventListener(Twitch.Player.PLAYING, this.handlePlay);\n\t\tthis.player.addEventListener(Twitch.Player.PAUSE, this.handlePause);\n\t\tthis.player.addEventListener(Twitch.Player.ENDED, this.handleEnded);\n\t\tthis.player.addEventListener(Twitch.Player.SEEK, this.handleSeek);\n\t}\n\n\tasync detach(): Promise<void> {}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.player.setVideo(id, 0);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.seek(seconds);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.setVolume(volume);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.player.setMuted(muted);\n\t}\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.getDuration();\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.getCurrentTime();\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.getVolume();\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.player.getMuted();\n\t}\n\n\tgetPlaybackRate = undefined;\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\n// https://github.com/cookpete/react-player/blob/e3c324bc6845698179d065fa408db515c2296b4b/src/players/Vimeo.js\nexport class VimeoPlayerController extends PlayerControllerImpl<Vimeo.Player> {\n\tasync attach(): Promise<void> {\n\t\tawait this.player.ready();\n\n\t\tthis.player.on('error', (data) => this.options?.onError?.(data));\n\t\tthis.player.on('loaded', (event) =>\n\t\t\tthis.options?.onLoaded?.({ id: event.id.toString() }),\n\t\t);\n\t\tthis.player.on('play', () => this.options?.onPlay?.());\n\t\tthis.player.on('pause', () => this.options?.onPause?.());\n\t\tthis.player.on('ended', () => this.options?.onEnded?.());\n\t\tthis.player.on('timeupdate', (data) => {\n\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\tduration: data.duration,\n\t\t\t\tpercent: data.percent,\n\t\t\t\tseconds: data.seconds,\n\t\t\t});\n\t\t});\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tthis.player.off('error');\n\t\tthis.player.off('loaded');\n\t\tthis.player.off('play');\n\t\tthis.player.off('pause');\n\t\tthis.player.off('ended');\n\t\tthis.player.off('timeupdate');\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tawait this.player.loadVideo(id);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tawait this.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tawait this.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tawait this.player.setCurrentTime(seconds);\n\t}\n\n\tasync setVolume(fraction: number): Promise<void> {\n\t\tawait this.player.setVolume(fraction);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tawait this.player.setMuted(muted);\n\t}\n\n\tasync setPlaybackRate(playbackRate: number): Promise<void> {\n\t\tawait this.player.setPlaybackRate(playbackRate);\n\t}\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.getDuration();\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.getCurrentTime();\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.getVolume();\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn await this.player.getMuted();\n\t}\n\n\tasync getPlaybackRate(): Promise<number> {\n\t\treturn this.player.getPlaybackRate();\n\t}\n}\n","import { LogLevel } from '@/controllers/Logger';\nimport { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\ndeclare global {\n\tinterface Window {\n\t\tonYouTubeIframeAPIReady(): void;\n\t}\n}\n\nenum PlayerState {\n\tUNSTARTED = -1,\n\tENDED = 0,\n\tPLAYING = 1,\n\tPAUSED = 2,\n\tBUFFERING = 3,\n\tCUED = 5,\n}\n\n// https://github.com/VocaDB/vocadb/blob/076dac9f0808aba5da7332209fdfd2ff4e12c235/VocaDbWeb/Scripts/ViewModels/PVs/PVPlayerYoutube.ts.\nexport class YouTubePlayerController extends PlayerControllerImpl<YT.Player> {\n\tprivate previousTime?: number;\n\n\tprivate timeUpdateIntervalId?: number;\n\n\tprivate clearTimeUpdateInterval(): void {\n\t\tthis.logger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'clearTimeUpdateInterval',\n\t\t\tthis.timeUpdateIntervalId,\n\t\t);\n\n\t\twindow.clearInterval(this.timeUpdateIntervalId);\n\n\t\tthis.timeUpdateIntervalId = undefined;\n\t}\n\n\tprivate invokeTimeUpdate(player: YT.Player): void {\n\t\tconst currentTime = player.getCurrentTime();\n\t\tif (currentTime === this.previousTime) return;\n\n\t\tconst duration = player.getDuration();\n\t\tthis.options?.onTimeUpdate?.({\n\t\t\tduration: duration,\n\t\t\tpercent: currentTime / duration,\n\t\t\tseconds: currentTime,\n\t\t});\n\n\t\tthis.previousTime = currentTime;\n\t}\n\n\tprivate setTimeUpdateInterval(): void {\n\t\tthis.logger.log(LogLevel.Debug, 'setTimeUpdateInterval');\n\n\t\tthis.clearTimeUpdateInterval();\n\n\t\tthis.timeUpdateIntervalId = window.setInterval(\n\t\t\t() => this.invokeTimeUpdate(this.player),\n\t\t\t250,\n\t\t);\n\n\t\tthis.logger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'timeUpdateIntervalId',\n\t\t\tthis.timeUpdateIntervalId,\n\t\t);\n\n\t\tthis.invokeTimeUpdate(this.player);\n\t}\n\n\tattach(id: string): Promise<void> {\n\t\treturn new Promise((resolve, _reject /* TODO: reject */) => {\n\t\t\tthis.player.addEventListener('onReady', async () => {\n\t\t\t\tthis.player.addEventListener('onError', (event) =>\n\t\t\t\t\tthis.options?.onError?.(event.data),\n\t\t\t\t);\n\t\t\t\tthis.player.addEventListener(\n\t\t\t\t\t'onStateChange',\n\t\t\t\t\t(event: YT.EventArgs): void => {\n\t\t\t\t\t\tthis.logger.log(\n\t\t\t\t\t\t\tLogLevel.Debug,\n\t\t\t\t\t\t\t`state changed: ${PlayerState[event.data]}`,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tswitch (event.data) {\n\t\t\t\t\t\t\tcase YT.PlayerState.CUED:\n\t\t\t\t\t\t\t\tthis.options?.onLoaded?.({ id: id });\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase YT.PlayerState.PLAYING:\n\t\t\t\t\t\t\t\tthis.options?.onPlay?.();\n\t\t\t\t\t\t\t\tthis.setTimeUpdateInterval();\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase YT.PlayerState.PAUSED:\n\t\t\t\t\t\t\t\tthis.options?.onPause?.();\n\t\t\t\t\t\t\t\tthis.clearTimeUpdateInterval();\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase YT.PlayerState.ENDED:\n\t\t\t\t\t\t\t\tthis.options?.onEnded?.();\n\t\t\t\t\t\t\t\tthis.clearTimeUpdateInterval();\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tawait this.loadVideo(id);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tthis.clearTimeUpdateInterval();\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.previousTime = undefined;\n\t\tthis.player.cueVideoById(id);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.player.playVideo();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pauseVideo();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.seekTo(seconds);\n\n\t\tthis.invokeTimeUpdate(this.player);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.setVolume(volume * 100);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tif (muted) {\n\t\t\tthis.player.mute();\n\t\t} else {\n\t\t\tthis.player.unMute();\n\t\t}\n\t}\n\n\tasync setPlaybackRate(playbackRate: number): Promise<void> {\n\t\tthis.player.setPlaybackRate(playbackRate);\n\t}\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.getDuration();\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.getCurrentTime();\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.getVolume() / 100;\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.player.isMuted();\n\t}\n\n\tasync getPlaybackRate(): Promise<number> {\n\t\treturn this.player.getPlaybackRate();\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","names":["#options","#handleControllerChange","#render"],"sources":["../src/components/NostalgicDivaProvider.tsx","../src/services/VideoService.ts","../src/services/AudioVideoService.ts","../src/services/DailymotionVideoService.ts","../src/services/NiconicoVideoService.ts","../src/services/SoundCloudVideoService.ts","../src/services/SpotifyVideoService.ts","../src/services/TwitchVideoService.ts","../src/services/VimeoVideoService.ts","../src/services/YouTubeVideoService.ts","../src/services/findVideoService.ts","../src/components/NostalgicDiva.tsx","../src/components/defineNostalgicDiva.tsx","../src/controllers/AudioPlayerController.ts","../src/controllers/DailymotionPlayerController.ts","../src/controllers/NiconicoPlayerController.ts","../src/controllers/SoundCloudPlayerController.ts","../src/controllers/SpotifyPlayerController.ts","../src/controllers/TwitchPlayerController.ts","../src/controllers/VimeoPlayerController.ts","../src/controllers/YouTubePlayerController.ts"],"sourcesContent":["import { type ILogger, LogLevel, defaultLogger } from '@/controllers/Logger';\nimport { nullPlayerController } from '@/controllers/NullPlayerController';\nimport type {\n\tIPlayerCommands,\n\tIPlayerController,\n} from '@/controllers/PlayerController';\nimport {\n\ttype ReactElement,\n\ttype ReactNode,\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseMemo,\n\tuseRef,\n} from 'react';\n\ninterface NostalgicDivaContextProps extends IPlayerController {\n\tlogger: ILogger;\n\thandleControllerChange: (value: IPlayerController) => void;\n}\n\nconst NostalgicDivaContext = createContext<NostalgicDivaContextProps>(\n\tundefined!,\n);\n\nexport interface NostalgicDivaProviderProps {\n\tchildren?: ReactNode;\n\tlogger?: ILogger;\n}\n\nexport const NostalgicDivaProvider = ({\n\tchildren,\n\tlogger = defaultLogger,\n}: NostalgicDivaProviderProps): ReactElement => {\n\tconst controllerRef = useRef<IPlayerController>(nullPlayerController);\n\n\tconst handleControllerChange = useCallback(\n\t\t(value: IPlayerController): void => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.handleControllerChange',\n\t\t\t\tcontrollerRef.current,\n\t\t\t\tvalue,\n\t\t\t);\n\n\t\t\tcontrollerRef.current = value;\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst loadVideo = useCallback(\n\t\tasync (id: string): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.loadVideo',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.loadVideo(id);\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst play = useCallback(async (): Promise<void> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.play',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\tawait controllerRef.current.play();\n\t}, [logger]);\n\n\tconst pause = useCallback(async (): Promise<void> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.pause',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\tawait controllerRef.current.pause();\n\t}, [logger]);\n\n\tconst setCurrentTime = useCallback(\n\t\tasync (seconds: number): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.setCurrentTime',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.setCurrentTime(seconds);\n\t\t\tawait controllerRef.current.play();\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst setVolume = useCallback(\n\t\tasync (volume: number): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.setVolume',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.setVolume(volume);\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst setMuted = useCallback(\n\t\tasync (muted: boolean): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.setMuted',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.setMuted(muted);\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst setPlaybackRate = useCallback(\n\t\tasync (playbackRate: number): Promise<void> => {\n\t\t\tlogger.log(\n\t\t\t\tLogLevel.Debug,\n\t\t\t\t'NostalgicDivaProvider.setPlaybackRate',\n\t\t\t\tcontrollerRef.current,\n\t\t\t);\n\n\t\t\tawait controllerRef.current.setPlaybackRate(playbackRate);\n\t\t},\n\t\t[logger],\n\t);\n\n\tconst getDuration = useCallback(async (): Promise<number> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getDuration',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getDuration();\n\t}, [logger]);\n\n\tconst getCurrentTime = useCallback(async (): Promise<number> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getCurrentTime',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getCurrentTime();\n\t}, [logger]);\n\n\tconst getVolume = useCallback(async (): Promise<number> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getVolume',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getVolume();\n\t}, [logger]);\n\n\tconst getMuted = useCallback(async (): Promise<boolean> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getMuted',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getMuted();\n\t}, [logger]);\n\n\tconst getPlaybackRate = useCallback(async (): Promise<number> => {\n\t\tlogger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'NostalgicDivaProvider.getPlaybackRate',\n\t\t\tcontrollerRef.current,\n\t\t);\n\n\t\treturn await controllerRef.current.getPlaybackRate();\n\t}, [logger]);\n\n\tconst supports = useCallback(\n\t\t(command: keyof IPlayerCommands): boolean =>\n\t\t\tcontrollerRef.current.supports(command),\n\t\t[],\n\t);\n\n\tconst value = useMemo(\n\t\t(): NostalgicDivaContextProps => ({\n\t\t\tlogger,\n\t\t\thandleControllerChange,\n\t\t\tloadVideo,\n\t\t\tplay,\n\t\t\tpause,\n\t\t\tsetCurrentTime,\n\t\t\tsetVolume,\n\t\t\tsetMuted,\n\t\t\tsetPlaybackRate,\n\t\t\tgetDuration,\n\t\t\tgetCurrentTime,\n\t\t\tgetVolume,\n\t\t\tgetMuted,\n\t\t\tgetPlaybackRate,\n\t\t\tsupports,\n\t\t}),\n\t\t[\n\t\t\tlogger,\n\t\t\thandleControllerChange,\n\t\t\tloadVideo,\n\t\t\tplay,\n\t\t\tpause,\n\t\t\tsetCurrentTime,\n\t\t\tsetVolume,\n\t\t\tsetMuted,\n\t\t\tsetPlaybackRate,\n\t\t\tgetDuration,\n\t\t\tgetCurrentTime,\n\t\t\tgetVolume,\n\t\t\tgetMuted,\n\t\t\tgetPlaybackRate,\n\t\t\tsupports,\n\t\t],\n\t);\n\n\treturn (\n\t\t<NostalgicDivaContext.Provider value={value}>\n\t\t\t{children}\n\t\t</NostalgicDivaContext.Provider>\n\t);\n};\n\nexport const useNostalgicDiva = (): NostalgicDivaContextProps => {\n\treturn useContext(NostalgicDivaContext);\n};\n","import type { PlayerType } from '@/controllers/PlayerController';\n\nexport abstract class VideoService {\n\tprotected constructor(readonly type: PlayerType) {}\n\n\tabstract canPlay(url: string): boolean;\n\n\tabstract extractVideoId(url: string): string | undefined;\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst AUDIO_EXTENSIONS =\n\t/\\.(m4a|m4b|mp4a|mpga|mp2|mp2a|mp3|m2a|m3a|wav|weba|aac|oga|spx)($|\\?)/i;\nconst VIDEO_EXTENSIONS = /\\.(mp4|og[gv]|webm|mov|m4v)(#t=[,\\d+]+)?($|\\?)/i;\n\nexport class AudioVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Audio');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn AUDIO_EXTENSIONS.test(url) || VIDEO_EXTENSIONS.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\treturn url;\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_DAILYMOTION =\n\t/^(?:(?:https?):)?(?:\\/\\/)?(?:www\\.)?(?:(?:dailymotion\\.com(?:\\/embed)?\\/video)|dai\\.ly)\\/([a-zA-Z0-9]+)(?:_[\\w_-]+)?(?:[\\w.#_-]+)?/;\n\nexport class DailymotionVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Dailymotion');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_DAILYMOTION.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\tconst matches = MATCH_URL_DAILYMOTION.exec(url);\n\t\treturn matches?.[1];\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\nconst MATCH_URL_NICONICO = /(?:www\\.|)?nicovideo\\.jp\\/watch\\/(\\w+)$/;\n\nexport class NiconicoVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Niconico');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_NICONICO.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\tconst matches = MATCH_URL_NICONICO.exec(url);\n\t\treturn matches?.[1];\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_SOUNDCLOUD = /(?:soundcloud\\.com|snd\\.sc)\\/[^.]+$/;\n\nexport class SoundCloudVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('SoundCloud');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_SOUNDCLOUD.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\treturn url;\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// Matches `https://open.spotify.com/track/<id>` (with an optional `intl-xx`\n// locale segment and query string) as well as bare `spotify:track:<id>` URIs.\nconst SPOTIFY_TYPES = 'track|episode|album|playlist|show|artist';\nconst MATCH_URL_SPOTIFY = new RegExp(\n\t`^https?://open\\\\.spotify\\\\.com/(?:intl-[a-z]{2}/)?(${SPOTIFY_TYPES})/([a-zA-Z0-9]+)`,\n);\nconst MATCH_URI_SPOTIFY = new RegExp(\n\t`^spotify:(${SPOTIFY_TYPES}):([a-zA-Z0-9]+)$`,\n);\n\nexport class SpotifyVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Spotify');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_SPOTIFY.test(url) || MATCH_URI_SPOTIFY.test(url);\n\t}\n\n\t// The Spotify iframe API is driven by Spotify URIs (`spotify:track:<id>`),\n\t// so normalize both URLs and URIs down to that form.\n\textractVideoId(url: string): string | undefined {\n\t\tconst match =\n\t\t\tMATCH_URL_SPOTIFY.exec(url) ?? MATCH_URI_SPOTIFY.exec(url);\n\t\tif (match === null) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst [, type, id] = match;\n\t\treturn `spotify:${type}:${id}`;\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_TWITCH_VIDEO = /(?:www\\.|go\\.)?twitch\\.tv\\/videos\\/(\\d+)($|\\?)/;\n\nexport class TwitchVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Twitch');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_TWITCH_VIDEO.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\tconst matches = MATCH_URL_TWITCH_VIDEO.exec(url);\n\t\treturn matches?.[1];\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_VIMEO = /vimeo\\.com\\/(\\d+)$/;\n\nexport class VimeoVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('Vimeo');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_VIMEO.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\treturn MATCH_URL_VIMEO.exec(url)?.[1];\n\t}\n}\n","import { VideoService } from '@/services/VideoService';\n\n// https://github.com/cookpete/react-player/blob/2811bc59b9368170acc20d4f1e39555413d0d9e1/src/patterns.js\nconst MATCH_URL_YOUTUBE =\n\t/(?:youtu\\.be\\/|youtube(?:-nocookie|education)?\\.com\\/(?:embed\\/|v\\/|watch\\/|watch\\?v=|watch\\?.+&v=|shorts\\/|live\\/))((\\w|-){11})|youtube\\.com\\/playlist\\?list=|youtube\\.com\\/user\\//;\n\nexport class YouTubeVideoService extends VideoService {\n\tconstructor() {\n\t\tsuper('YouTube');\n\t}\n\n\tcanPlay(url: string): boolean {\n\t\treturn MATCH_URL_YOUTUBE.test(url);\n\t}\n\n\textractVideoId(url: string): string | undefined {\n\t\tconst matches = MATCH_URL_YOUTUBE.exec(url);\n\t\treturn matches?.[1];\n\t}\n}\n","import { AudioVideoService } from '@/services/AudioVideoService';\nimport { DailymotionVideoService } from '@/services/DailymotionVideoService';\nimport { NiconicoVideoService } from '@/services/NiconicoVideoService';\nimport { SoundCloudVideoService } from '@/services/SoundCloudVideoService';\nimport { SpotifyVideoService } from '@/services/SpotifyVideoService';\nimport { TwitchVideoService } from '@/services/TwitchVideoService';\nimport type { VideoService } from '@/services/VideoService';\nimport { VimeoVideoService } from '@/services/VimeoVideoService';\nimport { YouTubeVideoService } from '@/services/YouTubeVideoService';\n\nexport const videoServices: VideoService[] = [\n\tnew YouTubeVideoService(),\n\tnew TwitchVideoService(),\n\tnew VimeoVideoService(),\n\tnew DailymotionVideoService(),\n\tnew SoundCloudVideoService(),\n\tnew SpotifyVideoService(),\n\tnew AudioVideoService(),\n\tnew NiconicoVideoService(),\n];\n\nexport function findVideoService(url: string): VideoService | undefined {\n\treturn videoServices.find((videoService) => videoService.canPlay(url));\n}\n","import { useNostalgicDiva } from '@/components/NostalgicDivaProvider';\nimport type { PlayerProps } from '@/components/PlayerContainer';\nimport { LogLevel } from '@/controllers/Logger';\nimport type {\n\tIPlayerController,\n\tPlayerOptions,\n\tPlayerType,\n} from '@/controllers/PlayerController';\nimport { findVideoService } from '@/services/findVideoService';\nimport {\n\ttype ElementType,\n\ttype ReactElement,\n\tSuspense,\n\tlazy,\n\tmemo,\n\tuseCallback,\n} from 'react';\n\nexport const players: Map<PlayerType, ElementType<PlayerProps>> = new Map(\n\tObject.entries({\n\t\tAudio: lazy(() => import('./AudioPlayer')),\n\t\tDailymotion: lazy(() => import('./DailymotionPlayer')),\n\t\tNiconico: lazy(() => import('./NiconicoPlayer')),\n\t\tSoundCloud: lazy(() => import('./SoundCloudPlayer')),\n\t\tSpotify: lazy(() => import('./SpotifyPlayer')),\n\t\tTwitch: lazy(() => import('./TwitchPlayer')),\n\t\tVimeo: lazy(() => import('./VimeoPlayer')),\n\t\tYouTube: lazy(() => import('./YouTubePlayer')),\n\t}),\n);\n\nexport interface NostalgicDivaProps {\n\tsrc: string;\n\toptions?: PlayerOptions;\n\tonControllerChange?: (value: IPlayerController) => void;\n}\n\nfunction getTypeAndVideoId(\n\turl: string,\n): { type: PlayerType; videoId: string } | undefined {\n\tconst videoService = findVideoService(url);\n\tif (videoService === undefined) {\n\t\treturn undefined;\n\t}\n\n\tconst { type, extractVideoId } = videoService;\n\n\tconst videoId = extractVideoId(url);\n\tif (videoId === undefined) {\n\t\treturn undefined;\n\t}\n\n\treturn { type: type, videoId: videoId };\n}\n\nconst EmptyPlayer = memo((): ReactElement => {\n\treturn (\n\t\t<div style={{ width: '100%', height: '100%' }}>\n\t\t\t<iframe\n\t\t\t\tsrc=\"about:blank\"\n\t\t\t\ttitle=\"about:blank\"\n\t\t\t\tstyle={{\n\t\t\t\t\twidth: '100%',\n\t\t\t\t\theight: '100%',\n\t\t\t\t\tborder: 0,\n\t\t\t\t}}\n\t\t\t/>\n\t\t</div>\n\t);\n});\n\nexport const NostalgicDiva = memo(\n\t({\n\t\tsrc,\n\t\toptions,\n\t\tonControllerChange,\n\t}: NostalgicDivaProps): ReactElement => {\n\t\tconst diva = useNostalgicDiva();\n\n\t\tconst handleControllerChange = useCallback(\n\t\t\t(value: IPlayerController) => {\n\t\t\t\tdiva.handleControllerChange(value);\n\n\t\t\t\tonControllerChange?.(value);\n\t\t\t},\n\t\t\t[diva, onControllerChange],\n\t\t);\n\n\t\tdiva.logger.log(LogLevel.Debug, 'NostalgicDiva');\n\n\t\tconst typeAndVideoId = getTypeAndVideoId(src);\n\t\tif (typeAndVideoId === undefined) {\n\t\t\tdiva.logger.log(\n\t\t\t\tLogLevel.Warning,\n\t\t\t\t`Failed to extract type and videoId from src: \"${src}\". Returning EmptyPlayer.`,\n\t\t\t);\n\t\t\treturn <EmptyPlayer />;\n\t\t}\n\n\t\tconst { type, videoId } = typeAndVideoId;\n\n\t\tconst Player = players.get(type);\n\t\tif (Player === undefined) {\n\t\t\tdiva.logger.log(\n\t\t\t\tLogLevel.Warning,\n\t\t\t\t`No player found for type \"${type}\" (videoId: \"${videoId}\"). Returning EmptyPlayer.`,\n\t\t\t);\n\t\t\treturn <EmptyPlayer />;\n\t\t}\n\n\t\treturn (\n\t\t\t<Suspense fallback={null}>\n\t\t\t\t<Player\n\t\t\t\t\tlogger={diva.logger}\n\t\t\t\t\ttype={type}\n\t\t\t\t\tonControllerChange={handleControllerChange}\n\t\t\t\t\tvideoId={videoId}\n\t\t\t\t\toptions={options}\n\t\t\t\t/>\n\t\t\t</Suspense>\n\t\t);\n\t},\n);\n","import { NostalgicDiva } from '@/components/NostalgicDiva';\nimport { NostalgicDivaProvider } from '@/components/NostalgicDivaProvider';\nimport { nullPlayerController } from '@/controllers/NullPlayerController';\nimport type {\n\tIPlayerCommands,\n\tIPlayerController,\n\tPlayerOptions,\n} from '@/controllers/PlayerController';\nimport ReactDOM from 'react-dom';\n\nexport class NostalgicDivaElement\n\textends HTMLElement\n\timplements IPlayerController\n{\n\tstatic readonly observedAttributes = ['src'];\n\n\tcontainer: ShadowRoot;\n\tcontroller: IPlayerController = nullPlayerController;\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis.container = this.attachShadow({ mode: 'closed' });\n\t}\n\n\tget src(): string {\n\t\treturn this.getAttribute('src') ?? '';\n\t}\n\n\tset src(value: string) {\n\t\tthis.setAttribute('src', value);\n\t}\n\n\treadonly #options: PlayerOptions = {\n\t\tonError: (e) =>\n\t\t\tthis.dispatchEvent(new CustomEvent('error', { detail: e })),\n\t\tonLoaded: (e) =>\n\t\t\tthis.dispatchEvent(new CustomEvent('loaded', { detail: e })),\n\t\tonPlay: () => this.dispatchEvent(new CustomEvent('play')),\n\t\tonPause: () => this.dispatchEvent(new CustomEvent('pause')),\n\t\tonEnded: () => this.dispatchEvent(new CustomEvent('ended')),\n\t\tonTimeUpdate: (e) =>\n\t\t\tthis.dispatchEvent(new CustomEvent('timeupdate', { detail: e })),\n\t};\n\n\t#handleControllerChange = (value: IPlayerController): void => {\n\t\tconsole.debug(\n\t\t\t'[@nostalgic-diva/web-components] handleControllerChange',\n\t\t);\n\n\t\tthis.controller = value;\n\t};\n\n\t#render(): void {\n\t\tReactDOM.render(\n\t\t\t<NostalgicDivaProvider>\n\t\t\t\t<NostalgicDiva\n\t\t\t\t\tsrc={this.src}\n\t\t\t\t\toptions={this.#options}\n\t\t\t\t\tonControllerChange={this.#handleControllerChange}\n\t\t\t\t/>\n\t\t\t</NostalgicDivaProvider>,\n\t\t\tthis.container,\n\t\t);\n\t}\n\n\tconnectedCallback(): void {\n\t\tconsole.debug('[@nostalgic-diva/web-components] connectedCallback');\n\n\t\tthis.#render();\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tconsole.debug('[@nostalgic-diva/web-components] disconnectedCallback');\n\t}\n\n\tattributeChangedCallback(): void {\n\t\tconsole.debug(\n\t\t\t'[@nostalgic-diva/web-components] attributeChangedCallback',\n\t\t);\n\n\t\tthis.#render();\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tawait this.controller.loadVideo(id);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tawait this.controller.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tawait this.controller.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tawait this.controller.setCurrentTime(seconds);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tawait this.controller.setVolume(volume);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tawait this.controller.setMuted(muted);\n\t}\n\n\tasync setPlaybackRate(playbackRate: number): Promise<void> {\n\t\tawait this.controller.setPlaybackRate(playbackRate);\n\t}\n\n\tasync getDuration(): Promise<number> {\n\t\treturn await this.controller.getDuration();\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn await this.controller.getCurrentTime();\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn await this.controller.getVolume();\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn await this.controller.getMuted();\n\t}\n\n\tasync getPlaybackRate(): Promise<number> {\n\t\treturn await this.controller.getPlaybackRate();\n\t}\n\n\tsupports(command: keyof IPlayerCommands): boolean {\n\t\treturn this.controller.supports(command);\n\t}\n}\n\nexport function defineNostalgicDiva(): void {\n\tcustomElements.define('nostalgic-diva', NostalgicDivaElement);\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\n// https://github.com/VocaDB/vocadb/blob/61b8c54f3eca906a477101dab4fdd9b154be310e/VocaDbWeb/Scripts/ViewModels/PVs/PVPlayerFile.ts.\nexport class AudioPlayerController extends PlayerControllerImpl<HTMLAudioElement> {\n\tasync attach(): Promise<void> {\n\t\tthis.player.onerror = (event): void => this.options?.onError?.(event);\n\t\tthis.player.onloadeddata = (): void =>\n\t\t\tthis.options?.onLoaded?.({ id: this.player.src });\n\t\tthis.player.onplay = (): void => this.options?.onPlay?.();\n\t\tthis.player.onpause = (): void => this.options?.onPause?.();\n\t\tthis.player.onended = (): void => this.options?.onEnded?.();\n\t\tthis.player.ontimeupdate = (): void => {\n\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\tduration: this.player.duration,\n\t\t\t\tpercent: this.player.currentTime / this.player.duration,\n\t\t\t\tseconds: this.player.currentTime,\n\t\t\t});\n\t\t};\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tthis.player.onerror = null;\n\t\tthis.player.onloadeddata = null;\n\t\tthis.player.onplay = null;\n\t\tthis.player.onpause = null;\n\t\tthis.player.onended = null;\n\t\tthis.player.ontimeupdate = null;\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.player.src = id;\n\t}\n\n\tasync play(): Promise<void> {\n\t\tawait this.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.currentTime = seconds;\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.volume = volume;\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.player.muted = muted;\n\t}\n\n\tasync setPlaybackRate(playbackRate: number): Promise<void> {\n\t\tthis.player.playbackRate = playbackRate;\n\t}\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.duration;\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.currentTime;\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.volume;\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.player.muted;\n\t}\n\n\tasync getPlaybackRate(): Promise<number> {\n\t\treturn this.player.playbackRate;\n\t}\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\nconst events = [\n\t'apiready',\n\t'seeked',\n\t'video_end',\n\t'durationchange',\n\t'pause',\n\t'playing',\n\t'error',\n] satisfies DM.EventType[];\n\nexport class DailymotionPlayerController extends PlayerControllerImpl<DM.player> {\n\tprivate handlePlayerEvents = (e: { type: DM.EventType }): void => {\n\t\tswitch (e.type) {\n\t\t\tcase 'apiready':\n\t\t\t\tthis.options?.onLoaded?.({ id: this.player.video.videoId });\n\t\t\t\tbreak;\n\t\t\tcase 'seeked':\n\t\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\t\tduration: this.player.duration,\n\t\t\t\t\tpercent: this.player.currentTime / this.player.duration,\n\t\t\t\t\tseconds: this.player.currentTime,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase 'video_end':\n\t\t\t\tthis.options?.onEnded?.();\n\t\t\t\tbreak;\n\t\t\tcase 'durationchange':\n\t\t\t\tbreak;\n\t\t\tcase 'pause':\n\t\t\t\tthis.options?.onPause?.();\n\t\t\t\tbreak;\n\t\t\tcase 'playing':\n\t\t\t\tthis.options?.onPlay?.();\n\t\t\t\tbreak;\n\t\t\tcase 'error':\n\t\t\t\tthis.options?.onError?.(e);\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\tasync attach(_id: string): Promise<void> {\n\t\tfor (const event of events) {\n\t\t\tthis.player.addEventListener(event, this.handlePlayerEvents);\n\t\t}\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tfor (const event of events) {\n\t\t\tthis.player.removeEventListener(event, this.handlePlayerEvents);\n\t\t}\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.player.load(id);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.seek(seconds);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.setVolume(volume);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.player.setMuted(muted);\n\t}\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.duration;\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.currentTime;\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.volume;\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.player.muted;\n\t}\n\n\tgetPlaybackRate = undefined;\n}\n","import { LogLevel } from '@/controllers/Logger';\nimport { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\ndeclare global {\n\tinterface Window {\n\t\tonNicoPlayerFactoryReady: (callback: nico.NicoPlayerFactory) => void;\n\t}\n}\n\nenum PlayerStatus {\n\tPlay = 2,\n\tPause = 3,\n\tEnd = 4,\n}\n\n// https://github.com/VocaDB/vocadb/blob/a4b5f9d8186772d7e6f58f997bbcbb51509d2539/VocaDbWeb/Scripts/ViewModels/PVs/PVPlayerNico.ts.\nexport class NiconicoPlayerController extends PlayerControllerImpl<HTMLIFrameElement> {\n\tprivate static readonly origin = 'https://embed.nicovideo.jp';\n\n\tprivate duration = 0;\n\tprivate currentTime = 0;\n\tprivate volume = 0;\n\tprivate muted = false;\n\n\tprivate handleMessage = (e: nico.PlayerEvent): void => {\n\t\tif (e.origin !== NiconicoPlayerController.origin) return;\n\n\t\tconst data = e.data;\n\n\t\tswitch (data.eventName) {\n\t\t\tcase 'playerStatusChange':\n\t\t\t\tthis.logger.log(\n\t\t\t\t\tLogLevel.Debug,\n\t\t\t\t\t`player status changed: ${\n\t\t\t\t\t\tPlayerStatus[data.data.playerStatus] ??\n\t\t\t\t\t\tdata.data.playerStatus\n\t\t\t\t\t}`,\n\t\t\t\t);\n\t\t\t\tbreak;\n\n\t\t\tcase 'statusChange':\n\t\t\t\tthis.logger.log(\n\t\t\t\t\tLogLevel.Debug,\n\t\t\t\t\t`status changed: ${\n\t\t\t\t\t\tPlayerStatus[data.data.playerStatus] ??\n\t\t\t\t\t\tdata.data.playerStatus\n\t\t\t\t\t}`,\n\t\t\t\t);\n\n\t\t\t\tswitch (data.data.playerStatus) {\n\t\t\t\t\tcase PlayerStatus.Play:\n\t\t\t\t\t\tthis.options?.onPlay?.();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase PlayerStatus.Pause:\n\t\t\t\t\t\tthis.options?.onPause?.();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase PlayerStatus.End:\n\t\t\t\t\t\tthis.options?.onEnded?.();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'playerMetadataChange':\n\t\t\t\tif (data.data.duration !== undefined)\n\t\t\t\t\tthis.duration = data.data.duration / 1000;\n\n\t\t\t\tthis.currentTime =\n\t\t\t\t\tdata.data.currentTime === undefined\n\t\t\t\t\t\t? 0\n\t\t\t\t\t\t: data.data.currentTime / 1000;\n\n\t\t\t\tthis.volume = data.data.volume;\n\t\t\t\tthis.muted = data.data.muted;\n\n\t\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\t\tduration: this.duration,\n\t\t\t\t\tpercent:\n\t\t\t\t\t\tthis.currentTime !== 0 && this.duration !== 0\n\t\t\t\t\t\t\t? this.currentTime / this.duration\n\t\t\t\t\t\t\t: 0,\n\t\t\t\t\tseconds: this.currentTime,\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase 'loadComplete':\n\t\t\t\tthis.logger.log(LogLevel.Debug, 'load completed');\n\n\t\t\t\tthis.duration = data.data.videoInfo.lengthInSeconds;\n\n\t\t\t\tthis.options?.onLoaded?.({ id: data.data.videoInfo.watchId });\n\t\t\t\tbreak;\n\n\t\t\tcase 'error':\n\t\t\t\t// TODO: Implement.\n\n\t\t\t\tthis.options?.onError?.(data);\n\t\t\t\tbreak;\n\n\t\t\tcase 'player-error:video:play':\n\t\t\tcase 'player-error:video:seek':\n\t\t\t\tthis.options?.onError?.(data);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthis.logger.log(\n\t\t\t\t\tLogLevel.Debug,\n\t\t\t\t\t'message',\n\t\t\t\t\t(data as any).eventName,\n\t\t\t\t\t(data as any).data,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\tasync attach(): Promise<void> {\n\t\twindow.addEventListener('message', this.handleMessage);\n\t}\n\n\tasync detach(): Promise<void> {\n\t\twindow.removeEventListener('message', this.handleMessage);\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tthis.duration = 0;\n\t\t\tthis.currentTime = 0;\n\t\t\tthis.volume = 0;\n\t\t\tthis.muted = false;\n\n\t\t\t// Wait for iframe to load.\n\t\t\tthis.player.onload = (): void => {\n\t\t\t\tthis.player.onload = null;\n\t\t\t\tresolve();\n\t\t\t};\n\n\t\t\tthis.player.src = `https://embed.nicovideo.jp/watch/${id}?jsapi=1&playerId=1`;\n\t\t});\n\t}\n\n\t// https://blog.hayu.io/web/create/nicovideo-embed-player-api/.\n\tprivate postMessage(message: any): void {\n\t\tthis.player.contentWindow?.postMessage(\n\t\t\t{\n\t\t\t\t...message,\n\t\t\t\tplayerId: '1' /* Needs to be a string, not a number. */,\n\t\t\t\tsourceConnectorType: 1,\n\t\t\t},\n\t\t\tNiconicoPlayerController.origin,\n\t\t);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.postMessage({ eventName: 'play' });\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.postMessage({ eventName: 'pause' });\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.postMessage({ eventName: 'seek', data: { time: seconds * 1000 } });\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.postMessage({\n\t\t\teventName: 'volumeChange',\n\t\t\tdata: { volume: volume },\n\t\t});\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.postMessage({\n\t\t\teventName: 'mute',\n\t\t\tdata: { mute: muted },\n\t\t});\n\t}\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.duration;\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.currentTime;\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.volume;\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.muted;\n\t}\n\n\tgetPlaybackRate = undefined;\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\n// https://github.com/VocaDB/vocadb/blob/e147650a8f1f85c8fa865d0ab562126c278527ec/VocaDbWeb/Scripts/ViewModels/PVs/PVPlayerSoundCloud.ts.\nexport class SoundCloudPlayerController extends PlayerControllerImpl<SC.SoundCloudWidget> {\n\tprivate getDurationCore(): Promise<number> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tthis.player.getDuration(resolve);\n\t\t});\n\t}\n\n\tattach(id: string): Promise<void> {\n\t\treturn new Promise((resolve, _reject /* TODO: reject */) => {\n\t\t\tthis.player.bind(SC.Widget.Events.READY, () => {\n\t\t\t\tthis.player.bind(\n\t\t\t\t\tSC.Widget.Events.PLAY_PROGRESS,\n\t\t\t\t\tasync (event) => {\n\t\t\t\t\t\tconst duration = await this.getDurationCore();\n\n\t\t\t\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\t\t\t\tduration: duration / 1000,\n\t\t\t\t\t\t\tpercent: event.currentPosition / duration,\n\t\t\t\t\t\t\tseconds: event.currentPosition / 1000,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tthis.player.bind(SC.Widget.Events.ERROR, (event) =>\n\t\t\t\t\tthis.options?.onError?.(event),\n\t\t\t\t);\n\t\t\t\tthis.player.bind(SC.Widget.Events.PLAY, () =>\n\t\t\t\t\tthis.options?.onPlay?.(),\n\t\t\t\t);\n\t\t\t\tthis.player.bind(SC.Widget.Events.PAUSE, () =>\n\t\t\t\t\tthis.options?.onPause?.(),\n\t\t\t\t);\n\t\t\t\tthis.player.bind(SC.Widget.Events.FINISH, () =>\n\t\t\t\t\tthis.options?.onEnded?.(),\n\t\t\t\t);\n\n\t\t\t\tthis.options?.onLoaded?.({ id: id });\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tthis.player.unbind(SC.Widget.Events.READY);\n\t\tthis.player.unbind(SC.Widget.Events.PLAY_PROGRESS);\n\t\tthis.player.unbind(SC.Widget.Events.ERROR);\n\t\tthis.player.unbind(SC.Widget.Events.PLAY);\n\t\tthis.player.unbind(SC.Widget.Events.PAUSE);\n\t\tthis.player.unbind(SC.Widget.Events.FINISH);\n\t}\n\n\tprivate static playerLoadAsync(\n\t\tplayer: SC.SoundCloudWidget,\n\t\turl: string,\n\t\toptions: Omit<SC.SoundCloudLoadOptions, 'callback'>,\n\t): Promise<void> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tplayer.load(url, { ...options, callback: resolve });\n\t\t});\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tawait SoundCloudPlayerController.playerLoadAsync(this.player, id, {\n\t\t\tauto_play: true,\n\t\t});\n\n\t\tthis.options?.onLoaded?.({ id: id });\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.seekTo(seconds * 1000);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.setVolume(volume * 100);\n\t}\n\n\tsetMuted = undefined;\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\tconst duration = await this.getDurationCore();\n\t\treturn duration / 1000;\n\t}\n\n\tprivate getCurrentTimeCore(): Promise<number> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tthis.player.getPosition(resolve);\n\t\t});\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\tconst position = await this.getCurrentTimeCore();\n\t\treturn position / 1000;\n\t}\n\n\tprivate getVolumeCore(): Promise<number> {\n\t\treturn new Promise((resolve, _reject /* TODO: Reject. */) => {\n\t\t\tthis.player.getVolume(resolve);\n\t\t});\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\tconst volume = await this.getVolumeCore();\n\t\treturn volume / 100;\n\t}\n\n\tgetMuted = undefined;\n\n\tgetPlaybackRate = undefined;\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\n// https://developer.spotify.com/documentation/embeds/references/iframe-api\nexport class SpotifyPlayerController extends PlayerControllerImpl<Spotify.EmbedController> {\n\t// The Spotify iframe API has no getters for the duration or the current\n\t// position, so cache the latest values reported by `playback_update` (both\n\t// in milliseconds).\n\tprivate duration = 0;\n\tprivate position = 0;\n\n\t// Spotify has no dedicated play/pause events, so derive them from `isPaused`\n\t// transitions in `playback_update`.\n\tprivate previousIsPaused = true;\n\n\t// Spotify has no `ended` event and reports the end of a track repeatedly,\n\t// including after the next track has been requested. Track the URI the embed\n\t// is currently playing so a stale end update (still tagged with the previous\n\t// track) cannot fire `onEnded` again and skip the next track.\n\tprivate currentUri: string | undefined;\n\tprivate ended = false;\n\n\tprivate handlePlaybackUpdate = (e: {\n\t\tdata: Spotify.PlaybackUpdateData;\n\t}): void => {\n\t\tconst { position, duration, isPaused, playingURI } = e.data;\n\n\t\t// A different URI means the embed has moved on to another track, so any\n\t\t// pending end state from the previous track no longer applies.\n\t\tif (playingURI !== this.currentUri) {\n\t\t\tthis.currentUri = playingURI;\n\t\t\tthis.ended = false;\n\t\t}\n\n\t\tthis.position = position;\n\t\tthis.duration = duration;\n\n\t\tthis.options?.onTimeUpdate?.({\n\t\t\tduration: duration / 1000,\n\t\t\tpercent: duration > 0 ? position / duration : 0,\n\t\t\tseconds: position / 1000,\n\t\t});\n\n\t\tif (isPaused !== this.previousIsPaused) {\n\t\t\tthis.previousIsPaused = isPaused;\n\n\t\t\tif (isPaused) {\n\t\t\t\tthis.options?.onPause?.();\n\t\t\t} else {\n\t\t\t\tthis.options?.onPlay?.();\n\t\t\t}\n\t\t}\n\n\t\t// Spotify has no `ended` event. When a track finishes, `position` reaches\n\t\t// `duration` (with `isPaused` staying false) and updates then stop, so\n\t\t// emit `onEnded` once at that point. Reset when playback moves back from\n\t\t// the end (e.g. repeat-one, which restarts the track) so it can fire\n\t\t// again on the next playthrough.\n\t\tif (duration > 0 && position >= duration) {\n\t\t\tif (!this.ended) {\n\t\t\t\tthis.ended = true;\n\t\t\t\tthis.options?.onEnded?.();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.ended = false;\n\t\t}\n\t};\n\n\tasync attach(id: string): Promise<void> {\n\t\t// Fire `onLoaded` only once the embed is `ready`. The host app autoplays\n\t\t// by calling `play` from its `onLoaded` handler, and the embed silently\n\t\t// drops playback commands issued before it is ready.\n\t\tthis.player.addListener('ready', () =>\n\t\t\tthis.options?.onLoaded?.({ id: id }),\n\t\t);\n\t\tthis.player.addListener('playback_update', this.handlePlaybackUpdate);\n\t}\n\n\tasync detach(): Promise<void> {\n\t\t// `removeListener` is unreliable in the Spotify iframe API, but the\n\t\t// embed (and thus its listeners) is torn down when React unmounts the\n\t\t// host element, so there is nothing to clean up here.\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.duration = 0;\n\t\tthis.position = 0;\n\t\tthis.previousIsPaused = true;\n\t\t// `ended` is intentionally not reset here: the previous track's final\n\t\t// update can still arrive after this call, and resetting would let it\n\t\t// fire `onEnded` again. It is reset once the embed reports the new URI.\n\n\t\tthis.player.loadUri(id);\n\n\t\tthis.options?.onLoaded?.({ id: id });\n\t}\n\n\tasync play(): Promise<void> {\n\t\t// `resume` both starts and resumes playback, unlike `play`.\n\t\tthis.player.resume();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\t// The Spotify embed ignores `seek(0)`, so use the dedicated `restart`\n\t\t// method to return to the beginning of the track.\n\t\tif (seconds <= 0) {\n\t\t\tthis.player.restart();\n\t\t} else {\n\t\t\tthis.player.seek(seconds);\n\t\t}\n\t}\n\n\tsetVolume = undefined;\n\n\tsetMuted = undefined;\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.duration / 1000;\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.position / 1000;\n\t}\n\n\tgetVolume = undefined;\n\n\tgetMuted = undefined;\n\n\tgetPlaybackRate = undefined;\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\nexport class TwitchPlayerController extends PlayerControllerImpl<Twitch.Player> {\n\tprivate handleReady = (): void => {\n\t\tthis.options?.onLoaded?.({ id: this.player.getVideo() });\n\t};\n\n\tprivate handlePlay = (): void => {\n\t\tthis.options?.onPlay?.();\n\t};\n\n\tprivate handlePause = (): void => {\n\t\tthis.options?.onPause?.();\n\t};\n\n\tprivate handleEnded = (): void => {\n\t\tthis.options?.onEnded?.();\n\t};\n\n\tprivate handleSeek = (): void => {\n\t\tthis.options?.onTimeUpdate?.({\n\t\t\tduration: 0,\n\t\t\tpercent: 0,\n\t\t\tseconds: 0,\n\t\t});\n\t};\n\n\tasync attach(_id: string): Promise<void> {\n\t\tthis.player.addEventListener(Twitch.Player.READY, this.handleReady);\n\t\tthis.player.addEventListener(Twitch.Player.PLAYING, this.handlePlay);\n\t\tthis.player.addEventListener(Twitch.Player.PAUSE, this.handlePause);\n\t\tthis.player.addEventListener(Twitch.Player.ENDED, this.handleEnded);\n\t\tthis.player.addEventListener(Twitch.Player.SEEK, this.handleSeek);\n\t}\n\n\tasync detach(): Promise<void> {}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.player.setVideo(id, 0);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.seek(seconds);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.setVolume(volume);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.player.setMuted(muted);\n\t}\n\n\tsetPlaybackRate = undefined;\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.getDuration();\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.getCurrentTime();\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.getVolume();\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.player.getMuted();\n\t}\n\n\tgetPlaybackRate = undefined;\n}\n","import { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\n// https://github.com/cookpete/react-player/blob/e3c324bc6845698179d065fa408db515c2296b4b/src/players/Vimeo.js\nexport class VimeoPlayerController extends PlayerControllerImpl<Vimeo.Player> {\n\tasync attach(): Promise<void> {\n\t\tawait this.player.ready();\n\n\t\tthis.player.on('error', (data) => this.options?.onError?.(data));\n\t\tthis.player.on('loaded', (event) =>\n\t\t\tthis.options?.onLoaded?.({ id: event.id.toString() }),\n\t\t);\n\t\tthis.player.on('play', () => this.options?.onPlay?.());\n\t\tthis.player.on('pause', () => this.options?.onPause?.());\n\t\tthis.player.on('ended', () => this.options?.onEnded?.());\n\t\tthis.player.on('timeupdate', (data) => {\n\t\t\tthis.options?.onTimeUpdate?.({\n\t\t\t\tduration: data.duration,\n\t\t\t\tpercent: data.percent,\n\t\t\t\tseconds: data.seconds,\n\t\t\t});\n\t\t});\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tthis.player.off('error');\n\t\tthis.player.off('loaded');\n\t\tthis.player.off('play');\n\t\tthis.player.off('pause');\n\t\tthis.player.off('ended');\n\t\tthis.player.off('timeupdate');\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tawait this.player.loadVideo(id);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tawait this.player.play();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tawait this.player.pause();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tawait this.player.setCurrentTime(seconds);\n\t}\n\n\tasync setVolume(fraction: number): Promise<void> {\n\t\tawait this.player.setVolume(fraction);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tawait this.player.setMuted(muted);\n\t}\n\n\tasync setPlaybackRate(playbackRate: number): Promise<void> {\n\t\tawait this.player.setPlaybackRate(playbackRate);\n\t}\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.getDuration();\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.getCurrentTime();\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.getVolume();\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn await this.player.getMuted();\n\t}\n\n\tasync getPlaybackRate(): Promise<number> {\n\t\treturn this.player.getPlaybackRate();\n\t}\n}\n","import { LogLevel } from '@/controllers/Logger';\nimport { PlayerControllerImpl } from '@/controllers/PlayerControllerImpl';\n\ndeclare global {\n\tinterface Window {\n\t\tonYouTubeIframeAPIReady(): void;\n\t}\n}\n\nenum PlayerState {\n\tUNSTARTED = -1,\n\tENDED = 0,\n\tPLAYING = 1,\n\tPAUSED = 2,\n\tBUFFERING = 3,\n\tCUED = 5,\n}\n\n// https://github.com/VocaDB/vocadb/blob/076dac9f0808aba5da7332209fdfd2ff4e12c235/VocaDbWeb/Scripts/ViewModels/PVs/PVPlayerYoutube.ts.\nexport class YouTubePlayerController extends PlayerControllerImpl<YT.Player> {\n\tprivate previousTime?: number;\n\n\tprivate timeUpdateIntervalId?: number;\n\n\tprivate clearTimeUpdateInterval(): void {\n\t\tthis.logger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'clearTimeUpdateInterval',\n\t\t\tthis.timeUpdateIntervalId,\n\t\t);\n\n\t\twindow.clearInterval(this.timeUpdateIntervalId);\n\n\t\tthis.timeUpdateIntervalId = undefined;\n\t}\n\n\tprivate invokeTimeUpdate(player: YT.Player): void {\n\t\tconst currentTime = player.getCurrentTime();\n\t\tif (currentTime === this.previousTime) return;\n\n\t\tconst duration = player.getDuration();\n\t\tthis.options?.onTimeUpdate?.({\n\t\t\tduration: duration,\n\t\t\tpercent: currentTime / duration,\n\t\t\tseconds: currentTime,\n\t\t});\n\n\t\tthis.previousTime = currentTime;\n\t}\n\n\tprivate setTimeUpdateInterval(): void {\n\t\tthis.logger.log(LogLevel.Debug, 'setTimeUpdateInterval');\n\n\t\tthis.clearTimeUpdateInterval();\n\n\t\tthis.timeUpdateIntervalId = window.setInterval(\n\t\t\t() => this.invokeTimeUpdate(this.player),\n\t\t\t250,\n\t\t);\n\n\t\tthis.logger.log(\n\t\t\tLogLevel.Debug,\n\t\t\t'timeUpdateIntervalId',\n\t\t\tthis.timeUpdateIntervalId,\n\t\t);\n\n\t\tthis.invokeTimeUpdate(this.player);\n\t}\n\n\tattach(id: string): Promise<void> {\n\t\treturn new Promise((resolve, _reject /* TODO: reject */) => {\n\t\t\tthis.player.addEventListener('onReady', async () => {\n\t\t\t\tthis.player.addEventListener('onError', (event) =>\n\t\t\t\t\tthis.options?.onError?.(event.data),\n\t\t\t\t);\n\t\t\t\tthis.player.addEventListener(\n\t\t\t\t\t'onStateChange',\n\t\t\t\t\t(event: YT.EventArgs): void => {\n\t\t\t\t\t\tthis.logger.log(\n\t\t\t\t\t\t\tLogLevel.Debug,\n\t\t\t\t\t\t\t`state changed: ${PlayerState[event.data]}`,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tswitch (event.data) {\n\t\t\t\t\t\t\tcase YT.PlayerState.CUED:\n\t\t\t\t\t\t\t\tthis.options?.onLoaded?.({ id: id });\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase YT.PlayerState.PLAYING:\n\t\t\t\t\t\t\t\tthis.options?.onPlay?.();\n\t\t\t\t\t\t\t\tthis.setTimeUpdateInterval();\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase YT.PlayerState.PAUSED:\n\t\t\t\t\t\t\t\tthis.options?.onPause?.();\n\t\t\t\t\t\t\t\tthis.clearTimeUpdateInterval();\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase YT.PlayerState.ENDED:\n\t\t\t\t\t\t\t\tthis.options?.onEnded?.();\n\t\t\t\t\t\t\t\tthis.clearTimeUpdateInterval();\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tawait this.loadVideo(id);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tasync detach(): Promise<void> {\n\t\tthis.clearTimeUpdateInterval();\n\t}\n\n\tasync loadVideo(id: string): Promise<void> {\n\t\tthis.previousTime = undefined;\n\t\tthis.player.cueVideoById(id);\n\t}\n\n\tasync play(): Promise<void> {\n\t\tthis.player.playVideo();\n\t}\n\n\tasync pause(): Promise<void> {\n\t\tthis.player.pauseVideo();\n\t}\n\n\tasync setCurrentTime(seconds: number): Promise<void> {\n\t\tthis.player.seekTo(seconds);\n\n\t\tthis.invokeTimeUpdate(this.player);\n\t}\n\n\tasync setVolume(volume: number): Promise<void> {\n\t\tthis.player.setVolume(volume * 100);\n\t}\n\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tif (muted) {\n\t\t\tthis.player.mute();\n\t\t} else {\n\t\t\tthis.player.unMute();\n\t\t}\n\t}\n\n\tasync setPlaybackRate(playbackRate: number): Promise<void> {\n\t\tthis.player.setPlaybackRate(playbackRate);\n\t}\n\n\tasync getDuration(): Promise<number> {\n\t\treturn this.player.getDuration();\n\t}\n\n\tasync getCurrentTime(): Promise<number> {\n\t\treturn this.player.getCurrentTime();\n\t}\n\n\tasync getVolume(): Promise<number> {\n\t\treturn this.player.getVolume() / 100;\n\t}\n\n\tasync getMuted(): Promise<boolean> {\n\t\treturn this.player.isMuted();\n\t}\n\n\tasync getPlaybackRate(): Promise<number> {\n\t\treturn this.player.getPlaybackRate();\n\t}\n}\n"],"mappings":";;;;;AAqBA,IAAM,IAAuB,EAC5B,KAAA,CACD,GAOa,KAAyB,EACrC,aACA,YAAS,QACsC;CAC/C,IAAM,IAAgB,EAA0B,CAAoB,GAE9D,IAAyB,GAC7B,MAAmC;EAQnC,AAPA,EAAO,IACN,EAAS,OACT,gDACA,EAAc,SACd,CACD,GAEA,EAAc,UAAU;CACzB,GACA,CAAC,CAAM,CACR,GAEM,IAAY,EACjB,OAAO,MAA8B;EAOpC,AANA,EAAO,IACN,EAAS,OACT,mCACA,EAAc,OACf,GAEA,MAAM,EAAc,QAAQ,UAAU,CAAE;CACzC,GACA,CAAC,CAAM,CACR,GAEM,IAAO,EAAY,YAA2B;EAOnD,AANA,EAAO,IACN,EAAS,OACT,8BACA,EAAc,OACf,GAEA,MAAM,EAAc,QAAQ,KAAK;CAClC,GAAG,CAAC,CAAM,CAAC,GAEL,IAAQ,EAAY,YAA2B;EAOpD,AANA,EAAO,IACN,EAAS,OACT,+BACA,EAAc,OACf,GAEA,MAAM,EAAc,QAAQ,MAAM;CACnC,GAAG,CAAC,CAAM,CAAC,GAEL,IAAiB,EACtB,OAAO,MAAmC;EAQzC,AAPA,EAAO,IACN,EAAS,OACT,wCACA,EAAc,OACf,GAEA,MAAM,EAAc,QAAQ,eAAe,CAAO,GAClD,MAAM,EAAc,QAAQ,KAAK;CAClC,GACA,CAAC,CAAM,CACR,GAEM,IAAY,EACjB,OAAO,MAAkC;EAOxC,AANA,EAAO,IACN,EAAS,OACT,mCACA,EAAc,OACf,GAEA,MAAM,EAAc,QAAQ,UAAU,CAAM;CAC7C,GACA,CAAC,CAAM,CACR,GAEM,IAAW,EAChB,OAAO,MAAkC;EAOxC,AANA,EAAO,IACN,EAAS,OACT,kCACA,EAAc,OACf,GAEA,MAAM,EAAc,QAAQ,SAAS,CAAK;CAC3C,GACA,CAAC,CAAM,CACR,GAEM,IAAkB,EACvB,OAAO,MAAwC;EAO9C,AANA,EAAO,IACN,EAAS,OACT,yCACA,EAAc,OACf,GAEA,MAAM,EAAc,QAAQ,gBAAgB,CAAY;CACzD,GACA,CAAC,CAAM,CACR,GAEM,IAAc,EAAY,aAC/B,EAAO,IACN,EAAS,OACT,qCACA,EAAc,OACf,GAEO,MAAM,EAAc,QAAQ,YAAY,IAC7C,CAAC,CAAM,CAAC,GAEL,IAAiB,EAAY,aAClC,EAAO,IACN,EAAS,OACT,wCACA,EAAc,OACf,GAEO,MAAM,EAAc,QAAQ,eAAe,IAChD,CAAC,CAAM,CAAC,GAEL,IAAY,EAAY,aAC7B,EAAO,IACN,EAAS,OACT,mCACA,EAAc,OACf,GAEO,MAAM,EAAc,QAAQ,UAAU,IAC3C,CAAC,CAAM,CAAC,GAEL,IAAW,EAAY,aAC5B,EAAO,IACN,EAAS,OACT,kCACA,EAAc,OACf,GAEO,MAAM,EAAc,QAAQ,SAAS,IAC1C,CAAC,CAAM,CAAC,GAEL,IAAkB,EAAY,aACnC,EAAO,IACN,EAAS,OACT,yCACA,EAAc,OACf,GAEO,MAAM,EAAc,QAAQ,gBAAgB,IACjD,CAAC,CAAM,CAAC,GAEL,IAAW,GACf,MACA,EAAc,QAAQ,SAAS,CAAO,GACvC,CAAC,CACF,GAEM,IAAQ,SACqB;EACjC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD,IACA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD,CACD;CAEA,OACC,kBAAC,EAAqB,UAAtB;EAAsC;EACpC;CAC6B,CAAA;AAEjC,GAEa,UACL,EAAW,CAAoB,GC3OjB,IAAtB,MAAmC;CACH;CAA/B,YAAsB,GAA2B;EAAlB,KAAA,OAAA;CAAmB;AAKnD,GCLM,IACL,0EACK,IAAmB,mDAEZ,IAAb,cAAuC,EAAa;CACnD,cAAc;EACb,MAAM,OAAO;CACd;CAEA,QAAQ,GAAsB;EAC7B,OAAO,EAAiB,KAAK,CAAG,KAAK,EAAiB,KAAK,CAAG;CAC/D;CAEA,eAAe,GAAiC;EAC/C,OAAO;CACR;AACD,GChBM,IACL,sIAEY,IAAb,cAA6C,EAAa;CACzD,cAAc;EACb,MAAM,aAAa;CACpB;CAEA,QAAQ,GAAsB;EAC7B,OAAO,EAAsB,KAAK,CAAG;CACtC;CAEA,eAAe,GAAiC;EAE/C,OADgB,EAAsB,KAAK,CACpC,IAAU;CAClB;AACD,GCjBM,IAAqB,2CAEd,IAAb,cAA0C,EAAa;CACtD,cAAc;EACb,MAAM,UAAU;CACjB;CAEA,QAAQ,GAAsB;EAC7B,OAAO,EAAmB,KAAK,CAAG;CACnC;CAEA,eAAe,GAAiC;EAE/C,OADgB,EAAmB,KAAK,CACjC,IAAU;CAClB;AACD,GCdM,IAAuB,uCAEhB,IAAb,cAA4C,EAAa;CACxD,cAAc;EACb,MAAM,YAAY;CACnB;CAEA,QAAQ,GAAsB;EAC7B,OAAO,EAAqB,KAAK,CAAG;CACrC;CAEA,eAAe,GAAiC;EAC/C,OAAO;CACR;AACD,GCbM,IAAgB,4CAChB,IAAwB,OAC7B,sDAAsD,EAAc,iBACrE,GACM,IAAwB,OAC7B,aAAa,EAAc,kBAC5B,GAEa,IAAb,cAAyC,EAAa;CACrD,cAAc;EACb,MAAM,SAAS;CAChB;CAEA,QAAQ,GAAsB;EAC7B,OAAO,EAAkB,KAAK,CAAG,KAAK,EAAkB,KAAK,CAAG;CACjE;CAIA,eAAe,GAAiC;EAC/C,IAAM,IACL,EAAkB,KAAK,CAAG,KAAK,EAAkB,KAAK,CAAG;EAC1D,IAAI,MAAU,MACb;EAGD,IAAM,GAAG,GAAM,KAAM;EACrB,OAAO,WAAW,EAAK,GAAG;CAC3B;AACD,GC9BM,IAAyB,kDAElB,KAAb,cAAwC,EAAa;CACpD,cAAc;EACb,MAAM,QAAQ;CACf;CAEA,QAAQ,GAAsB;EAC7B,OAAO,EAAuB,KAAK,CAAG;CACvC;CAEA,eAAe,GAAiC;EAE/C,OADgB,EAAuB,KAAK,CACrC,IAAU;CAClB;AACD,GCfM,IAAkB,sBAEX,IAAb,cAAuC,EAAa;CACnD,cAAc;EACb,MAAM,OAAO;CACd;CAEA,QAAQ,GAAsB;EAC7B,OAAO,EAAgB,KAAK,CAAG;CAChC;CAEA,eAAe,GAAiC;EAC/C,OAAO,EAAgB,KAAK,CAAG,IAAI;CACpC;AACD,GCdM,IACL,uLCMY,IAAgC;CAC5C,IAAI,cDLoC,EAAa;EACrD,cAAc;GACb,MAAM,SAAS;EAChB;EAEA,QAAQ,GAAsB;GAC7B,OAAO,EAAkB,KAAK,CAAG;EAClC;EAEA,eAAe,GAAiC;GAE/C,OADgB,EAAkB,KAAK,CAChC,IAAU;EAClB;CACD,ECRyB;CACxB,IAAI,GAAmB;CACvB,IAAI,EAAkB;CACtB,IAAI,EAAwB;CAC5B,IAAI,EAAuB;CAC3B,IAAI,EAAoB;CACxB,IAAI,EAAkB;CACtB,IAAI,EAAqB;AAC1B;AAEA,SAAgB,EAAiB,GAAuC;CACvE,OAAO,EAAc,MAAM,MAAiB,EAAa,QAAQ,CAAG,CAAC;AACtE;;;ACLA,IAAa,IAAqD,IAAI,IACrE,OAAO,QAAQ;CACd,OAAO,QAAW,OAAO,4BAAgB;CACzC,aAAa,QAAW,OAAO,kCAAsB;CACrD,UAAU,QAAW,OAAO,+BAAmB;CAC/C,YAAY,QAAW,OAAO,iCAAqB;CACnD,SAAS,QAAW,OAAO,8BAAkB;CAC7C,QAAQ,QAAW,OAAO,6BAAiB;CAC3C,OAAO,QAAW,OAAO,4BAAgB;CACzC,SAAS,QAAW,OAAO,8BAAkB;AAC9C,CAAC,CACF;AAQA,SAAS,EACR,GACoD;CACpD,IAAM,IAAe,EAAiB,CAAG;CACzC,IAAI,MAAiB,KAAA,GACpB;CAGD,IAAM,EAAE,SAAM,sBAAmB,GAE3B,IAAU,EAAe,CAAG;CAC9B,UAAY,KAAA,GAIhB,OAAO;EAAQ;EAAe;CAAQ;AACvC;AAEA,IAAM,IAAc,QAElB,kBAAC,OAAD;CAAK,OAAO;EAAE,OAAO;EAAQ,QAAQ;CAAO;WAC3C,kBAAC,UAAD;EACC,KAAI;EACJ,OAAM;EACN,OAAO;GACN,OAAO;GACP,QAAQ;GACR,QAAQ;EACT;CACA,CAAA;AACG,CAAA,CAEN,GAEY,IAAgB,GAC3B,EACA,QACA,YACA,4BACuC;CACvC,IAAM,IAAO,EAAiB,GAExB,IAAyB,GAC7B,MAA6B;EAG7B,AAFA,EAAK,uBAAuB,CAAK,GAEjC,IAAqB,CAAK;CAC3B,GACA,CAAC,GAAM,CAAkB,CAC1B;CAEA,EAAK,OAAO,IAAI,EAAS,OAAO,eAAe;CAE/C,IAAM,IAAiB,EAAkB,CAAG;CAC5C,IAAI,MAAmB,KAAA,GAKtB,OAJA,EAAK,OAAO,IACX,EAAS,SACT,iDAAiD,EAAI,0BACtD,GACO,kBAAC,GAAD,CAAc,CAAA;CAGtB,IAAM,EAAE,SAAM,eAAY,GAEpB,IAAS,EAAQ,IAAI,CAAI;CAS/B,OARI,MAAW,KAAA,KACd,EAAK,OAAO,IACX,EAAS,SACT,6BAA6B,EAAK,eAAe,EAAQ,2BAC1D,GACO,kBAAC,GAAD,CAAc,CAAA,KAIrB,kBAAC,GAAD;EAAU,UAAU;YACnB,kBAAC,GAAD;GACC,QAAQ,EAAK;GACP;GACN,oBAAoB;GACX;GACA;EACT,CAAA;CACQ,CAAA;AAEZ,CACD,GChHa,IAAb,cACS,YAET;CACC,OAAgB,qBAAqB,CAAC,KAAK;CAE3C;CACA,aAAgC;CAEhC,cAAc;EAGb,AAFA,MAAM,GAEN,KAAK,YAAY,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;CACtD;CAEA,IAAI,MAAc;EACjB,OAAO,KAAK,aAAa,KAAK,KAAK;CACpC;CAEA,IAAI,IAAI,GAAe;EACtB,KAAK,aAAa,OAAO,CAAK;CAC/B;CAEA,KAAmC;EAClC,UAAU,MACT,KAAK,cAAc,IAAI,YAAY,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;EAC3D,WAAW,MACV,KAAK,cAAc,IAAI,YAAY,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;EAC5D,cAAc,KAAK,cAAc,IAAI,YAAY,MAAM,CAAC;EACxD,eAAe,KAAK,cAAc,IAAI,YAAY,OAAO,CAAC;EAC1D,eAAe,KAAK,cAAc,IAAI,YAAY,OAAO,CAAC;EAC1D,eAAe,MACd,KAAK,cAAc,IAAI,YAAY,cAAc,EAAE,QAAQ,EAAE,CAAC,CAAC;CACjE;CAEA,MAA2B,MAAmC;EAK7D,AAJA,QAAQ,MACP,yDACD,GAEA,KAAK,aAAa;CACnB;CAEA,KAAgB;EACf,EAAS,OACR,kBAAC,GAAD,EAAA,UACC,kBAAC,GAAD;GACC,KAAK,KAAK;GACV,SAAS,KAAKA;GACd,oBAAoB,KAAKC;EACzB,CAAA,EACqB,CAAA,GACvB,KAAK,SACN;CACD;CAEA,oBAA0B;EAGzB,AAFA,QAAQ,MAAM,oDAAoD,GAElE,KAAKC,GAAQ;CACd;CAEA,uBAA6B;EAC5B,QAAQ,MAAM,uDAAuD;CACtE;CAEA,2BAAiC;EAKhC,AAJA,QAAQ,MACP,2DACD,GAEA,KAAKA,GAAQ;CACd;CAEA,MAAM,UAAU,GAA2B;EAC1C,MAAM,KAAK,WAAW,UAAU,CAAE;CACnC;CAEA,MAAM,OAAsB;EAC3B,MAAM,KAAK,WAAW,KAAK;CAC5B;CAEA,MAAM,QAAuB;EAC5B,MAAM,KAAK,WAAW,MAAM;CAC7B;CAEA,MAAM,eAAe,GAAgC;EACpD,MAAM,KAAK,WAAW,eAAe,CAAO;CAC7C;CAEA,MAAM,UAAU,GAA+B;EAC9C,MAAM,KAAK,WAAW,UAAU,CAAM;CACvC;CAEA,MAAM,SAAS,GAA+B;EAC7C,MAAM,KAAK,WAAW,SAAS,CAAK;CACrC;CAEA,MAAM,gBAAgB,GAAqC;EAC1D,MAAM,KAAK,WAAW,gBAAgB,CAAY;CACnD;CAEA,MAAM,cAA+B;EACpC,OAAO,MAAM,KAAK,WAAW,YAAY;CAC1C;CAEA,MAAM,iBAAkC;EACvC,OAAO,MAAM,KAAK,WAAW,eAAe;CAC7C;CAEA,MAAM,YAA6B;EAClC,OAAO,MAAM,KAAK,WAAW,UAAU;CACxC;CAEA,MAAM,WAA6B;EAClC,OAAO,MAAM,KAAK,WAAW,SAAS;CACvC;CAEA,MAAM,kBAAmC;EACxC,OAAO,MAAM,KAAK,WAAW,gBAAgB;CAC9C;CAEA,SAAS,GAAyC;EACjD,OAAO,KAAK,WAAW,SAAS,CAAO;CACxC;AACD;AAEA,SAAgB,IAA4B;CAC3C,eAAe,OAAO,kBAAkB,CAAoB;AAC7D;;;ACxIA,IAAa,IAAb,cAA2C,EAAuC;CACjF,MAAM,SAAwB;EAO7B,AANA,KAAK,OAAO,WAAW,MAAgB,KAAK,SAAS,UAAU,CAAK,GACpE,KAAK,OAAO,qBACX,KAAK,SAAS,WAAW,EAAE,IAAI,KAAK,OAAO,IAAI,CAAC,GACjD,KAAK,OAAO,eAAqB,KAAK,SAAS,SAAS,GACxD,KAAK,OAAO,gBAAsB,KAAK,SAAS,UAAU,GAC1D,KAAK,OAAO,gBAAsB,KAAK,SAAS,UAAU,GAC1D,KAAK,OAAO,qBAA2B;GACtC,KAAK,SAAS,eAAe;IAC5B,UAAU,KAAK,OAAO;IACtB,SAAS,KAAK,OAAO,cAAc,KAAK,OAAO;IAC/C,SAAS,KAAK,OAAO;GACtB,CAAC;EACF;CACD;CAEA,MAAM,SAAwB;EAM7B,AALA,KAAK,OAAO,UAAU,MACtB,KAAK,OAAO,eAAe,MAC3B,KAAK,OAAO,SAAS,MACrB,KAAK,OAAO,UAAU,MACtB,KAAK,OAAO,UAAU,MACtB,KAAK,OAAO,eAAe;CAC5B;CAEA,MAAM,UAAU,GAA2B;EAC1C,KAAK,OAAO,MAAM;CACnB;CAEA,MAAM,OAAsB;EAC3B,MAAM,KAAK,OAAO,KAAK;CACxB;CAEA,MAAM,QAAuB;EAC5B,KAAK,OAAO,MAAM;CACnB;CAEA,MAAM,eAAe,GAAgC;EACpD,KAAK,OAAO,cAAc;CAC3B;CAEA,MAAM,UAAU,GAA+B;EAC9C,KAAK,OAAO,SAAS;CACtB;CAEA,MAAM,SAAS,GAA+B;EAC7C,KAAK,OAAO,QAAQ;CACrB;CAEA,MAAM,gBAAgB,GAAqC;EAC1D,KAAK,OAAO,eAAe;CAC5B;CAEA,MAAM,cAA+B;EACpC,OAAO,KAAK,OAAO;CACpB;CAEA,MAAM,iBAAkC;EACvC,OAAO,KAAK,OAAO;CACpB;CAEA,MAAM,YAA6B;EAClC,OAAO,KAAK,OAAO;CACpB;CAEA,MAAM,WAA6B;EAClC,OAAO,KAAK,OAAO;CACpB;CAEA,MAAM,kBAAmC;EACxC,OAAO,KAAK,OAAO;CACpB;AACD,GC1EM,IAAS;CACd;CACA;CACA;CACA;CACA;CACA;CACA;AACD,GAEa,IAAb,cAAiD,EAAgC;CAChF,sBAA8B,MAAoC;EACjE,QAAQ,EAAE,MAAV;GACC,KAAK;IACJ,KAAK,SAAS,WAAW,EAAE,IAAI,KAAK,OAAO,MAAM,QAAQ,CAAC;IAC1D;GACD,KAAK;IACJ,KAAK,SAAS,eAAe;KAC5B,UAAU,KAAK,OAAO;KACtB,SAAS,KAAK,OAAO,cAAc,KAAK,OAAO;KAC/C,SAAS,KAAK,OAAO;IACtB,CAAC;IACD;GACD,KAAK;IACJ,KAAK,SAAS,UAAU;IACxB;GACD,KAAK,kBACJ;GACD,KAAK;IACJ,KAAK,SAAS,UAAU;IACxB;GACD,KAAK;IACJ,KAAK,SAAS,SAAS;IACvB;GACD,KAAK;IACJ,KAAK,SAAS,UAAU,CAAC;IACzB;EACF;CACD;CAEA,MAAM,OAAO,GAA4B;EACxC,KAAK,IAAM,KAAS,GACnB,KAAK,OAAO,iBAAiB,GAAO,KAAK,kBAAkB;CAE7D;CAEA,MAAM,SAAwB;EAC7B,KAAK,IAAM,KAAS,GACnB,KAAK,OAAO,oBAAoB,GAAO,KAAK,kBAAkB;CAEhE;CAEA,MAAM,UAAU,GAA2B;EAC1C,KAAK,OAAO,KAAK,CAAE;CACpB;CAEA,MAAM,OAAsB;EAC3B,KAAK,OAAO,KAAK;CAClB;CAEA,MAAM,QAAuB;EAC5B,KAAK,OAAO,MAAM;CACnB;CAEA,MAAM,eAAe,GAAgC;EACpD,KAAK,OAAO,KAAK,CAAO;CACzB;CAEA,MAAM,UAAU,GAA+B;EAC9C,KAAK,OAAO,UAAU,CAAM;CAC7B;CAEA,MAAM,SAAS,GAA+B;EAC7C,KAAK,OAAO,SAAS,CAAK;CAC3B;CAEA,kBAAkB,KAAA;CAElB,MAAM,cAA+B;EACpC,OAAO,KAAK,OAAO;CACpB;CAEA,MAAM,iBAAkC;EACvC,OAAO,KAAK,OAAO;CACpB;CAEA,MAAM,YAA6B;EAClC,OAAO,KAAK,OAAO;CACpB;CAEA,MAAM,WAA6B;EAClC,OAAO,KAAK,OAAO;CACpB;CAEA,kBAAkB,KAAA;AACnB,GCxFK,IAAL,yBAAA,GAAA;QACC,EAAA,EAAA,OAAA,KAAA,QACA,EAAA,EAAA,QAAA,KAAA,SACA,EAAA,EAAA,MAAA,KAAA;AACD,EAJK,KAAA,CAAA,CAIL,GAGa,IAAb,MAAa,UAAiC,EAAwC;CACrF,OAAwB,SAAS;CAEjC,WAAmB;CACnB,cAAsB;CACtB,SAAiB;CACjB,QAAgB;CAEhB,iBAAyB,MAA8B;EACtD,IAAI,EAAE,WAAW,EAAyB,QAAQ;EAElD,IAAM,IAAO,EAAE;EAEf,QAAQ,EAAK,WAAb;GACC,KAAK;IACJ,KAAK,OAAO,IACX,EAAS,OACT,0BACC,EAAa,EAAK,KAAK,iBACvB,EAAK,KAAK,cAEZ;IACA;GAED,KAAK;IASJ,QARA,KAAK,OAAO,IACX,EAAS,OACT,mBACC,EAAa,EAAK,KAAK,iBACvB,EAAK,KAAK,cAEZ,GAEQ,EAAK,KAAK,cAAlB;KACC,KAAA;MACC,KAAK,SAAS,SAAS;MACvB;KAED,KAAA;MACC,KAAK,SAAS,UAAU;MACxB;KAED,KAAA;MACC,KAAK,SAAS,UAAU;MACxB;IACF;IACA;GAED,KAAK;IAYJ,AAXI,EAAK,KAAK,aAAa,KAAA,MAC1B,KAAK,WAAW,EAAK,KAAK,WAAW,MAEtC,KAAK,cACJ,EAAK,KAAK,gBAAgB,KAAA,IACvB,IACA,EAAK,KAAK,cAAc,KAE5B,KAAK,SAAS,EAAK,KAAK,QACxB,KAAK,QAAQ,EAAK,KAAK,OAEvB,KAAK,SAAS,eAAe;KAC5B,UAAU,KAAK;KACf,SACC,KAAK,gBAAgB,KAAK,KAAK,aAAa,IACzC,KAAK,cAAc,KAAK,WACxB;KACJ,SAAS,KAAK;IACf,CAAC;IACD;GAED,KAAK;IAKJ,AAJA,KAAK,OAAO,IAAI,EAAS,OAAO,gBAAgB,GAEhD,KAAK,WAAW,EAAK,KAAK,UAAU,iBAEpC,KAAK,SAAS,WAAW,EAAE,IAAI,EAAK,KAAK,UAAU,QAAQ,CAAC;IAC5D;GAED,KAAK;IAGJ,KAAK,SAAS,UAAU,CAAI;IAC5B;GAED,KAAK;GACL,KAAK;IACJ,KAAK,SAAS,UAAU,CAAI;IAC5B;GAED;IACC,KAAK,OAAO,IACX,EAAS,OACT,WACC,EAAa,WACb,EAAa,IACf;IACA;EACF;CACD;CAEA,MAAM,SAAwB;EAC7B,OAAO,iBAAiB,WAAW,KAAK,aAAa;CACtD;CAEA,MAAM,SAAwB;EAC7B,OAAO,oBAAoB,WAAW,KAAK,aAAa;CACzD;CAEA,MAAM,UAAU,GAA2B;EAC1C,OAAO,IAAI,SAAS,GAAS,MAAgC;GAY5D,AAXA,KAAK,WAAW,GAChB,KAAK,cAAc,GACnB,KAAK,SAAS,GACd,KAAK,QAAQ,IAGb,KAAK,OAAO,eAAqB;IAEhC,AADA,KAAK,OAAO,SAAS,MACrB,EAAQ;GACT,GAEA,KAAK,OAAO,MAAM,oCAAoC,EAAG;EAC1D,CAAC;CACF;CAGA,YAAoB,GAAoB;EACvC,KAAK,OAAO,eAAe,YAC1B;GACC,GAAG;GACH,UAAU;GACV,qBAAqB;EACtB,GACA,EAAyB,MAC1B;CACD;CAEA,MAAM,OAAsB;EAC3B,KAAK,YAAY,EAAE,WAAW,OAAO,CAAC;CACvC;CAEA,MAAM,QAAuB;EAC5B,KAAK,YAAY,EAAE,WAAW,QAAQ,CAAC;CACxC;CAEA,MAAM,eAAe,GAAgC;EACpD,KAAK,YAAY;GAAE,WAAW;GAAQ,MAAM,EAAE,MAAM,IAAU,IAAK;EAAE,CAAC;CACvE;CAEA,MAAM,UAAU,GAA+B;EAC9C,KAAK,YAAY;GAChB,WAAW;GACX,MAAM,EAAU,UAAO;EACxB,CAAC;CACF;CAEA,MAAM,SAAS,GAA+B;EAC7C,KAAK,YAAY;GAChB,WAAW;GACX,MAAM,EAAE,MAAM,EAAM;EACrB,CAAC;CACF;CAEA,kBAAkB,KAAA;CAElB,MAAM,cAA+B;EACpC,OAAO,KAAK;CACb;CAEA,MAAM,iBAAkC;EACvC,OAAO,KAAK;CACb;CAEA,MAAM,YAA6B;EAClC,OAAO,KAAK;CACb;CAEA,MAAM,WAA6B;EAClC,OAAO,KAAK;CACb;CAEA,kBAAkB,KAAA;AACnB,GCnMa,IAAb,MAAa,UAAmC,EAA0C;CACzF,kBAA2C;EAC1C,OAAO,IAAI,SAAS,GAAS,MAAgC;GAC5D,KAAK,OAAO,YAAY,CAAO;EAChC,CAAC;CACF;CAEA,OAAO,GAA2B;EACjC,OAAO,IAAI,SAAS,GAAS,MAA+B;GAC3D,KAAK,OAAO,KAAK,GAAG,OAAO,OAAO,aAAa;IA2B9C,AA1BA,KAAK,OAAO,KACX,GAAG,OAAO,OAAO,eACjB,OAAO,MAAU;KAChB,IAAM,IAAW,MAAM,KAAK,gBAAgB;KAE5C,KAAK,SAAS,eAAe;MAC5B,UAAU,IAAW;MACrB,SAAS,EAAM,kBAAkB;MACjC,SAAS,EAAM,kBAAkB;KAClC,CAAC;IACF,CACD,GACA,KAAK,OAAO,KAAK,GAAG,OAAO,OAAO,QAAQ,MACzC,KAAK,SAAS,UAAU,CAAK,CAC9B,GACA,KAAK,OAAO,KAAK,GAAG,OAAO,OAAO,YACjC,KAAK,SAAS,SAAS,CACxB,GACA,KAAK,OAAO,KAAK,GAAG,OAAO,OAAO,aACjC,KAAK,SAAS,UAAU,CACzB,GACA,KAAK,OAAO,KAAK,GAAG,OAAO,OAAO,cACjC,KAAK,SAAS,UAAU,CACzB,GAEA,KAAK,SAAS,WAAW,EAAM,MAAG,CAAC,GACnC,EAAQ;GACT,CAAC;EACF,CAAC;CACF;CAEA,MAAM,SAAwB;EAM7B,AALA,KAAK,OAAO,OAAO,GAAG,OAAO,OAAO,KAAK,GACzC,KAAK,OAAO,OAAO,GAAG,OAAO,OAAO,aAAa,GACjD,KAAK,OAAO,OAAO,GAAG,OAAO,OAAO,KAAK,GACzC,KAAK,OAAO,OAAO,GAAG,OAAO,OAAO,IAAI,GACxC,KAAK,OAAO,OAAO,GAAG,OAAO,OAAO,KAAK,GACzC,KAAK,OAAO,OAAO,GAAG,OAAO,OAAO,MAAM;CAC3C;CAEA,OAAe,gBACd,GACA,GACA,GACgB;EAChB,OAAO,IAAI,SAAS,GAAS,MAAgC;GAC5D,EAAO,KAAK,GAAK;IAAE,GAAG;IAAS,UAAU;GAAQ,CAAC;EACnD,CAAC;CACF;CAEA,MAAM,UAAU,GAA2B;EAK1C,AAJA,MAAM,EAA2B,gBAAgB,KAAK,QAAQ,GAAI,EACjE,WAAW,GACZ,CAAC,GAED,KAAK,SAAS,WAAW,EAAM,MAAG,CAAC;CACpC;CAEA,MAAM,OAAsB;EAC3B,KAAK,OAAO,KAAK;CAClB;CAEA,MAAM,QAAuB;EAC5B,KAAK,OAAO,MAAM;CACnB;CAEA,MAAM,eAAe,GAAgC;EACpD,KAAK,OAAO,OAAO,IAAU,GAAI;CAClC;CAEA,MAAM,UAAU,GAA+B;EAC9C,KAAK,OAAO,UAAU,IAAS,GAAG;CACnC;CAEA,WAAW,KAAA;CAEX,kBAAkB,KAAA;CAElB,MAAM,cAA+B;EAEpC,OAAO,MADgB,KAAK,gBAAgB,IAC1B;CACnB;CAEA,qBAA8C;EAC7C,OAAO,IAAI,SAAS,GAAS,MAAgC;GAC5D,KAAK,OAAO,YAAY,CAAO;EAChC,CAAC;CACF;CAEA,MAAM,iBAAkC;EAEvC,OAAO,MADgB,KAAK,mBAAmB,IAC7B;CACnB;CAEA,gBAAyC;EACxC,OAAO,IAAI,SAAS,GAAS,MAAgC;GAC5D,KAAK,OAAO,UAAU,CAAO;EAC9B,CAAC;CACF;CAEA,MAAM,YAA6B;EAElC,OAAO,MADc,KAAK,cAAc,IACxB;CACjB;CAEA,WAAW,KAAA;CAEX,kBAAkB,KAAA;AACnB,GCtHa,IAAb,cAA6C,EAA8C;CAI1F,WAAmB;CACnB,WAAmB;CAInB,mBAA2B;CAM3B;CACA,QAAgB;CAEhB,wBAAgC,MAEpB;EACX,IAAM,EAAE,aAAU,aAAU,aAAU,kBAAe,EAAE;EAiCvD,AA7BI,MAAe,KAAK,eACvB,KAAK,aAAa,GAClB,KAAK,QAAQ,KAGd,KAAK,WAAW,GAChB,KAAK,WAAW,GAEhB,KAAK,SAAS,eAAe;GAC5B,UAAU,IAAW;GACrB,SAAS,IAAW,IAAI,IAAW,IAAW;GAC9C,SAAS,IAAW;EACrB,CAAC,GAEG,MAAa,KAAK,qBACrB,KAAK,mBAAmB,GAEpB,IACH,KAAK,SAAS,UAAU,IAExB,KAAK,SAAS,SAAS,IASrB,IAAW,KAAK,KAAY,IAC1B,KAAK,UACT,KAAK,QAAQ,IACb,KAAK,SAAS,UAAU,KAGzB,KAAK,QAAQ;CAEf;CAEA,MAAM,OAAO,GAA2B;EAOvC,AAHA,KAAK,OAAO,YAAY,eACvB,KAAK,SAAS,WAAW,EAAM,MAAG,CAAC,CACpC,GACA,KAAK,OAAO,YAAY,mBAAmB,KAAK,oBAAoB;CACrE;CAEA,MAAM,SAAwB,CAI9B;CAEA,MAAM,UAAU,GAA2B;EAU1C,AATA,KAAK,WAAW,GAChB,KAAK,WAAW,GAChB,KAAK,mBAAmB,IAKxB,KAAK,OAAO,QAAQ,CAAE,GAEtB,KAAK,SAAS,WAAW,EAAM,MAAG,CAAC;CACpC;CAEA,MAAM,OAAsB;EAE3B,KAAK,OAAO,OAAO;CACpB;CAEA,MAAM,QAAuB;EAC5B,KAAK,OAAO,MAAM;CACnB;CAEA,MAAM,eAAe,GAAgC;EAGpD,AAAI,KAAW,IACd,KAAK,OAAO,QAAQ,IAEpB,KAAK,OAAO,KAAK,CAAO;CAE1B;CAEA,YAAY,KAAA;CAEZ,WAAW,KAAA;CAEX,kBAAkB,KAAA;CAElB,MAAM,cAA+B;EACpC,OAAO,KAAK,WAAW;CACxB;CAEA,MAAM,iBAAkC;EACvC,OAAO,KAAK,WAAW;CACxB;CAEA,YAAY,KAAA;CAEZ,WAAW,KAAA;CAEX,kBAAkB,KAAA;AACnB,GCpIa,IAAb,cAA4C,EAAoC;CAC/E,oBAAkC;EACjC,KAAK,SAAS,WAAW,EAAE,IAAI,KAAK,OAAO,SAAS,EAAE,CAAC;CACxD;CAEA,mBAAiC;EAChC,KAAK,SAAS,SAAS;CACxB;CAEA,oBAAkC;EACjC,KAAK,SAAS,UAAU;CACzB;CAEA,oBAAkC;EACjC,KAAK,SAAS,UAAU;CACzB;CAEA,mBAAiC;EAChC,KAAK,SAAS,eAAe;GAC5B,UAAU;GACV,SAAS;GACT,SAAS;EACV,CAAC;CACF;CAEA,MAAM,OAAO,GAA4B;EAKxC,AAJA,KAAK,OAAO,iBAAiB,OAAO,OAAO,OAAO,KAAK,WAAW,GAClE,KAAK,OAAO,iBAAiB,OAAO,OAAO,SAAS,KAAK,UAAU,GACnE,KAAK,OAAO,iBAAiB,OAAO,OAAO,OAAO,KAAK,WAAW,GAClE,KAAK,OAAO,iBAAiB,OAAO,OAAO,OAAO,KAAK,WAAW,GAClE,KAAK,OAAO,iBAAiB,OAAO,OAAO,MAAM,KAAK,UAAU;CACjE;CAEA,MAAM,SAAwB,CAAC;CAE/B,MAAM,UAAU,GAA2B;EAC1C,KAAK,OAAO,SAAS,GAAI,CAAC;CAC3B;CAEA,MAAM,OAAsB;EAC3B,KAAK,OAAO,KAAK;CAClB;CAEA,MAAM,QAAuB;EAC5B,KAAK,OAAO,MAAM;CACnB;CAEA,MAAM,eAAe,GAAgC;EACpD,KAAK,OAAO,KAAK,CAAO;CACzB;CAEA,MAAM,UAAU,GAA+B;EAC9C,KAAK,OAAO,UAAU,CAAM;CAC7B;CAEA,MAAM,SAAS,GAA+B;EAC7C,KAAK,OAAO,SAAS,CAAK;CAC3B;CAEA,kBAAkB,KAAA;CAElB,MAAM,cAA+B;EACpC,OAAO,KAAK,OAAO,YAAY;CAChC;CAEA,MAAM,iBAAkC;EACvC,OAAO,KAAK,OAAO,eAAe;CACnC;CAEA,MAAM,YAA6B;EAClC,OAAO,KAAK,OAAO,UAAU;CAC9B;CAEA,MAAM,WAA6B;EAClC,OAAO,KAAK,OAAO,SAAS;CAC7B;CAEA,kBAAkB,KAAA;AACnB,GC7Ea,KAAb,cAA2C,EAAmC;CAC7E,MAAM,SAAwB;EAU7B,AATA,MAAM,KAAK,OAAO,MAAM,GAExB,KAAK,OAAO,GAAG,UAAU,MAAS,KAAK,SAAS,UAAU,CAAI,CAAC,GAC/D,KAAK,OAAO,GAAG,WAAW,MACzB,KAAK,SAAS,WAAW,EAAE,IAAI,EAAM,GAAG,SAAS,EAAE,CAAC,CACrD,GACA,KAAK,OAAO,GAAG,cAAc,KAAK,SAAS,SAAS,CAAC,GACrD,KAAK,OAAO,GAAG,eAAe,KAAK,SAAS,UAAU,CAAC,GACvD,KAAK,OAAO,GAAG,eAAe,KAAK,SAAS,UAAU,CAAC,GACvD,KAAK,OAAO,GAAG,eAAe,MAAS;GACtC,KAAK,SAAS,eAAe;IAC5B,UAAU,EAAK;IACf,SAAS,EAAK;IACd,SAAS,EAAK;GACf,CAAC;EACF,CAAC;CACF;CAEA,MAAM,SAAwB;EAM7B,AALA,KAAK,OAAO,IAAI,OAAO,GACvB,KAAK,OAAO,IAAI,QAAQ,GACxB,KAAK,OAAO,IAAI,MAAM,GACtB,KAAK,OAAO,IAAI,OAAO,GACvB,KAAK,OAAO,IAAI,OAAO,GACvB,KAAK,OAAO,IAAI,YAAY;CAC7B;CAEA,MAAM,UAAU,GAA2B;EAC1C,MAAM,KAAK,OAAO,UAAU,CAAE;CAC/B;CAEA,MAAM,OAAsB;EAC3B,MAAM,KAAK,OAAO,KAAK;CACxB;CAEA,MAAM,QAAuB;EAC5B,MAAM,KAAK,OAAO,MAAM;CACzB;CAEA,MAAM,eAAe,GAAgC;EACpD,MAAM,KAAK,OAAO,eAAe,CAAO;CACzC;CAEA,MAAM,UAAU,GAAiC;EAChD,MAAM,KAAK,OAAO,UAAU,CAAQ;CACrC;CAEA,MAAM,SAAS,GAA+B;EAC7C,MAAM,KAAK,OAAO,SAAS,CAAK;CACjC;CAEA,MAAM,gBAAgB,GAAqC;EAC1D,MAAM,KAAK,OAAO,gBAAgB,CAAY;CAC/C;CAEA,MAAM,cAA+B;EACpC,OAAO,KAAK,OAAO,YAAY;CAChC;CAEA,MAAM,iBAAkC;EACvC,OAAO,KAAK,OAAO,eAAe;CACnC;CAEA,MAAM,YAA6B;EAClC,OAAO,KAAK,OAAO,UAAU;CAC9B;CAEA,MAAM,WAA6B;EAClC,OAAO,MAAM,KAAK,OAAO,SAAS;CACnC;CAEA,MAAM,kBAAmC;EACxC,OAAO,KAAK,OAAO,gBAAgB;CACpC;AACD,GCtEK,IAAL,yBAAA,GAAA;QACC,EAAA,EAAA,YAAA,MAAA,aACA,EAAA,EAAA,QAAA,KAAA,SACA,EAAA,EAAA,UAAA,KAAA,WACA,EAAA,EAAA,SAAA,KAAA,UACA,EAAA,EAAA,YAAA,KAAA,aACA,EAAA,EAAA,OAAA,KAAA;AACD,EAPK,KAAA,CAAA,CAOL,GAGa,KAAb,cAA6C,EAAgC;CAC5E;CAEA;CAEA,0BAAwC;EASvC,AARA,KAAK,OAAO,IACX,EAAS,OACT,2BACA,KAAK,oBACN,GAEA,OAAO,cAAc,KAAK,oBAAoB,GAE9C,KAAK,uBAAuB,KAAA;CAC7B;CAEA,iBAAyB,GAAyB;EACjD,IAAM,IAAc,EAAO,eAAe;EAC1C,IAAI,MAAgB,KAAK,cAAc;EAEvC,IAAM,IAAW,EAAO,YAAY;EAOpC,AANA,KAAK,SAAS,eAAe;GAClB;GACV,SAAS,IAAc;GACvB,SAAS;EACV,CAAC,GAED,KAAK,eAAe;CACrB;CAEA,wBAAsC;EAgBrC,AAfA,KAAK,OAAO,IAAI,EAAS,OAAO,uBAAuB,GAEvD,KAAK,wBAAwB,GAE7B,KAAK,uBAAuB,OAAO,kBAC5B,KAAK,iBAAiB,KAAK,MAAM,GACvC,GACD,GAEA,KAAK,OAAO,IACX,EAAS,OACT,wBACA,KAAK,oBACN,GAEA,KAAK,iBAAiB,KAAK,MAAM;CAClC;CAEA,OAAO,GAA2B;EACjC,OAAO,IAAI,SAAS,GAAS,MAA+B;GAC3D,KAAK,OAAO,iBAAiB,WAAW,YAAY;IAoCnD,AAnCA,KAAK,OAAO,iBAAiB,YAAY,MACxC,KAAK,SAAS,UAAU,EAAM,IAAI,CACnC,GACA,KAAK,OAAO,iBACX,kBACC,MAA8B;KAM9B,QALA,KAAK,OAAO,IACX,EAAS,OACT,kBAAkB,EAAY,EAAM,OACrC,GAEQ,EAAM,MAAd;MACC,KAAK,GAAG,YAAY;OACnB,KAAK,SAAS,WAAW,EAAM,MAAG,CAAC;OACnC;MAED,KAAK,GAAG,YAAY;OAEnB,AADA,KAAK,SAAS,SAAS,GACvB,KAAK,sBAAsB;OAC3B;MAED,KAAK,GAAG,YAAY;OAEnB,AADA,KAAK,SAAS,UAAU,GACxB,KAAK,wBAAwB;OAC7B;MAED,KAAK,GAAG,YAAY;OAEnB,AADA,KAAK,SAAS,UAAU,GACxB,KAAK,wBAAwB;OAC7B;KACF;IACD,CACD,GAEA,MAAM,KAAK,UAAU,CAAE,GACvB,EAAQ;GACT,CAAC;EACF,CAAC;CACF;CAEA,MAAM,SAAwB;EAC7B,KAAK,wBAAwB;CAC9B;CAEA,MAAM,UAAU,GAA2B;EAE1C,AADA,KAAK,eAAe,KAAA,GACpB,KAAK,OAAO,aAAa,CAAE;CAC5B;CAEA,MAAM,OAAsB;EAC3B,KAAK,OAAO,UAAU;CACvB;CAEA,MAAM,QAAuB;EAC5B,KAAK,OAAO,WAAW;CACxB;CAEA,MAAM,eAAe,GAAgC;EAGpD,AAFA,KAAK,OAAO,OAAO,CAAO,GAE1B,KAAK,iBAAiB,KAAK,MAAM;CAClC;CAEA,MAAM,UAAU,GAA+B;EAC9C,KAAK,OAAO,UAAU,IAAS,GAAG;CACnC;CAEA,MAAM,SAAS,GAA+B;EAC7C,AAAI,IACH,KAAK,OAAO,KAAK,IAEjB,KAAK,OAAO,OAAO;CAErB;CAEA,MAAM,gBAAgB,GAAqC;EAC1D,KAAK,OAAO,gBAAgB,CAAY;CACzC;CAEA,MAAM,cAA+B;EACpC,OAAO,KAAK,OAAO,YAAY;CAChC;CAEA,MAAM,iBAAkC;EACvC,OAAO,KAAK,OAAO,eAAe;CACnC;CAEA,MAAM,YAA6B;EAClC,OAAO,KAAK,OAAO,UAAU,IAAI;CAClC;CAEA,MAAM,WAA6B;EAClC,OAAO,KAAK,OAAO,QAAQ;CAC5B;CAEA,MAAM,kBAAmC;EACxC,OAAO,KAAK,OAAO,gBAAgB;CACpC;AACD"}
@@ -0,0 +1,6 @@
1
+ import { VideoService } from './VideoService';
2
+ export declare class SpotifyVideoService extends VideoService {
3
+ constructor();
4
+ canPlay(url: string): boolean;
5
+ extractVideoId(url: string): string | undefined;
6
+ }