myetv-player 1.0.10 → 1.1.0

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.
@@ -422,6 +422,7 @@ constructor(videoElement, options = {}) {
422
422
  showSeekTooltip: true,
423
423
  showTitleOverlay: false,
424
424
  videoTitle: '',
425
+ videoSubtitle: '',
425
426
  persistentTitle: false,
426
427
  debug: false, // Enable/disable debug logging
427
428
  autoplay: false, // if video should autoplay at start
@@ -978,9 +979,16 @@ createTitleOverlay() {
978
979
  const titleText = document.createElement('h2');
979
980
  titleText.className = 'title-text';
980
981
  titleText.textContent = this.options.videoTitle || '';
981
-
982
982
  overlay.appendChild(titleText);
983
983
 
984
+ // add subtitles
985
+ if (this.options.videoSubtitle) {
986
+ const subtitleText = document.createElement('p');
987
+ subtitleText.className = 'subtitle-text';
988
+ subtitleText.textContent = this.options.videoSubtitle;
989
+ overlay.appendChild(subtitleText);
990
+ }
991
+
984
992
  if (this.controls) {
985
993
  this.container.insertBefore(overlay, this.controls);
986
994
  } else {
@@ -1054,6 +1062,31 @@ getVideoTitle() {
1054
1062
  return this.options.videoTitle;
1055
1063
  }
1056
1064
 
1065
+ setVideoSubtitle(subtitle) {
1066
+ this.options.videoSubtitle = subtitle || '';
1067
+
1068
+ if (this.titleOverlay) {
1069
+ let subtitleElement = this.titleOverlay.querySelector('.subtitle-text');
1070
+
1071
+ if (subtitle) {
1072
+ if (!subtitleElement) {
1073
+ subtitleElement = document.createElement('p');
1074
+ subtitleElement.className = 'subtitle-text';
1075
+ this.titleOverlay.appendChild(subtitleElement);
1076
+ }
1077
+ subtitleElement.textContent = subtitle;
1078
+ } else if (subtitleElement) {
1079
+ subtitleElement.remove();
1080
+ }
1081
+ }
1082
+
1083
+ return this;
1084
+ }
1085
+
1086
+ getVideoSubtitle() {
1087
+ return this.options.videoSubtitle;
1088
+ }
1089
+
1057
1090
  setPersistentTitle(persistent) {
1058
1091
  this.options.persistentTitle = persistent;
1059
1092
 
@@ -6766,15 +6799,29 @@ getBufferedTime() {
6766
6799
  this.video.currentTime = Math.max(0, Math.min(this.video.duration, this.video.currentTime + seconds));
6767
6800
  }
6768
6801
 
6769
- updateTimeDisplay() {
6770
- if (this.currentTimeEl && this.video) {
6771
- this.currentTimeEl.textContent = this.formatTime(this.video.currentTime || 0);
6772
- }
6802
+ updateTimeDisplay() {
6803
+ // update current time
6804
+ if (this.currentTimeEl && this.video) {
6805
+ this.currentTimeEl.textContent = this.formatTime(this.video.currentTime || 0);
6806
+ }
6807
+
6808
+ // update duration or show badge if encoding
6809
+ if (this.durationEl && this.video) {
6810
+ const duration = this.video.duration;
6773
6811
 
6774
- if (this.durationEl && this.video && this.video.duration && !isNaN(this.video.duration)) {
6775
- this.durationEl.textContent = this.formatTime(this.video.duration);
6812
+ // check if duration is valid
6813
+ if (!duration || isNaN(duration) || !isFinite(duration)) {
6814
+ // Video in encoding - show badge instead of duration
6815
+ this.durationEl.innerHTML = '<span class="encoding-badge">Encoding in progress</span>';
6816
+ this.durationEl.classList.add('encoding-state');
6817
+ } else {
6818
+ // valid duration - show normal
6819
+ this.durationEl.textContent = this.formatTime(duration);
6820
+ this.durationEl.classList.remove('encoding-state');
6776
6821
  }
6777
6822
  }
6823
+ }
6824
+
6778
6825
 
6779
6826
  formatTime(seconds) {
6780
6827
  if (isNaN(seconds) || seconds < 0) return '0:00';
@@ -408,6 +408,7 @@ constructor(videoElement, options = {}) {
408
408
  showSeekTooltip: true,
409
409
  showTitleOverlay: false,
410
410
  videoTitle: '',
411
+ videoSubtitle: '',
411
412
  persistentTitle: false,
412
413
  debug: false,
413
414
  autoplay: false,
@@ -964,9 +965,16 @@ createTitleOverlay() {
964
965
  const titleText = document.createElement('h2');
965
966
  titleText.className = 'title-text';
966
967
  titleText.textContent = this.options.videoTitle || '';
967
-
968
968
  overlay.appendChild(titleText);
969
969
 
970
+
971
+ if (this.options.videoSubtitle) {
972
+ const subtitleText = document.createElement('p');
973
+ subtitleText.className = 'subtitle-text';
974
+ subtitleText.textContent = this.options.videoSubtitle;
975
+ overlay.appendChild(subtitleText);
976
+ }
977
+
970
978
  if (this.controls) {
971
979
  this.container.insertBefore(overlay, this.controls);
972
980
  } else {
@@ -1040,6 +1048,31 @@ getVideoTitle() {
1040
1048
  return this.options.videoTitle;
1041
1049
  }
1042
1050
 
1051
+ setVideoSubtitle(subtitle) {
1052
+ this.options.videoSubtitle = subtitle || '';
1053
+
1054
+ if (this.titleOverlay) {
1055
+ let subtitleElement = this.titleOverlay.querySelector('.subtitle-text');
1056
+
1057
+ if (subtitle) {
1058
+ if (!subtitleElement) {
1059
+ subtitleElement = document.createElement('p');
1060
+ subtitleElement.className = 'subtitle-text';
1061
+ this.titleOverlay.appendChild(subtitleElement);
1062
+ }
1063
+ subtitleElement.textContent = subtitle;
1064
+ } else if (subtitleElement) {
1065
+ subtitleElement.remove();
1066
+ }
1067
+ }
1068
+
1069
+ return this;
1070
+ }
1071
+
1072
+ getVideoSubtitle() {
1073
+ return this.options.videoSubtitle;
1074
+ }
1075
+
1043
1076
  setPersistentTitle(persistent) {
1044
1077
  this.options.persistentTitle = persistent;
1045
1078
 
@@ -6517,15 +6550,29 @@ getBufferedTime() {
6517
6550
  this.video.currentTime = Math.max(0, Math.min(this.video.duration, this.video.currentTime + seconds));
6518
6551
  }
6519
6552
 
6520
- updateTimeDisplay() {
6521
- if (this.currentTimeEl && this.video) {
6522
- this.currentTimeEl.textContent = this.formatTime(this.video.currentTime || 0);
6523
- }
6553
+ updateTimeDisplay() {
6554
+
6555
+ if (this.currentTimeEl && this.video) {
6556
+ this.currentTimeEl.textContent = this.formatTime(this.video.currentTime || 0);
6557
+ }
6558
+
6559
+
6560
+ if (this.durationEl && this.video) {
6561
+ const duration = this.video.duration;
6524
6562
 
6525
- if (this.durationEl && this.video && this.video.duration && !isNaN(this.video.duration)) {
6526
- this.durationEl.textContent = this.formatTime(this.video.duration);
6563
+
6564
+ if (!duration || isNaN(duration) || !isFinite(duration)) {
6565
+
6566
+ this.durationEl.innerHTML = '<span class="encoding-badge">Encoding in progress</span>';
6567
+ this.durationEl.classList.add('encoding-state');
6568
+ } else {
6569
+
6570
+ this.durationEl.textContent = this.formatTime(duration);
6571
+ this.durationEl.classList.remove('encoding-state');
6527
6572
  }
6528
6573
  }
6574
+ }
6575
+
6529
6576
 
6530
6577
  formatTime(seconds) {
6531
6578
  if (isNaN(seconds) || seconds < 0) return '0:00';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myetv-player",
3
- "version": "1.0.10",
3
+ "version": "1.1.0",
4
4
  "description": "MYETV Video Player - Modular JavaScript and SCSS Build System",
5
5
  "main": "dist/myetv-player.js",
6
6
  "scripts": {
@@ -32,3 +32,4 @@
32
32
 
33
33
 
34
34
 
35
+
@@ -23,10 +23,12 @@ Official Cloudflare Stream integration plugin for MYETV Video Player. Embed vide
23
23
  ## Features
24
24
 
25
25
  - **Cloudflare Stream Integration**: Full support for Cloudflare Stream videos
26
+ - **DASH/HLS** adaptive streaming ready with full support and libraries hosted on cdnjs.com
26
27
  - **Private Videos**: Support for signed URLs and private video access
27
28
  - **Live Streaming**: Real-time live stream playback
28
29
  - **Player Customization**: Custom colors, poster images, and branding
29
30
  - **Auto-Detection**: Automatically detects Cloudflare Stream URLs
31
+ - **Auto-Quality**: Automatically detect video quality (also for hls/dash)
30
32
  - **Complete API**: Full control over playback, volume, seeking
31
33
  - **Analytics Ready**: Works with Cloudflare Analytics
32
34
  - **Ad Support**: VAST ad tag integration
@@ -122,6 +124,7 @@ const player = new MYETVPlayer('myVideo', {
122
124
  preload: 'metadata', // 'none', 'metadata', 'auto'
123
125
  controls: true, // Show player controls
124
126
  startTime: 0, // Start position in seconds
127
+ defaultQuality: 'auto', // the default quality of the video (auto, 720p, 480p, 360p ecc.)
125
128
 
126
129
  // ========== Player Customization ==========
127
130
  poster: 'https://example.com/poster.jpg', // Custom poster image
@@ -272,15 +275,34 @@ plugins: {
272
275
  });
273
276
  </script>
274
277
  ```
275
-
276
278
  **Supported URL Formats:**
277
- - `https://iframe.videodelivery.net/VIDEO_ID`
278
- - `https://customer-CODE.cloudflarestream.com/VIDEO_ID/iframe`
279
+ - `https://iframe.videodelivery.net/VIDEO_ID` (iframe)
280
+ - `https://customer-[code].cloudflarestream.com/VIDEO_ID/iframe` (iframe)
279
281
  - `https://videodelivery.net/VIDEO_ID`
280
282
 
283
+ ### Method 4: HLS / DASH Adaptive Streaming
284
+
285
+ ```html
286
+ <video id="myVideo" class="video-player"></video>
287
+
288
+ <script>
289
+ const player = new MYETVPlayer('myVideo', {
290
+ plugins: {
291
+ cloudflare: {
292
+ manifestUrl: 'https://customer-[code].cloudflarestream.com/VIDEO_ID/manifest/video.m3u8'
293
+ }
294
+ }
295
+ });
296
+ </script>
297
+ ```
298
+
299
+ **Supported URL Formats:**
300
+ - `https://customer-[code].cloudflarestream.com/VIDEO_ID/manifest/video.m3u8` (hls)
301
+ - `https://customer-[code].cloudflarestream.com/VIDEO_ID/manifest/video.mpd` (dash)
302
+
281
303
  ---
282
304
 
283
- ### Method 4: Load Dynamically
305
+ ### Method 5: Load Dynamically
284
306
 
285
307
  ```html
286
308
  <video id="myVideo" class="video-player"></video>