musora-content-services 2.3.21 → 2.3.23
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
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [2.3.23](https://github.com/railroadmedia/musora-content-services/compare/v2.3.22...v2.3.23) (2025-05-06)
|
|
6
|
+
|
|
7
|
+
### [2.3.22](https://github.com/railroadmedia/musora-content-services/compare/v2.3.21...v2.3.22) (2025-05-05)
|
|
8
|
+
|
|
5
9
|
### [2.3.21](https://github.com/railroadmedia/musora-content-services/compare/v2.3.20...v2.3.21) (2025-05-02)
|
|
6
10
|
|
|
7
11
|
### [2.3.20](https://github.com/railroadmedia/musora-content-services/compare/v2.3.19...v2.3.20) (2025-04-30)
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -29,6 +29,10 @@ import {
|
|
|
29
29
|
getTabResults
|
|
30
30
|
} from './services/content.js';
|
|
31
31
|
|
|
32
|
+
import {
|
|
33
|
+
addContextToContent
|
|
34
|
+
} from './services/contentAggregator.js';
|
|
35
|
+
|
|
32
36
|
import {
|
|
33
37
|
isContentLiked,
|
|
34
38
|
isContentLikedByIds,
|
|
@@ -215,6 +219,7 @@ import {
|
|
|
215
219
|
} from './services/user/sessions.js';
|
|
216
220
|
|
|
217
221
|
import {
|
|
222
|
+
calculateLongestStreaks,
|
|
218
223
|
createPracticeNotes,
|
|
219
224
|
deletePracticeSession,
|
|
220
225
|
getPracticeNotes,
|
|
@@ -232,6 +237,7 @@ import {
|
|
|
232
237
|
|
|
233
238
|
declare module 'musora-content-services' {
|
|
234
239
|
export {
|
|
240
|
+
addContextToContent,
|
|
235
241
|
addItemToPlaylist,
|
|
236
242
|
applyCloudflareWrapper,
|
|
237
243
|
applySanityTransformations,
|
|
@@ -240,6 +246,7 @@ declare module 'musora-content-services' {
|
|
|
240
246
|
assignmentStatusReset,
|
|
241
247
|
blockUser,
|
|
242
248
|
buildImageSRC,
|
|
249
|
+
calculateLongestStreaks,
|
|
243
250
|
closeComment,
|
|
244
251
|
contentStatusCompleted,
|
|
245
252
|
contentStatusReset,
|
package/src/index.js
CHANGED
|
@@ -29,6 +29,10 @@ import {
|
|
|
29
29
|
getTabResults
|
|
30
30
|
} from './services/content.js';
|
|
31
31
|
|
|
32
|
+
import {
|
|
33
|
+
addContextToContent
|
|
34
|
+
} from './services/contentAggregator.js';
|
|
35
|
+
|
|
32
36
|
import {
|
|
33
37
|
isContentLiked,
|
|
34
38
|
isContentLikedByIds,
|
|
@@ -215,6 +219,7 @@ import {
|
|
|
215
219
|
} from './services/user/sessions.js';
|
|
216
220
|
|
|
217
221
|
import {
|
|
222
|
+
calculateLongestStreaks,
|
|
218
223
|
createPracticeNotes,
|
|
219
224
|
deletePracticeSession,
|
|
220
225
|
getPracticeNotes,
|
|
@@ -231,6 +236,7 @@ import {
|
|
|
231
236
|
} from './services/userActivity.js';
|
|
232
237
|
|
|
233
238
|
export {
|
|
239
|
+
addContextToContent,
|
|
234
240
|
addItemToPlaylist,
|
|
235
241
|
applyCloudflareWrapper,
|
|
236
242
|
applySanityTransformations,
|
|
@@ -239,6 +245,7 @@ export {
|
|
|
239
245
|
assignmentStatusReset,
|
|
240
246
|
blockUser,
|
|
241
247
|
buildImageSRC,
|
|
248
|
+
calculateLongestStreaks,
|
|
242
249
|
closeComment,
|
|
243
250
|
contentStatusCompleted,
|
|
244
251
|
contentStatusReset,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { getProgressStateByIds, getProgressPercentageByIds, getResumeTimeSecondsByIds } from "./services/contentProgress"
|
|
1
|
+
import { getProgressStateByIds, getProgressPercentageByIds, getResumeTimeSecondsByIds } from "./services/contentProgress"
|
|
2
2
|
import { isContentLikedByIds } from "./services/contentLikes"
|
|
3
3
|
import { fetchLikeCount } from "./services/railcontent"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export async function addContextToContent(dataPromise, ...dataArgs)
|
|
8
|
+
{
|
|
6
9
|
const lastArg = dataArgs[dataArgs.length - 1]
|
|
7
10
|
const options = typeof lastArg === 'object' && !Array.isArray(lastArg) ? lastArg : {}
|
|
8
11
|
|
|
@@ -47,7 +50,7 @@ export const addContextToContent = async (dataPromise, ...dataArgs) => {
|
|
|
47
50
|
...(addLikeCount && ids.length === 1 ? { likeCount: await fetchLikeCount(item.id) } : {}),
|
|
48
51
|
...(addResumeTimeSeconds ? { resumeTime: resumeTimeData?.[item.id] } : {}),
|
|
49
52
|
})
|
|
50
|
-
|
|
53
|
+
|
|
51
54
|
const newData = Array.isArray(data)
|
|
52
55
|
? await Promise.all(data.map(addContext))
|
|
53
56
|
: await addContext(data)
|
|
@@ -290,6 +290,10 @@ async function patchDataHandler(url, data) {
|
|
|
290
290
|
return fetchHandler(url, 'patch', null, data)
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
async function putDataHandler(url, data) {
|
|
294
|
+
return fetchHandler(url, 'put', null, data)
|
|
295
|
+
}
|
|
296
|
+
|
|
293
297
|
async function deleteDataHandler(url, data) {
|
|
294
298
|
return fetchHandler(url, 'delete')
|
|
295
299
|
}
|
|
@@ -726,7 +730,7 @@ export async function editComment(commentId, comment) {
|
|
|
726
730
|
const data = {
|
|
727
731
|
comment: comment,
|
|
728
732
|
}
|
|
729
|
-
return await
|
|
733
|
+
return await putDataHandler(url, data)
|
|
730
734
|
}
|
|
731
735
|
|
|
732
736
|
/**
|
|
@@ -688,6 +688,87 @@ function calculateStreaks(practices, includeStreakMessage = false) {
|
|
|
688
688
|
return { currentDailyStreak, currentWeeklyStreak, streakMessage };
|
|
689
689
|
}
|
|
690
690
|
|
|
691
|
+
/**
|
|
692
|
+
* Calculates the longest daily, weekly streaks and totalPracticeSeconds from user practice dates.
|
|
693
|
+
* @returns {{ longestDailyStreak: number, longestWeeklyStreak: number, totalPracticeSeconds:number }}
|
|
694
|
+
*/
|
|
695
|
+
export async function calculateLongestStreaks() {
|
|
696
|
+
let data = await userActivityContext.getData()
|
|
697
|
+
let practices = data?.[DATA_KEY_PRACTICES] ?? {}
|
|
698
|
+
let totalPracticeSeconds = 0;
|
|
699
|
+
// Calculate total practice duration
|
|
700
|
+
for (const date in practices) {
|
|
701
|
+
for (const entry of practices[date]) {
|
|
702
|
+
totalPracticeSeconds += entry.duration_seconds;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
let practiceDates = Object.keys(practices)
|
|
707
|
+
.map(dateStr => {
|
|
708
|
+
const [y, m, d] = dateStr.split('-').map(Number);
|
|
709
|
+
const newDate = new Date();
|
|
710
|
+
newDate.setFullYear(y, m - 1, d);
|
|
711
|
+
return newDate;
|
|
712
|
+
})
|
|
713
|
+
.sort((a, b) => a - b);
|
|
714
|
+
|
|
715
|
+
if (!practiceDates || practiceDates.length === 0) {
|
|
716
|
+
return {longestDailyStreak: 0, longestWeeklyStreak: 0, totalPracticeSeconds: 0};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Normalize to Date objects
|
|
720
|
+
const normalizedDates = [
|
|
721
|
+
...new Set(practiceDates.map(d => {
|
|
722
|
+
const date = new Date(d);
|
|
723
|
+
date.setHours(0, 0, 0, 0);
|
|
724
|
+
return date.getTime();
|
|
725
|
+
}))
|
|
726
|
+
].sort((a, b) => a - b);
|
|
727
|
+
|
|
728
|
+
// ----- Daily Streak -----
|
|
729
|
+
let longestDailyStreak = 1;
|
|
730
|
+
let currentDailyStreak = 1;
|
|
731
|
+
for (let i = 1; i < normalizedDates.length; i++) {
|
|
732
|
+
const diffInDays = (normalizedDates[i] - normalizedDates[i - 1]) / (1000 * 60 * 60 * 24);
|
|
733
|
+
if (diffInDays === 1) {
|
|
734
|
+
currentDailyStreak++;
|
|
735
|
+
longestDailyStreak = Math.max(longestDailyStreak, currentDailyStreak);
|
|
736
|
+
} else {
|
|
737
|
+
currentDailyStreak = 1;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// ----- Weekly Streak -----
|
|
742
|
+
const weekStartDates = [
|
|
743
|
+
...new Set(normalizedDates.map(ts => {
|
|
744
|
+
const d = new Date(ts);
|
|
745
|
+
const day = d.getDay();
|
|
746
|
+
const diff = d.getDate() - day + (day === 0 ? -6 : 1); // adjust to Monday
|
|
747
|
+
d.setDate(diff);
|
|
748
|
+
return d.getTime(); // timestamp for Monday
|
|
749
|
+
}))
|
|
750
|
+
].sort((a, b) => a - b);
|
|
751
|
+
|
|
752
|
+
let longestWeeklyStreak = 1;
|
|
753
|
+
let currentWeeklyStreak = 1;
|
|
754
|
+
|
|
755
|
+
for (let i = 1; i < weekStartDates.length; i++) {
|
|
756
|
+
const diffInWeeks = (weekStartDates[i] - weekStartDates[i - 1]) / (1000 * 60 * 60 * 24 * 7);
|
|
757
|
+
if (diffInWeeks === 1) {
|
|
758
|
+
currentWeeklyStreak++;
|
|
759
|
+
longestWeeklyStreak = Math.max(longestWeeklyStreak, currentWeeklyStreak);
|
|
760
|
+
} else {
|
|
761
|
+
currentWeeklyStreak = 1;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
longestDailyStreak,
|
|
767
|
+
longestWeeklyStreak,
|
|
768
|
+
totalPracticeSeconds
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
|
|
691
772
|
|
|
692
773
|
|
|
693
774
|
|