saltfish 0.3.71 → 0.3.73
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/core/services/PlaylistOrchestrator.d.ts.map +1 -1
- package/dist/managers/AnalyticsManager.d.ts +11 -0
- package/dist/managers/AnalyticsManager.d.ts.map +1 -1
- package/dist/player.js +3 -3
- package/dist/player.min.js +3 -3
- package/dist/saltfish-playlist-player.es.js +150 -31
- package/dist/saltfish-playlist-player.umd.js +1 -1
- package/dist/updaters/EventUpdater.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -2983,7 +2983,6 @@ class PlaylistOrchestrator {
|
|
|
2983
2983
|
});
|
|
2984
2984
|
}
|
|
2985
2985
|
}
|
|
2986
|
-
this.managers.analyticsManager.trackPlaylistStart(playlistId);
|
|
2987
2986
|
this.managers.cursorManager.resetFirstAnimation();
|
|
2988
2987
|
log(`[PlaylistOrchestrator.startPlaylist] Using validated manifest path: ${manifestPathToLoad}`);
|
|
2989
2988
|
await this.managers.playlistManager.load(manifestPathToLoad, { ...finalOptions, persistence: playlistPersistence });
|
|
@@ -3750,6 +3749,39 @@ function setupEventUpdater(eventManager) {
|
|
|
3750
3749
|
let prevPreviousState = null;
|
|
3751
3750
|
let prevIsMinimized = null;
|
|
3752
3751
|
let prevStepId = null;
|
|
3752
|
+
let pendingStartEvents = { playlistData: null, stepData: null };
|
|
3753
|
+
let autoplayConfirmationTimer = null;
|
|
3754
|
+
const firePendingEvents = () => {
|
|
3755
|
+
if (autoplayConfirmationTimer) {
|
|
3756
|
+
clearTimeout(autoplayConfirmationTimer);
|
|
3757
|
+
autoplayConfirmationTimer = null;
|
|
3758
|
+
}
|
|
3759
|
+
if (pendingStartEvents.playlistData) {
|
|
3760
|
+
eventManager.trigger("playlistStarted", {
|
|
3761
|
+
timestamp: Date.now(),
|
|
3762
|
+
playlist: pendingStartEvents.playlistData
|
|
3763
|
+
});
|
|
3764
|
+
}
|
|
3765
|
+
if (pendingStartEvents.stepData) {
|
|
3766
|
+
eventManager.trigger("stepStarted", {
|
|
3767
|
+
timestamp: Date.now(),
|
|
3768
|
+
step: { id: pendingStartEvents.stepData.id, title: pendingStartEvents.stepData.title },
|
|
3769
|
+
playlist: { id: pendingStartEvents.stepData.playlistId, title: pendingStartEvents.stepData.playlistTitle }
|
|
3770
|
+
});
|
|
3771
|
+
}
|
|
3772
|
+
pendingStartEvents = { playlistData: null, stepData: null };
|
|
3773
|
+
};
|
|
3774
|
+
const startAutoplayConfirmationTimer = () => {
|
|
3775
|
+
if (autoplayConfirmationTimer) {
|
|
3776
|
+
clearTimeout(autoplayConfirmationTimer);
|
|
3777
|
+
}
|
|
3778
|
+
autoplayConfirmationTimer = setTimeout(() => {
|
|
3779
|
+
if (pendingStartEvents.playlistData || pendingStartEvents.stepData) {
|
|
3780
|
+
firePendingEvents();
|
|
3781
|
+
}
|
|
3782
|
+
autoplayConfirmationTimer = null;
|
|
3783
|
+
}, 500);
|
|
3784
|
+
};
|
|
3753
3785
|
const unsubscribe = useSaltfishStore.subscribe(
|
|
3754
3786
|
(state) => {
|
|
3755
3787
|
var _a;
|
|
@@ -3774,30 +3806,55 @@ function setupEventUpdater(eventManager) {
|
|
|
3774
3806
|
log(`EventUpdater: Processing state change from '${eventData.previousState}' to '${eventData.currentState}'`, {
|
|
3775
3807
|
manifestId: (_a = state.manifest) == null ? void 0 : _a.id
|
|
3776
3808
|
});
|
|
3777
|
-
|
|
3809
|
+
if (eventData.previousState === "playing") {
|
|
3810
|
+
if (eventData.currentState === "autoplayBlocked" || eventData.currentState === "idleMode") {
|
|
3811
|
+
if (autoplayConfirmationTimer) {
|
|
3812
|
+
clearTimeout(autoplayConfirmationTimer);
|
|
3813
|
+
autoplayConfirmationTimer = null;
|
|
3814
|
+
}
|
|
3815
|
+
if (pendingStartEvents.playlistData || pendingStartEvents.stepData) {
|
|
3816
|
+
pendingStartEvents = { playlistData: null, stepData: null };
|
|
3817
|
+
}
|
|
3818
|
+
} else if (pendingStartEvents.playlistData || pendingStartEvents.stepData) {
|
|
3819
|
+
firePendingEvents();
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
handleStateTransitionEvents(eventData, state, eventManager, pendingStartEvents);
|
|
3778
3823
|
handleMinimizeEvents(eventData, state, eventManager, actualPrevMinimized);
|
|
3779
|
-
handleStepEvents(eventData, state, eventManager, actualPrevStepId);
|
|
3824
|
+
handleStepEvents(eventData, state, eventManager, actualPrevStepId, pendingStartEvents);
|
|
3780
3825
|
handleErrorEvents(eventData, state, eventManager);
|
|
3826
|
+
if ((pendingStartEvents.playlistData || pendingStartEvents.stepData) && !autoplayConfirmationTimer) {
|
|
3827
|
+
startAutoplayConfirmationTimer();
|
|
3828
|
+
}
|
|
3781
3829
|
}
|
|
3782
3830
|
);
|
|
3783
3831
|
return unsubscribe;
|
|
3784
3832
|
}
|
|
3785
|
-
function handleStateTransitionEvents(eventData, store, eventManager) {
|
|
3833
|
+
function handleStateTransitionEvents(eventData, store, eventManager, pendingStartEvents) {
|
|
3786
3834
|
const { prevPreviousState, previousState, currentState, currentStepId } = eventData;
|
|
3787
3835
|
const isNormalPlaylistStart = currentState === "playing" && previousState === "paused" && prevPreviousState === "loading";
|
|
3788
|
-
const
|
|
3789
|
-
if (
|
|
3836
|
+
const isUserInitiatedPlaylistStart = currentState === "playing" && (previousState === "autoplayBlocked" || previousState === "idleMode");
|
|
3837
|
+
if (store.manifest && currentStepId) {
|
|
3790
3838
|
const isStartingNode = currentStepId === store.manifest.startStep;
|
|
3791
3839
|
if (isStartingNode) {
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3840
|
+
if (isUserInitiatedPlaylistStart) {
|
|
3841
|
+
log(`EventUpdater: Triggering playlistStarted event for ${store.manifest.id} (user-initiated from ${previousState})`);
|
|
3842
|
+
eventManager.trigger("playlistStarted", {
|
|
3843
|
+
timestamp: Date.now(),
|
|
3844
|
+
playlist: {
|
|
3845
|
+
id: store.manifest.id,
|
|
3846
|
+
title: store.manifest.name
|
|
3847
|
+
}
|
|
3848
|
+
});
|
|
3849
|
+
return;
|
|
3850
|
+
} else if (isNormalPlaylistStart) {
|
|
3851
|
+
log(`EventUpdater: Deferring playlistStarted event for ${store.manifest.id} (pending autoplay confirmation)`);
|
|
3852
|
+
pendingStartEvents.playlistData = {
|
|
3796
3853
|
id: store.manifest.id,
|
|
3797
3854
|
title: store.manifest.name
|
|
3798
|
-
}
|
|
3799
|
-
|
|
3800
|
-
|
|
3855
|
+
};
|
|
3856
|
+
return;
|
|
3857
|
+
}
|
|
3801
3858
|
}
|
|
3802
3859
|
}
|
|
3803
3860
|
if (previousState === "paused" && currentState === "playing") {
|
|
@@ -3831,7 +3888,7 @@ function handleMinimizeEvents(eventData, _store, eventManager, prevIsMinimized)
|
|
|
3831
3888
|
});
|
|
3832
3889
|
}
|
|
3833
3890
|
}
|
|
3834
|
-
function handleStepEvents(eventData, store, eventManager, prevStepId) {
|
|
3891
|
+
function handleStepEvents(eventData, store, eventManager, prevStepId, pendingStartEvents) {
|
|
3835
3892
|
var _a, _b, _c;
|
|
3836
3893
|
const { prevPreviousState, previousState, currentStepId, currentState } = eventData;
|
|
3837
3894
|
const currentStep = store.currentStepId ? (((_a = store.manifest) == null ? void 0 : _a.steps) || []).find((s) => s.id === store.currentStepId) : null;
|
|
@@ -3865,26 +3922,38 @@ function handleStepEvents(eventData, store, eventManager, prevStepId) {
|
|
|
3865
3922
|
}
|
|
3866
3923
|
}
|
|
3867
3924
|
const isStepChange = currentStepId !== prevStepId && currentState === "playing";
|
|
3868
|
-
const
|
|
3869
|
-
const
|
|
3870
|
-
const
|
|
3925
|
+
const isUserInitiatedStepStart = (previousState === "autoplayBlocked" || previousState === "idleMode") && currentState === "playing" && prevStepId === currentStepId;
|
|
3926
|
+
const isFirstPlayOfPlaylist = prevPreviousState === "loading" && previousState === "paused" && currentState === "playing" && currentStepId;
|
|
3927
|
+
const isStartingNode = store.manifest && currentStepId === store.manifest.startStep;
|
|
3928
|
+
const isFirstStepAutoplayAttempt = isStartingNode && isFirstPlayOfPlaylist;
|
|
3929
|
+
const isNonStartingNodeFirstPlay = !isStartingNode && isFirstPlayOfPlaylist;
|
|
3871
3930
|
log("EventUpdater.handleStepEvents: Step started check", {
|
|
3872
3931
|
currentStep: currentStep == null ? void 0 : currentStep.id,
|
|
3873
3932
|
hasManifest: !!store.manifest
|
|
3874
3933
|
});
|
|
3875
|
-
if (
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3934
|
+
if (currentStep && store.manifest) {
|
|
3935
|
+
if (isStepChange || isUserInitiatedStepStart || isNonStartingNodeFirstPlay) {
|
|
3936
|
+
log(`EventUpdater: Triggering stepStarted for ${currentStep.id}`);
|
|
3937
|
+
eventManager.trigger("stepStarted", {
|
|
3938
|
+
timestamp: Date.now(),
|
|
3939
|
+
step: {
|
|
3940
|
+
id: currentStep.id,
|
|
3941
|
+
title: currentStep.title || currentStep.id
|
|
3942
|
+
},
|
|
3943
|
+
playlist: {
|
|
3944
|
+
id: store.manifest.id,
|
|
3945
|
+
title: store.manifest.name
|
|
3946
|
+
}
|
|
3947
|
+
});
|
|
3948
|
+
} else if (isFirstStepAutoplayAttempt) {
|
|
3949
|
+
log(`EventUpdater: Deferring stepStarted for ${currentStep.id} (pending autoplay confirmation)`);
|
|
3950
|
+
pendingStartEvents.stepData = {
|
|
3880
3951
|
id: currentStep.id,
|
|
3881
|
-
title: currentStep.title || currentStep.id
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
}
|
|
3887
|
-
});
|
|
3952
|
+
title: currentStep.title || currentStep.id,
|
|
3953
|
+
playlistId: store.manifest.id,
|
|
3954
|
+
playlistTitle: store.manifest.name
|
|
3955
|
+
};
|
|
3956
|
+
}
|
|
3888
3957
|
}
|
|
3889
3958
|
}
|
|
3890
3959
|
function handleErrorEvents(eventData, store, eventManager) {
|
|
@@ -8960,7 +9029,6 @@ class EventSubscriberManager {
|
|
|
8960
9029
|
}
|
|
8961
9030
|
}
|
|
8962
9031
|
class AnalyticsManager extends EventSubscriberManager {
|
|
8963
|
-
// Default to enabled
|
|
8964
9032
|
/**
|
|
8965
9033
|
* Creates a new AnalyticsManager
|
|
8966
9034
|
* @param eventManager - Optional event manager to subscribe to events
|
|
@@ -8974,6 +9042,8 @@ class AnalyticsManager extends EventSubscriberManager {
|
|
|
8974
9042
|
__publicField(this, "flushInterval", null);
|
|
8975
9043
|
__publicField(this, "sessionId", null);
|
|
8976
9044
|
__publicField(this, "analyticsEnabled", true);
|
|
9045
|
+
// Default to enabled
|
|
9046
|
+
__publicField(this, "boundVisibilityHandler", null);
|
|
8977
9047
|
}
|
|
8978
9048
|
/**
|
|
8979
9049
|
* Subscribe to relevant player events for analytics tracking
|
|
@@ -9060,6 +9130,10 @@ class AnalyticsManager extends EventSubscriberManager {
|
|
|
9060
9130
|
});
|
|
9061
9131
|
}
|
|
9062
9132
|
});
|
|
9133
|
+
this.eventManager.on("playlistStarted", (event) => {
|
|
9134
|
+
log(`AnalyticsManager: Playlist started event received - ${event.playlist.id}`);
|
|
9135
|
+
this.trackPlaylistStart(event.playlist.id);
|
|
9136
|
+
});
|
|
9063
9137
|
}
|
|
9064
9138
|
/**
|
|
9065
9139
|
* Initializes the analytics manager
|
|
@@ -9076,6 +9150,8 @@ class AnalyticsManager extends EventSubscriberManager {
|
|
|
9076
9150
|
this.flushInterval = window.setInterval(() => {
|
|
9077
9151
|
this.flushEvents();
|
|
9078
9152
|
}, ANALYTICS.FLUSH_INTERVAL_MS);
|
|
9153
|
+
this.boundVisibilityHandler = this.handleVisibilityChange.bind(this);
|
|
9154
|
+
document.addEventListener("visibilitychange", this.boundVisibilityHandler);
|
|
9079
9155
|
}
|
|
9080
9156
|
}
|
|
9081
9157
|
/**
|
|
@@ -9272,6 +9348,45 @@ class AnalyticsManager extends EventSubscriberManager {
|
|
|
9272
9348
|
this.isSending = false;
|
|
9273
9349
|
}
|
|
9274
9350
|
}
|
|
9351
|
+
/**
|
|
9352
|
+
* Handles visibility change events to flush analytics when page is hidden
|
|
9353
|
+
* Uses sendBeacon for reliable delivery during page unload
|
|
9354
|
+
*/
|
|
9355
|
+
handleVisibilityChange() {
|
|
9356
|
+
if (document.visibilityState === "hidden") {
|
|
9357
|
+
this.flushWithBeacon();
|
|
9358
|
+
}
|
|
9359
|
+
}
|
|
9360
|
+
/**
|
|
9361
|
+
* Flushes events using sendBeacon API for reliable delivery during page unload
|
|
9362
|
+
* sendBeacon is fire-and-forget and survives page navigation/close
|
|
9363
|
+
*/
|
|
9364
|
+
flushWithBeacon() {
|
|
9365
|
+
if (this.eventQueue.length === 0 || !this.config || !this.analyticsEnabled) {
|
|
9366
|
+
return;
|
|
9367
|
+
}
|
|
9368
|
+
const events = [...this.eventQueue];
|
|
9369
|
+
this.eventQueue = [];
|
|
9370
|
+
const payload = {
|
|
9371
|
+
token: this.config.token,
|
|
9372
|
+
sessionId: this.sessionId,
|
|
9373
|
+
user: this.user,
|
|
9374
|
+
events
|
|
9375
|
+
};
|
|
9376
|
+
try {
|
|
9377
|
+
fetch("https://player.saltfish.ai/analytics", {
|
|
9378
|
+
method: "POST",
|
|
9379
|
+
headers: {
|
|
9380
|
+
"Content-Type": "application/json"
|
|
9381
|
+
},
|
|
9382
|
+
body: JSON.stringify(payload),
|
|
9383
|
+
keepalive: true
|
|
9384
|
+
});
|
|
9385
|
+
} catch (error2) {
|
|
9386
|
+
console.warn("AnalyticsManager: fetch keepalive failed, events returned to queue");
|
|
9387
|
+
this.eventQueue = [...events, ...this.eventQueue];
|
|
9388
|
+
}
|
|
9389
|
+
}
|
|
9275
9390
|
/**
|
|
9276
9391
|
* Cleans up resources used by the analytics manager
|
|
9277
9392
|
*/
|
|
@@ -9283,6 +9398,10 @@ class AnalyticsManager extends EventSubscriberManager {
|
|
|
9283
9398
|
clearInterval(this.flushInterval);
|
|
9284
9399
|
this.flushInterval = null;
|
|
9285
9400
|
}
|
|
9401
|
+
if (this.boundVisibilityHandler) {
|
|
9402
|
+
document.removeEventListener("visibilitychange", this.boundVisibilityHandler);
|
|
9403
|
+
this.boundVisibilityHandler = null;
|
|
9404
|
+
}
|
|
9286
9405
|
if (this.eventManager) {
|
|
9287
9406
|
this.eventManager = null;
|
|
9288
9407
|
}
|
|
@@ -12590,7 +12709,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
|
|
|
12590
12709
|
__proto__: null,
|
|
12591
12710
|
SaltfishPlayer
|
|
12592
12711
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
12593
|
-
const version = "0.3.
|
|
12712
|
+
const version = "0.3.73";
|
|
12594
12713
|
const packageJson = {
|
|
12595
12714
|
version
|
|
12596
12715
|
};
|