vidply 1.0.25 → 1.0.27

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 (46) hide show
  1. package/README.md +5 -0
  2. package/dist/dev/{vidply.HLSRenderer-PNP5OPES.js → vidply.HLSRenderer-ENLZE4QS.js} +19 -8
  3. package/dist/dev/vidply.HLSRenderer-ENLZE4QS.js.map +7 -0
  4. package/dist/dev/{vidply.HTML5Renderer-LXQ3I45Q.js → vidply.HTML5Renderer-6SBDI6S2.js} +2 -2
  5. package/dist/dev/vidply.SoundCloudRenderer-CD7VJKNS.js +280 -0
  6. package/dist/dev/vidply.SoundCloudRenderer-CD7VJKNS.js.map +7 -0
  7. package/dist/dev/{vidply.VimeoRenderer-DCETT5IZ.js → vidply.VimeoRenderer-VPH4RNES.js} +17 -4
  8. package/dist/dev/vidply.VimeoRenderer-VPH4RNES.js.map +7 -0
  9. package/dist/dev/{vidply.YouTubeRenderer-QLMMD757.js → vidply.YouTubeRenderer-6MGKEFTZ.js} +14 -6
  10. package/dist/dev/vidply.YouTubeRenderer-6MGKEFTZ.js.map +7 -0
  11. package/dist/dev/{vidply.chunk-UEIJOJH6.js → vidply.chunk-BCOFCT6U.js} +4 -1
  12. package/dist/dev/vidply.chunk-BCOFCT6U.js.map +7 -0
  13. package/dist/dev/vidply.esm.js +292 -13
  14. package/dist/dev/vidply.esm.js.map +2 -2
  15. package/dist/legacy/vidply.js +619 -24
  16. package/dist/legacy/vidply.js.map +3 -3
  17. package/dist/legacy/vidply.min.js +1 -1
  18. package/dist/legacy/vidply.min.meta.json +26 -13
  19. package/dist/prod/vidply.HLSRenderer-CBXZ4RF2.min.js +6 -0
  20. package/dist/prod/{vidply.HTML5Renderer-XJCSUETP.min.js → vidply.HTML5Renderer-MY7XDV7R.min.js} +1 -1
  21. package/dist/prod/vidply.SoundCloudRenderer-MOR2CUFH.min.js +6 -0
  22. package/dist/prod/vidply.VimeoRenderer-3HBMM2WR.min.js +6 -0
  23. package/dist/prod/vidply.YouTubeRenderer-MFC2GMAC.min.js +6 -0
  24. package/dist/prod/vidply.chunk-OXXPY2XB.min.js +6 -0
  25. package/dist/prod/vidply.esm.min.js +6 -6
  26. package/dist/vidply.css +52 -1
  27. package/dist/vidply.esm.min.meta.json +56 -28
  28. package/dist/vidply.min.css +2 -2
  29. package/package.json +1 -1
  30. package/src/core/Player.js +124 -10
  31. package/src/features/PlaylistManager.js +312 -4
  32. package/src/renderers/HLSRenderer.js +17 -9
  33. package/src/renderers/HTML5Renderer.js +5 -0
  34. package/src/renderers/SoundCloudRenderer.js +355 -0
  35. package/src/renderers/VimeoRenderer.js +20 -4
  36. package/src/renderers/YouTubeRenderer.js +12 -6
  37. package/src/styles/vidply.css +51 -0
  38. package/dist/dev/vidply.HLSRenderer-PNP5OPES.js.map +0 -7
  39. package/dist/dev/vidply.VimeoRenderer-DCETT5IZ.js.map +0 -7
  40. package/dist/dev/vidply.YouTubeRenderer-QLMMD757.js.map +0 -7
  41. package/dist/dev/vidply.chunk-UEIJOJH6.js.map +0 -7
  42. package/dist/prod/vidply.HLSRenderer-4PW35TCX.min.js +0 -6
  43. package/dist/prod/vidply.VimeoRenderer-P3PU27S7.min.js +0 -6
  44. package/dist/prod/vidply.YouTubeRenderer-DGKKWB5M.min.js +0 -6
  45. package/dist/prod/vidply.chunk-BQBGEJF7.min.js +0 -6
  46. /package/dist/dev/{vidply.HTML5Renderer-LXQ3I45Q.js.map → vidply.HTML5Renderer-6SBDI6S2.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/renderers/HTML5Renderer.js"],
4
+ "sourcesContent": ["/**\r\n * HTML5 Media Renderer\r\n */\r\n\r\nexport class HTML5Renderer {\r\n constructor(player) {\r\n this.player = player;\r\n this.media = player.element;\r\n }\r\n\r\n async init() {\r\n // Hide native controls\r\n this.media.controls = false;\r\n this.media.removeAttribute('controls');\r\n \r\n this.attachEvents();\r\n \r\n // Set preload\r\n this.media.preload = this.player.options.preload;\r\n \r\n // Load media\r\n this.media.load();\r\n \r\n // Show VidPly controls (remove external controls class if present)\r\n if (this.player.container) {\r\n this.player.container.classList.remove('vidply-external-controls');\r\n }\r\n }\r\n\r\n attachEvents() {\r\n // Playback events\r\n this.media.addEventListener('loadedmetadata', () => {\r\n this.player.state.duration = this.media.duration;\r\n this.player.emit('loadedmetadata');\r\n });\r\n\r\n this.media.addEventListener('play', () => {\r\n this.player.state.playing = true;\r\n this.player.state.paused = false;\r\n this.player.state.ended = false;\r\n this.player.emit('play');\r\n \r\n if (this.player.options.onPlay) {\r\n this.player.options.onPlay.call(this.player);\r\n }\r\n \r\n // Pause other players if enabled\r\n if (this.player.options.pauseOthersOnPlay) {\r\n this.pauseOtherPlayers();\r\n }\r\n });\r\n\r\n this.media.addEventListener('pause', () => {\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.emit('pause');\r\n \r\n if (this.player.options.onPause) {\r\n this.player.options.onPause.call(this.player);\r\n }\r\n });\r\n\r\n this.media.addEventListener('ended', () => {\r\n this.player.state.playing = false;\r\n this.player.state.paused = true;\r\n this.player.state.ended = true;\r\n this.player.emit('ended');\r\n \r\n if (this.player.options.onEnded) {\r\n this.player.options.onEnded.call(this.player);\r\n }\r\n \r\n // Handle loop\r\n if (this.player.options.loop) {\r\n this.player.seek(0);\r\n this.player.play();\r\n }\r\n });\r\n\r\n this.media.addEventListener('timeupdate', () => {\r\n this.player.state.currentTime = this.media.currentTime;\r\n this.player.emit('timeupdate', this.media.currentTime);\r\n \r\n if (this.player.options.onTimeUpdate) {\r\n this.player.options.onTimeUpdate.call(this.player, this.media.currentTime);\r\n }\r\n });\r\n\r\n this.media.addEventListener('volumechange', () => {\r\n this.player.state.volume = this.media.volume;\r\n this.player.state.muted = this.media.muted;\r\n this.player.emit('volumechange', this.media.volume);\r\n \r\n if (this.player.options.onVolumeChange) {\r\n this.player.options.onVolumeChange.call(this.player, this.media.volume);\r\n }\r\n });\r\n\r\n this.media.addEventListener('seeking', () => {\r\n this.player.state.seeking = true;\r\n this.player.emit('seeking');\r\n });\r\n\r\n this.media.addEventListener('seeked', () => {\r\n this.player.state.seeking = false;\r\n this.player.emit('seeked');\r\n });\r\n\r\n this.media.addEventListener('waiting', () => {\r\n this.player.state.buffering = true;\r\n this.player.emit('waiting');\r\n });\r\n\r\n this.media.addEventListener('canplay', () => {\r\n this.player.state.buffering = false;\r\n this.player.emit('canplay');\r\n });\r\n\r\n this.media.addEventListener('progress', () => {\r\n if (this.media.buffered.length > 0) {\r\n const buffered = this.media.buffered.end(this.media.buffered.length - 1);\r\n this.player.emit('progress', buffered);\r\n }\r\n });\r\n\r\n this.media.addEventListener('error', (e) => {\r\n this.player.handleError(this.media.error);\r\n });\r\n\r\n this.media.addEventListener('ratechange', () => {\r\n this.player.state.playbackSpeed = this.media.playbackRate;\r\n this.player.emit('ratechange', this.media.playbackRate);\r\n });\r\n }\r\n\r\n pauseOtherPlayers() {\r\n // Pause other VidPly instances\r\n const allPlayers = document.querySelectorAll('.vidply-player');\r\n allPlayers.forEach(playerEl => {\r\n if (playerEl !== this.player.container) {\r\n const video = playerEl.querySelector('video, audio');\r\n if (video && !video.paused) {\r\n video.pause();\r\n }\r\n }\r\n });\r\n }\r\n\r\n play() {\r\n // Save scroll position to prevent browser from scrolling to video\r\n const scrollX = window.scrollX;\r\n const scrollY = window.scrollY;\r\n \r\n const promise = this.media.play();\r\n \r\n // Restore scroll position immediately to prevent auto-scroll\r\n window.scrollTo(scrollX, scrollY);\r\n \r\n if (promise !== undefined) {\r\n promise.catch(error => {\r\n this.player.log('Play failed:', error, 'warn');\r\n \r\n // If autoplay failed, try muted autoplay\r\n if (this.player.options.autoplay && !this.player.state.muted) {\r\n this.player.log('Retrying play with muted audio', 'info');\r\n this.media.muted = true;\r\n \r\n // Save scroll position again for retry\r\n const retryScrollX = window.scrollX;\r\n const retryScrollY = window.scrollY;\r\n this.media.play().then(() => {\r\n window.scrollTo(retryScrollX, retryScrollY);\r\n }).catch(err => {\r\n this.player.handleError(err);\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n pause() {\r\n this.media.pause();\r\n }\r\n\r\n seek(time) {\r\n this.media.currentTime = time;\r\n }\r\n\r\n setVolume(volume) {\r\n this.media.volume = volume;\r\n }\r\n\r\n setMuted(muted) {\r\n this.media.muted = muted;\r\n }\r\n\r\n setPlaybackSpeed(speed) {\r\n this.media.playbackRate = speed;\r\n }\r\n\r\n /**\r\n * Get available quality levels from source elements\r\n * @returns {Array} Array of quality objects with index, height, width, and src\r\n */\r\n getQualities() {\r\n const sources = Array.from(this.media.querySelectorAll('source'));\r\n \r\n if (sources.length <= 1) {\r\n return [];\r\n }\r\n\r\n return sources.map((source, index) => {\r\n // Try to extract quality from data attributes or label\r\n const label = source.getAttribute('data-quality') || source.getAttribute('label') || '';\r\n const height = source.getAttribute('data-height') || this.extractHeightFromLabel(label);\r\n const width = source.getAttribute('data-width') || '';\r\n \r\n return {\r\n index,\r\n height: height ? parseInt(height) : 0,\r\n width: width ? parseInt(width) : 0,\r\n src: source.src,\r\n type: source.type,\r\n name: label || (height ? `${height}p` : `Quality ${index + 1}`)\r\n };\r\n }).filter(q => q.height > 0); // Only return qualities with valid height\r\n }\r\n\r\n /**\r\n * Extract height from quality label (e.g., \"1080p\" -> 1080)\r\n * @param {string} label \r\n * @returns {number}\r\n */\r\n extractHeightFromLabel(label) {\r\n const match = label.match(/(\\d+)p/i);\r\n return match ? parseInt(match[1]) : 0;\r\n }\r\n\r\n /**\r\n * Switch to a specific quality level\r\n * @param {number} qualityIndex - Index of the quality level (-1 for auto, not applicable for HTML5)\r\n */\r\n switchQuality(qualityIndex) {\r\n const qualities = this.getQualities();\r\n \r\n if (qualityIndex < 0 || qualityIndex >= qualities.length) {\r\n this.player.log('Invalid quality index', 'warn');\r\n return;\r\n }\r\n\r\n const quality = qualities[qualityIndex];\r\n const currentTime = this.media.currentTime;\r\n const wasPlaying = !this.media.paused;\r\n\r\n // Store the current source for comparison\r\n const currentSrc = this.media.currentSrc;\r\n \r\n // Don't switch if already at this quality\r\n if (currentSrc === quality.src) {\r\n this.player.log('Already at this quality level', 'info');\r\n return;\r\n }\r\n\r\n this.player.log(`Switching to quality: ${quality.name}`, 'info');\r\n\r\n // Update the src\r\n this.media.src = quality.src;\r\n \r\n // Wait for the new source to load, then restore playback state\r\n const onLoadedMetadata = () => {\r\n this.media.removeEventListener('loadedmetadata', onLoadedMetadata);\r\n \r\n // Restore playback position\r\n this.media.currentTime = currentTime;\r\n \r\n // Resume playback if it was playing\r\n if (wasPlaying) {\r\n this.media.play().catch(err => {\r\n this.player.log('Failed to resume playback after quality switch', 'warn');\r\n });\r\n }\r\n \r\n // Emit quality change event\r\n this.player.emit('qualitychange', { quality: quality.name, index: qualityIndex });\r\n };\r\n\r\n this.media.addEventListener('loadedmetadata', onLoadedMetadata);\r\n this.media.load();\r\n }\r\n\r\n /**\r\n * Get current quality index\r\n * @returns {number}\r\n */\r\n getCurrentQuality() {\r\n const qualities = this.getQualities();\r\n const currentSrc = this.media.currentSrc;\r\n \r\n for (let i = 0; i < qualities.length; i++) {\r\n if (qualities[i].src === currentSrc) {\r\n return i;\r\n }\r\n }\r\n \r\n return 0; // Default to first quality if not found\r\n }\r\n\r\n destroy() {\r\n // Remove event listeners\r\n this.media.removeEventListener('loadedmetadata', () => {});\r\n this.media.removeEventListener('play', () => {});\r\n this.media.removeEventListener('pause', () => {});\r\n // ... (other listeners would be removed in a real implementation)\r\n }\r\n}\r\n\r\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import {
7
7
  HTML5Renderer
8
- } from "./vidply.chunk-UEIJOJH6.js";
8
+ } from "./vidply.chunk-BCOFCT6U.js";
9
9
  import {
10
10
  DOMUtils,
11
11
  DraggableResizable,
@@ -3086,6 +3086,7 @@ var Player = class _Player extends EventEmitter {
3086
3086
  this.element.appendChild(mediaElement);
3087
3087
  this.element = mediaElement;
3088
3088
  }
3089
+ this._originalElement = this.element;
3089
3090
  this.options = {
3090
3091
  // Display
3091
3092
  width: null,
@@ -3359,7 +3360,7 @@ var Player = class _Player extends EventEmitter {
3359
3360
  }
3360
3361
  /**
3361
3362
  * Detect language from HTML lang attribute
3362
- * @returns {string|null} Language code if available in translations, null otherwise
3363
+ * @returns {string|null} Language code if available in translations or as built-in, null otherwise
3363
3364
  */
3364
3365
  detectHtmlLanguage() {
3365
3366
  const htmlLang = document.documentElement.lang || document.documentElement.getAttribute("lang");
@@ -3370,6 +3371,9 @@ var Player = class _Player extends EventEmitter {
3370
3371
  if (i18n.translations[normalizedLang]) {
3371
3372
  return normalizedLang;
3372
3373
  }
3374
+ if (i18n.builtInLanguageLoaders && i18n.builtInLanguageLoaders[normalizedLang]) {
3375
+ return normalizedLang;
3376
+ }
3373
3377
  this.log(`Language "${htmlLang}" not available, using English as fallback`);
3374
3378
  return null;
3375
3379
  }
@@ -3496,10 +3500,12 @@ var Player = class _Player extends EventEmitter {
3496
3500
  this.playButtonOverlay.style.top = `${videoCenter}px`;
3497
3501
  }
3498
3502
  async initializeRenderer() {
3499
- const src = this.element.src || this.element.querySelector("source")?.src;
3503
+ let src = this._pendingSource || this.element.src || this.element.querySelector("source")?.src;
3500
3504
  if (!src) {
3501
3505
  throw new Error("No media source found");
3502
3506
  }
3507
+ this.currentSource = src;
3508
+ this._pendingSource = null;
3503
3509
  const sourceElements = this.sourceElements;
3504
3510
  for (const sourceEl of sourceElements) {
3505
3511
  const descSrc = sourceEl.getAttribute("data-desc-src");
@@ -3552,14 +3558,17 @@ var Player = class _Player extends EventEmitter {
3552
3558
  }
3553
3559
  let rendererClass = HTML5Renderer;
3554
3560
  if (src.includes("youtube.com") || src.includes("youtu.be")) {
3555
- const module = await import("./vidply.YouTubeRenderer-QLMMD757.js");
3561
+ const module = await import("./vidply.YouTubeRenderer-6MGKEFTZ.js");
3556
3562
  rendererClass = module.YouTubeRenderer || module.default;
3557
3563
  } else if (src.includes("vimeo.com")) {
3558
- const module = await import("./vidply.VimeoRenderer-DCETT5IZ.js");
3564
+ const module = await import("./vidply.VimeoRenderer-VPH4RNES.js");
3559
3565
  rendererClass = module.VimeoRenderer || module.default;
3560
3566
  } else if (src.includes(".m3u8")) {
3561
- const module = await import("./vidply.HLSRenderer-PNP5OPES.js");
3567
+ const module = await import("./vidply.HLSRenderer-ENLZE4QS.js");
3562
3568
  rendererClass = module.HLSRenderer || module.default;
3569
+ } else if (src.includes("soundcloud.com") || src.includes("api.soundcloud.com")) {
3570
+ const module = await import("./vidply.SoundCloudRenderer-CD7VJKNS.js");
3571
+ rendererClass = module.SoundCloudRenderer || module.default;
3563
3572
  }
3564
3573
  this.log(`Using ${rendererClass?.name || "HTML5Renderer"} renderer`);
3565
3574
  this.renderer = new rendererClass(this);
@@ -3671,6 +3680,11 @@ var Player = class _Player extends EventEmitter {
3671
3680
  const resolvedPoster = this.resolvePosterPath(poster);
3672
3681
  this.videoWrapper.style.setProperty("--vidply-poster-image", `url("${resolvedPoster}")`);
3673
3682
  this.videoWrapper.classList.add("vidply-forced-poster");
3683
+ if (this._isAudioContent && this.container) {
3684
+ this.container.classList.add("vidply-audio-content");
3685
+ } else if (this.container) {
3686
+ this.container.classList.remove("vidply-audio-content");
3687
+ }
3674
3688
  }
3675
3689
  hidePosterOverlay() {
3676
3690
  if (!this.videoWrapper) {
@@ -3713,6 +3727,15 @@ var Player = class _Player extends EventEmitter {
3713
3727
  * @param {string} [config.audioDescriptionSrc] - Audio description video URL
3714
3728
  * @param {string} [config.signLanguageSrc] - Sign language video URL
3715
3729
  */
3730
+ /**
3731
+ * Check if a source URL requires an external renderer (YouTube, Vimeo, SoundCloud, HLS)
3732
+ * @param {string} src - Source URL
3733
+ * @returns {boolean}
3734
+ */
3735
+ isExternalRendererUrl(src) {
3736
+ if (!src) return false;
3737
+ return src.includes("youtube.com") || src.includes("youtu.be") || src.includes("vimeo.com") || src.includes("soundcloud.com") || src.includes("api.soundcloud.com") || src.includes(".m3u8");
3738
+ }
3716
3739
  async load(config) {
3717
3740
  try {
3718
3741
  this.log("Loading new media:", config.src);
@@ -3724,12 +3747,44 @@ var Player = class _Player extends EventEmitter {
3724
3747
  const existingTracks = this.trackElements;
3725
3748
  existingTracks.forEach((track) => track.remove());
3726
3749
  this.invalidateTrackCache();
3727
- this.element.src = config.src;
3728
- if (config.type) {
3729
- this.element.type = config.type;
3750
+ const isExternalRenderer = this.isExternalRendererUrl(config.src);
3751
+ if (isExternalRenderer) {
3752
+ this._switchingRenderer = true;
3753
+ }
3754
+ if (!isExternalRenderer) {
3755
+ this.element.src = config.src;
3756
+ if (config.type) {
3757
+ this.element.type = config.type;
3758
+ }
3759
+ } else {
3760
+ this.element.removeAttribute("src");
3761
+ const sources = this.element.querySelectorAll("source");
3762
+ sources.forEach((s) => s.removeAttribute("src"));
3763
+ }
3764
+ this._pendingSource = config.src;
3765
+ this._isAudioContent = config.type && config.type.startsWith("audio/");
3766
+ if (this.container) {
3767
+ if (this._isAudioContent) {
3768
+ this.container.classList.add("vidply-audio-content");
3769
+ } else {
3770
+ this.container.classList.remove("vidply-audio-content");
3771
+ }
3730
3772
  }
3731
3773
  if (config.poster && this.element.tagName === "VIDEO") {
3732
- this.element.poster = this.resolvePosterPath(config.poster);
3774
+ if (this._isAudioContent) {
3775
+ this.element.removeAttribute("poster");
3776
+ if (this.videoWrapper) {
3777
+ const resolvedPoster = this.resolvePosterPath(config.poster);
3778
+ this.videoWrapper.style.setProperty("--vidply-poster-image", `url("${resolvedPoster}")`);
3779
+ this.videoWrapper.classList.add("vidply-forced-poster");
3780
+ }
3781
+ } else {
3782
+ this.element.poster = this.resolvePosterPath(config.poster);
3783
+ if (this.videoWrapper) {
3784
+ this.videoWrapper.classList.remove("vidply-forced-poster");
3785
+ this.videoWrapper.style.removeProperty("--vidply-poster-image");
3786
+ }
3787
+ }
3733
3788
  }
3734
3789
  if (config.tracks && config.tracks.length > 0) {
3735
3790
  config.tracks.forEach((trackConfig) => {
@@ -3772,6 +3827,13 @@ var Player = class _Player extends EventEmitter {
3772
3827
  this.renderer.media = this.element;
3773
3828
  this.element.load();
3774
3829
  }
3830
+ if (isExternalRenderer) {
3831
+ setTimeout(() => {
3832
+ this._switchingRenderer = false;
3833
+ }, 500);
3834
+ } else {
3835
+ this._switchingRenderer = false;
3836
+ }
3775
3837
  window.scrollTo(scrollX, scrollY);
3776
3838
  if (this.captionManager) {
3777
3839
  this.captionManager.destroy();
@@ -3830,11 +3892,13 @@ var Player = class _Player extends EventEmitter {
3830
3892
  const isYouTube = src.includes("youtube.com") || src.includes("youtu.be");
3831
3893
  const isVimeo = src.includes("vimeo.com");
3832
3894
  const isHLS = src.includes(".m3u8");
3895
+ const isSoundCloud = src.includes("soundcloud.com") || src.includes("api.soundcloud.com");
3833
3896
  const currentRendererName = this.renderer.constructor.name;
3834
3897
  if (isYouTube && currentRendererName !== "YouTubeRenderer") return true;
3835
3898
  if (isVimeo && currentRendererName !== "VimeoRenderer") return true;
3836
3899
  if (isHLS && currentRendererName !== "HLSRenderer") return true;
3837
- if (!isYouTube && !isVimeo && !isHLS && currentRendererName !== "HTML5Renderer") return true;
3900
+ if (isSoundCloud && currentRendererName !== "SoundCloudRenderer") return true;
3901
+ if (!isYouTube && !isVimeo && !isHLS && !isSoundCloud && currentRendererName !== "HTML5Renderer") return true;
3838
3902
  return false;
3839
3903
  }
3840
3904
  // Playback controls
@@ -6046,6 +6110,10 @@ var Player = class _Player extends EventEmitter {
6046
6110
  }
6047
6111
  // Error handling
6048
6112
  handleError(error) {
6113
+ if (this._switchingRenderer) {
6114
+ this.log("Suppressing error during renderer switch:", error, "debug");
6115
+ return;
6116
+ }
6049
6117
  this.log("Error:", error, "error");
6050
6118
  this.emit("error", error);
6051
6119
  if (this.options.onError) {
@@ -6584,6 +6652,8 @@ var PlaylistManager = class {
6584
6652
  loop: options.loop || false,
6585
6653
  showPanel: options.showPanel !== false,
6586
6654
  // Default true
6655
+ recreatePlayers: options.recreatePlayers || false,
6656
+ // New: recreate player for each track type
6587
6657
  ...options
6588
6658
  };
6589
6659
  this.container = null;
@@ -6592,6 +6662,8 @@ var PlaylistManager = class {
6592
6662
  this.navigationFeedback = null;
6593
6663
  this.isPanelVisible = this.options.showPanel !== false;
6594
6664
  this.isChangingTrack = false;
6665
+ this.hostElement = options.hostElement || null;
6666
+ this.PlayerClass = options.PlayerClass || null;
6595
6667
  this.handleTrackEnd = this.handleTrackEnd.bind(this);
6596
6668
  this.handleTrackError = this.handleTrackError.bind(this);
6597
6669
  this.player.playlistManager = this;
@@ -6601,6 +6673,159 @@ var PlaylistManager = class {
6601
6673
  this.loadPlaylist(this.initialTracks);
6602
6674
  }
6603
6675
  }
6676
+ /**
6677
+ * Determine the media type for a track
6678
+ * @param {Object} track - Track object
6679
+ * @returns {string} - 'audio', 'video', 'youtube', 'vimeo', 'soundcloud', 'hls'
6680
+ */
6681
+ getTrackMediaType(track) {
6682
+ const src = track.src || "";
6683
+ if (src.includes("youtube.com") || src.includes("youtu.be")) {
6684
+ return "youtube";
6685
+ }
6686
+ if (src.includes("vimeo.com")) {
6687
+ return "vimeo";
6688
+ }
6689
+ if (src.includes("soundcloud.com") || src.includes("api.soundcloud.com")) {
6690
+ return "soundcloud";
6691
+ }
6692
+ if (src.includes(".m3u8")) {
6693
+ return "hls";
6694
+ }
6695
+ if (track.type && track.type.startsWith("audio/")) {
6696
+ return "audio";
6697
+ }
6698
+ return "video";
6699
+ }
6700
+ /**
6701
+ * Recreate the player with the appropriate element type for the track
6702
+ * @param {Object} track - Track to load
6703
+ * @param {boolean} autoPlay - Whether to auto-play after creation
6704
+ */
6705
+ async recreatePlayerForTrack(track, autoPlay = false) {
6706
+ if (!this.hostElement || !this.PlayerClass) {
6707
+ console.warn("VidPly Playlist: Cannot recreate player - missing hostElement or PlayerClass");
6708
+ return false;
6709
+ }
6710
+ const mediaType = this.getTrackMediaType(track);
6711
+ const elementType = mediaType === "audio" ? "audio" : "video";
6712
+ const wasVisible = this.isPanelVisible;
6713
+ const savedTracks = [...this.tracks];
6714
+ const savedIndex = this.currentIndex;
6715
+ if (this.trackArtworkElement && this.trackArtworkElement.parentNode) {
6716
+ this.trackArtworkElement.parentNode.removeChild(this.trackArtworkElement);
6717
+ }
6718
+ if (this.trackInfoElement && this.trackInfoElement.parentNode) {
6719
+ this.trackInfoElement.parentNode.removeChild(this.trackInfoElement);
6720
+ }
6721
+ if (this.navigationFeedback && this.navigationFeedback.parentNode) {
6722
+ this.navigationFeedback.parentNode.removeChild(this.navigationFeedback);
6723
+ }
6724
+ if (this.playlistPanel && this.playlistPanel.parentNode) {
6725
+ this.playlistPanel.parentNode.removeChild(this.playlistPanel);
6726
+ }
6727
+ if (this.player) {
6728
+ this.player.off("ended", this.handleTrackEnd);
6729
+ this.player.off("error", this.handleTrackError);
6730
+ this.player.destroy();
6731
+ }
6732
+ this.hostElement.innerHTML = "";
6733
+ const mediaElement = document.createElement(elementType);
6734
+ mediaElement.setAttribute("preload", "metadata");
6735
+ if (elementType === "video" && track.poster && (mediaType === "video" || mediaType === "hls")) {
6736
+ mediaElement.setAttribute("poster", track.poster);
6737
+ }
6738
+ const isExternalRenderer = ["youtube", "vimeo", "soundcloud", "hls"].includes(mediaType);
6739
+ if (!isExternalRenderer) {
6740
+ const source = document.createElement("source");
6741
+ source.src = track.src;
6742
+ if (track.type) {
6743
+ source.type = track.type;
6744
+ }
6745
+ mediaElement.appendChild(source);
6746
+ if (track.tracks && track.tracks.length > 0) {
6747
+ track.tracks.forEach((trackConfig) => {
6748
+ const trackEl = document.createElement("track");
6749
+ trackEl.src = trackConfig.src;
6750
+ trackEl.kind = trackConfig.kind || "captions";
6751
+ trackEl.srclang = trackConfig.srclang || "en";
6752
+ trackEl.label = trackConfig.label || trackConfig.srclang;
6753
+ if (trackConfig.default) {
6754
+ trackEl.default = true;
6755
+ }
6756
+ mediaElement.appendChild(trackEl);
6757
+ });
6758
+ }
6759
+ }
6760
+ this.hostElement.appendChild(mediaElement);
6761
+ const playerOptions = {
6762
+ mediaType: elementType,
6763
+ poster: track.poster,
6764
+ audioDescriptionSrc: track.audioDescriptionSrc || null,
6765
+ audioDescriptionDuration: track.audioDescriptionDuration || null,
6766
+ signLanguageSrc: track.signLanguageSrc || null
6767
+ };
6768
+ this.player = new this.PlayerClass(mediaElement, playerOptions);
6769
+ this.player.playlistManager = this;
6770
+ await new Promise((resolve) => {
6771
+ this.player.on("ready", resolve);
6772
+ });
6773
+ this.player.on("ended", this.handleTrackEnd);
6774
+ this.player.on("error", this.handleTrackError);
6775
+ if (this.player.container) {
6776
+ if (this.trackArtworkElement) {
6777
+ const videoWrapper = this.player.container.querySelector(".vidply-video-wrapper");
6778
+ if (videoWrapper) {
6779
+ this.player.container.insertBefore(this.trackArtworkElement, videoWrapper);
6780
+ } else {
6781
+ this.player.container.appendChild(this.trackArtworkElement);
6782
+ }
6783
+ }
6784
+ if (this.trackInfoElement) {
6785
+ this.player.container.appendChild(this.trackInfoElement);
6786
+ }
6787
+ if (this.navigationFeedback) {
6788
+ this.player.container.appendChild(this.navigationFeedback);
6789
+ }
6790
+ if (this.playlistPanel) {
6791
+ this.player.container.appendChild(this.playlistPanel);
6792
+ }
6793
+ }
6794
+ this.container = this.player.container;
6795
+ this.updatePlayerControls();
6796
+ this.tracks = savedTracks;
6797
+ this.currentIndex = savedIndex;
6798
+ this.updatePlaylistUI();
6799
+ this.isPanelVisible = wasVisible;
6800
+ if (this.playlistPanel) {
6801
+ this.playlistPanel.style.display = wasVisible ? "" : "none";
6802
+ }
6803
+ if (isExternalRenderer) {
6804
+ this.player.load({
6805
+ src: track.src,
6806
+ type: track.type,
6807
+ poster: track.poster,
6808
+ tracks: track.tracks || [],
6809
+ audioDescriptionSrc: track.audioDescriptionSrc || null,
6810
+ signLanguageSrc: track.signLanguageSrc || null
6811
+ });
6812
+ } else {
6813
+ this.player.load({
6814
+ src: track.src,
6815
+ type: track.type,
6816
+ poster: track.poster,
6817
+ tracks: track.tracks || [],
6818
+ audioDescriptionSrc: track.audioDescriptionSrc || null,
6819
+ signLanguageSrc: track.signLanguageSrc || null
6820
+ });
6821
+ }
6822
+ if (autoPlay) {
6823
+ setTimeout(() => {
6824
+ this.player.play();
6825
+ }, 100);
6826
+ }
6827
+ return true;
6828
+ }
6604
6829
  init() {
6605
6830
  this.player.on("ended", this.handleTrackEnd);
6606
6831
  this.player.on("error", this.handleTrackError);
@@ -6711,7 +6936,7 @@ var PlaylistManager = class {
6711
6936
  * Load a track without playing
6712
6937
  * @param {number} index - Track index
6713
6938
  */
6714
- loadTrack(index) {
6939
+ async loadTrack(index) {
6715
6940
  if (index < 0 || index >= this.tracks.length) {
6716
6941
  console.warn("VidPly Playlist: Invalid track index", index);
6717
6942
  return;
@@ -6719,6 +6944,25 @@ var PlaylistManager = class {
6719
6944
  const track = this.tracks[index];
6720
6945
  this.isChangingTrack = true;
6721
6946
  this.currentIndex = index;
6947
+ if (this.options.recreatePlayers && this.hostElement && this.PlayerClass) {
6948
+ const currentMediaType = this.player ? this.player.element.tagName === "AUDIO" ? "audio" : "video" : null;
6949
+ const newMediaType = this.getTrackMediaType(track);
6950
+ const newElementType = newMediaType === "audio" || newMediaType === "soundcloud" ? "audio" : "video";
6951
+ if (currentMediaType !== newElementType) {
6952
+ await this.recreatePlayerForTrack(track, false);
6953
+ this.updateTrackInfo(track);
6954
+ this.updatePlaylistUI();
6955
+ this.player.emit("playlisttrackchange", {
6956
+ index,
6957
+ item: track,
6958
+ total: this.tracks.length
6959
+ });
6960
+ setTimeout(() => {
6961
+ this.isChangingTrack = false;
6962
+ }, 150);
6963
+ return;
6964
+ }
6965
+ }
6722
6966
  this.player.load({
6723
6967
  src: track.src,
6724
6968
  type: track.type,
@@ -6743,7 +6987,7 @@ var PlaylistManager = class {
6743
6987
  * @param {number} index - Track index
6744
6988
  * @param {boolean} userInitiated - Whether this was triggered by user action (default: false)
6745
6989
  */
6746
- play(index, userInitiated = false) {
6990
+ async play(index, userInitiated = false) {
6747
6991
  if (index < 0 || index >= this.tracks.length) {
6748
6992
  console.warn("VidPly Playlist: Invalid track index", index);
6749
6993
  return;
@@ -6751,6 +6995,25 @@ var PlaylistManager = class {
6751
6995
  const track = this.tracks[index];
6752
6996
  this.isChangingTrack = true;
6753
6997
  this.currentIndex = index;
6998
+ if (this.options.recreatePlayers && this.hostElement && this.PlayerClass) {
6999
+ const currentMediaType = this.player ? this.player.element.tagName === "AUDIO" ? "audio" : "video" : null;
7000
+ const newMediaType = this.getTrackMediaType(track);
7001
+ const newElementType = newMediaType === "audio" || newMediaType === "soundcloud" ? "audio" : "video";
7002
+ if (currentMediaType !== newElementType) {
7003
+ await this.recreatePlayerForTrack(track, true);
7004
+ this.updateTrackInfo(track);
7005
+ this.updatePlaylistUI();
7006
+ this.player.emit("playlisttrackchange", {
7007
+ index,
7008
+ item: track,
7009
+ total: this.tracks.length
7010
+ });
7011
+ setTimeout(() => {
7012
+ this.isChangingTrack = false;
7013
+ }, 150);
7014
+ return;
7015
+ }
7016
+ }
6754
7017
  this.player.load({
6755
7018
  src: track.src,
6756
7019
  type: track.type,
@@ -6812,10 +7075,26 @@ var PlaylistManager = class {
6812
7075
  this.next();
6813
7076
  }
6814
7077
  }
7078
+ /**
7079
+ * Check if a source URL requires an external renderer
7080
+ * @param {string} src - Source URL
7081
+ * @returns {boolean}
7082
+ */
7083
+ isExternalRendererUrl(src) {
7084
+ if (!src) return false;
7085
+ return src.includes("youtube.com") || src.includes("youtu.be") || src.includes("vimeo.com") || src.includes("soundcloud.com") || src.includes("api.soundcloud.com") || src.includes(".m3u8");
7086
+ }
6815
7087
  /**
6816
7088
  * Handle track error
6817
7089
  */
6818
7090
  handleTrackError(e) {
7091
+ const currentTrack = this.getCurrentTrack();
7092
+ if (currentTrack && currentTrack.src && this.isExternalRendererUrl(currentTrack.src)) {
7093
+ return;
7094
+ }
7095
+ if (this.isChangingTrack) {
7096
+ return;
7097
+ }
6819
7098
  console.error("VidPly Playlist: Track error", e);
6820
7099
  if (this.options.autoAdvance) {
6821
7100
  setTimeout(() => {