vidply 1.0.26 → 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 (45) hide show
  1. package/dist/dev/{vidply.HLSRenderer-X46P47LY.js → vidply.HLSRenderer-ENLZE4QS.js} +13 -8
  2. package/dist/dev/vidply.HLSRenderer-ENLZE4QS.js.map +7 -0
  3. package/dist/dev/{vidply.HTML5Renderer-LXQ3I45Q.js → vidply.HTML5Renderer-6SBDI6S2.js} +2 -2
  4. package/dist/dev/vidply.SoundCloudRenderer-CD7VJKNS.js +280 -0
  5. package/dist/dev/vidply.SoundCloudRenderer-CD7VJKNS.js.map +7 -0
  6. package/dist/dev/{vidply.VimeoRenderer-DCETT5IZ.js → vidply.VimeoRenderer-VPH4RNES.js} +17 -4
  7. package/dist/dev/vidply.VimeoRenderer-VPH4RNES.js.map +7 -0
  8. package/dist/dev/{vidply.YouTubeRenderer-QLMMD757.js → vidply.YouTubeRenderer-6MGKEFTZ.js} +14 -6
  9. package/dist/dev/vidply.YouTubeRenderer-6MGKEFTZ.js.map +7 -0
  10. package/dist/dev/{vidply.chunk-UEIJOJH6.js → vidply.chunk-BCOFCT6U.js} +4 -1
  11. package/dist/dev/vidply.chunk-BCOFCT6U.js.map +7 -0
  12. package/dist/dev/vidply.esm.js +288 -12
  13. package/dist/dev/vidply.esm.js.map +2 -2
  14. package/dist/legacy/vidply.js +609 -23
  15. package/dist/legacy/vidply.js.map +3 -3
  16. package/dist/legacy/vidply.min.js +1 -1
  17. package/dist/legacy/vidply.min.meta.json +26 -13
  18. package/dist/prod/vidply.HLSRenderer-CBXZ4RF2.min.js +6 -0
  19. package/dist/prod/{vidply.HTML5Renderer-XJCSUETP.min.js → vidply.HTML5Renderer-MY7XDV7R.min.js} +1 -1
  20. package/dist/prod/vidply.SoundCloudRenderer-MOR2CUFH.min.js +6 -0
  21. package/dist/prod/vidply.VimeoRenderer-3HBMM2WR.min.js +6 -0
  22. package/dist/prod/vidply.YouTubeRenderer-MFC2GMAC.min.js +6 -0
  23. package/dist/prod/vidply.chunk-OXXPY2XB.min.js +6 -0
  24. package/dist/prod/vidply.esm.min.js +6 -6
  25. package/dist/vidply.css +51 -0
  26. package/dist/vidply.esm.min.meta.json +56 -28
  27. package/dist/vidply.min.css +1 -1
  28. package/package.json +1 -1
  29. package/src/core/Player.js +117 -8
  30. package/src/features/PlaylistManager.js +312 -4
  31. package/src/renderers/HLSRenderer.js +17 -9
  32. package/src/renderers/HTML5Renderer.js +5 -0
  33. package/src/renderers/SoundCloudRenderer.js +355 -0
  34. package/src/renderers/VimeoRenderer.js +20 -4
  35. package/src/renderers/YouTubeRenderer.js +12 -6
  36. package/src/styles/vidply.css +51 -0
  37. package/dist/dev/vidply.HLSRenderer-X46P47LY.js.map +0 -7
  38. package/dist/dev/vidply.VimeoRenderer-DCETT5IZ.js.map +0 -7
  39. package/dist/dev/vidply.YouTubeRenderer-QLMMD757.js.map +0 -7
  40. package/dist/dev/vidply.chunk-UEIJOJH6.js.map +0 -7
  41. package/dist/prod/vidply.HLSRenderer-LDXSMWTI.min.js +0 -6
  42. package/dist/prod/vidply.VimeoRenderer-P3PU27S7.min.js +0 -6
  43. package/dist/prod/vidply.YouTubeRenderer-DGKKWB5M.min.js +0 -6
  44. package/dist/prod/vidply.chunk-BQBGEJF7.min.js +0 -6
  45. /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,
@@ -3499,10 +3500,12 @@ var Player = class _Player extends EventEmitter {
3499
3500
  this.playButtonOverlay.style.top = `${videoCenter}px`;
3500
3501
  }
3501
3502
  async initializeRenderer() {
3502
- const src = this.element.src || this.element.querySelector("source")?.src;
3503
+ let src = this._pendingSource || this.element.src || this.element.querySelector("source")?.src;
3503
3504
  if (!src) {
3504
3505
  throw new Error("No media source found");
3505
3506
  }
3507
+ this.currentSource = src;
3508
+ this._pendingSource = null;
3506
3509
  const sourceElements = this.sourceElements;
3507
3510
  for (const sourceEl of sourceElements) {
3508
3511
  const descSrc = sourceEl.getAttribute("data-desc-src");
@@ -3555,14 +3558,17 @@ var Player = class _Player extends EventEmitter {
3555
3558
  }
3556
3559
  let rendererClass = HTML5Renderer;
3557
3560
  if (src.includes("youtube.com") || src.includes("youtu.be")) {
3558
- const module = await import("./vidply.YouTubeRenderer-QLMMD757.js");
3561
+ const module = await import("./vidply.YouTubeRenderer-6MGKEFTZ.js");
3559
3562
  rendererClass = module.YouTubeRenderer || module.default;
3560
3563
  } else if (src.includes("vimeo.com")) {
3561
- const module = await import("./vidply.VimeoRenderer-DCETT5IZ.js");
3564
+ const module = await import("./vidply.VimeoRenderer-VPH4RNES.js");
3562
3565
  rendererClass = module.VimeoRenderer || module.default;
3563
3566
  } else if (src.includes(".m3u8")) {
3564
- const module = await import("./vidply.HLSRenderer-X46P47LY.js");
3567
+ const module = await import("./vidply.HLSRenderer-ENLZE4QS.js");
3565
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;
3566
3572
  }
3567
3573
  this.log(`Using ${rendererClass?.name || "HTML5Renderer"} renderer`);
3568
3574
  this.renderer = new rendererClass(this);
@@ -3674,6 +3680,11 @@ var Player = class _Player extends EventEmitter {
3674
3680
  const resolvedPoster = this.resolvePosterPath(poster);
3675
3681
  this.videoWrapper.style.setProperty("--vidply-poster-image", `url("${resolvedPoster}")`);
3676
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
+ }
3677
3688
  }
3678
3689
  hidePosterOverlay() {
3679
3690
  if (!this.videoWrapper) {
@@ -3716,6 +3727,15 @@ var Player = class _Player extends EventEmitter {
3716
3727
  * @param {string} [config.audioDescriptionSrc] - Audio description video URL
3717
3728
  * @param {string} [config.signLanguageSrc] - Sign language video URL
3718
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
+ }
3719
3739
  async load(config) {
3720
3740
  try {
3721
3741
  this.log("Loading new media:", config.src);
@@ -3727,12 +3747,44 @@ var Player = class _Player extends EventEmitter {
3727
3747
  const existingTracks = this.trackElements;
3728
3748
  existingTracks.forEach((track) => track.remove());
3729
3749
  this.invalidateTrackCache();
3730
- this.element.src = config.src;
3731
- if (config.type) {
3732
- 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
+ }
3733
3772
  }
3734
3773
  if (config.poster && this.element.tagName === "VIDEO") {
3735
- 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
+ }
3736
3788
  }
3737
3789
  if (config.tracks && config.tracks.length > 0) {
3738
3790
  config.tracks.forEach((trackConfig) => {
@@ -3775,6 +3827,13 @@ var Player = class _Player extends EventEmitter {
3775
3827
  this.renderer.media = this.element;
3776
3828
  this.element.load();
3777
3829
  }
3830
+ if (isExternalRenderer) {
3831
+ setTimeout(() => {
3832
+ this._switchingRenderer = false;
3833
+ }, 500);
3834
+ } else {
3835
+ this._switchingRenderer = false;
3836
+ }
3778
3837
  window.scrollTo(scrollX, scrollY);
3779
3838
  if (this.captionManager) {
3780
3839
  this.captionManager.destroy();
@@ -3833,11 +3892,13 @@ var Player = class _Player extends EventEmitter {
3833
3892
  const isYouTube = src.includes("youtube.com") || src.includes("youtu.be");
3834
3893
  const isVimeo = src.includes("vimeo.com");
3835
3894
  const isHLS = src.includes(".m3u8");
3895
+ const isSoundCloud = src.includes("soundcloud.com") || src.includes("api.soundcloud.com");
3836
3896
  const currentRendererName = this.renderer.constructor.name;
3837
3897
  if (isYouTube && currentRendererName !== "YouTubeRenderer") return true;
3838
3898
  if (isVimeo && currentRendererName !== "VimeoRenderer") return true;
3839
3899
  if (isHLS && currentRendererName !== "HLSRenderer") return true;
3840
- 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;
3841
3902
  return false;
3842
3903
  }
3843
3904
  // Playback controls
@@ -6049,6 +6110,10 @@ var Player = class _Player extends EventEmitter {
6049
6110
  }
6050
6111
  // Error handling
6051
6112
  handleError(error) {
6113
+ if (this._switchingRenderer) {
6114
+ this.log("Suppressing error during renderer switch:", error, "debug");
6115
+ return;
6116
+ }
6052
6117
  this.log("Error:", error, "error");
6053
6118
  this.emit("error", error);
6054
6119
  if (this.options.onError) {
@@ -6587,6 +6652,8 @@ var PlaylistManager = class {
6587
6652
  loop: options.loop || false,
6588
6653
  showPanel: options.showPanel !== false,
6589
6654
  // Default true
6655
+ recreatePlayers: options.recreatePlayers || false,
6656
+ // New: recreate player for each track type
6590
6657
  ...options
6591
6658
  };
6592
6659
  this.container = null;
@@ -6595,6 +6662,8 @@ var PlaylistManager = class {
6595
6662
  this.navigationFeedback = null;
6596
6663
  this.isPanelVisible = this.options.showPanel !== false;
6597
6664
  this.isChangingTrack = false;
6665
+ this.hostElement = options.hostElement || null;
6666
+ this.PlayerClass = options.PlayerClass || null;
6598
6667
  this.handleTrackEnd = this.handleTrackEnd.bind(this);
6599
6668
  this.handleTrackError = this.handleTrackError.bind(this);
6600
6669
  this.player.playlistManager = this;
@@ -6604,6 +6673,159 @@ var PlaylistManager = class {
6604
6673
  this.loadPlaylist(this.initialTracks);
6605
6674
  }
6606
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
+ }
6607
6829
  init() {
6608
6830
  this.player.on("ended", this.handleTrackEnd);
6609
6831
  this.player.on("error", this.handleTrackError);
@@ -6714,7 +6936,7 @@ var PlaylistManager = class {
6714
6936
  * Load a track without playing
6715
6937
  * @param {number} index - Track index
6716
6938
  */
6717
- loadTrack(index) {
6939
+ async loadTrack(index) {
6718
6940
  if (index < 0 || index >= this.tracks.length) {
6719
6941
  console.warn("VidPly Playlist: Invalid track index", index);
6720
6942
  return;
@@ -6722,6 +6944,25 @@ var PlaylistManager = class {
6722
6944
  const track = this.tracks[index];
6723
6945
  this.isChangingTrack = true;
6724
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
+ }
6725
6966
  this.player.load({
6726
6967
  src: track.src,
6727
6968
  type: track.type,
@@ -6746,7 +6987,7 @@ var PlaylistManager = class {
6746
6987
  * @param {number} index - Track index
6747
6988
  * @param {boolean} userInitiated - Whether this was triggered by user action (default: false)
6748
6989
  */
6749
- play(index, userInitiated = false) {
6990
+ async play(index, userInitiated = false) {
6750
6991
  if (index < 0 || index >= this.tracks.length) {
6751
6992
  console.warn("VidPly Playlist: Invalid track index", index);
6752
6993
  return;
@@ -6754,6 +6995,25 @@ var PlaylistManager = class {
6754
6995
  const track = this.tracks[index];
6755
6996
  this.isChangingTrack = true;
6756
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
+ }
6757
7017
  this.player.load({
6758
7018
  src: track.src,
6759
7019
  type: track.type,
@@ -6815,10 +7075,26 @@ var PlaylistManager = class {
6815
7075
  this.next();
6816
7076
  }
6817
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
+ }
6818
7087
  /**
6819
7088
  * Handle track error
6820
7089
  */
6821
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
+ }
6822
7098
  console.error("VidPly Playlist: Track error", e);
6823
7099
  if (this.options.autoAdvance) {
6824
7100
  setTimeout(() => {