musora-content-services 1.0.147 → 1.0.150
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/CHANGELOG.md +6 -0
- package/docs/config.js.html +2 -2
- package/docs/index.html +2 -2
- package/docs/module-Config.html +2 -2
- package/docs/module-Railcontent-Services.html +2593 -221
- package/docs/module-Sanity-Services.html +30 -30
- package/docs/railcontent.js.html +308 -5
- package/docs/sanity.js.html +7 -3
- package/link_mcs.sh +0 -0
- package/package.json +1 -1
- package/src/contentTypeConfig.js +3 -0
- package/src/index.d.ts +61 -4
- package/src/index.js +61 -4
- package/src/services/contentLikes.js +11 -11
- package/src/services/contentProgress.js +153 -0
- package/src/services/dataContext.js +3 -2
- package/src/services/railcontent.js +363 -6
- package/src/services/sanity.js +74 -0
- package/test/contentLikes.test.js +1 -1
- package/test/contentProgress.test.js +56 -0
- package/test/sanityQueryService.test.js +84 -49
package/src/index.js
CHANGED
|
@@ -12,6 +12,20 @@ import {
|
|
|
12
12
|
} from './services/contentLikes.js';
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
+
contentStatusCompleted,
|
|
16
|
+
contentStatusReset,
|
|
17
|
+
contentStatusStarted,
|
|
18
|
+
getProgressPercentage,
|
|
19
|
+
getProgressState,
|
|
20
|
+
getResumeTimeSeconds,
|
|
21
|
+
recordWatchSession
|
|
22
|
+
} from './services/contentProgress.js';
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
createPlaylist,
|
|
26
|
+
deletePlaylist,
|
|
27
|
+
deletePlaylistLike,
|
|
28
|
+
duplicatePlaylist,
|
|
15
29
|
fetchAllCompletedStates,
|
|
16
30
|
fetchChallengeLessonData,
|
|
17
31
|
fetchChallengeMetadata,
|
|
@@ -19,17 +33,31 @@ import {
|
|
|
19
33
|
fetchCompletedState,
|
|
20
34
|
fetchContentInProgress,
|
|
21
35
|
fetchContentPageUserData,
|
|
36
|
+
fetchContentProgress,
|
|
22
37
|
fetchHandler,
|
|
38
|
+
fetchPlaylist,
|
|
39
|
+
fetchPlaylistItems,
|
|
23
40
|
fetchSongsInProgress,
|
|
24
41
|
fetchUserAward,
|
|
25
42
|
fetchUserChallengeProgress,
|
|
43
|
+
fetchUserLikes,
|
|
26
44
|
fetchUserPermissions,
|
|
45
|
+
fetchUserPlaylists,
|
|
46
|
+
likePlaylist,
|
|
27
47
|
postChallengesCommunityNotification,
|
|
28
48
|
postChallengesEnroll,
|
|
29
49
|
postChallengesEnrollmentNotification,
|
|
30
50
|
postChallengesLeave,
|
|
31
51
|
postChallengesSetStartDate,
|
|
32
|
-
postChallengesUnlock
|
|
52
|
+
postChallengesUnlock,
|
|
53
|
+
postContentCompleted,
|
|
54
|
+
postContentLiked,
|
|
55
|
+
postContentReset,
|
|
56
|
+
postContentStarted,
|
|
57
|
+
postContentUnliked,
|
|
58
|
+
postRecordWatchSession,
|
|
59
|
+
updatePlaylist,
|
|
60
|
+
updatePlaylistItem
|
|
33
61
|
} from './services/railcontent.js';
|
|
34
62
|
|
|
35
63
|
import {
|
|
@@ -49,6 +77,7 @@ import {
|
|
|
49
77
|
fetchCourseOverview,
|
|
50
78
|
fetchFoundation,
|
|
51
79
|
fetchGenreLessons,
|
|
80
|
+
fetchHierarchy,
|
|
52
81
|
fetchLessonContent,
|
|
53
82
|
fetchLiveEvent,
|
|
54
83
|
fetchMetadata,
|
|
@@ -64,6 +93,7 @@ import {
|
|
|
64
93
|
fetchPackChildren,
|
|
65
94
|
fetchPackData,
|
|
66
95
|
fetchParentByRailContentId,
|
|
96
|
+
fetchParentForDownload,
|
|
67
97
|
fetchRelatedLessons,
|
|
68
98
|
fetchRelatedMethodLessons,
|
|
69
99
|
fetchRelatedSongs,
|
|
@@ -74,13 +104,20 @@ import {
|
|
|
74
104
|
fetchSongById,
|
|
75
105
|
fetchSongCount,
|
|
76
106
|
fetchSongFilterOptions,
|
|
107
|
+
fetchTopLevelParentId,
|
|
77
108
|
fetchUpcomingEvents,
|
|
78
109
|
fetchWorkouts,
|
|
79
|
-
getSortOrder
|
|
80
|
-
fetchParentForDownload,
|
|
110
|
+
getSortOrder
|
|
81
111
|
} from './services/sanity.js';
|
|
82
112
|
|
|
83
113
|
export {
|
|
114
|
+
contentStatusCompleted,
|
|
115
|
+
contentStatusReset,
|
|
116
|
+
contentStatusStarted,
|
|
117
|
+
createPlaylist,
|
|
118
|
+
deletePlaylist,
|
|
119
|
+
deletePlaylistLike,
|
|
120
|
+
duplicatePlaylist,
|
|
84
121
|
fetchAll,
|
|
85
122
|
fetchAllCompletedStates,
|
|
86
123
|
fetchAllFilterOptions,
|
|
@@ -101,10 +138,12 @@ export {
|
|
|
101
138
|
fetchCompletedState,
|
|
102
139
|
fetchContentInProgress,
|
|
103
140
|
fetchContentPageUserData,
|
|
141
|
+
fetchContentProgress,
|
|
104
142
|
fetchCourseOverview,
|
|
105
143
|
fetchFoundation,
|
|
106
144
|
fetchGenreLessons,
|
|
107
145
|
fetchHandler,
|
|
146
|
+
fetchHierarchy,
|
|
108
147
|
fetchLessonContent,
|
|
109
148
|
fetchLiveEvent,
|
|
110
149
|
fetchMetadata,
|
|
@@ -120,6 +159,9 @@ export {
|
|
|
120
159
|
fetchPackChildren,
|
|
121
160
|
fetchPackData,
|
|
122
161
|
fetchParentByRailContentId,
|
|
162
|
+
fetchParentForDownload,
|
|
163
|
+
fetchPlaylist,
|
|
164
|
+
fetchPlaylistItems,
|
|
123
165
|
fetchRelatedLessons,
|
|
124
166
|
fetchRelatedMethodLessons,
|
|
125
167
|
fetchRelatedSongs,
|
|
@@ -131,22 +173,37 @@ export {
|
|
|
131
173
|
fetchSongCount,
|
|
132
174
|
fetchSongFilterOptions,
|
|
133
175
|
fetchSongsInProgress,
|
|
176
|
+
fetchTopLevelParentId,
|
|
134
177
|
fetchUpcomingEvents,
|
|
135
178
|
fetchUserAward,
|
|
136
179
|
fetchUserChallengeProgress,
|
|
180
|
+
fetchUserLikes,
|
|
137
181
|
fetchUserPermissions,
|
|
182
|
+
fetchUserPlaylists,
|
|
138
183
|
fetchWorkouts,
|
|
184
|
+
getProgressPercentage,
|
|
185
|
+
getProgressState,
|
|
186
|
+
getResumeTimeSeconds,
|
|
139
187
|
getSortOrder,
|
|
140
188
|
globalConfig,
|
|
141
189
|
initializeService,
|
|
142
190
|
isContentLiked,
|
|
143
191
|
likeContent,
|
|
192
|
+
likePlaylist,
|
|
144
193
|
postChallengesCommunityNotification,
|
|
145
194
|
postChallengesEnroll,
|
|
146
195
|
postChallengesEnrollmentNotification,
|
|
147
196
|
postChallengesLeave,
|
|
148
197
|
postChallengesSetStartDate,
|
|
149
198
|
postChallengesUnlock,
|
|
199
|
+
postContentCompleted,
|
|
200
|
+
postContentLiked,
|
|
201
|
+
postContentReset,
|
|
202
|
+
postContentStarted,
|
|
203
|
+
postContentUnliked,
|
|
204
|
+
postRecordWatchSession,
|
|
205
|
+
recordWatchSession,
|
|
150
206
|
unlikeContent,
|
|
151
|
-
|
|
207
|
+
updatePlaylist,
|
|
208
|
+
updatePlaylistItem,
|
|
152
209
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {fetchUserLikes, postContentLiked, postContentUnliked} from "./railcontent";
|
|
2
|
-
import {DataContext,
|
|
2
|
+
import {DataContext, ContentLikesVersionKey} from "./dataContext";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Exported functions that are excluded from index generation.
|
|
@@ -8,7 +8,7 @@ import {DataContext, ContentVersionKey} from "./dataContext";
|
|
|
8
8
|
*/
|
|
9
9
|
const excludeFromGeneratedIndex = [];
|
|
10
10
|
|
|
11
|
-
export let dataContext = new DataContext(
|
|
11
|
+
export let dataContext = new DataContext(ContentLikesVersionKey, fetchUserLikes);
|
|
12
12
|
|
|
13
13
|
export async function isContentLiked(contentId) {
|
|
14
14
|
contentId = parseInt(contentId);
|
|
@@ -19,12 +19,12 @@ export async function isContentLiked(contentId) {
|
|
|
19
19
|
export async function likeContent(contentId) {
|
|
20
20
|
contentId = parseInt(contentId);
|
|
21
21
|
await dataContext.update(
|
|
22
|
-
function (
|
|
23
|
-
if (!
|
|
24
|
-
|
|
22
|
+
function (localContext) {
|
|
23
|
+
if (!localContext.data.includes(contentId)) {
|
|
24
|
+
localContext.data.push(contentId);
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
-
async function(){
|
|
27
|
+
async function () {
|
|
28
28
|
return postContentLiked(contentId);
|
|
29
29
|
}
|
|
30
30
|
);
|
|
@@ -33,15 +33,15 @@ export async function likeContent(contentId) {
|
|
|
33
33
|
export async function unlikeContent(contentId) {
|
|
34
34
|
contentId = parseInt(contentId);
|
|
35
35
|
await dataContext.update(
|
|
36
|
-
function (
|
|
37
|
-
if (
|
|
38
|
-
const index =
|
|
36
|
+
function (localContext) {
|
|
37
|
+
if (localContext.data.includes(contentId)) {
|
|
38
|
+
const index = localContext.data.indexOf(contentId);
|
|
39
39
|
if (index > -1) { // only splice array when item is found
|
|
40
|
-
|
|
40
|
+
localContext.data.splice(index, 1); // 2nd parameter means remove one item only
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
|
-
async function(){
|
|
44
|
+
async function () {
|
|
45
45
|
return postContentUnliked(contentId);
|
|
46
46
|
}
|
|
47
47
|
);
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fetchContentProgress,
|
|
3
|
+
postContentCompleted,
|
|
4
|
+
postContentReset,
|
|
5
|
+
postContentStarted,
|
|
6
|
+
postRecordWatchSession
|
|
7
|
+
} from "./railcontent";
|
|
8
|
+
import {DataContext, ContentProgressVersionKey} from "./dataContext";
|
|
9
|
+
import {fetchHierarchy, fetchParentByRailContentId} from "./sanity";
|
|
10
|
+
|
|
11
|
+
const STATE_STARTED = 'started';
|
|
12
|
+
const STATE_COMPLETED = 'completed';
|
|
13
|
+
const DATA_KEY_STATUS = 's';
|
|
14
|
+
const DATA_KEY_PROGRESS = 'p';
|
|
15
|
+
const DATA_KEY_RESUME_TIME = 't';
|
|
16
|
+
export let dataContext = new DataContext(ContentProgressVersionKey, fetchContentProgress());
|
|
17
|
+
|
|
18
|
+
export async function getProgressPercentage(contentId) {
|
|
19
|
+
let data = await dataContext.getData();
|
|
20
|
+
return data[contentId]?.[DATA_KEY_PROGRESS] ?? 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function getProgressState(contentId) {
|
|
24
|
+
let data = await dataContext.getData();
|
|
25
|
+
return data[contentId]?.[DATA_KEY_STATUS] ?? 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function getResumeTimeSeconds(contentId) {
|
|
29
|
+
let data = await dataContext.getData();
|
|
30
|
+
return data[contentId]?.[DATA_KEY_RESUME_TIME] ?? 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function contentStatusStarted(contentId) {
|
|
34
|
+
await dataContext.update(
|
|
35
|
+
function (localContext) {
|
|
36
|
+
let data = localContext.data[contentId] ?? [];
|
|
37
|
+
let progress = data?.[DATA_KEY_PROGRESS] ?? 0;
|
|
38
|
+
let status = data?.[DATA_KEY_STATUS] ?? 0;
|
|
39
|
+
|
|
40
|
+
if (status !== STATE_COMPLETED && progress !== 100) {
|
|
41
|
+
status = STATE_STARTED;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
data[DATA_KEY_STATUS] = status;
|
|
45
|
+
localContext.data[contentId] = data;
|
|
46
|
+
},
|
|
47
|
+
async function () {
|
|
48
|
+
return postContentStarted(contentId);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
export async function contentStatusCompleted(contentId) {
|
|
54
|
+
await dataContext.update(
|
|
55
|
+
function (localContext) {
|
|
56
|
+
let hierarchy = fetchHierarchy(contentId);
|
|
57
|
+
completeStatusInLocalContext(contentId, localContext, hierarchy);
|
|
58
|
+
},
|
|
59
|
+
async function () {
|
|
60
|
+
return postContentCompleted(contentId);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function completeStatusInLocalContext(contentId, localContext, hierarchy) {
|
|
65
|
+
let data = localContext.data[contentId] ?? [];
|
|
66
|
+
data[DATA_KEY_STATUS] = STATE_COMPLETED;
|
|
67
|
+
data[DATA_KEY_PROGRESS] = 100;
|
|
68
|
+
localContext.data[contentId] = data;
|
|
69
|
+
|
|
70
|
+
let children = hierarchy.children[contentId] ?? [];
|
|
71
|
+
for(let i = 0; i < children.length; i++) {
|
|
72
|
+
let childId = children[i];
|
|
73
|
+
completeStatusInLocalContext(childId, localContext, hierarchy);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function contentStatusReset(contentId) {
|
|
78
|
+
await dataContext.update(
|
|
79
|
+
function (localContext) {
|
|
80
|
+
const index = localContext.data.indexOf(contentId);
|
|
81
|
+
if (index > -1) { // only splice array when item is found
|
|
82
|
+
localContext.data.splice(index, 1); // 2nd parameter means remove one item only
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
async function () {
|
|
86
|
+
return postContentReset(contentId);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
export async function recordWatchSession({
|
|
92
|
+
mediaId,
|
|
93
|
+
mediaType,
|
|
94
|
+
mediaCategory,
|
|
95
|
+
watchPositionSeconds,
|
|
96
|
+
totalDurationSeconds,
|
|
97
|
+
sessionToken,
|
|
98
|
+
brand,
|
|
99
|
+
contentId = null
|
|
100
|
+
}) {
|
|
101
|
+
await dataContext.update(
|
|
102
|
+
async function (localContext) {
|
|
103
|
+
if (contentId) {
|
|
104
|
+
let data = localContext.data[contentId] ?? [];
|
|
105
|
+
let progress = data?.[DATA_KEY_PROGRESS] ?? 0;
|
|
106
|
+
let status = data?.[DATA_KEY_STATUS] ?? 0;
|
|
107
|
+
|
|
108
|
+
if (status !== STATE_COMPLETED && progress !== 100) {
|
|
109
|
+
status = STATE_STARTED;
|
|
110
|
+
progress = Math.min(99, Math.round(watchPositionSeconds ?? 0 / Math.max(1, totalDurationSeconds ?? 0) * 100));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
data[DATA_KEY_PROGRESS] = progress;
|
|
114
|
+
data[DATA_KEY_STATUS] = status;
|
|
115
|
+
data[DATA_KEY_RESUME_TIME] = watchPositionSeconds;
|
|
116
|
+
localContext.data[contentId] = data;
|
|
117
|
+
|
|
118
|
+
let hierarchy = await fetchHierarchy(contentId);
|
|
119
|
+
bubbleProgress(hierarchy, contentId, localContext);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
async function () {
|
|
123
|
+
return postRecordWatchSession({
|
|
124
|
+
mediaId,
|
|
125
|
+
mediaType,
|
|
126
|
+
mediaCategory,
|
|
127
|
+
watchPositionSeconds,
|
|
128
|
+
totalDurationSeconds,
|
|
129
|
+
sessionToken,
|
|
130
|
+
brand,
|
|
131
|
+
contentId
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function bubbleProgress(hierarchy, contentId, localContext) {
|
|
138
|
+
let parentId = hierarchy.parents[contentId];
|
|
139
|
+
if (!parentId) return;
|
|
140
|
+
let data = localContext.data[parentId] ?? [];
|
|
141
|
+
let progress = data[DATA_KEY_PROGRESS];
|
|
142
|
+
let status = data[DATA_KEY_STATUS];
|
|
143
|
+
if (status !== STATE_COMPLETED && progress !== 100) {
|
|
144
|
+
let childProgress = hierarchy.children[parentId].map(function (childId) {
|
|
145
|
+
return localContext.data[childId]?.[DATA_KEY_PROGRESS] ?? 0;
|
|
146
|
+
});
|
|
147
|
+
progress = Math.round(childProgress.reduce((a, b) => a + b, 0) / childProgress.length);
|
|
148
|
+
data[DATA_KEY_PROGRESS] = progress;
|
|
149
|
+
localContext.data[parentId] = data;
|
|
150
|
+
}
|
|
151
|
+
bubbleProgress(hierarchy, parentId, localContext);
|
|
152
|
+
}
|
|
153
|
+
|
|
@@ -8,7 +8,8 @@ import {globalConfig} from "./config";
|
|
|
8
8
|
const excludeFromGeneratedIndex = [];
|
|
9
9
|
|
|
10
10
|
//These constants need to match MWP UserDataVersionKeyEnum enum
|
|
11
|
-
export const
|
|
11
|
+
export const ContentLikesVersionKey = 0;
|
|
12
|
+
export const ContentProgressVersionKey = 1;
|
|
12
13
|
|
|
13
14
|
let cache = null;
|
|
14
15
|
|
|
@@ -78,7 +79,7 @@ export class DataContext {
|
|
|
78
79
|
async update(localUpdateFunction, serverUpdateFunction) {
|
|
79
80
|
await this.ensureLocalContextLoaded();
|
|
80
81
|
if (this.context) {
|
|
81
|
-
localUpdateFunction(this.context);
|
|
82
|
+
await localUpdateFunction(this.context);
|
|
82
83
|
this.context.version++;
|
|
83
84
|
let data = JSON.stringify(this.context);
|
|
84
85
|
cache.setItem(this.localStorageKey, data);
|