saltfish 0.2.52 → 0.2.54
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/core/services/StateMachineActionHandler.d.ts.map +1 -1
- package/dist/core/store.d.ts.map +1 -1
- package/dist/loaders/PlaylistLoader.d.ts +2 -3
- package/dist/loaders/PlaylistLoader.d.ts.map +1 -1
- package/dist/managers/InteractionManager.d.ts +1 -0
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/PlaylistManager.d.ts.map +1 -1
- package/dist/managers/VideoManager.d.ts.map +1 -1
- package/dist/player.js +2 -2
- package/dist/player.min.js +2 -2
- package/dist/saltfish-playlist-player.es.js +397 -298
- package/dist/saltfish-playlist-player.umd.js +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -951,6 +951,280 @@ const playerStateMachineConfig = {
|
|
|
951
951
|
}
|
|
952
952
|
}
|
|
953
953
|
};
|
|
954
|
+
const STORAGE_KEYS = {
|
|
955
|
+
PROGRESS: "saltfish_progress",
|
|
956
|
+
SESSION: "saltfish_session",
|
|
957
|
+
ANONYMOUS_USER: "saltfish_anonymous_user_data"
|
|
958
|
+
};
|
|
959
|
+
const TIMING = {
|
|
960
|
+
// 5 seconds
|
|
961
|
+
STEP_TIMEOUT: 6e4,
|
|
962
|
+
// Session persistence
|
|
963
|
+
SESSION_EXPIRY: 30 * 60 * 1e3
|
|
964
|
+
// 30 minutes in milliseconds
|
|
965
|
+
};
|
|
966
|
+
const API = {
|
|
967
|
+
BASE_URL: "https://player.saltfish.ai",
|
|
968
|
+
ENDPOINTS: {
|
|
969
|
+
VALIDATE_TOKEN: "/validate-token",
|
|
970
|
+
USERS: "/clients/{token}/users/{userId}"
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
const CSS_CLASSES = {
|
|
974
|
+
PLAYER: "sf-player",
|
|
975
|
+
PLAYER_MINIMIZED: "sf-player--minimized",
|
|
976
|
+
CONTROLS_CONTAINER: "sf-controls-container",
|
|
977
|
+
LOGO: "sf-player__logo",
|
|
978
|
+
// Legacy error class
|
|
979
|
+
ERROR_DISPLAY: "sf-error-display",
|
|
980
|
+
ERROR_DISPLAY_VISIBLE: "sf-error-display--visible",
|
|
981
|
+
ERROR_DISPLAY_CONTENT: "sf-error-display__content",
|
|
982
|
+
ERROR_DISPLAY_MESSAGE: "sf-error-display__message",
|
|
983
|
+
LOADING_SPINNER: "sf-loading-spinner"
|
|
984
|
+
};
|
|
985
|
+
class StorageManager {
|
|
986
|
+
constructor() {
|
|
987
|
+
__publicField(this, "isLocalStorageAvailable");
|
|
988
|
+
this.isLocalStorageAvailable = this.checkLocalStorageAvailability();
|
|
989
|
+
if (!this.isLocalStorageAvailable) ;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Check if localStorage is available and working
|
|
993
|
+
*/
|
|
994
|
+
checkLocalStorageAvailability() {
|
|
995
|
+
if (typeof window === "undefined") {
|
|
996
|
+
return false;
|
|
997
|
+
}
|
|
998
|
+
try {
|
|
999
|
+
const testKey = "__storage_test__";
|
|
1000
|
+
localStorage.setItem(testKey, "test");
|
|
1001
|
+
localStorage.removeItem(testKey);
|
|
1002
|
+
return true;
|
|
1003
|
+
} catch (error2) {
|
|
1004
|
+
return false;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Safely get an item from localStorage with JSON parsing
|
|
1009
|
+
*/
|
|
1010
|
+
safeGetItem(key) {
|
|
1011
|
+
if (!this.isLocalStorageAvailable) {
|
|
1012
|
+
return null;
|
|
1013
|
+
}
|
|
1014
|
+
try {
|
|
1015
|
+
const item = localStorage.getItem(key);
|
|
1016
|
+
if (item === null) {
|
|
1017
|
+
return null;
|
|
1018
|
+
}
|
|
1019
|
+
return JSON.parse(item);
|
|
1020
|
+
} catch (error2) {
|
|
1021
|
+
this.safeClearItem(key);
|
|
1022
|
+
return null;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Safely set an item in localStorage with JSON stringification
|
|
1027
|
+
*/
|
|
1028
|
+
safeSetItem(key, value) {
|
|
1029
|
+
if (!this.isLocalStorageAvailable) {
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
1032
|
+
try {
|
|
1033
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
1034
|
+
return true;
|
|
1035
|
+
} catch (error2) {
|
|
1036
|
+
if (error2 instanceof DOMException && error2.code === 22) {
|
|
1037
|
+
this.clearOldData();
|
|
1038
|
+
try {
|
|
1039
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
1040
|
+
return true;
|
|
1041
|
+
} catch (retryError) {
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
return false;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Safely clear an item from localStorage
|
|
1049
|
+
*/
|
|
1050
|
+
safeClearItem(key) {
|
|
1051
|
+
if (!this.isLocalStorageAvailable) {
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
try {
|
|
1055
|
+
localStorage.removeItem(key);
|
|
1056
|
+
} catch (error2) {
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Clear old data to free up storage space
|
|
1061
|
+
*/
|
|
1062
|
+
clearOldData() {
|
|
1063
|
+
this.safeClearItem(STORAGE_KEYS.SESSION);
|
|
1064
|
+
}
|
|
1065
|
+
// =============================================================================
|
|
1066
|
+
// Progress Data Methods
|
|
1067
|
+
// =============================================================================
|
|
1068
|
+
/**
|
|
1069
|
+
* Get playlist progress data for a specific user
|
|
1070
|
+
* If userId doesn't match stored userId, returns null (stale data)
|
|
1071
|
+
* @param userId - The user ID to validate against stored data
|
|
1072
|
+
*/
|
|
1073
|
+
getProgress(userId) {
|
|
1074
|
+
const stored = this.safeGetItem(STORAGE_KEYS.PROGRESS);
|
|
1075
|
+
if (!stored) {
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
if (userId && stored.userId && stored.userId !== userId) {
|
|
1079
|
+
log(`[StorageManager] Progress belongs to different user (${stored.userId}), ignoring`);
|
|
1080
|
+
return null;
|
|
1081
|
+
}
|
|
1082
|
+
return stored.playlists || null;
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Set playlist progress data for a specific user
|
|
1086
|
+
* Clears existing data if userId changes
|
|
1087
|
+
* @param progress - The progress data to save
|
|
1088
|
+
* @param userId - The user ID to associate with this progress
|
|
1089
|
+
*/
|
|
1090
|
+
setProgress(progress, userId) {
|
|
1091
|
+
const stored = {
|
|
1092
|
+
userId,
|
|
1093
|
+
playlists: progress
|
|
1094
|
+
};
|
|
1095
|
+
return this.safeSetItem(STORAGE_KEYS.PROGRESS, stored);
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Clear all progress data
|
|
1099
|
+
*/
|
|
1100
|
+
clearProgress() {
|
|
1101
|
+
this.safeClearItem(STORAGE_KEYS.PROGRESS);
|
|
1102
|
+
}
|
|
1103
|
+
// =============================================================================
|
|
1104
|
+
// Session Data Methods
|
|
1105
|
+
// =============================================================================
|
|
1106
|
+
/**
|
|
1107
|
+
* Get session data
|
|
1108
|
+
*/
|
|
1109
|
+
getSession() {
|
|
1110
|
+
return this.safeGetItem(STORAGE_KEYS.SESSION);
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Set session data
|
|
1114
|
+
*/
|
|
1115
|
+
setSession(session) {
|
|
1116
|
+
return this.safeSetItem(STORAGE_KEYS.SESSION, session);
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Clear session data
|
|
1120
|
+
*/
|
|
1121
|
+
clearSession() {
|
|
1122
|
+
this.safeClearItem(STORAGE_KEYS.SESSION);
|
|
1123
|
+
}
|
|
1124
|
+
// =============================================================================
|
|
1125
|
+
// Anonymous User Data Methods
|
|
1126
|
+
// =============================================================================
|
|
1127
|
+
/**
|
|
1128
|
+
* Get anonymous user data
|
|
1129
|
+
*/
|
|
1130
|
+
getAnonymousUserData() {
|
|
1131
|
+
return this.safeGetItem(STORAGE_KEYS.ANONYMOUS_USER);
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* Set anonymous user data
|
|
1135
|
+
*/
|
|
1136
|
+
setAnonymousUserData(data) {
|
|
1137
|
+
return this.safeSetItem(STORAGE_KEYS.ANONYMOUS_USER, data);
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Clear anonymous user data
|
|
1141
|
+
*/
|
|
1142
|
+
clearAnonymousUserData() {
|
|
1143
|
+
this.safeClearItem(STORAGE_KEYS.ANONYMOUS_USER);
|
|
1144
|
+
}
|
|
1145
|
+
// =============================================================================
|
|
1146
|
+
// Anonymous User ID Methods
|
|
1147
|
+
// =============================================================================
|
|
1148
|
+
/**
|
|
1149
|
+
* Get anonymous user ID
|
|
1150
|
+
*/
|
|
1151
|
+
getAnonymousUserId() {
|
|
1152
|
+
if (!this.isLocalStorageAvailable) {
|
|
1153
|
+
return null;
|
|
1154
|
+
}
|
|
1155
|
+
try {
|
|
1156
|
+
return localStorage.getItem("saltfish_anonymous_user_id");
|
|
1157
|
+
} catch (error2) {
|
|
1158
|
+
return null;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Set anonymous user ID
|
|
1163
|
+
*/
|
|
1164
|
+
setAnonymousUserId(userId) {
|
|
1165
|
+
if (!this.isLocalStorageAvailable) {
|
|
1166
|
+
return false;
|
|
1167
|
+
}
|
|
1168
|
+
try {
|
|
1169
|
+
localStorage.setItem("saltfish_anonymous_user_id", userId);
|
|
1170
|
+
return true;
|
|
1171
|
+
} catch (error2) {
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Clear anonymous user ID
|
|
1177
|
+
*/
|
|
1178
|
+
clearAnonymousUserId() {
|
|
1179
|
+
if (!this.isLocalStorageAvailable) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
try {
|
|
1183
|
+
localStorage.removeItem("saltfish_anonymous_user_id");
|
|
1184
|
+
} catch (error2) {
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
// =============================================================================
|
|
1188
|
+
// Utility Methods
|
|
1189
|
+
// =============================================================================
|
|
1190
|
+
/**
|
|
1191
|
+
* Clear all storage data
|
|
1192
|
+
*/
|
|
1193
|
+
clearAll() {
|
|
1194
|
+
this.clearProgress();
|
|
1195
|
+
this.clearSession();
|
|
1196
|
+
this.clearAnonymousUserData();
|
|
1197
|
+
this.clearAnonymousUserId();
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Get storage availability status
|
|
1201
|
+
*/
|
|
1202
|
+
isStorageAvailable() {
|
|
1203
|
+
return this.isLocalStorageAvailable;
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Get storage usage information (if available)
|
|
1207
|
+
*/
|
|
1208
|
+
getStorageInfo() {
|
|
1209
|
+
const keys = [];
|
|
1210
|
+
if (this.isLocalStorageAvailable) {
|
|
1211
|
+
try {
|
|
1212
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
1213
|
+
const key = localStorage.key(i);
|
|
1214
|
+
if (key && key.startsWith("saltfish_")) {
|
|
1215
|
+
keys.push(key);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
} catch (error2) {
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return {
|
|
1222
|
+
available: this.isLocalStorageAvailable,
|
|
1223
|
+
keys
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
const storageManager = new StorageManager();
|
|
954
1228
|
const createInitialContext = () => ({
|
|
955
1229
|
currentStep: null,
|
|
956
1230
|
error: null
|
|
@@ -1071,7 +1345,7 @@ const saltfishStore = createStore()(
|
|
|
1071
1345
|
if (manifest && manifest.steps.some((step) => step.id === stepId)) {
|
|
1072
1346
|
const targetStep = manifest.steps.find((step) => step.id === stepId);
|
|
1073
1347
|
set2((state) => {
|
|
1074
|
-
var _a;
|
|
1348
|
+
var _a, _b, _c;
|
|
1075
1349
|
state.currentStepId = stepId;
|
|
1076
1350
|
if (targetStep) {
|
|
1077
1351
|
state.currentState = transitionState({
|
|
@@ -1087,6 +1361,11 @@ const saltfishStore = createStore()(
|
|
|
1087
1361
|
lastStepId: stepId,
|
|
1088
1362
|
lastVisited: (/* @__PURE__ */ new Date()).toISOString()
|
|
1089
1363
|
};
|
|
1364
|
+
const playlistPersistence = ((_b = state.playlistOptions) == null ? void 0 : _b.persistence) ?? true;
|
|
1365
|
+
if (playlistPersistence) {
|
|
1366
|
+
const userId = (_c = state.user) == null ? void 0 : _c.id;
|
|
1367
|
+
storageManager.setProgress(state.progress, userId);
|
|
1368
|
+
}
|
|
1090
1369
|
});
|
|
1091
1370
|
}
|
|
1092
1371
|
},
|
|
@@ -1185,6 +1464,7 @@ const saltfishStore = createStore()(
|
|
|
1185
1464
|
// New action to update progress when transitioning to completion waiting state
|
|
1186
1465
|
updateProgressWithCompletion: (playlistId, currentStepId) => {
|
|
1187
1466
|
set2((state) => {
|
|
1467
|
+
var _a, _b;
|
|
1188
1468
|
state.currentState = transitionState({ type: "COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION" });
|
|
1189
1469
|
state.progress[playlistId] = {
|
|
1190
1470
|
...state.progress[playlistId],
|
|
@@ -1192,6 +1472,11 @@ const saltfishStore = createStore()(
|
|
|
1192
1472
|
lastVisited: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1193
1473
|
completedWaitingForInteraction: true
|
|
1194
1474
|
};
|
|
1475
|
+
const playlistPersistence = ((_a = state.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
|
|
1476
|
+
if (playlistPersistence) {
|
|
1477
|
+
const userId = (_b = state.user) == null ? void 0 : _b.id;
|
|
1478
|
+
storageManager.setProgress(state.progress, userId);
|
|
1479
|
+
}
|
|
1195
1480
|
});
|
|
1196
1481
|
},
|
|
1197
1482
|
setABTests: (abTests) => {
|
|
@@ -1232,37 +1517,6 @@ const useSaltfishStore = {
|
|
|
1232
1517
|
subscribe: saltfishStore.subscribe,
|
|
1233
1518
|
destroy: saltfishStore.destroy
|
|
1234
1519
|
};
|
|
1235
|
-
const STORAGE_KEYS = {
|
|
1236
|
-
PROGRESS: "saltfish_progress",
|
|
1237
|
-
SESSION: "saltfish_session",
|
|
1238
|
-
ANONYMOUS_USER: "saltfish_anonymous_user_data"
|
|
1239
|
-
};
|
|
1240
|
-
const TIMING = {
|
|
1241
|
-
// 5 seconds
|
|
1242
|
-
STEP_TIMEOUT: 6e4,
|
|
1243
|
-
// Session persistence
|
|
1244
|
-
SESSION_EXPIRY: 30 * 60 * 1e3
|
|
1245
|
-
// 30 minutes in milliseconds
|
|
1246
|
-
};
|
|
1247
|
-
const API = {
|
|
1248
|
-
BASE_URL: "https://player.saltfish.ai",
|
|
1249
|
-
ENDPOINTS: {
|
|
1250
|
-
VALIDATE_TOKEN: "/validate-token",
|
|
1251
|
-
USERS: "/clients/{token}/users/{userId}"
|
|
1252
|
-
}
|
|
1253
|
-
};
|
|
1254
|
-
const CSS_CLASSES = {
|
|
1255
|
-
PLAYER: "sf-player",
|
|
1256
|
-
PLAYER_MINIMIZED: "sf-player--minimized",
|
|
1257
|
-
CONTROLS_CONTAINER: "sf-controls-container",
|
|
1258
|
-
LOGO: "sf-player__logo",
|
|
1259
|
-
// Legacy error class
|
|
1260
|
-
ERROR_DISPLAY: "sf-error-display",
|
|
1261
|
-
ERROR_DISPLAY_VISIBLE: "sf-error-display--visible",
|
|
1262
|
-
ERROR_DISPLAY_CONTENT: "sf-error-display__content",
|
|
1263
|
-
ERROR_DISPLAY_MESSAGE: "sf-error-display__message",
|
|
1264
|
-
LOADING_SPINNER: "sf-loading-spinner"
|
|
1265
|
-
};
|
|
1266
1520
|
class ErrorHandler {
|
|
1267
1521
|
/**
|
|
1268
1522
|
* Handles an error with consistent logging, reporting, and response
|
|
@@ -2270,7 +2524,7 @@ class PlaylistOrchestrator {
|
|
|
2270
2524
|
* Start a playlist with given options
|
|
2271
2525
|
*/
|
|
2272
2526
|
async startPlaylist(playlistId, options) {
|
|
2273
|
-
var _a, _b, _c;
|
|
2527
|
+
var _a, _b, _c, _d;
|
|
2274
2528
|
try {
|
|
2275
2529
|
const needsManagerRecreation = this.isInitialized() && !this.managers.uiManager.getPlayerElement();
|
|
2276
2530
|
if (!this.isInitialized() && this.playerInitializationService) {
|
|
@@ -2392,11 +2646,35 @@ class PlaylistOrchestrator {
|
|
|
2392
2646
|
}
|
|
2393
2647
|
this.managers.uiManager.updatePosition();
|
|
2394
2648
|
store.sendStateMachineEvent({ type: "LOAD_MANIFEST" });
|
|
2649
|
+
const playlistPersistence = options == null ? void 0 : options.persistence;
|
|
2650
|
+
if (typeof window !== "undefined") {
|
|
2651
|
+
const userId = (_d = store.user) == null ? void 0 : _d.id;
|
|
2652
|
+
const progressFromStorage = this.managers.storageManager.getProgress(userId);
|
|
2653
|
+
if (progressFromStorage && progressFromStorage[playlistId]) {
|
|
2654
|
+
store.loadPlaylistProgress(playlistId, progressFromStorage[playlistId]);
|
|
2655
|
+
} else if (store.progress[playlistId]) {
|
|
2656
|
+
log(`PlaylistOrchestrator: Clearing stale progress for ${playlistId} from store.progress`);
|
|
2657
|
+
const cleanedProgress = { ...store.progress };
|
|
2658
|
+
delete cleanedProgress[playlistId];
|
|
2659
|
+
useSaltfishStore.setState((state) => {
|
|
2660
|
+
state.progress = cleanedProgress;
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2395
2664
|
this.managers.analyticsManager.trackPlaylistStart(playlistId);
|
|
2396
2665
|
this.managers.cursorManager.resetFirstAnimation();
|
|
2397
2666
|
log(`[PlaylistOrchestrator.startPlaylist] Using validated manifest path: ${manifestPathToLoad}`);
|
|
2398
|
-
await this.managers.playlistManager.load(manifestPathToLoad, finalOptions);
|
|
2667
|
+
await this.managers.playlistManager.load(manifestPathToLoad, { ...finalOptions, persistence: playlistPersistence });
|
|
2399
2668
|
const updatedStore = useSaltfishStore.getState();
|
|
2669
|
+
if (updatedStore.manifest) {
|
|
2670
|
+
const manifestPersistence = finalOptions.persistence ?? updatedStore.manifest.isPersistent ?? true;
|
|
2671
|
+
const currentOptions = updatedStore.playlistOptions || {};
|
|
2672
|
+
updatedStore.setPlaylistOptions({
|
|
2673
|
+
...currentOptions,
|
|
2674
|
+
...finalOptions,
|
|
2675
|
+
persistence: manifestPersistence
|
|
2676
|
+
});
|
|
2677
|
+
}
|
|
2400
2678
|
if (finalOptions.startNodeId && updatedStore.manifest) {
|
|
2401
2679
|
const targetStep = updatedStore.manifest.steps.find((step) => step.id === finalOptions.startNodeId);
|
|
2402
2680
|
if (targetStep) {
|
|
@@ -2819,6 +3097,7 @@ class StateMachineActionHandler {
|
|
|
2819
3097
|
}
|
|
2820
3098
|
}
|
|
2821
3099
|
handleTrackPlaylistComplete() {
|
|
3100
|
+
var _a, _b;
|
|
2822
3101
|
const store = useSaltfishStore.getState();
|
|
2823
3102
|
if (store.manifest && this.managers.eventManager) {
|
|
2824
3103
|
const playlistId = store.manifest.id;
|
|
@@ -2829,6 +3108,13 @@ class StateMachineActionHandler {
|
|
|
2829
3108
|
title: store.manifest.name
|
|
2830
3109
|
}
|
|
2831
3110
|
});
|
|
3111
|
+
const playlistPersistence = ((_a = store.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
|
|
3112
|
+
if (playlistPersistence && store.progress[playlistId]) {
|
|
3113
|
+
const updatedProgress = { ...store.progress };
|
|
3114
|
+
delete updatedProgress[playlistId];
|
|
3115
|
+
const userId = (_b = store.user) == null ? void 0 : _b.id;
|
|
3116
|
+
this.managers.storageManager.setProgress(updatedProgress, userId);
|
|
3117
|
+
}
|
|
2832
3118
|
}
|
|
2833
3119
|
}
|
|
2834
3120
|
handleError(context) {
|
|
@@ -4761,6 +5047,7 @@ class VideoManager {
|
|
|
4761
5047
|
* @param url - URL of the video to load
|
|
4762
5048
|
*/
|
|
4763
5049
|
async loadVideo(url) {
|
|
5050
|
+
var _a;
|
|
4764
5051
|
const activeVideo = this.getActiveVideo();
|
|
4765
5052
|
if (!activeVideo) {
|
|
4766
5053
|
return;
|
|
@@ -4777,9 +5064,20 @@ class VideoManager {
|
|
|
4777
5064
|
if (this.controls) {
|
|
4778
5065
|
this.controls.reset();
|
|
4779
5066
|
}
|
|
5067
|
+
const store2 = useSaltfishStore.getState();
|
|
5068
|
+
const isPersistenceEnabled = ((_a = store2.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
|
|
4780
5069
|
if (this.currentVideoUrl === url && activeVideo.src && (activeVideo.src === url || activeVideo.src.endsWith(url))) {
|
|
5070
|
+
if (isPersistenceEnabled) {
|
|
5071
|
+
const savedPosition = this.playbackPositions.get(url);
|
|
5072
|
+
if (savedPosition !== void 0 && savedPosition > 0 && Math.abs(activeVideo.currentTime - savedPosition) > 0.5) {
|
|
5073
|
+
activeVideo.currentTime = savedPosition;
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
4781
5076
|
return;
|
|
4782
5077
|
}
|
|
5078
|
+
if (isPersistenceEnabled && this.currentVideoUrl && activeVideo.currentTime > 0) {
|
|
5079
|
+
this.playbackPositions.set(this.currentVideoUrl, activeVideo.currentTime);
|
|
5080
|
+
}
|
|
4783
5081
|
const inactiveVideo = this.getInactiveVideo();
|
|
4784
5082
|
if (inactiveVideo && this.nextVideoUrl === url) {
|
|
4785
5083
|
this.swapVideos();
|
|
@@ -4826,8 +5124,16 @@ class VideoManager {
|
|
|
4826
5124
|
if (!activeVideo) {
|
|
4827
5125
|
return;
|
|
4828
5126
|
}
|
|
4829
|
-
clearTimeout(loadTimeout);
|
|
4830
|
-
|
|
5127
|
+
clearTimeout(loadTimeout);
|
|
5128
|
+
if (isPersistenceEnabled) {
|
|
5129
|
+
const savedPosition = this.playbackPositions.get(url);
|
|
5130
|
+
if (savedPosition !== void 0 && savedPosition > 0) {
|
|
5131
|
+
const safePosition = Math.min(savedPosition, activeVideo.duration - 0.5);
|
|
5132
|
+
activeVideo.currentTime = safePosition;
|
|
5133
|
+
}
|
|
5134
|
+
} else {
|
|
5135
|
+
activeVideo.currentTime = 0;
|
|
5136
|
+
}
|
|
4831
5137
|
this.transcriptManager.updateVideoElement(activeVideo);
|
|
4832
5138
|
if (this.controls) {
|
|
4833
5139
|
this.controls.updateVideoElement(activeVideo);
|
|
@@ -4916,6 +5222,7 @@ class VideoManager {
|
|
|
4916
5222
|
* Plays the video
|
|
4917
5223
|
*/
|
|
4918
5224
|
play() {
|
|
5225
|
+
var _a;
|
|
4919
5226
|
const activeVideo = this.getActiveVideo();
|
|
4920
5227
|
if (!activeVideo) {
|
|
4921
5228
|
console.error("VideoManager: No active video element found");
|
|
@@ -4928,6 +5235,14 @@ class VideoManager {
|
|
|
4928
5235
|
if (activeVideo.ended) {
|
|
4929
5236
|
activeVideo.currentTime = 0;
|
|
4930
5237
|
}
|
|
5238
|
+
const store = useSaltfishStore.getState();
|
|
5239
|
+
const isPersistenceEnabled = ((_a = store.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
|
|
5240
|
+
if (isPersistenceEnabled && this.currentVideoUrl) {
|
|
5241
|
+
const savedPosition = this.playbackPositions.get(this.currentVideoUrl);
|
|
5242
|
+
if (savedPosition && Math.abs(activeVideo.currentTime - savedPosition) > 0.5) {
|
|
5243
|
+
activeVideo.currentTime = savedPosition;
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
4931
5246
|
activeVideo.loop = false;
|
|
4932
5247
|
if (!activeVideo.paused) {
|
|
4933
5248
|
if (this.controls) {
|
|
@@ -4944,7 +5259,6 @@ class VideoManager {
|
|
|
4944
5259
|
this.controls.startProgressTracking();
|
|
4945
5260
|
}
|
|
4946
5261
|
} else {
|
|
4947
|
-
const store = useSaltfishStore.getState();
|
|
4948
5262
|
store.setAutoplayFallback();
|
|
4949
5263
|
if (this.isMobileDevice()) {
|
|
4950
5264
|
activeVideo.playsInline = true;
|
|
@@ -4960,8 +5274,8 @@ class VideoManager {
|
|
|
4960
5274
|
}
|
|
4961
5275
|
}).catch(() => {
|
|
4962
5276
|
console.warn("VideoManager: Autoplay handler threw error - browser has strict autoplay policy");
|
|
4963
|
-
const
|
|
4964
|
-
|
|
5277
|
+
const store2 = useSaltfishStore.getState();
|
|
5278
|
+
store2.setAutoplayFallback();
|
|
4965
5279
|
});
|
|
4966
5280
|
}
|
|
4967
5281
|
/**
|
|
@@ -6439,6 +6753,7 @@ class InteractionManager {
|
|
|
6439
6753
|
__publicField(this, "scrollIndicator", null);
|
|
6440
6754
|
__publicField(this, "domEventListeners", /* @__PURE__ */ new Map());
|
|
6441
6755
|
__publicField(this, "storeUnsubscribe", null);
|
|
6756
|
+
__publicField(this, "storageManager", new StorageManager());
|
|
6442
6757
|
/**
|
|
6443
6758
|
* Handles the video90PercentReached event
|
|
6444
6759
|
* @param _event - The custom event dispatched when video reaches 90%
|
|
@@ -6658,6 +6973,7 @@ class InteractionManager {
|
|
|
6658
6973
|
* @param buttonConfig - The button configuration
|
|
6659
6974
|
*/
|
|
6660
6975
|
async handleButtonClick(event, buttonConfig) {
|
|
6976
|
+
var _a, _b;
|
|
6661
6977
|
log(`InteractionManager: Button click detected on button "${buttonConfig.id}"`);
|
|
6662
6978
|
event.preventDefault();
|
|
6663
6979
|
event.stopPropagation();
|
|
@@ -6682,6 +6998,13 @@ class InteractionManager {
|
|
|
6682
6998
|
};
|
|
6683
6999
|
}
|
|
6684
7000
|
});
|
|
7001
|
+
const playlistPersistence = ((_a = currentStore.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
|
|
7002
|
+
if (playlistPersistence) {
|
|
7003
|
+
const userId = (_b = currentStore.user) == null ? void 0 : _b.id;
|
|
7004
|
+
const updatedStore = useSaltfishStore.getState();
|
|
7005
|
+
this.storageManager.setProgress(updatedStore.progress, userId);
|
|
7006
|
+
log(`InteractionManager: Saved progress for step ${buttonConfig.action.target} before URL redirect`);
|
|
7007
|
+
}
|
|
6685
7008
|
}
|
|
6686
7009
|
log(`InteractionManager: Redirecting to ${buttonConfig.action.url}`);
|
|
6687
7010
|
window.location.href = buttonConfig.action.url;
|
|
@@ -7199,254 +7522,12 @@ class AnalyticsManager {
|
|
|
7199
7522
|
}
|
|
7200
7523
|
}
|
|
7201
7524
|
}
|
|
7202
|
-
class StorageManager {
|
|
7203
|
-
constructor() {
|
|
7204
|
-
__publicField(this, "isLocalStorageAvailable");
|
|
7205
|
-
this.isLocalStorageAvailable = this.checkLocalStorageAvailability();
|
|
7206
|
-
if (!this.isLocalStorageAvailable) ;
|
|
7207
|
-
}
|
|
7208
|
-
/**
|
|
7209
|
-
* Check if localStorage is available and working
|
|
7210
|
-
*/
|
|
7211
|
-
checkLocalStorageAvailability() {
|
|
7212
|
-
if (typeof window === "undefined") {
|
|
7213
|
-
return false;
|
|
7214
|
-
}
|
|
7215
|
-
try {
|
|
7216
|
-
const testKey = "__storage_test__";
|
|
7217
|
-
localStorage.setItem(testKey, "test");
|
|
7218
|
-
localStorage.removeItem(testKey);
|
|
7219
|
-
return true;
|
|
7220
|
-
} catch (error2) {
|
|
7221
|
-
return false;
|
|
7222
|
-
}
|
|
7223
|
-
}
|
|
7224
|
-
/**
|
|
7225
|
-
* Safely get an item from localStorage with JSON parsing
|
|
7226
|
-
*/
|
|
7227
|
-
safeGetItem(key) {
|
|
7228
|
-
if (!this.isLocalStorageAvailable) {
|
|
7229
|
-
return null;
|
|
7230
|
-
}
|
|
7231
|
-
try {
|
|
7232
|
-
const item = localStorage.getItem(key);
|
|
7233
|
-
if (item === null) {
|
|
7234
|
-
return null;
|
|
7235
|
-
}
|
|
7236
|
-
return JSON.parse(item);
|
|
7237
|
-
} catch (error2) {
|
|
7238
|
-
this.safeClearItem(key);
|
|
7239
|
-
return null;
|
|
7240
|
-
}
|
|
7241
|
-
}
|
|
7242
|
-
/**
|
|
7243
|
-
* Safely set an item in localStorage with JSON stringification
|
|
7244
|
-
*/
|
|
7245
|
-
safeSetItem(key, value) {
|
|
7246
|
-
if (!this.isLocalStorageAvailable) {
|
|
7247
|
-
return false;
|
|
7248
|
-
}
|
|
7249
|
-
try {
|
|
7250
|
-
localStorage.setItem(key, JSON.stringify(value));
|
|
7251
|
-
return true;
|
|
7252
|
-
} catch (error2) {
|
|
7253
|
-
if (error2 instanceof DOMException && error2.code === 22) {
|
|
7254
|
-
this.clearOldData();
|
|
7255
|
-
try {
|
|
7256
|
-
localStorage.setItem(key, JSON.stringify(value));
|
|
7257
|
-
return true;
|
|
7258
|
-
} catch (retryError) {
|
|
7259
|
-
}
|
|
7260
|
-
}
|
|
7261
|
-
return false;
|
|
7262
|
-
}
|
|
7263
|
-
}
|
|
7264
|
-
/**
|
|
7265
|
-
* Safely clear an item from localStorage
|
|
7266
|
-
*/
|
|
7267
|
-
safeClearItem(key) {
|
|
7268
|
-
if (!this.isLocalStorageAvailable) {
|
|
7269
|
-
return;
|
|
7270
|
-
}
|
|
7271
|
-
try {
|
|
7272
|
-
localStorage.removeItem(key);
|
|
7273
|
-
} catch (error2) {
|
|
7274
|
-
}
|
|
7275
|
-
}
|
|
7276
|
-
/**
|
|
7277
|
-
* Clear old data to free up storage space
|
|
7278
|
-
*/
|
|
7279
|
-
clearOldData() {
|
|
7280
|
-
this.safeClearItem(STORAGE_KEYS.SESSION);
|
|
7281
|
-
}
|
|
7282
|
-
// =============================================================================
|
|
7283
|
-
// Progress Data Methods
|
|
7284
|
-
// =============================================================================
|
|
7285
|
-
/**
|
|
7286
|
-
* Get playlist progress data for a specific user
|
|
7287
|
-
* If userId doesn't match stored userId, returns null (stale data)
|
|
7288
|
-
* @param userId - The user ID to validate against stored data
|
|
7289
|
-
*/
|
|
7290
|
-
getProgress(userId) {
|
|
7291
|
-
const stored = this.safeGetItem(STORAGE_KEYS.PROGRESS);
|
|
7292
|
-
if (!stored) {
|
|
7293
|
-
return null;
|
|
7294
|
-
}
|
|
7295
|
-
if (userId && stored.userId && stored.userId !== userId) {
|
|
7296
|
-
log(`[StorageManager] Progress belongs to different user (${stored.userId}), ignoring`);
|
|
7297
|
-
return null;
|
|
7298
|
-
}
|
|
7299
|
-
return stored.playlists || null;
|
|
7300
|
-
}
|
|
7301
|
-
/**
|
|
7302
|
-
* Set playlist progress data for a specific user
|
|
7303
|
-
* Clears existing data if userId changes
|
|
7304
|
-
* @param progress - The progress data to save
|
|
7305
|
-
* @param userId - The user ID to associate with this progress
|
|
7306
|
-
*/
|
|
7307
|
-
setProgress(progress, userId) {
|
|
7308
|
-
const stored = {
|
|
7309
|
-
userId,
|
|
7310
|
-
playlists: progress
|
|
7311
|
-
};
|
|
7312
|
-
return this.safeSetItem(STORAGE_KEYS.PROGRESS, stored);
|
|
7313
|
-
}
|
|
7314
|
-
/**
|
|
7315
|
-
* Clear all progress data
|
|
7316
|
-
*/
|
|
7317
|
-
clearProgress() {
|
|
7318
|
-
this.safeClearItem(STORAGE_KEYS.PROGRESS);
|
|
7319
|
-
}
|
|
7320
|
-
// =============================================================================
|
|
7321
|
-
// Session Data Methods
|
|
7322
|
-
// =============================================================================
|
|
7323
|
-
/**
|
|
7324
|
-
* Get session data
|
|
7325
|
-
*/
|
|
7326
|
-
getSession() {
|
|
7327
|
-
return this.safeGetItem(STORAGE_KEYS.SESSION);
|
|
7328
|
-
}
|
|
7329
|
-
/**
|
|
7330
|
-
* Set session data
|
|
7331
|
-
*/
|
|
7332
|
-
setSession(session) {
|
|
7333
|
-
return this.safeSetItem(STORAGE_KEYS.SESSION, session);
|
|
7334
|
-
}
|
|
7335
|
-
/**
|
|
7336
|
-
* Clear session data
|
|
7337
|
-
*/
|
|
7338
|
-
clearSession() {
|
|
7339
|
-
this.safeClearItem(STORAGE_KEYS.SESSION);
|
|
7340
|
-
}
|
|
7341
|
-
// =============================================================================
|
|
7342
|
-
// Anonymous User Data Methods
|
|
7343
|
-
// =============================================================================
|
|
7344
|
-
/**
|
|
7345
|
-
* Get anonymous user data
|
|
7346
|
-
*/
|
|
7347
|
-
getAnonymousUserData() {
|
|
7348
|
-
return this.safeGetItem(STORAGE_KEYS.ANONYMOUS_USER);
|
|
7349
|
-
}
|
|
7350
|
-
/**
|
|
7351
|
-
* Set anonymous user data
|
|
7352
|
-
*/
|
|
7353
|
-
setAnonymousUserData(data) {
|
|
7354
|
-
return this.safeSetItem(STORAGE_KEYS.ANONYMOUS_USER, data);
|
|
7355
|
-
}
|
|
7356
|
-
/**
|
|
7357
|
-
* Clear anonymous user data
|
|
7358
|
-
*/
|
|
7359
|
-
clearAnonymousUserData() {
|
|
7360
|
-
this.safeClearItem(STORAGE_KEYS.ANONYMOUS_USER);
|
|
7361
|
-
}
|
|
7362
|
-
// =============================================================================
|
|
7363
|
-
// Anonymous User ID Methods
|
|
7364
|
-
// =============================================================================
|
|
7365
|
-
/**
|
|
7366
|
-
* Get anonymous user ID
|
|
7367
|
-
*/
|
|
7368
|
-
getAnonymousUserId() {
|
|
7369
|
-
if (!this.isLocalStorageAvailable) {
|
|
7370
|
-
return null;
|
|
7371
|
-
}
|
|
7372
|
-
try {
|
|
7373
|
-
return localStorage.getItem("saltfish_anonymous_user_id");
|
|
7374
|
-
} catch (error2) {
|
|
7375
|
-
return null;
|
|
7376
|
-
}
|
|
7377
|
-
}
|
|
7378
|
-
/**
|
|
7379
|
-
* Set anonymous user ID
|
|
7380
|
-
*/
|
|
7381
|
-
setAnonymousUserId(userId) {
|
|
7382
|
-
if (!this.isLocalStorageAvailable) {
|
|
7383
|
-
return false;
|
|
7384
|
-
}
|
|
7385
|
-
try {
|
|
7386
|
-
localStorage.setItem("saltfish_anonymous_user_id", userId);
|
|
7387
|
-
return true;
|
|
7388
|
-
} catch (error2) {
|
|
7389
|
-
return false;
|
|
7390
|
-
}
|
|
7391
|
-
}
|
|
7392
|
-
/**
|
|
7393
|
-
* Clear anonymous user ID
|
|
7394
|
-
*/
|
|
7395
|
-
clearAnonymousUserId() {
|
|
7396
|
-
if (!this.isLocalStorageAvailable) {
|
|
7397
|
-
return;
|
|
7398
|
-
}
|
|
7399
|
-
try {
|
|
7400
|
-
localStorage.removeItem("saltfish_anonymous_user_id");
|
|
7401
|
-
} catch (error2) {
|
|
7402
|
-
}
|
|
7403
|
-
}
|
|
7404
|
-
// =============================================================================
|
|
7405
|
-
// Utility Methods
|
|
7406
|
-
// =============================================================================
|
|
7407
|
-
/**
|
|
7408
|
-
* Clear all storage data
|
|
7409
|
-
*/
|
|
7410
|
-
clearAll() {
|
|
7411
|
-
this.clearProgress();
|
|
7412
|
-
this.clearSession();
|
|
7413
|
-
this.clearAnonymousUserData();
|
|
7414
|
-
this.clearAnonymousUserId();
|
|
7415
|
-
}
|
|
7416
|
-
/**
|
|
7417
|
-
* Get storage availability status
|
|
7418
|
-
*/
|
|
7419
|
-
isStorageAvailable() {
|
|
7420
|
-
return this.isLocalStorageAvailable;
|
|
7421
|
-
}
|
|
7422
|
-
/**
|
|
7423
|
-
* Get storage usage information (if available)
|
|
7424
|
-
*/
|
|
7425
|
-
getStorageInfo() {
|
|
7426
|
-
const keys = [];
|
|
7427
|
-
if (this.isLocalStorageAvailable) {
|
|
7428
|
-
try {
|
|
7429
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
7430
|
-
const key = localStorage.key(i);
|
|
7431
|
-
if (key && key.startsWith("saltfish_")) {
|
|
7432
|
-
keys.push(key);
|
|
7433
|
-
}
|
|
7434
|
-
}
|
|
7435
|
-
} catch (error2) {
|
|
7436
|
-
}
|
|
7437
|
-
}
|
|
7438
|
-
return {
|
|
7439
|
-
available: this.isLocalStorageAvailable,
|
|
7440
|
-
keys
|
|
7441
|
-
};
|
|
7442
|
-
}
|
|
7443
|
-
}
|
|
7444
7525
|
class SessionManager {
|
|
7445
|
-
constructor(
|
|
7526
|
+
constructor(storageManager2) {
|
|
7446
7527
|
__publicField(this, "sessionId");
|
|
7447
7528
|
__publicField(this, "currentRunId", null);
|
|
7448
7529
|
__publicField(this, "storageManager");
|
|
7449
|
-
this.storageManager =
|
|
7530
|
+
this.storageManager = storageManager2 || new StorageManager();
|
|
7450
7531
|
this.sessionId = this.getOrCreateSession();
|
|
7451
7532
|
log(`SessionManager: Initialized with sessionId: ${this.sessionId}`);
|
|
7452
7533
|
}
|
|
@@ -8768,11 +8849,11 @@ class PlaylistLoader {
|
|
|
8768
8849
|
* @returns Promise resolving to manifest and determined start step
|
|
8769
8850
|
*/
|
|
8770
8851
|
async loadManifest(options) {
|
|
8771
|
-
const { manifestPath, playlistOptions } = options;
|
|
8852
|
+
const { manifestPath, playlistOptions, savedProgress } = options;
|
|
8772
8853
|
try {
|
|
8773
8854
|
const manifest = await this.fetchManifest(manifestPath);
|
|
8774
8855
|
this.validateManifest(manifest);
|
|
8775
|
-
const startStepId = this.determineStartStep(manifest, playlistOptions);
|
|
8856
|
+
const startStepId = this.determineStartStep(manifest, playlistOptions, savedProgress);
|
|
8776
8857
|
log(`PlaylistLoader: Successfully loaded manifest '${manifest.id}' with start step '${startStepId}'`);
|
|
8777
8858
|
return {
|
|
8778
8859
|
manifest,
|
|
@@ -8858,14 +8939,15 @@ class PlaylistLoader {
|
|
|
8858
8939
|
}
|
|
8859
8940
|
}
|
|
8860
8941
|
/**
|
|
8861
|
-
* Determines which step to start from based on
|
|
8862
|
-
* Note: Persistence has been removed - playlists always start from beginning unless startNodeId is specified
|
|
8863
|
-
* The 4-second rule in PlayerInitializationService handles immediate resume during page transitions
|
|
8942
|
+
* Determines which step to start from based on persistence and saved progress
|
|
8864
8943
|
* @param manifest - The loaded playlist manifest
|
|
8865
8944
|
* @param options - Playlist configuration options
|
|
8945
|
+
* @param savedProgress - Previously saved progress data
|
|
8866
8946
|
* @returns The step ID to start from
|
|
8867
8947
|
*/
|
|
8868
|
-
determineStartStep(manifest, options) {
|
|
8948
|
+
determineStartStep(manifest, options, savedProgress) {
|
|
8949
|
+
const isPersistenceEnabled = options.persistence ?? manifest.isPersistent ?? true;
|
|
8950
|
+
const manifestIdForProgress = manifest.id;
|
|
8869
8951
|
let startStepId = manifest.startStep;
|
|
8870
8952
|
if (options.startNodeId) {
|
|
8871
8953
|
const customStep = manifest.steps.find((step) => step.id === options.startNodeId);
|
|
@@ -8875,6 +8957,19 @@ class PlaylistLoader {
|
|
|
8875
8957
|
} else {
|
|
8876
8958
|
log(`PlaylistLoader: Custom start node '${options.startNodeId}' not found, using default start step`);
|
|
8877
8959
|
}
|
|
8960
|
+
} else if (isPersistenceEnabled && savedProgress && savedProgress[manifestIdForProgress]) {
|
|
8961
|
+
const progressData = savedProgress[manifestIdForProgress];
|
|
8962
|
+
if (progressData.status === "completed") {
|
|
8963
|
+
startStepId = manifest.startStep;
|
|
8964
|
+
} else {
|
|
8965
|
+
const lastStepId = progressData.currentStepId || progressData.lastStepId;
|
|
8966
|
+
if (lastStepId) {
|
|
8967
|
+
const savedStep = manifest.steps.find((step) => step.id === lastStepId);
|
|
8968
|
+
if (savedStep) {
|
|
8969
|
+
startStepId = lastStepId;
|
|
8970
|
+
}
|
|
8971
|
+
}
|
|
8972
|
+
}
|
|
8878
8973
|
}
|
|
8879
8974
|
return startStepId;
|
|
8880
8975
|
}
|
|
@@ -8885,13 +8980,13 @@ class PlaylistManager {
|
|
|
8885
8980
|
* @param eventManager - Optional event manager to subscribe to events
|
|
8886
8981
|
* @param storageManager - Optional storage manager for localStorage operations
|
|
8887
8982
|
*/
|
|
8888
|
-
constructor(eventManager,
|
|
8983
|
+
constructor(eventManager, storageManager2) {
|
|
8889
8984
|
__publicField(this, "eventManager", null);
|
|
8890
8985
|
__publicField(this, "isUpdatingWatchedPlaylists", false);
|
|
8891
8986
|
__publicField(this, "playlistLoader");
|
|
8892
8987
|
__publicField(this, "storageManager");
|
|
8893
8988
|
this.playlistLoader = new PlaylistLoader();
|
|
8894
|
-
this.storageManager =
|
|
8989
|
+
this.storageManager = storageManager2 || new StorageManager();
|
|
8895
8990
|
if (eventManager) {
|
|
8896
8991
|
this.setEventManager(eventManager);
|
|
8897
8992
|
}
|
|
@@ -8962,7 +9057,8 @@ class PlaylistManager {
|
|
|
8962
9057
|
const currentWatchedPlaylists = currentUserData.watchedPlaylists || {};
|
|
8963
9058
|
const updatedPlaylistData = {
|
|
8964
9059
|
status,
|
|
8965
|
-
|
|
9060
|
+
// Don't save currentStepId for completed playlists - they should restart from beginning
|
|
9061
|
+
currentStepId: status === "completed" ? null : currentStepId || store.currentStepId || null,
|
|
8966
9062
|
timestamp: Date.now(),
|
|
8967
9063
|
// Use timestamp for consistency with checkAndResumeInProgressPlaylist
|
|
8968
9064
|
lastProgressAt: Date.now()
|
|
@@ -9042,12 +9138,15 @@ class PlaylistManager {
|
|
|
9042
9138
|
* @param options - Playlist configuration options
|
|
9043
9139
|
*/
|
|
9044
9140
|
async load(playlistId, options) {
|
|
9141
|
+
var _a, _b;
|
|
9045
9142
|
try {
|
|
9046
9143
|
const store = useSaltfishStore.getState();
|
|
9144
|
+
const isAnonymous = ((_a = store.user) == null ? void 0 : _a.__isAnonymous) === true;
|
|
9145
|
+
const savedProgress = isAnonymous ? store.progress : ((_b = store.userData) == null ? void 0 : _b.watchedPlaylists) || store.progress;
|
|
9047
9146
|
const loadResult = await this.playlistLoader.loadManifest({
|
|
9048
9147
|
manifestPath: playlistId,
|
|
9049
9148
|
playlistOptions: options,
|
|
9050
|
-
savedProgress
|
|
9149
|
+
savedProgress
|
|
9051
9150
|
});
|
|
9052
9151
|
const { manifest, startStepId } = loadResult;
|
|
9053
9152
|
const firstStep = manifest.steps.find((step) => step.id === startStepId);
|
|
@@ -9973,13 +10072,13 @@ class ManagerFactory {
|
|
|
9973
10072
|
* Create all manager instances with proper dependencies
|
|
9974
10073
|
*/
|
|
9975
10074
|
createManagers() {
|
|
9976
|
-
const
|
|
9977
|
-
const sessionManager = new SessionManager(
|
|
10075
|
+
const storageManager2 = new StorageManager();
|
|
10076
|
+
const sessionManager = new SessionManager(storageManager2);
|
|
9978
10077
|
const shadowDOMManager = new ShadowDOMManager();
|
|
9979
10078
|
const videoManager = new VideoManager();
|
|
9980
10079
|
const eventManager = new EventManager();
|
|
9981
10080
|
const analyticsManager = new AnalyticsManager(eventManager);
|
|
9982
|
-
const playlistManager = new PlaylistManager(eventManager,
|
|
10081
|
+
const playlistManager = new PlaylistManager(eventManager, storageManager2);
|
|
9983
10082
|
const abTestManager = new ABTestManager(eventManager);
|
|
9984
10083
|
const cursorManager = new CursorManager();
|
|
9985
10084
|
const interactionManager = new InteractionManager();
|
|
@@ -10003,7 +10102,7 @@ class ManagerFactory {
|
|
|
10003
10102
|
playlistManager,
|
|
10004
10103
|
stepTimeoutManager,
|
|
10005
10104
|
uiManager,
|
|
10006
|
-
storageManager
|
|
10105
|
+
storageManager: storageManager2
|
|
10007
10106
|
};
|
|
10008
10107
|
return managers;
|
|
10009
10108
|
}
|
|
@@ -10224,7 +10323,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
|
|
|
10224
10323
|
__proto__: null,
|
|
10225
10324
|
SaltfishPlayer
|
|
10226
10325
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
10227
|
-
const version = "0.2.
|
|
10326
|
+
const version = "0.2.54";
|
|
10228
10327
|
const packageJson = {
|
|
10229
10328
|
version
|
|
10230
10329
|
};
|