@thestatic-tv/dcl-sdk 2.5.1 → 2.5.3

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.
package/dist/index.d.mts CHANGED
@@ -995,6 +995,10 @@ declare class StaticTVClient {
995
995
  */
996
996
  getConfig(): StaticTVConfig;
997
997
  private _currentVideoUrl;
998
+ private _pendingVideoData;
999
+ private _streamVerified;
1000
+ private _verificationTimeoutId;
1001
+ private _videoEventsRegistered;
998
1002
  /**
999
1003
  * Play a video on the configured videoScreen entity.
1000
1004
  * Called by Guide UI and Admin Panel.
@@ -1013,15 +1017,41 @@ declare class StaticTVClient {
1013
1017
  * @internal
1014
1018
  */
1015
1019
  private _playVideoInternal;
1020
+ /**
1021
+ * Register video event handlers for stream verification
1022
+ * @internal
1023
+ */
1024
+ private _registerVideoEvents;
1025
+ /**
1026
+ * Start stream verification timeout
1027
+ * @internal
1028
+ */
1029
+ private _startStreamVerification;
1030
+ /**
1031
+ * Handle stream that's offline or failed to verify
1032
+ * @internal
1033
+ */
1034
+ private _handleStreamOffline;
1035
+ /**
1036
+ * Clear verification timeout
1037
+ * @internal
1038
+ */
1039
+ private _clearVerificationTimeout;
1016
1040
  /**
1017
1041
  * Get the currently playing video URL
1018
1042
  */
1019
1043
  get currentVideoUrl(): string;
1020
1044
  /**
1021
1045
  * Internal handler for Guide video selection
1046
+ * Tries to play the stream and verifies it's working (like M1D-HQ behavior)
1022
1047
  * @internal
1023
1048
  */
1024
1049
  _handleGuideVideoSelect(video: GuideVideo): void;
1050
+ /**
1051
+ * Play video with stream verification for live content
1052
+ * @internal
1053
+ */
1054
+ private _playVideoWithVerification;
1025
1055
  /**
1026
1056
  * Internal handler for broadcast messages
1027
1057
  * @internal
package/dist/index.d.ts CHANGED
@@ -995,6 +995,10 @@ declare class StaticTVClient {
995
995
  */
996
996
  getConfig(): StaticTVConfig;
997
997
  private _currentVideoUrl;
998
+ private _pendingVideoData;
999
+ private _streamVerified;
1000
+ private _verificationTimeoutId;
1001
+ private _videoEventsRegistered;
998
1002
  /**
999
1003
  * Play a video on the configured videoScreen entity.
1000
1004
  * Called by Guide UI and Admin Panel.
@@ -1013,15 +1017,41 @@ declare class StaticTVClient {
1013
1017
  * @internal
1014
1018
  */
1015
1019
  private _playVideoInternal;
1020
+ /**
1021
+ * Register video event handlers for stream verification
1022
+ * @internal
1023
+ */
1024
+ private _registerVideoEvents;
1025
+ /**
1026
+ * Start stream verification timeout
1027
+ * @internal
1028
+ */
1029
+ private _startStreamVerification;
1030
+ /**
1031
+ * Handle stream that's offline or failed to verify
1032
+ * @internal
1033
+ */
1034
+ private _handleStreamOffline;
1035
+ /**
1036
+ * Clear verification timeout
1037
+ * @internal
1038
+ */
1039
+ private _clearVerificationTimeout;
1016
1040
  /**
1017
1041
  * Get the currently playing video URL
1018
1042
  */
1019
1043
  get currentVideoUrl(): string;
1020
1044
  /**
1021
1045
  * Internal handler for Guide video selection
1046
+ * Tries to play the stream and verifies it's working (like M1D-HQ behavior)
1022
1047
  * @internal
1023
1048
  */
1024
1049
  _handleGuideVideoSelect(video: GuideVideo): void;
1050
+ /**
1051
+ * Play video with stream verification for live content
1052
+ * @internal
1053
+ */
1054
+ private _playVideoWithVerification;
1025
1055
  /**
1026
1056
  * Internal handler for broadcast messages
1027
1057
  * @internal
package/dist/index.js CHANGED
@@ -3493,6 +3493,7 @@ function setupStaticUI(client) {
3493
3493
 
3494
3494
  // src/StaticTVClient.ts
3495
3495
  var import_ecs3 = require("@dcl/sdk/ecs");
3496
+ var utils = __toESM(require("@dcl-sdk/utils"));
3496
3497
  var DEFAULT_BASE_URL = "https://thestatic.tv/api/v1/dcl";
3497
3498
  var DEFAULT_FALLBACK_VIDEO = "https://media.thestatic.tv/fallback-loop.mp4";
3498
3499
  var KEY_TYPE_CHANNEL = "channel";
@@ -3557,6 +3558,11 @@ var StaticTVClient = class {
3557
3558
  // --- VIDEO PLAYBACK (Internal handler for videoScreen) ---
3558
3559
  // =============================================================================
3559
3560
  this._currentVideoUrl = "";
3561
+ this._pendingVideoData = null;
3562
+ this._streamVerified = false;
3563
+ this._verificationTimeoutId = null;
3564
+ // DCL timer ID
3565
+ this._videoEventsRegistered = false;
3560
3566
  this._featuresReadyPromise = new Promise((resolve) => {
3561
3567
  this._featuresReadyResolve = resolve;
3562
3568
  });
@@ -3779,9 +3785,11 @@ var StaticTVClient = class {
3779
3785
  * Internal video player - handles both regular videos and fallback
3780
3786
  * @internal
3781
3787
  */
3782
- _playVideoInternal(url, isFallback = false) {
3788
+ _playVideoInternal(url, isFallback = false, isLiveStream = false) {
3783
3789
  const screen = this.config.videoScreen;
3784
3790
  if (screen === void 0) return;
3791
+ this._clearVerificationTimeout();
3792
+ this._streamVerified = false;
3785
3793
  if (import_ecs3.VideoPlayer.has(screen)) {
3786
3794
  import_ecs3.VideoPlayer.deleteFrom(screen);
3787
3795
  }
@@ -3795,6 +3803,74 @@ var StaticTVClient = class {
3795
3803
  import_ecs3.Material.setBasicMaterial(screen, {
3796
3804
  texture: import_ecs3.Material.Texture.Video({ videoPlayerEntity: screen })
3797
3805
  });
3806
+ if (!this._videoEventsRegistered) {
3807
+ this._registerVideoEvents();
3808
+ }
3809
+ if (isLiveStream && !isFallback) {
3810
+ this._startStreamVerification();
3811
+ }
3812
+ }
3813
+ /**
3814
+ * Register video event handlers for stream verification
3815
+ * @internal
3816
+ */
3817
+ _registerVideoEvents() {
3818
+ const screen = this.config.videoScreen;
3819
+ if (screen === void 0) return;
3820
+ this._videoEventsRegistered = true;
3821
+ import_ecs3.videoEventsSystem.registerVideoEventsEntity(screen, (videoEvent) => {
3822
+ if (videoEvent.state === import_ecs3.VideoState.VS_READY || videoEvent.state === import_ecs3.VideoState.VS_PLAYING) {
3823
+ if (this._pendingVideoData && !this._streamVerified) {
3824
+ this._streamVerified = true;
3825
+ this._clearVerificationTimeout();
3826
+ this.log(`Stream verified: ${this._pendingVideoData.name}`);
3827
+ }
3828
+ }
3829
+ if (videoEvent.state === import_ecs3.VideoState.VS_ERROR) {
3830
+ if (this._pendingVideoData) {
3831
+ this.log(`Stream error for: ${this._pendingVideoData.name}`);
3832
+ this._handleStreamOffline();
3833
+ }
3834
+ }
3835
+ });
3836
+ }
3837
+ /**
3838
+ * Start stream verification timeout
3839
+ * @internal
3840
+ */
3841
+ _startStreamVerification() {
3842
+ if (this._pendingVideoData) {
3843
+ this.showNotification(`Connecting to ${this._pendingVideoData.name}...`, 1e4);
3844
+ }
3845
+ this._verificationTimeoutId = utils.timers.setTimeout(() => {
3846
+ if (!this._streamVerified && this._pendingVideoData) {
3847
+ this.log(`Stream verification timeout for: ${this._pendingVideoData.name}`);
3848
+ this._handleStreamOffline();
3849
+ }
3850
+ }, 8e3);
3851
+ }
3852
+ /**
3853
+ * Handle stream that's offline or failed to verify
3854
+ * @internal
3855
+ */
3856
+ _handleStreamOffline() {
3857
+ const videoData = this._pendingVideoData;
3858
+ this._pendingVideoData = null;
3859
+ this._clearVerificationTimeout();
3860
+ if (videoData) {
3861
+ this.showNotification(`${videoData.name} is offline`, 4e3);
3862
+ }
3863
+ this.stopVideo();
3864
+ }
3865
+ /**
3866
+ * Clear verification timeout
3867
+ * @internal
3868
+ */
3869
+ _clearVerificationTimeout() {
3870
+ if (this._verificationTimeoutId) {
3871
+ utils.timers.clearTimeout(this._verificationTimeoutId);
3872
+ this._verificationTimeoutId = null;
3873
+ }
3798
3874
  }
3799
3875
  /**
3800
3876
  * Get the currently playing video URL
@@ -3804,16 +3880,31 @@ var StaticTVClient = class {
3804
3880
  }
3805
3881
  /**
3806
3882
  * Internal handler for Guide video selection
3883
+ * Tries to play the stream and verifies it's working (like M1D-HQ behavior)
3807
3884
  * @internal
3808
3885
  */
3809
3886
  _handleGuideVideoSelect(video) {
3810
- if (video.channelId && video.isLive === false) {
3811
- this.showNotification(`${video.name} is offline`);
3812
- this.stopVideo();
3813
- return;
3887
+ if (!video.src) return;
3888
+ this._pendingVideoData = video;
3889
+ const isLiveStream = video.channelId !== void 0 || video.src.includes(".m3u8") || video.src.includes("media.thestatic.tv");
3890
+ this._playVideoWithVerification(video, isLiveStream);
3891
+ }
3892
+ /**
3893
+ * Play video with stream verification for live content
3894
+ * @internal
3895
+ */
3896
+ _playVideoWithVerification(video, isLiveStream) {
3897
+ const screen = this.config.videoScreen;
3898
+ if (screen !== void 0) {
3899
+ this.log(`Playing video: ${video.src} (live: ${isLiveStream})`);
3900
+ this._currentVideoUrl = video.src;
3901
+ this._playVideoInternal(video.src, false, isLiveStream);
3902
+ if (this.guideUI) {
3903
+ this.guideUI.currentVideoId = video.id;
3904
+ }
3814
3905
  }
3815
- if (video.src) {
3816
- this.playVideo(video.src);
3906
+ if (this.config.onVideoPlay) {
3907
+ this.config.onVideoPlay(video.src);
3817
3908
  }
3818
3909
  }
3819
3910
  /**
package/dist/index.mjs CHANGED
@@ -3449,7 +3449,8 @@ function setupStaticUI(client) {
3449
3449
  }
3450
3450
 
3451
3451
  // src/StaticTVClient.ts
3452
- import { VideoPlayer, Material } from "@dcl/sdk/ecs";
3452
+ import { VideoPlayer, Material, videoEventsSystem, VideoState } from "@dcl/sdk/ecs";
3453
+ import * as utils from "@dcl-sdk/utils";
3453
3454
  var DEFAULT_BASE_URL = "https://thestatic.tv/api/v1/dcl";
3454
3455
  var DEFAULT_FALLBACK_VIDEO = "https://media.thestatic.tv/fallback-loop.mp4";
3455
3456
  var KEY_TYPE_CHANNEL = "channel";
@@ -3514,6 +3515,11 @@ var StaticTVClient = class {
3514
3515
  // --- VIDEO PLAYBACK (Internal handler for videoScreen) ---
3515
3516
  // =============================================================================
3516
3517
  this._currentVideoUrl = "";
3518
+ this._pendingVideoData = null;
3519
+ this._streamVerified = false;
3520
+ this._verificationTimeoutId = null;
3521
+ // DCL timer ID
3522
+ this._videoEventsRegistered = false;
3517
3523
  this._featuresReadyPromise = new Promise((resolve) => {
3518
3524
  this._featuresReadyResolve = resolve;
3519
3525
  });
@@ -3736,9 +3742,11 @@ var StaticTVClient = class {
3736
3742
  * Internal video player - handles both regular videos and fallback
3737
3743
  * @internal
3738
3744
  */
3739
- _playVideoInternal(url, isFallback = false) {
3745
+ _playVideoInternal(url, isFallback = false, isLiveStream = false) {
3740
3746
  const screen = this.config.videoScreen;
3741
3747
  if (screen === void 0) return;
3748
+ this._clearVerificationTimeout();
3749
+ this._streamVerified = false;
3742
3750
  if (VideoPlayer.has(screen)) {
3743
3751
  VideoPlayer.deleteFrom(screen);
3744
3752
  }
@@ -3752,6 +3760,74 @@ var StaticTVClient = class {
3752
3760
  Material.setBasicMaterial(screen, {
3753
3761
  texture: Material.Texture.Video({ videoPlayerEntity: screen })
3754
3762
  });
3763
+ if (!this._videoEventsRegistered) {
3764
+ this._registerVideoEvents();
3765
+ }
3766
+ if (isLiveStream && !isFallback) {
3767
+ this._startStreamVerification();
3768
+ }
3769
+ }
3770
+ /**
3771
+ * Register video event handlers for stream verification
3772
+ * @internal
3773
+ */
3774
+ _registerVideoEvents() {
3775
+ const screen = this.config.videoScreen;
3776
+ if (screen === void 0) return;
3777
+ this._videoEventsRegistered = true;
3778
+ videoEventsSystem.registerVideoEventsEntity(screen, (videoEvent) => {
3779
+ if (videoEvent.state === VideoState.VS_READY || videoEvent.state === VideoState.VS_PLAYING) {
3780
+ if (this._pendingVideoData && !this._streamVerified) {
3781
+ this._streamVerified = true;
3782
+ this._clearVerificationTimeout();
3783
+ this.log(`Stream verified: ${this._pendingVideoData.name}`);
3784
+ }
3785
+ }
3786
+ if (videoEvent.state === VideoState.VS_ERROR) {
3787
+ if (this._pendingVideoData) {
3788
+ this.log(`Stream error for: ${this._pendingVideoData.name}`);
3789
+ this._handleStreamOffline();
3790
+ }
3791
+ }
3792
+ });
3793
+ }
3794
+ /**
3795
+ * Start stream verification timeout
3796
+ * @internal
3797
+ */
3798
+ _startStreamVerification() {
3799
+ if (this._pendingVideoData) {
3800
+ this.showNotification(`Connecting to ${this._pendingVideoData.name}...`, 1e4);
3801
+ }
3802
+ this._verificationTimeoutId = utils.timers.setTimeout(() => {
3803
+ if (!this._streamVerified && this._pendingVideoData) {
3804
+ this.log(`Stream verification timeout for: ${this._pendingVideoData.name}`);
3805
+ this._handleStreamOffline();
3806
+ }
3807
+ }, 8e3);
3808
+ }
3809
+ /**
3810
+ * Handle stream that's offline or failed to verify
3811
+ * @internal
3812
+ */
3813
+ _handleStreamOffline() {
3814
+ const videoData = this._pendingVideoData;
3815
+ this._pendingVideoData = null;
3816
+ this._clearVerificationTimeout();
3817
+ if (videoData) {
3818
+ this.showNotification(`${videoData.name} is offline`, 4e3);
3819
+ }
3820
+ this.stopVideo();
3821
+ }
3822
+ /**
3823
+ * Clear verification timeout
3824
+ * @internal
3825
+ */
3826
+ _clearVerificationTimeout() {
3827
+ if (this._verificationTimeoutId) {
3828
+ utils.timers.clearTimeout(this._verificationTimeoutId);
3829
+ this._verificationTimeoutId = null;
3830
+ }
3755
3831
  }
3756
3832
  /**
3757
3833
  * Get the currently playing video URL
@@ -3761,16 +3837,31 @@ var StaticTVClient = class {
3761
3837
  }
3762
3838
  /**
3763
3839
  * Internal handler for Guide video selection
3840
+ * Tries to play the stream and verifies it's working (like M1D-HQ behavior)
3764
3841
  * @internal
3765
3842
  */
3766
3843
  _handleGuideVideoSelect(video) {
3767
- if (video.channelId && video.isLive === false) {
3768
- this.showNotification(`${video.name} is offline`);
3769
- this.stopVideo();
3770
- return;
3844
+ if (!video.src) return;
3845
+ this._pendingVideoData = video;
3846
+ const isLiveStream = video.channelId !== void 0 || video.src.includes(".m3u8") || video.src.includes("media.thestatic.tv");
3847
+ this._playVideoWithVerification(video, isLiveStream);
3848
+ }
3849
+ /**
3850
+ * Play video with stream verification for live content
3851
+ * @internal
3852
+ */
3853
+ _playVideoWithVerification(video, isLiveStream) {
3854
+ const screen = this.config.videoScreen;
3855
+ if (screen !== void 0) {
3856
+ this.log(`Playing video: ${video.src} (live: ${isLiveStream})`);
3857
+ this._currentVideoUrl = video.src;
3858
+ this._playVideoInternal(video.src, false, isLiveStream);
3859
+ if (this.guideUI) {
3860
+ this.guideUI.currentVideoId = video.id;
3861
+ }
3771
3862
  }
3772
- if (video.src) {
3773
- this.playVideo(video.src);
3863
+ if (this.config.onVideoPlay) {
3864
+ this.config.onVideoPlay(video.src);
3774
3865
  }
3775
3866
  }
3776
3867
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thestatic-tv/dcl-sdk",
3
- "version": "2.5.1",
3
+ "version": "2.5.3",
4
4
  "description": "Connect your Decentraland scene to thestatic.tv - full channel lineup, metrics tracking, and interactions",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -46,9 +46,11 @@
46
46
  "url": "https://github.com/thestatic-tv/dcl-sdk/issues"
47
47
  },
48
48
  "peerDependencies": {
49
+ "@dcl-sdk/utils": ">=1.0.0",
49
50
  "@dcl/sdk": ">=7.0.0"
50
51
  },
51
52
  "devDependencies": {
53
+ "@dcl-sdk/utils": "^1.4.0",
52
54
  "@dcl/sdk": "^7.0.0",
53
55
  "@vitest/coverage-v8": "^4.0.16",
54
56
  "tsup": "^8.0.0",