musora-content-services 2.147.1 → 2.149.0

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,26 @@
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.149.0](https://github.com/railroadmedia/musora-content-services/compare/v2.148.0...v2.149.0) (2026-04-07)
6
+
7
+
8
+ ### Features
9
+
10
+ * remove countdown logic for GC in progress card ([#897](https://github.com/railroadmedia/musora-content-services/issues/897)) ([254bc2a](https://github.com/railroadmedia/musora-content-services/commit/254bc2a0a695f68e449a49a71197be01654ba9aa))
11
+
12
+ ## [2.148.0](https://github.com/railroadmedia/musora-content-services/compare/v2.145.6...v2.148.0) (2026-04-03)
13
+
14
+
15
+ ### Features
16
+
17
+ * Add children to fetchScheduledAndNewReleases for navigateTo calculations ([#901](https://github.com/railroadmedia/musora-content-services/issues/901)) ([3ade1ad](https://github.com/railroadmedia/musora-content-services/commit/3ade1ad400e1dd9e56d245f3a37d77d709a0d4e1))
18
+ * **BEHLPT-18:** remove user from muppet ([#891](https://github.com/railroadmedia/musora-content-services/issues/891)) ([ecdf778](https://github.com/railroadmedia/musora-content-services/commit/ecdf778108f974f59885c3d442c47c90152c5554))
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * patches indexedDB.deleteDatabase to silence noisy safari errs ([#888](https://github.com/railroadmedia/musora-content-services/issues/888)) ([c67d408](https://github.com/railroadmedia/musora-content-services/commit/c67d40800ffe64d3eab204b97eaf26413b5a6e79))
24
+
5
25
  ### [2.147.1](https://github.com/railroadmedia/musora-content-services/compare/v2.147.0...v2.147.1) (2026-04-02)
6
26
 
7
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.147.1",
3
+ "version": "2.149.0",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -12,7 +12,6 @@ import {
12
12
  showsLessonTypes,
13
13
  songs,
14
14
  } from '../../../contentTypeConfig.js'
15
- import { getTimeRemainingUntilLocal } from '../../dateUtils.js'
16
15
  import { PARENT_ID_TOP_LEVEL } from '../../sync/models/ContentProgress'
17
16
 
18
17
  /**
@@ -58,7 +57,7 @@ function generateContentPromises(contents) {
58
57
  const promises = []
59
58
  if (!contents) return promises
60
59
  const existingShows = new Set()
61
- let allRecentTypeSet = new Set(Object.values(recentTypes.homeRow))
60
+ const allRecentTypeSet = new Set(Object.values(recentTypes.homeRow))
62
61
  allRecentTypeSet.delete('learning-path-v2') // we do this to remove from homepage, until we allow a-la-carte learning paths
63
62
  contents.forEach((content) => {
64
63
  const type = content.type
@@ -80,33 +79,12 @@ function generateContentPromises(contents) {
80
79
  export async function processContentItem(content) {
81
80
  const contentType = getFormattedType(content.type, content.brand)
82
81
  const isLive = content.isLive ?? false
83
- let ctaText = getDefaultCTATextForContent(content, contentType)
82
+ const ctaText = getDefaultCTATextForContent(content, contentType)
84
83
 
85
84
  const { completedChildren, allChildren } = await getCompletedChildren(content, contentType)
86
85
  content.completed_children = completedChildren
87
86
  content.all_children = allChildren
88
87
 
89
- if (content.type === 'guided-course') {
90
- const nextLessonPublishedOn = content.children.find(
91
- (child) => child.id === content.navigateTo.id
92
- )?.published_on
93
- let isLocked = new Date(nextLessonPublishedOn) > new Date()
94
- if (isLocked) {
95
- content.is_locked = true
96
- const timeRemaining = getTimeRemainingUntilLocal(nextLessonPublishedOn, {
97
- withTotalSeconds: true,
98
- })
99
- content.time_remaining_seconds = timeRemaining.totalSeconds
100
- ctaText = 'Next lesson in ' + timeRemaining.formatted
101
- } else if (
102
- !content.progressStatus ||
103
- content.progressStatus === 'not-started' ||
104
- content.progressPercentage === 0
105
- ) {
106
- ctaText = 'Start Course'
107
- }
108
- }
109
-
110
88
  return {
111
89
  id: content.id,
112
90
  progressType: 'content',
@@ -125,16 +103,10 @@ export async function processContentItem(content) {
125
103
  badge_template: content.badge_template ?? null,
126
104
  badge_template_rear: content.badge_template_rear ?? null,
127
105
  isLocked: content.is_locked ?? false,
128
- subtitle:
129
- collectionLessonTypes.includes(content.type) || content.lesson_count > 1
130
- ? `${content.completed_children ?? 0} of ${content.all_children ?? content.lesson_count ?? content.child_count} Lessons Complete`
131
- : (contentType === 'lesson' || contentType === 'show') && isLive === false
132
- ? `${content.progressPercentage}% Complete`
133
- : `${content.difficulty_string} • ${content.artist_name}`,
106
+ subtitle: getSubtitle(content, contentType, isLive),
134
107
  },
135
108
  cta: {
136
109
  text: ctaText,
137
- timeRemainingToUnlockSeconds: content.time_remaining_seconds ?? null,
138
110
  action: {
139
111
  type: content.type,
140
112
  brand: content.brand,
@@ -147,21 +119,37 @@ export async function processContentItem(content) {
147
119
  }
148
120
  }
149
121
 
122
+ function getSubtitle(content, contentType, isLive) {
123
+ if (collectionLessonTypes.includes(content.type) || content.lesson_count > 1) {
124
+ return `${content.completed_children ?? 0} of ${content.all_children ?? content.lesson_count ?? content.child_count} Lessons Complete`
125
+ }
126
+ if ((contentType === 'lesson' || contentType === 'show') && !isLive) {
127
+ return `${content.progressPercentage}% Complete`
128
+ }
129
+ return `${content.difficulty_string} • ${content.artist_name}`
130
+ }
131
+
150
132
  function getDefaultCTATextForContent(content, contentType) {
151
- let ctaText = 'Continue'
133
+ const notStarted =
134
+ !content.progressStatus ||
135
+ content.progressStatus === 'not-started' ||
136
+ content.progressPercentage === 0
137
+ if (content.type === 'guided-course' && notStarted) return 'Start Course'
138
+
152
139
  if (content.progressStatus === 'completed') {
153
140
  if (
154
141
  contentType === songs[content.brand] ||
155
142
  contentType === 'play along' ||
156
143
  contentType === 'jam track'
157
144
  )
158
- ctaText = 'Replay Song'
159
- if (contentType === 'lesson' || contentType === 'show') ctaText = 'Revisit Lesson'
145
+ return 'Replay Song'
146
+ if (contentType === 'lesson' || contentType === 'show') return 'Revisit Lesson'
160
147
  if (contentType === 'song tutorial' || collectionLessonTypes.includes(content.type))
161
- ctaText = 'Revisit Lessons'
162
- if (contentType === 'course-collection') ctaText = 'View Lessons'
148
+ return 'Revisit Lessons'
149
+ if (contentType === 'course-collection') return 'View Lessons'
163
150
  }
164
- return ctaText
151
+
152
+ return 'Continue'
165
153
  }
166
154
 
167
155
  async function getCompletedChildren(content, contentType) {
@@ -718,8 +718,7 @@ export async function calculateLongestStreaks(userId = globalConfig.sessionConfi
718
718
  let practiceDates = Object.keys(practices)
719
719
  .map((dateStr) => {
720
720
  const [y, m, d] = dateStr.split('-').map(Number)
721
- const newDate = new Date()
722
- newDate.setFullYear(y, m - 1, d)
721
+ const newDate = new Date(y, m - 1, d, 0, 0, 0, 0)
723
722
  return newDate
724
723
  })
725
724
  .sort((a, b) => a - b)
@@ -744,7 +743,7 @@ export async function calculateLongestStreaks(userId = globalConfig.sessionConfi
744
743
  let currentDailyStreak = 1
745
744
  for (let i = 1; i < normalizedDates.length; i++) {
746
745
  const diffInDays = (normalizedDates[i] - normalizedDates[i - 1]) / (1000 * 60 * 60 * 24)
747
- if (diffInDays === 1) {
746
+ if (Math.round(diffInDays) === 1) {
748
747
  currentDailyStreak++
749
748
  longestDailyStreak = Math.max(longestDailyStreak, currentDailyStreak)
750
749
  } else {
@@ -770,7 +769,7 @@ export async function calculateLongestStreaks(userId = globalConfig.sessionConfi
770
769
 
771
770
  for (let i = 1; i < weekStartDates.length; i++) {
772
771
  const diffInWeeks = (weekStartDates[i] - weekStartDates[i - 1]) / (1000 * 60 * 60 * 24 * 7)
773
- if (diffInWeeks === 1) {
772
+ if (Math.round(diffInWeeks) === 1) {
774
773
  currentWeeklyStreak++
775
774
  longestWeeklyStreak = Math.max(longestWeeklyStreak, currentWeeklyStreak)
776
775
  } else {