musora-content-services 1.0.19 → 1.0.21

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/docs/config.js.html +124 -0
  3. package/docs/index.html +2 -2
  4. package/docs/module-Config.html +669 -0
  5. package/docs/module-Railcontent-Services.html +751 -0
  6. package/docs/{global.html → module-Sanity-Services.html} +52 -501
  7. package/docs/railcontent.js.html +178 -0
  8. package/docs/sanity.js.html +994 -0
  9. package/jsdoc.json +1 -1
  10. package/package.json +1 -1
  11. package/src/contentTypeConfig.js +30 -0
  12. package/src/index.d.ts +2 -2
  13. package/src/index.js +32 -1029
  14. package/src/services/config.js +52 -0
  15. package/src/services/railcontent.js +106 -0
  16. package/src/services/sanity.js +922 -0
  17. package/test/sanityQueryService.test.js +37 -2
  18. package/docs/data/search.json +0 -1
  19. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  20. package/docs/fonts/OpenSans-Bold-webfont.eot +0 -0
  21. package/docs/fonts/OpenSans-Bold-webfont.svg +0 -1830
  22. package/docs/fonts/OpenSans-Bold-webfont.woff +0 -0
  23. package/docs/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  24. package/docs/fonts/OpenSans-BoldItalic-webfont.svg +0 -1830
  25. package/docs/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  26. package/docs/fonts/OpenSans-Italic-webfont.eot +0 -0
  27. package/docs/fonts/OpenSans-Italic-webfont.svg +0 -1830
  28. package/docs/fonts/OpenSans-Italic-webfont.woff +0 -0
  29. package/docs/fonts/OpenSans-Light-webfont.eot +0 -0
  30. package/docs/fonts/OpenSans-Light-webfont.svg +0 -1831
  31. package/docs/fonts/OpenSans-Light-webfont.woff +0 -0
  32. package/docs/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  33. package/docs/fonts/OpenSans-LightItalic-webfont.svg +0 -1835
  34. package/docs/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  35. package/docs/fonts/OpenSans-Regular-webfont.eot +0 -0
  36. package/docs/fonts/OpenSans-Regular-webfont.svg +0 -1831
  37. package/docs/fonts/OpenSans-Regular-webfont.woff +0 -0
  38. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  39. package/docs/fonts/OpenSans-Semibold-webfont.eot +0 -0
  40. package/docs/fonts/OpenSans-Semibold-webfont.svg +0 -1830
  41. package/docs/fonts/OpenSans-Semibold-webfont.ttf +0 -0
  42. package/docs/fonts/OpenSans-Semibold-webfont.woff +0 -0
  43. package/docs/fonts/OpenSans-SemiboldItalic-webfont.eot +0 -0
  44. package/docs/fonts/OpenSans-SemiboldItalic-webfont.svg +0 -1830
  45. package/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf +0 -0
  46. package/docs/fonts/OpenSans-SemiboldItalic-webfont.woff +0 -0
  47. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  48. package/docs/index.js.html +0 -1122
  49. package/docs/scripts/core.js +0 -726
  50. package/docs/scripts/core.min.js +0 -23
  51. package/docs/scripts/resize.js +0 -90
  52. package/docs/scripts/search.min.js +0 -6
  53. package/docs/scripts/third-party/Apache-License-2.0.txt +0 -202
  54. package/docs/scripts/third-party/fuse.js +0 -9
  55. package/docs/scripts/third-party/hljs-line-num-original.js +0 -369
  56. package/docs/scripts/third-party/hljs-line-num.js +0 -1
  57. package/docs/scripts/third-party/hljs-original.js +0 -5171
  58. package/docs/scripts/third-party/hljs.js +0 -1
  59. package/docs/scripts/third-party/popper.js +0 -5
  60. package/docs/scripts/third-party/tippy.js +0 -1
  61. package/docs/scripts/third-party/tocbot.js +0 -672
  62. package/docs/scripts/third-party/tocbot.min.js +0 -1
  63. package/docs/styles/clean-jsdoc-theme-base.css +0 -1159
  64. package/docs/styles/clean-jsdoc-theme-dark.css +0 -412
  65. package/docs/styles/clean-jsdoc-theme-light.css +0 -482
  66. package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -30
  67. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -1
  68. package/docs/styles/clean-jsdoc-theme.min.css +0 -1
  69. package/docs/styles/jsdoc-default.css +0 -692
  70. package/docs/styles/prettify-jsdoc.css +0 -111
  71. package/docs/styles/prettify-tomorrow.css +0 -132
package/src/index.js CHANGED
@@ -1,1030 +1,34 @@
1
- let globalConfig = {};
2
-
3
- /**
4
- * Initializes the Sanity service with the given configuration.
5
- * This function must be called before using any other functions in this library.
6
- *
7
- * @param {Object} config - Configuration object containing Sanity API settings.
8
- * @param {string} config.token - The API token for authenticating with Sanity.
9
- * @param {string} config.projectId - The project ID in Sanity.
10
- * @param {string} config.dataset - The dataset name in Sanity.
11
- * @param {string} config.version - The API version to use.
12
- * @param {boolean} [config.debug=false] - Optional flag to enable debug mode, which logs the query and results.
13
- * @param {boolean} [config.useCachedAPI=true] - Optional flag to disable cached API.
14
- *
15
- * @example
16
- * // Initialize the Sanity service in your app.js
17
- * initializeSanityService({
18
- * token: 'your-sanity-api-token',
19
- * projectId: 'your-sanity-project-id',
20
- * dataset: 'your-dataset-name',
21
- * version: '2021-06-07',
22
- * debug: true, // Optional: Enable debug mode
23
- * useCachedAPI: true // Optional: Use cached API
24
- * });
25
- */
26
- function initializeSanityService(config) {
27
- globalConfig = config;
28
- }
29
-
30
- /**
31
- * Fetch a song by its document ID from Sanity.
32
- *
33
- * @param {string} documentId - The ID of the document to fetch.
34
- * @returns {Promise<Object|null>} - A promise that resolves to an object containing the song data or null if not found.
35
- *
36
- * @example
37
- * fetchSongById('abc123')
38
- * .then(song => console.log(song))
39
- * .catch(error => console.error(error));
40
- */
41
- async function fetchSongById(documentId) {
42
- const fields = [
43
- 'title',
44
- '"thumbnail_url": thumbnail.asset->url',
45
- '"style": genre[0]->name',
46
- '"artist": artist->name',
47
- 'album',
48
- 'instrumentless',
49
- 'soundslice',
50
- 'railcontent_id',
51
- '"resources": resource[]{resource_url, resource_name}',
52
- ];
53
-
54
- const query = `
55
- *[_type == "song" && railcontent_id == ${documentId}]{
56
- ${fields.join(', ')}
57
- }`;
58
- return fetchSanity(query, false);
59
- }
60
-
61
- /**
62
- * Fetch all artists with lessons available for a specific brand.
63
- *
64
- * @param {string} brand - The brand for which to fetch artists.
65
- * @returns {Promise<Object|null>} - A promise that resolves to an array of artist objects or null if not found.
66
- *
67
- * @example
68
- * fetchArtists('drumeo')
69
- * .then(artists => console.log(artists))
70
- * .catch(error => console.error(error));
71
- */
72
- async function fetchArtists(brand) {
73
- const query = `
74
- *[_type == "artist"]{
75
- name,
76
- "lessonsCount": count(*[_type == "song" && brand == "${brand}" && references(^._id)])
77
- }[lessonsCount > 0]`;
78
- return fetchSanity(query, true);
79
- }
80
-
81
- /**
82
- * Fetch current number of artists for songs within a brand.
83
- * @param {string} brand - The current brand.
84
- * @returns {Promise<int|null>} - The fetched count of artists.
85
- */
86
- async function fetchSongArtistCount(brand) {
87
- const query = `count(*[_type == 'artist']{'lessonsCount': count(*[_type == 'song' && brand == '${brand}' && references(^._id)]._id)}[lessonsCount > 0])`;
88
- return fetchSanity(query, true);
89
- }
90
-
91
- /**
92
- * Fetch related songs for a specific brand and song ID.
93
- *
94
- * @param {string} brand - The brand for which to fetch related songs.
95
- * @param {string} songId - The ID of the song to find related songs for.
96
- * @returns {Promise<Object|null>} - A promise that resolves to an array of related song objects or null if not found.
97
- *
98
- * @example
99
- * fetchRelatedSongs('drumeo', '12345')
100
- * .then(relatedSongs => console.log(relatedSongs))
101
- * .catch(error => console.error(error));
102
- */
103
- async function fetchRelatedSongs(brand, songId) {
104
- const query = `
105
- *[_type == "song" && railcontent_id == ${songId}]{
106
- "data": array::unique([
107
- ...(*[_type == "song" && brand == "${brand}" && railcontent_id != ${songId} && references(^.artist->_id)]{
108
- "type": _type,
109
- "id": railcontent_id,
110
- "url": web_url_path,
111
- "published_on": published_on,
112
- status,
113
- "fields": [
114
- {
115
- "key": "title",
116
- "value": title
117
- },
118
- {
119
- "key": "artist",
120
- "value": artist->name
121
- },
122
- {
123
- "key": "difficulty",
124
- "value": difficulty
125
- },
126
- {
127
- "key": "length_in_seconds",
128
- "value": soundslice[0].soundslice_length_in_second
129
- }
130
- ],
131
- "data": [{
132
- "key": "thumbnail_url",
133
- "value": thumbnail.asset->url
134
- }]
135
- }[0...10]),
136
- ...(*[_type == "song" && brand == "${brand}" && railcontent_id != ${songId} && references(^.genre[]->_id)]{
137
- "type": _type,
138
- "id": railcontent_id,
139
- "url": web_url_path,
140
- "published_on": published_on,
141
- status,
142
- "fields": [
143
- {
144
- "key": "title",
145
- "value": title
146
- },
147
- {
148
- "key": "artist",
149
- "value": artist->name
150
- },
151
- {
152
- "key": "difficulty",
153
- "value": difficulty
154
- },
155
- {
156
- "key": "length_in_seconds",
157
- "value": soundslice[0].soundslice_length_in_second
158
- }
159
- ],
160
- "data": [{
161
- "key": "thumbnail_url",
162
- "value": thumbnail.asset->url
163
- }]
164
- }[0...10])
165
- ])[0...10]
166
- }`;
167
-
168
- return fetchSanity(query, true);
169
- }
170
-
171
- /**
172
- * Fetch all songs for a specific brand with pagination and search options.
173
- * @param {string} brand - The brand for which to fetch songs.
174
- * @param {Object} params - Parameters for pagination, filtering, and sorting.
175
- * @param {number} [params.page=1] - The page number for pagination.
176
- * @param {number} [params.limit=10] - The number of songs per page.
177
- * @param {string} [params.searchTerm=""] - The search term to filter songs by title or artist.
178
- * @param {string} [params.sort="-published_on"] - The field to sort the songs by.
179
- * @param {Array<string>} [params.includedFields=[]] - The fields to include in the query.
180
- * @param {string} [params.groupBy=""] - The field to group the results by.
181
- * @returns {Promise<Object|null>} - The fetched song data or null if not found.
182
- *
183
- * @example
184
- * fetchAllSongs('drumeo', {
185
- * page: 2,
186
- * limit: 20,
187
- * searchTerm: 'rock',
188
- * sort: 'published_on',
189
- * includedFields: ['difficulty', 'style'],
190
- * groupBy: 'artist'
191
- * })
192
- * .then(result => console.log(result))
193
- * .catch(error => console.error(error));
194
- */
195
- async function fetchAllSongs(brand, {
196
- page = 1,
197
- limit = 10,
198
- searchTerm = "",
199
- sort = "-published_on",
200
- includedFields = [],
201
- groupBy = ""
202
- }) {
203
- console.log('groupBy', groupBy)
204
- const start = (page - 1) * limit;
205
- const end = start + limit;
206
-
207
- // Construct the search filter
208
- const searchFilter = searchTerm
209
- ? `&& (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
210
- : "";
211
-
212
- // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
213
- const includedFieldsFilter = includedFields.length > 0
214
- ? includedFields.map(field => {
215
- let [key, value] = field.split(',');
216
- if (key === 'difficulty') {
217
- key = 'difficulty_string';
218
- }
219
- return `&& ${key} == "${value}"`;
220
- }).join(' ')
221
- : "";
222
-
223
- // Determine the sort order
224
- let sortOrder;
225
- switch (sort) {
226
- case "slug":
227
- sortOrder = "artist->name asc";
228
- break;
229
- case "published_on":
230
- sortOrder = "published_on desc";
231
- break;
232
- case "-published_on":
233
- sortOrder = "published_on asc";
234
- break;
235
- case "-slug":
236
- sortOrder = "artist->name desc";
237
- break;
238
- case "-popularity":
239
- sortOrder = "popularity desc";
240
- break;
241
- default:
242
- sortOrder = "published_on asc";
243
- break;
244
- }
245
-
246
- // Determine the group by clause
247
- let query = "";
248
- if (groupBy === "artist") {
249
- query = `
250
- {
251
- "total": count(*[_type == 'artist' && count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id) > 0]),
252
- "entity": *[_type == 'artist' && count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id) > 0]
253
- {
254
- 'id': _id,
255
- 'type': _type,
256
- name,
257
- 'head_shot_picture_url': thumbnail_url.asset->url,
258
- 'all_lessons_count': count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id),
259
- 'lessons': *[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]{
260
- "id": railcontent_id,
261
- "type": _type,
262
- title,
263
- "thumbnail_url": thumbnail.asset->url,
264
- "artist_name": artist->name,
265
- difficulty_string,
266
- published_on,
267
- soundslice,
268
- instrumentless,
269
- }[0...10]
270
- }
271
- |order(${sortOrder})
272
- [${start}...${end}]
273
- }`;
274
- } else if (groupBy === "style") {
275
- query = `
276
- {
277
- "total": count(*[_type == 'genre' && count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id) > 0]),
278
- "entity":
279
- *[_type == 'genre' && count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id)>0]
280
- {
281
- 'id': _id,
282
- 'type': _type,
283
- name,
284
- 'head_shot_picture_url': thumbnail_url.asset->url,
285
- 'all_lessons_count': count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id),
286
- 'lessons': *[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]{
287
- "id": railcontent_id,
288
- "type": _type,
289
- title,
290
- "thumbnail_url": thumbnail.asset->url,
291
- "artist_name": artist->name,
292
- difficulty_string,
293
- published_on,
294
- soundslice,
295
- instrumentless,
296
- }[0...10]
297
- }
298
- |order(${sortOrder})
299
- [${start}...${end}]
300
- }`;
301
- } else {
302
- query = `
303
- {
304
- "entity": *[_type == 'song' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}] | order(${sortOrder}) [${start}...${end}] {
305
- "id": railcontent_id,
306
- "type": _type,
307
- title,
308
- "thumbnail_url": thumbnail.asset->url,
309
- "artist_name": artist->name,
310
- difficulty_string,
311
- published_on,
312
- soundslice,
313
- instrumentless,
314
- },
315
- "total": count(*[_type == 'song' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}])
316
- }
317
- `;
318
- }
319
-
320
- return fetchSanity(query, true);
321
- }
322
-
323
- /**
324
- * Fetch filter options for a specific brand.
325
- *
326
- * @param {string} brand - The brand for which to fetch filter options.
327
- * @returns {Promise<Object|null>} - A promise that resolves to an object containing filter options or null if not found.
328
- *
329
- * @example
330
- * fetchSongFilterOptions('drumeo')
331
- * .then(options => console.log(options))
332
- * .catch(error => console.error(error));
333
- */
334
- async function fetchSongFilterOptions(brand) {
335
- const query = `
336
- {
337
- "difficulty": [
338
- {"type": "Introductory", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Introductory"]._id)},
339
- {"type": "Beginner", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Beginner"]._id)},
340
- {"type": "Intermediate", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Intermediate"]._id)},
341
- {"type": "Advanced", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Advanced"]._id)},
342
- {"type": "Expert", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Expert"]._id)}
343
- ],
344
- "genre": *[_type == 'genre' && 'song' in filter_types] {
345
- "type": name,
346
- "count": count(*[_type == 'song' && brand == '${brand}' && references(^._id)]._id)
347
- },
348
- "instrumentless": [
349
- {"type": "Full Song Only", "count": count(*[_type == 'song' && brand == '${brand}' && instrumentless == false]._id)},
350
- {"type": "Instrument Removed", "count": count(*[_type == 'song' && brand == '${brand}' && instrumentless == true]._id)}
351
- ]
352
- }
353
- `;
354
-
355
- return fetchSanity(query, true);
356
- }
357
-
358
- /**
359
- * Fetch the total count of songs for a specific brand.
360
- * @param {string} brand - The brand for which to fetch the song count.
361
- * @returns {Promise<number|null>} - The total count of songs or null if an error occurs.
362
- */
363
- async function fetchSongCount(brand) {
364
- const query = `count(*[_type == 'song' && brand == "${brand}"])`;
365
- return fetchSanity(query, false);
366
- }
367
-
368
- /**
369
- * Fetch the latest workouts for the home page of a specific brand.
370
- * This function retrieves the latest workout content for a given brand, fetching up to five workouts. The workouts are sorted in descending order by their publication date.
371
- * @param {string} brand - The brand for which to fetch workouts (e.g., 'drumeo', 'pianote').
372
- * @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of workout data objects or null if no workouts are found.
373
- *
374
- * @example
375
- * fetchWorkouts('drumeo')
376
- * .then(workouts => console.log(workouts))
377
- * .catch(error => console.error(error));
378
- */
379
- async function fetchWorkouts(brand) {
380
- const query = `*[_type == 'workout' && brand == '${brand}'] [0...5] {
381
- "id": railcontent_id,
382
- title,
383
- "image": thumbnail.asset->url,
384
- "artist_name": instructor[0]->name,
385
- "artists": instructor[]->name,
386
- difficulty,
387
- difficulty_string,
388
- length_in_seconds,
389
- published_on,
390
- "type": _type,
391
- web_url_path,
392
- } | order(published_on desc)[0...5]`
393
- return fetchSanity(query, true);
394
- }
395
-
396
- /**
397
- * Fetch the latest new releases for a specific brand.
398
- * @param {string} brand - The brand for which to fetch new releases.
399
- * @returns {Promise<Object|null>} - The fetched new releases data or null if not found.
400
- */
401
- async function fetchNewReleases(brand) {
402
- const newTypes = {
403
- 'drumeo': ["drum-fest-international-2022", "spotlight", "the-history-of-electronic-drums", "backstage-secrets", "quick-tips", "question-and-answer", "student-collaborations", "live-streams", "live", "podcasts", "solos", "boot-camps", "gear-guides", "performances", "in-rhythm", "challenges", "on-the-road", "diy-drum-experiments", "rhythmic-adventures-of-captain-carson", "study-the-greats", "rhythms-from-another-planet", "tama-drums", "paiste-cymbals", "behind-the-scenes", "exploring-beats", "sonor-drums", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"],
404
- 'pianote': ["student-review", "student-reviews", "question-and-answer", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"],
405
- 'guitareo': ["student-review", "student-reviews", "question-and-answer", "archives", "recording", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"],
406
- 'singeo': ["student-review", "student-reviews", "question-and-answer", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"],
407
- 'default': ["student-review", "student-reviews", "question-and-answer", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"]
408
- };
409
- const typesString = arrayJoinWithQuotes(newTypes[brand] ?? newTypes['default']);
410
- const query = `*[_type in [${typesString}] && brand == '${brand}'] | order(releaseDate desc) [0...5] {
411
- "id": railcontent_id,
412
- title,
413
- "image": thumbnail.asset->url,
414
- "artist_name": instructor[0]->name,
415
- "artists": instructor[]->name,
416
- difficulty,
417
- difficulty_string,
418
- length_in_seconds,
419
- published_on,
420
- "type": _type,
421
- web_url_path,
422
- } | order(published_on desc)[0...5]`
423
- return fetchSanity(query, true);
424
- }
425
-
426
- /**
427
- * Fetch upcoming events for a specific brand.
428
- *
429
- * @param {string} brand - The brand for which to fetch upcoming events.
430
- * @returns {Promise<Object|null>} - A promise that resolves to an array of upcoming event objects or null if not found.
431
- *
432
- * @example
433
- * fetchUpcomingEvents('drumeo')
434
- * .then(events => console.log(events))
435
- * .catch(error => console.error(error));
436
- */
437
- async function fetchUpcomingEvents(brand) {
438
- const baseLiveTypes = ["student-review", "student-reviews", "student-focus", "coach-stream", "live", "question-and-answer", "student-review", "boot-camps", "recording", "pack-bundle-lesson"];
439
- const liveTypes = {
440
- 'drumeo': [...baseLiveTypes, "drum-fest-international-2022", "spotlight", "the-history-of-electronic-drums", "backstage-secrets", "quick-tips", "student-collaborations", "live-streams", "podcasts", "solos", "gear-guides", "performances", "in-rhythm", "challenges", "on-the-road", "diy-drum-experiments", "rhythmic-adventures-of-captain-carson", "study-the-greats", "rhythms-from-another-planet", "tama-drums", "paiste-cymbals", "behind-the-scenes", "exploring-beats", "sonor-drums"],
441
- 'pianote': baseLiveTypes,
442
- 'guitareo': [...baseLiveTypes, "archives"],
443
- 'singeo': baseLiveTypes,
444
- 'default': baseLiveTypes
445
- };
446
- const typesString = arrayJoinWithQuotes(liveTypes[brand] ?? liveTypes['default']);
447
- const now = getSanityDate(new Date());
448
- //TODO: status = 'scheduled' is this handled in sanity?
449
- const query = `*[_type in [${typesString}] && brand == '${brand}' && published_on > '${now}']{
450
- "id": railcontent_id,
451
- title,
452
- "image": thumbnail.asset->url,
453
- "artist_name": instructor[0]->name,
454
- "artists": instructor[]->name,
455
- difficulty,
456
- difficulty_string,
457
- length_in_seconds,
458
- published_on,
459
- "type": _type,
460
- web_url_path,
461
- } | order(published_on asc)[0...5]`;
462
- return fetchSanity(query, true);
463
- }
464
-
465
- /**
466
- * Fetch upcoming events for a specific brand that are within 48 hours before their `published_on` date
467
- * and are currently ongoing based on their `length_in_seconds`.
468
- *
469
- * This function retrieves events that have a `published_on` date within the last 48 hours or are currently
470
- * ongoing based on the event's duration (`length_in_seconds`).
471
- *
472
- * @param {string} brand - The brand for which to fetch upcoming events (e.g., 'drumeo', 'pianote', etc.).
473
- * @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of event objects or null if no events are found.
474
- *
475
- * @example
476
- * // Example usage:
477
- * fetchUpcomingEvents('drumeo')
478
- * .then(events => console.log(events))
479
- * .catch(error => console.error(error));
480
- *
481
- */
482
- async function fetchLiveEvent(brand) {
483
- const baseLiveTypes = ["student-review", "student-reviews", "student-focus", "coach-stream", "live", "question-and-answer", "student-review", "boot-camps", "recording", "pack-bundle-lesson"];
484
- const liveTypes = {
485
- 'drumeo': [...baseLiveTypes, "drum-fest-international-2022", "spotlight", "the-history-of-electronic-drums", "backstage-secrets", "quick-tips", "student-collaborations", "live-streams", "podcasts", "solos", "gear-guides", "performances", "in-rhythm", "challenges", "on-the-road", "diy-drum-experiments", "rhythmic-adventures-of-captain-carson", "study-the-greats", "rhythms-from-another-planet", "tama-drums", "paiste-cymbals", "behind-the-scenes", "exploring-beats", "sonor-drums"],
486
- 'pianote': baseLiveTypes,
487
- 'guitareo': [...baseLiveTypes, "archives"],
488
- 'singeo': baseLiveTypes,
489
- 'default': baseLiveTypes
490
- };
491
-
492
- const typesString = arrayJoinWithQuotes(liveTypes[brand] ?? liveTypes['default']);
493
- const now = getSanityDate(new Date());
494
- const twoDaysAgo = getSanityDate(new Date(Date.now() - 48 * 60 * 60 * 1000)); // 48 hours ago
495
-
496
- // Adjust the query to filter events based on the calculated time window
497
- const query = `
498
- *[_type in [${typesString}] && brand == '${brand}'
499
- && published_on > '${twoDaysAgo}'
500
- || (published_on <= '${now}' && dateTime(published_on) + length_in_seconds * 1000 > '${now}')
501
- ] {
502
- "id": railcontent_id,
503
- title,
504
- "image": thumbnail.asset->url,
505
- "artist_name": instructor[0]->name,
506
- "artists": instructor[]->name,
507
- difficulty,
508
- difficulty_string,
509
- length_in_seconds,
510
- published_on,
511
- "type": _type,
512
- web_url_path,
513
- } | order(published_on asc)[0]`;
514
-
515
- return fetchSanity(query, true);
516
- }
517
-
518
-
519
- /**
520
- * Fetch content by a specific Railcontent ID.
521
- *
522
- * @param {string} id - The Railcontent ID of the content to fetch.
523
- * @returns {Promise<Object|null>} - A promise that resolves to the content object or null if not found.
524
- *
525
- * @example
526
- * fetchByRailContentId('abc123')
527
- * .then(content => console.log(content))
528
- * .catch(error => console.error(error));
529
- */
530
- async function fetchByRailContentId(id) {
531
- const query = `*[railcontent_id == ${id}]{
532
- railcontent_id,
533
- title,
534
- "image": thumbnail.asset->url,
535
- "artist_name": artist->name,
536
- artist,
537
- difficulty,
538
- difficulty_string,
539
- web_url_path,
540
- published_on
541
- }`
542
- return fetchSanity(query, false);
543
- }
544
-
545
- /**
546
- * Fetch content by an array of Railcontent IDs.
547
- *
548
- * @param {Array<string>} ids - The array of Railcontent IDs of the content to fetch.
549
- * @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of content objects or null if not found.
550
- *
551
- * @example
552
- * fetchByRailContentIds(['abc123', 'def456', 'ghi789'])
553
- * .then(contents => console.log(contents))
554
- * .catch(error => console.error(error));
555
- */
556
- async function fetchByRailContentIds(ids) {
557
- const idsString = ids.join(',');
558
- const query = `*[railcontent_id in [${idsString}]]{
559
- railcontent_id,
560
- title,
561
- "image": thumbnail.asset->url,
562
- "artist_name": artist->name,
563
- artist,
564
- difficulty,
565
- difficulty_string,
566
- web_url_path,
567
- published_on
568
- }`
569
- return fetchSanity(query, true);
570
- }
571
-
572
- /**
573
- * Fetch all content for a specific brand and type with pagination, search, and grouping options.
574
- * @param {string} brand - The brand for which to fetch content.
575
- * @param {string} type - The content type to fetch (e.g., 'song', 'artist').
576
- * @param {Object} params - Parameters for pagination, filtering, sorting, and grouping.
577
- * @param {number} [params.page=1] - The page number for pagination.
578
- * @param {number} [params.limit=10] - The number of items per page.
579
- * @param {string} [params.searchTerm=""] - The search term to filter content by title or artist.
580
- * @param {string} [params.sort="-published_on"] - The field to sort the content by.
581
- * @param {Array<string>} [params.includedFields=[]] - The fields to include in the query.
582
- * @param {string} [params.groupBy=""] - The field to group the results by (e.g., 'artist', 'genre').
583
- * @returns {Promise<Object|null>} - The fetched content data or null if not found.
584
- *
585
- * @example
586
- * fetchAll('drumeo', 'song', {
587
- * page: 2,
588
- * limit: 20,
589
- * searchTerm: 'jazz',
590
- * sort: '-popularity',
591
- * includedFields: ['difficulty,Intermediate'],
592
- * groupBy: 'artist'
593
- * })
594
- * .then(content => console.log(content))
595
- * .catch(error => console.error(error));
596
- */
597
- async function fetchAll(brand, type, {
598
- page = 1,
599
- limit = 10,
600
- searchTerm = "",
601
- sort = "-published_on",
602
- includedFields = [],
603
- groupBy = ""
604
- }) {
605
- const start = (page - 1) * limit;
606
- const end = start + limit;
607
-
608
- // Construct the search filter
609
- const searchFilter = searchTerm
610
- ? `&& (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
611
- : "";
612
-
613
- // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
614
- const includedFieldsFilter = includedFields.length > 0
615
- ? includedFields.map(field => {
616
- let [key, value] = field.split(',');
617
- if (key === 'difficulty') {
618
- key = 'difficulty_string';
619
- }
620
- return `&& ${key} == "${value}"`;
621
- }).join(' ')
622
- : "";
623
-
624
- // Determine the sort order
625
- let sortOrder;
626
- switch (sort) {
627
- case "slug":
628
- sortOrder = "artist->name asc";
629
- break;
630
- case "published_on":
631
- sortOrder = "published_on desc";
632
- break;
633
- case "-published_on":
634
- sortOrder = "published_on asc";
635
- break;
636
- case "-slug":
637
- sortOrder = "artist->name desc";
638
- break;
639
- case "-popularity":
640
- sortOrder = "popularity desc";
641
- break;
642
- default:
643
- sortOrder = "published_on asc";
644
- break;
645
- }
646
-
647
- // Determine the group by clause
648
- let query = "";
649
- let manyReference = true; //TODO: define whether reference is one to one or one to many
650
- if (groupBy !== "" && !manyReference) {
651
- query = `
652
- {
653
- "total": count(*[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id) > 0]),
654
- "entity": *[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id) > 0]
655
- {
656
- 'id': _id,
657
- 'type': _type,
658
- name,
659
- 'head_shot_picture_url': thumbnail_url.asset->url,
660
- 'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id),
661
- 'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]{
662
- railcontent_id,
663
- title,
664
- "image": thumbnail.asset->url,
665
- difficulty,
666
- difficulty_string,
667
- web_url_path,
668
- published_on,
669
- ${groupBy}
670
- }[0...10]
671
- }
672
- |order(${sortOrder})
673
- [${start}...${end}]
674
- }`;
675
- } else if (groupBy !== "" && manyReference) {
676
- query = `
677
- {
678
- "total": count(*[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref]._id)>0]),
679
- "entity": *[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref]._id) > 0]
680
- {
681
- 'id': _id,
682
- 'type': _type,
683
- name,
684
- 'head_shot_picture_url': thumbnail_url.asset->url,
685
- 'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref ]._id),
686
- 'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref ]{
687
- railcontent_id,
688
- title,
689
- "image": thumbnail.asset->url,
690
- difficulty,
691
- difficulty_string,
692
- web_url_path,
693
- published_on,
694
- ${groupBy}
695
- }[0...10]
696
- }
697
- |order(${sortOrder})
698
- [${start}...${end}]
699
- }`;
700
- } else {
701
- query = `
702
- {
703
- "entity": *[_type == '${type}' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}] | order(${sortOrder}) [${start}...${end}] {
704
- railcontent_id,
705
- title,
706
- "image": thumbnail.asset->url,
707
- difficulty,
708
- difficulty_string,
709
- web_url_path,
710
- published_on
711
- },
712
- "total": count(*[_type == '${type}' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}])
713
- }
714
- `;
715
- }
716
-
717
- return fetchSanity(query, false);
718
- }
719
-
720
- /**
721
- * Fetches all available filter options based on various criteria such as brand, filters, style, artist, content type, and search term.
722
- *
723
- * This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
724
- * The filter options are dynamically generated based on the provided filters, style, artist, and content type.
725
- *
726
- * @param {string} brand - The brand for which to fetch the filter options.
727
- * @param {string} filters - Additional filters to apply to the query, typically in the format of Sanity GROQ queries.
728
- * @param {string} [style] - Optional style or genre to filter the results. If provided, the query will check if the style exists in the genre array.
729
- * @param {string} [artist] - Optional artist name to filter the results. If provided, the query will check if the artist's name matches.
730
- * @param {string} contentType - The content type to fetch (e.g., 'song', 'lesson').
731
- * @param {string} [term] - Optional search term to match against various fields such as title, album, artist name, and genre.
732
- *
733
- * @returns {Promise<Object|null>} - A promise that resolves to an object containing the total results and filter options, or null if the query fails.
734
- *
735
- * @example
736
- * // Example usage:
737
- * fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
738
- * .then(options => console.log(options))
739
- * .catch(error => console.error(error));
740
- */
741
- async function fetchAllFilterOptions(
742
- brand,
743
- filters,
744
- style,
745
- artist,
746
- contentType,
747
- term
748
- ){
749
- const query = `
750
- {
751
- "meta": {
752
- "totalResults": count(*[_type == '${contentType}' && brand == "${brand}" && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} ${filters}
753
- ${term ? `&& (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
754
- "filterOptions": {
755
- "difficulty": [
756
- {"type": "Introductory", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Introductory" ${filters}])},
757
- {"type": "Beginner", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Beginner" ${filters}])},
758
- {"type": "Intermediate", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Intermediate" ${filters}])},
759
- {"type": "Advanced", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Advanced" ${filters}])},
760
- {"type": "Expert", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Expert" ${filters}])}
761
- ][count > 0],
762
- "instrumentless": [
763
- {"type": "Full Song Only", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && instrumentless == false ${filters}])},
764
- {"type": "Instrument Removed", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && instrumentless == true ${filters}])}
765
- ][count > 0],
766
- "genre": *[_type == 'genre' && '${contentType}' in filter_types] {
767
- "type": name,
768
- "count": count(*[_type == '${contentType}' && brand == "${brand}" && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && references(^._id)])
769
- }[count > 0]
770
- }
771
- }
772
- }
773
- `;
774
-
775
- return fetchSanity(query, false);
776
- }
777
-
778
- /**
779
- * Fetch children content by Railcontent ID.
780
- * @param {string} railcontentId - The Railcontent ID of the parent content.
781
- * @returns {Promise<Array<Object>|null>} - The fetched children content data or null if not found.
782
- */
783
- async function fetchChildren(railcontentId) {
784
- //TODO: Implement getByParentId include sum XP
785
- const query = `*[_railcontent_id == ${railcontentId}]{
786
- railcontent_id,
787
- title,
788
- "image": thumbnail.asset->url,
789
- "artist_name": artist->name,
790
- artist,
791
- difficulty,
792
- difficulty_string,
793
- web_url_path,
794
- published_on
795
- } | order(published_on asc)`
796
- return fetchSanity(query, true);
797
- }
798
-
799
- /**
800
- * Fetch the next lesson for a specific method by Railcontent ID.
801
- * @param {string} railcontentId - The Railcontent ID of the current lesson.
802
- * @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
803
- */
804
- async function fetchMethodNextLesson(railcontentId) {
805
- //TODO: Implement getNextContentForParentContentForUser
806
- const query = `*[_railcontent_id == ${railcontentId}]{
807
- railcontent_id,
808
- title,
809
- "image": thumbnail.asset->url,
810
- "artist_name": artist->name,
811
- artist,
812
- difficulty,
813
- difficulty_string,
814
- web_url_path,
815
- published_on
816
- }`
817
- return fetchSanity(query, false);
818
- }
819
-
820
- /**
821
- * Fetch all children of a specific method by Railcontent ID.
822
- * @param {string} railcontentId - The Railcontent ID of the method.
823
- * @returns {Promise<Array<Object>|null>} - The fetched children data or null if not found.
824
- */
825
- async function fetchMethodChildren(railcontentId) {
826
- //TODO: Implement getByParentId include sum XP
827
- return fetchChildren(railcontentId);
828
- }
829
-
830
- /**
831
- * Fetch the next and previous lessons for a specific lesson by Railcontent ID.
832
- * @param {string} railcontentId - The Railcontent ID of the current lesson.
833
- * @returns {Promise<Object|null>} - The fetched next and previous lesson data or null if found.
834
- */
835
- async function fetchNextPreviousLesson(railcontentId) {
836
- //TODO: Implement getTypeNeighbouringSiblings/getNextAndPreviousLessons
837
- const query = `*[_railcontent_id == ${railcontentId}]{
838
- railcontent_id,
839
- title,
840
- "image": thumbnail.asset->url,
841
- "artist_name": artist->name,
842
- artist,
843
- difficulty,
844
- difficulty_string,
845
- web_url_path,
846
- published_on
847
- }`
848
- return fetchSanity(query, false);
849
- }
850
-
851
- /**
852
- * Fetch the page data for a specific lesson by Railcontent ID.
853
- * @param {string} railContentId - The Railcontent ID of the current lesson.
854
- * @returns {Promise<Object|null>} - The fetched page data or null if found.
855
- *
856
- * @example
857
- * fetchLessonContent('lesson123')
858
- * .then(data => console.log(data))
859
- * .catch(error => console.error(error));
860
- */
861
- async function fetchLessonContent(railContentId) {
862
- const query = `*[railcontent_id == ${railContentId} ]
863
- {title, published_on,"type":_type, "resources": resource, difficulty, difficulty_string, brand, soundslice, instrumentless, railcontent_id, "id":railcontent_id, slug, artist->,"thumbnail_url":thumbnail.asset->url, "url": web_url_path, soundslice_slug,description,
864
- "chapters": chapter[]{
865
- chapter_description,
866
- chapter_timecode,
867
- "chapter_thumbnail_url": chapter_thumbnail_url.asset->url
868
- },
869
- "coaches": instructor[]-> {
870
- name,
871
- "id":_id,
872
- "coach_profile_image":thumbnail_url.asset->url
873
- },
874
- "instructors":instructor[]->name,
875
- instructor[]->,
876
- "assignments":assignment[]{
877
- "id": railcontent_id,
878
- "soundslice_slug": assignment_soundslice,
879
- "title": assignment_title,
880
- "sheet_music_image_url": assignment_sheet_music_image,
881
- "timecode": assignment_timecode,
882
- "description": assignment_description
883
- },
884
- video}`
885
- return fetchSanity(query, false);
886
- }
887
-
888
- /**
889
- * Fetch related lessons for a specific lesson by RailContent ID and type.
890
- * @param {string} railContentId - The RailContent ID of the current lesson.
891
- * @param {string} brand - The current brand.
892
- * @returns {Promise<Array<Object>|null>} - The fetched related lessons data or null if not found.
893
- */
894
- async function fetchRelatedLessons(railContentId, brand) {
895
- // let sort = 'published_on'
896
- // if (type == 'rhythmic-adventures-of-captain-carson' ||
897
- // type == 'diy-drum-experiments' ||
898
- // type == 'in-rhythm') {
899
- // sort = 'sort';
900
- // }
901
- //TODO: Implement $this->contentService->getFiltered
902
- const query = `*[railcontent_id == ${railContentId} && brand == "${brand}" && references(*[_type=='permission']._id)]{
903
- "related_lessons" : array::unique([
904
- ...(*[_type=="song" && brand == "${brand}" && references(^.artist->_id)]{_id, "id":railcontent_id, published_on, title, "thumbnail_url":thumbnail.asset->url, difficulty_string, railcontent_id, artist->}[0...11]),
905
- ...(*[_type=="song" && brand == "${brand}" && references(^.genre[]->_id)]{_id, "id":railcontent_id, published_on, title, "thumbnail_url":thumbnail.asset->url, difficulty_string, railcontent_id, artist->}[0...11])
906
- ])|order(published_on, railcontent_id)[0...11]}`;
907
- return fetchSanity(query, false);
908
- }
909
-
910
- /**
911
- * Fetch all content for a specific pack by Railcontent ID.
912
- * @param {string} railcontentId - The Railcontent ID of the pack.
913
- * @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
914
- */
915
- async function fetchPackAll(railcontentId) {
916
- //TODO: Implement getPacks
917
- const query = `*[_railcontent_id == ${railcontentId}]{
918
- railcontent_id,
919
- title,
920
- "image": thumbnail.asset->url,
921
- "artist_name": artist->name,
922
- artist,
923
- difficulty,
924
- difficulty_string,
925
- web_url_path,
926
- published_on
927
- } | order(published_on asc)[0...5]`
928
- return fetchSanity(query, true);
929
- }
930
-
931
- /**
932
- * Fetch all children of a specific pack by Railcontent ID.
933
- * @param {string} railcontentId - The Railcontent ID of the pack.
934
- * @returns {Promise<Array<Object>|null>} - The fetched pack children data or null if not found.
935
- *
936
- * @example
937
- * fetchPackChildren('pack123')
938
- * .then(children => console.log(children))
939
- * .catch(error => console.error(error));
940
- */
941
- async function fetchPackChildren(railcontentId) {
942
- return fetchChildren(railcontentId, 'pack');
943
- }
944
-
945
- /**
946
- * Fetch data from the Sanity API based on a provided query.
947
- *
948
- * @param {string} query - The GROQ query to execute against the Sanity API.
949
- * @param {boolean} isList - Whether to return an array or a single result.
950
- * @returns {Promise<Object|null>} - A promise that resolves to the fetched data or null if an error occurs or no results are found.
951
- *
952
- * @example
953
- * const query = `*[_type == "song"]{title, artist->name}`;
954
- * fetchSanity(query, true)
955
- * .then(data => console.log(data))
956
- * .catch(error => console.error(error));
957
- */
958
- async function fetchSanity(query, isList) {
959
- // Check the config object before proceeding
960
- if (!checkConfig(globalConfig)) {
961
- return null;
962
- }
963
-
964
- if (globalConfig.debug) {
965
- console.log("fetchSanity Query:", query);
966
- }
967
-
968
- const encodedQuery = encodeURIComponent(query);
969
- const api = globalConfig.useCachedAPI ? 'apicdn' : 'api'
970
- const url = `https://${globalConfig.projectId}.${api}.sanity.io/v${globalConfig.version}/data/query/${globalConfig.dataset}?query=${encodedQuery}`;
971
- const headers = {
972
- 'Authorization': `Bearer ${globalConfig.token}`,
973
- 'Content-Type': 'application/json'
974
- };
975
-
976
- try {
977
- const response = await fetch(url, {headers});
978
- const result = await response.json();
979
- if (result.result) {
980
- if (globalConfig.debug) {
981
- console.log("fetchSanity Results:", result);
982
- }
983
- return isList ? result.result : result.result[0];
984
- } else {
985
- throw new Error('No results found');
986
- }
987
- } catch (error) {
988
- console.error('fetchSanity: Fetch error:', error);
989
- return null;
990
- }
991
- }
992
-
993
-
994
- //Helper Functions
995
- function arrayJoinWithQuotes(array, delimiter = ',') {
996
- const wrapped = array.map(value => `'${value}'`);
997
- return wrapped.join(delimiter)
998
- }
999
-
1000
- function getSanityDate(date) {
1001
- return date.toISOString();
1002
- }
1003
-
1004
- function checkConfig(config) {
1005
- if (!config.token) {
1006
- console.warn('fetchSanity: The "token" property is missing in the config object.');
1007
- return false;
1008
- }
1009
- if (!config.projectId) {
1010
- console.warn('fetchSanity: The "projectId" property is missing in the config object.');
1011
- return false;
1012
- }
1013
- if (!config.dataset) {
1014
- console.warn('fetchSanity: The "dataset" property is missing in the config object.');
1015
- return false;
1016
- }
1017
- if (!config.version) {
1018
- console.warn('fetchSanity: The "version" property is missing in the config object.');
1019
- return false;
1020
- }
1021
- return true;
1022
- }
1023
-
1024
-
1025
- //Main
1026
- module.exports = {
1027
- initializeSanityService,
1
+ import {
2
+ fetchSongById,
3
+ fetchArtists,
4
+ fetchSongArtistCount,
5
+ fetchRelatedSongs,
6
+ fetchAllSongs,
7
+ fetchSongFilterOptions,
8
+ fetchSongCount,
9
+ fetchWorkouts,
10
+ fetchNewReleases,
11
+ fetchUpcomingEvents,
12
+ fetchByRailContentId,
13
+ fetchByRailContentIds,
14
+ fetchAll,
15
+ fetchAllFilterOptions,
16
+ fetchMethodNextLesson,
17
+ fetchMethodChildren,
18
+ fetchNextPreviousLesson,
19
+ fetchRelatedLessons,
20
+ fetchPackAll,
21
+ fetchPackChildren,
22
+ fetchLessonContent
23
+ } from './services/sanity.js';
24
+
25
+ import {
26
+ initializeService
27
+ } from './services/config.js'
28
+
29
+
30
+ export {
31
+ initializeService,
1028
32
  fetchSongById,
1029
33
  fetchArtists,
1030
34
  fetchSongArtistCount,
@@ -1034,7 +38,6 @@ module.exports = {
1034
38
  fetchSongCount,
1035
39
  fetchWorkouts,
1036
40
  fetchNewReleases,
1037
- fetchLiveEvent,
1038
41
  fetchUpcomingEvents,
1039
42
  fetchByRailContentId,
1040
43
  fetchByRailContentIds,
@@ -1047,4 +50,4 @@ module.exports = {
1047
50
  fetchPackAll,
1048
51
  fetchPackChildren,
1049
52
  fetchLessonContent
1050
- };
53
+ }