@churchapps/content-providers 0.3.0 → 0.4.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/dist/index.cjs CHANGED
@@ -21,43 +21,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  APlayProvider: () => APlayProvider,
24
- ApiHelper: () => ApiHelper,
25
24
  B1ChurchProvider: () => B1ChurchProvider,
26
25
  BibleProjectProvider: () => BibleProjectProvider,
27
26
  CbnProvider: () => CbnProvider,
28
- DEFAULT_DURATION_CONFIG: () => DEFAULT_DURATION_CONFIG,
29
- DeviceFlowHelper: () => DeviceFlowHelper,
30
27
  DropboxProvider: () => DropboxProvider,
31
- FormatConverters: () => FormatConverters_exports,
32
- FormatResolver: () => FormatResolver,
33
28
  HighVoltageKidsProvider: () => HighVoltageKidsProvider,
34
29
  JesusFilmProvider: () => JesusFilmProvider,
35
30
  LessonsChurchProvider: () => LessonsChurchProvider,
36
- OAuthHelper: () => OAuthHelper,
31
+ LifeChurchProvider: () => LifeChurchProvider,
37
32
  PlanningCenterProvider: () => PlanningCenterProvider,
38
33
  SignPresenterProvider: () => SignPresenterProvider,
39
34
  TokenHelper: () => TokenHelper,
40
35
  VERSION: () => VERSION,
41
- appendToPath: () => appendToPath,
42
- buildPath: () => buildPath,
43
- countWords: () => countWords,
44
- createFile: () => createFile,
45
- createFolder: () => createFolder,
46
- detectMediaType: () => detectMediaType,
47
- estimateDuration: () => estimateDuration,
48
- estimateImageDuration: () => estimateImageDuration,
49
- estimateTextDuration: () => estimateTextDuration,
50
- generatePath: () => generatePath,
51
36
  getAllProviders: () => getAllProviders,
52
37
  getAvailableProviders: () => getAvailableProviders,
53
38
  getProvider: () => getProvider,
54
39
  getProviderConfig: () => getProviderConfig,
55
- getSegment: () => getSegment,
56
40
  isContentFile: () => isContentFile,
57
41
  isContentFolder: () => isContentFolder,
58
- isMediaFile: () => isMediaFile,
59
42
  navigateToPath: () => navigateToPath,
60
- parsePath: () => parsePath,
61
43
  registerProvider: () => registerProvider
62
44
  });
63
45
  module.exports = __toCommonJS(index_exports);
@@ -70,64 +52,6 @@ function isContentFile(item) {
70
52
  return item.type === "file";
71
53
  }
72
54
 
73
- // src/utils.ts
74
- function slugify(text) {
75
- return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
76
- }
77
- var VIDEO_EXTENSIONS = [".mp4", ".webm", ".m3u8", ".mov", ".avi", ".mkv", ".m4v"];
78
- var IMAGE_EXTENSIONS = [
79
- ".jpg",
80
- ".jpeg",
81
- ".png",
82
- ".gif",
83
- ".bmp",
84
- ".svg",
85
- ".webp",
86
- ".tiff",
87
- ".tif"
88
- ];
89
- function detectMediaType(url, explicitType) {
90
- if (explicitType === "video" || explicitType?.startsWith("video/")) return "video";
91
- if (explicitType === "image" || explicitType?.startsWith("image/")) return "image";
92
- const lower = url.toLowerCase();
93
- if (VIDEO_EXTENSIONS.some((p) => lower.includes(p)) || lower.includes("stream.mux.com")) return "video";
94
- return "image";
95
- }
96
- function isMediaFile(filename) {
97
- const lower = filename.toLowerCase();
98
- return [...VIDEO_EXTENSIONS, ...IMAGE_EXTENSIONS].some((ext) => lower.endsWith(ext));
99
- }
100
- function createFolder(id, title, path, thumbnail, isLeaf) {
101
- return { type: "folder", id, title, path, thumbnail, isLeaf };
102
- }
103
- function createFile(id, title, url, options) {
104
- return { type: "file", id, title, url, mediaType: options?.mediaType ?? detectMediaType(url), thumbnail: options?.thumbnail, muxPlaybackId: options?.muxPlaybackId, seconds: options?.seconds, loop: options?.loop, loopVideo: options?.loopVideo, streamUrl: options?.streamUrl };
105
- }
106
-
107
- // src/pathUtils.ts
108
- function parsePath(path) {
109
- if (!path || path === "/" || path === "") {
110
- return { segments: [], depth: 0 };
111
- }
112
- const segments = path.replace(/^\//, "").split("/").filter(Boolean);
113
- return { segments, depth: segments.length };
114
- }
115
- function getSegment(path, index) {
116
- const { segments } = parsePath(path);
117
- return segments[index] ?? null;
118
- }
119
- function buildPath(segments) {
120
- if (segments.length === 0) return "/";
121
- return "/" + segments.join("/");
122
- }
123
- function appendToPath(basePath, segment) {
124
- if (!basePath || basePath === "/" || basePath === "") {
125
- return "/" + segment;
126
- }
127
- const cleanBase = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
128
- return cleanBase + "/" + segment;
129
- }
130
-
131
55
  // src/instructionPathUtils.ts
132
56
  function navigateToPath(instructions, path) {
133
57
  if (!path || !instructions?.items) return null;
@@ -139,283 +63,6 @@ function navigateToPath(instructions, path) {
139
63
  }
140
64
  return current;
141
65
  }
142
- function generatePath(indices) {
143
- return indices.join(".");
144
- }
145
-
146
- // src/durationUtils.ts
147
- var DEFAULT_DURATION_CONFIG = {
148
- secondsPerImage: 15,
149
- wordsPerMinute: 150
150
- };
151
- function countWords(text) {
152
- if (!text || !text.trim()) return 0;
153
- return text.trim().split(/\s+/).length;
154
- }
155
- function estimateImageDuration(config = {}) {
156
- return config.secondsPerImage ?? DEFAULT_DURATION_CONFIG.secondsPerImage;
157
- }
158
- function estimateTextDuration(text, config = {}) {
159
- const words = countWords(text);
160
- const wpm = config.wordsPerMinute ?? DEFAULT_DURATION_CONFIG.wordsPerMinute;
161
- return Math.ceil(words / wpm * 60);
162
- }
163
- function estimateDuration(mediaType, options) {
164
- const config = options?.config ?? {};
165
- switch (mediaType) {
166
- case "image":
167
- return estimateImageDuration(config);
168
- case "text":
169
- if (options?.wordCount) {
170
- const wpm = config.wordsPerMinute ?? DEFAULT_DURATION_CONFIG.wordsPerMinute;
171
- return Math.ceil(options.wordCount / wpm * 60);
172
- }
173
- if (options?.text) {
174
- return estimateTextDuration(options.text, config);
175
- }
176
- return 0;
177
- case "video":
178
- default:
179
- return 0;
180
- }
181
- }
182
-
183
- // src/FormatConverters.ts
184
- var FormatConverters_exports = {};
185
- __export(FormatConverters_exports, {
186
- expandedInstructionsToPlaylist: () => expandedInstructionsToPlaylist,
187
- expandedInstructionsToPresentations: () => expandedInstructionsToPresentations,
188
- instructionsToPlaylist: () => instructionsToPlaylist,
189
- instructionsToPresentations: () => instructionsToPresentations,
190
- playlistToExpandedInstructions: () => playlistToExpandedInstructions,
191
- playlistToInstructions: () => playlistToInstructions,
192
- playlistToPresentations: () => playlistToPresentations,
193
- presentationsToExpandedInstructions: () => presentationsToExpandedInstructions,
194
- presentationsToPlaylist: () => presentationsToPlaylist
195
- });
196
- function generateId() {
197
- return "gen-" + Math.random().toString(36).substring(2, 11);
198
- }
199
- function mapItemTypeToActionType(itemType) {
200
- switch (itemType) {
201
- case "action":
202
- case "lessonAction":
203
- case "providerPresentation":
204
- case "play":
205
- case "addon":
206
- case "add-on":
207
- case "lessonAddOn":
208
- case "providerFile":
209
- return "play";
210
- default:
211
- return "other";
212
- }
213
- }
214
- function presentationsToPlaylist(plan) {
215
- if (plan.allFiles && plan.allFiles.length > 0) {
216
- return [...plan.allFiles];
217
- }
218
- const files = [];
219
- for (const section of plan.sections) {
220
- for (const presentation of section.presentations) {
221
- files.push(...presentation.files);
222
- }
223
- }
224
- return files;
225
- }
226
- function mapActionTypeToItemType(actionType) {
227
- switch (actionType) {
228
- case "play":
229
- return "action";
230
- default:
231
- return "item";
232
- }
233
- }
234
- function presentationsToExpandedInstructions(plan) {
235
- return {
236
- name: plan.name,
237
- items: plan.sections.map((section) => ({
238
- id: section.id,
239
- itemType: "section",
240
- label: section.name,
241
- children: section.presentations.map((pres) => ({
242
- id: pres.id,
243
- itemType: mapActionTypeToItemType(pres.actionType),
244
- label: pres.name,
245
- description: pres.actionType !== "other" ? pres.actionType : void 0,
246
- seconds: pres.files.reduce((sum, f) => sum + (f.seconds || 0), 0) || void 0,
247
- children: pres.files.map((f) => ({
248
- id: f.id,
249
- itemType: "file",
250
- label: f.title,
251
- seconds: f.seconds,
252
- downloadUrl: f.downloadUrl || f.url,
253
- thumbnail: f.thumbnail
254
- }))
255
- }))
256
- }))
257
- };
258
- }
259
- function instructionsToPlaylist(instructions) {
260
- const files = [];
261
- function extractFiles(items) {
262
- for (const item of items) {
263
- if (item.downloadUrl && (item.itemType === "file" || !item.children?.length)) {
264
- files.push({ type: "file", id: item.id || item.relatedId || generateId(), title: item.label || "Untitled", mediaType: detectMediaType(item.downloadUrl), url: item.downloadUrl, downloadUrl: item.downloadUrl, seconds: item.seconds, thumbnail: item.thumbnail });
265
- }
266
- if (item.children) {
267
- extractFiles(item.children);
268
- }
269
- }
270
- }
271
- extractFiles(instructions.items);
272
- return files;
273
- }
274
- var expandedInstructionsToPlaylist = instructionsToPlaylist;
275
- function instructionsToPresentations(instructions, planId) {
276
- const allFiles = [];
277
- const sections = instructions.items.filter((item) => item.children && item.children.length > 0).map((sectionItem) => {
278
- const presentations = (sectionItem.children || []).map((presItem) => {
279
- const files = [];
280
- if (presItem.children && presItem.children.length > 0) {
281
- for (const child of presItem.children) {
282
- if (child.downloadUrl) {
283
- const file = { type: "file", id: child.id || child.relatedId || generateId(), title: child.label || "Untitled", mediaType: detectMediaType(child.downloadUrl), url: child.downloadUrl, downloadUrl: child.downloadUrl, seconds: child.seconds, thumbnail: child.thumbnail };
284
- allFiles.push(file);
285
- files.push(file);
286
- }
287
- }
288
- }
289
- if (files.length === 0 && presItem.downloadUrl) {
290
- const file = { type: "file", id: presItem.id || presItem.relatedId || generateId(), title: presItem.label || "Untitled", mediaType: detectMediaType(presItem.downloadUrl), url: presItem.downloadUrl, downloadUrl: presItem.downloadUrl, seconds: presItem.seconds, thumbnail: presItem.thumbnail };
291
- allFiles.push(file);
292
- files.push(file);
293
- }
294
- return { id: presItem.id || presItem.relatedId || generateId(), name: presItem.label || "Presentation", actionType: mapItemTypeToActionType(presItem.itemType), files };
295
- });
296
- return { id: sectionItem.id || sectionItem.relatedId || generateId(), name: sectionItem.label || "Section", presentations };
297
- });
298
- return { id: planId || generateId(), name: instructions.name || "Plan", sections, allFiles };
299
- }
300
- var expandedInstructionsToPresentations = instructionsToPresentations;
301
- function playlistToPresentations(files, planName = "Playlist", sectionName = "Content") {
302
- const presentations = files.map((file, index) => ({ id: `pres-${index}-${file.id}`, name: file.title, actionType: "play", files: [file] }));
303
- return { id: "playlist-plan-" + generateId(), name: planName, sections: [{ id: "main-section", name: sectionName, presentations }], allFiles: [...files] };
304
- }
305
- function playlistToInstructions(files, name = "Playlist") {
306
- return { name, items: [{ id: "main-section", itemType: "section", label: "Content", children: files.map((file, index) => ({ id: file.id || `item-${index}`, itemType: "file", label: file.title, seconds: file.seconds, downloadUrl: file.downloadUrl || file.url, thumbnail: file.thumbnail })) }] };
307
- }
308
- var playlistToExpandedInstructions = playlistToInstructions;
309
-
310
- // src/FormatResolver.ts
311
- var FormatResolver = class {
312
- constructor(provider, options = {}) {
313
- this.provider = provider;
314
- this.options = { allowLossy: options.allowLossy ?? true };
315
- }
316
- getProvider() {
317
- return this.provider;
318
- }
319
- /** Extract the last segment from a path to use as fallback ID/title */
320
- getIdFromPath(path) {
321
- const { segments } = parsePath(path);
322
- return segments[segments.length - 1] || "content";
323
- }
324
- async getPlaylist(path, auth) {
325
- const caps = this.provider.capabilities;
326
- if (caps.playlist && this.provider.getPlaylist) {
327
- const result = await this.provider.getPlaylist(path, auth);
328
- if (result && result.length > 0) return result;
329
- }
330
- if (caps.instructions && this.provider.getInstructions) {
331
- const expanded = await this.provider.getInstructions(path, auth);
332
- if (expanded) return instructionsToPlaylist(expanded);
333
- }
334
- return null;
335
- }
336
- async getPlaylistWithMeta(path, auth) {
337
- const caps = this.provider.capabilities;
338
- if (caps.playlist && this.provider.getPlaylist) {
339
- const result = await this.provider.getPlaylist(path, auth);
340
- if (result && result.length > 0) {
341
- return { data: result, meta: { isNative: true, isLossy: false } };
342
- }
343
- }
344
- if (caps.instructions && this.provider.getInstructions) {
345
- const expanded = await this.provider.getInstructions(path, auth);
346
- if (expanded) return { data: instructionsToPlaylist(expanded), meta: { isNative: false, sourceFormat: "instructions", isLossy: false } };
347
- }
348
- return { data: null, meta: { isNative: false, isLossy: false } };
349
- }
350
- // async getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null> {
351
- // const caps = this.provider.capabilities;
352
- // const fallbackId = this.getIdFromPath(path);
353
- // if (caps.presentations) {
354
- // const result = await this.provider.getPresentations(path, auth);
355
- // if (result) return result;
356
- // }
357
- // if (caps.instructions && this.provider.getInstructions) {
358
- // const expanded = await this.provider.getInstructions(path, auth);
359
- // if (expanded) return Converters.instructionsToPresentations(expanded, fallbackId);
360
- // }
361
- // if (this.options.allowLossy && caps.playlist && this.provider.getPlaylist) {
362
- // const playlist = await this.provider.getPlaylist(path, auth);
363
- // if (playlist && playlist.length > 0) {
364
- // return Converters.playlistToPresentations(playlist, fallbackId);
365
- // }
366
- // }
367
- // return null;
368
- // }
369
- // async getPresentationsWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{ data: Plan | null; meta: ResolvedFormatMeta }> {
370
- // const caps = this.provider.capabilities;
371
- // const fallbackId = this.getIdFromPath(path);
372
- // if (caps.presentations) {
373
- // const result = await this.provider.getPresentations(path, auth);
374
- // if (result) {
375
- // return { data: result, meta: { isNative: true, isLossy: false } };
376
- // }
377
- // }
378
- // if (caps.instructions && this.provider.getInstructions) {
379
- // const expanded = await this.provider.getInstructions(path, auth);
380
- // if (expanded) return { data: Converters.instructionsToPresentations(expanded, fallbackId), meta: { isNative: false, sourceFormat: "instructions", isLossy: false } };
381
- // }
382
- // if (this.options.allowLossy && caps.playlist && this.provider.getPlaylist) {
383
- // const playlist = await this.provider.getPlaylist(path, auth);
384
- // if (playlist && playlist.length > 0) return { data: Converters.playlistToPresentations(playlist, fallbackId), meta: { isNative: false, sourceFormat: "playlist", isLossy: true } };
385
- // }
386
- // return { data: null, meta: { isNative: false, isLossy: false } };
387
- // }
388
- async getInstructions(path, auth) {
389
- const caps = this.provider.capabilities;
390
- const fallbackTitle = this.getIdFromPath(path);
391
- if (caps.instructions && this.provider.getInstructions) {
392
- const result = await this.provider.getInstructions(path, auth);
393
- if (result) return result;
394
- }
395
- if (this.options.allowLossy && caps.playlist && this.provider.getPlaylist) {
396
- const playlist = await this.provider.getPlaylist(path, auth);
397
- if (playlist && playlist.length > 0) {
398
- return playlistToInstructions(playlist, fallbackTitle);
399
- }
400
- }
401
- return null;
402
- }
403
- async getInstructionsWithMeta(path, auth) {
404
- const caps = this.provider.capabilities;
405
- const fallbackTitle = this.getIdFromPath(path);
406
- if (caps.instructions && this.provider.getInstructions) {
407
- const result = await this.provider.getInstructions(path, auth);
408
- if (result) {
409
- return { data: result, meta: { isNative: true, isLossy: false } };
410
- }
411
- }
412
- if (this.options.allowLossy && caps.playlist && this.provider.getPlaylist) {
413
- const playlist = await this.provider.getPlaylist(path, auth);
414
- if (playlist && playlist.length > 0) return { data: playlistToInstructions(playlist, fallbackTitle), meta: { isNative: false, sourceFormat: "playlist", isLossy: true } };
415
- }
416
- return { data: null, meta: { isNative: false, isLossy: false } };
417
- }
418
- };
419
66
 
420
67
  // src/helpers/OAuthHelper.ts
421
68
  var OAuthHelper = class {
@@ -579,6 +226,19 @@ var ApiHelper = class {
579
226
  }
580
227
  };
581
228
 
229
+ // src/pathUtils.ts
230
+ function parsePath(path) {
231
+ if (!path || path === "/" || path === "") {
232
+ return { segments: [], depth: 0 };
233
+ }
234
+ const segments = path.replace(/^\//, "").split("/").filter(Boolean);
235
+ return { segments, depth: segments.length };
236
+ }
237
+ function getSegment(path, index) {
238
+ const { segments } = parsePath(path);
239
+ return segments[index] ?? null;
240
+ }
241
+
582
242
  // src/providers/aPlay/APlayApi.ts
583
243
  var API_BASE = "https://api-prod.amazingkids.app";
584
244
  async function checkMediaLicense(mediaId, auth) {
@@ -599,6 +259,57 @@ async function checkMediaLicense(mediaId, auth) {
599
259
  }
600
260
  }
601
261
 
262
+ // src/utils.ts
263
+ var IMAGE_DURATION_SECONDS = 15;
264
+ function slugify(text) {
265
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
266
+ }
267
+ var VIDEO_EXTENSIONS = [".mp4", ".webm", ".m3u8", ".mov", ".avi", ".mkv", ".m4v"];
268
+ var IMAGE_EXTENSIONS = [
269
+ ".jpg",
270
+ ".jpeg",
271
+ ".png",
272
+ ".gif",
273
+ ".bmp",
274
+ ".svg",
275
+ ".webp",
276
+ ".tiff",
277
+ ".tif"
278
+ ];
279
+ function detectMediaType(url, explicitType) {
280
+ if (explicitType === "video" || explicitType?.startsWith("video/")) return "video";
281
+ if (explicitType === "image" || explicitType?.startsWith("image/")) return "image";
282
+ const lower = url.toLowerCase();
283
+ if (VIDEO_EXTENSIONS.some((p) => lower.includes(p)) || lower.includes("stream.mux.com")) return "video";
284
+ return "image";
285
+ }
286
+ function isMediaFile(filename) {
287
+ const lower = filename.toLowerCase();
288
+ return [...VIDEO_EXTENSIONS, ...IMAGE_EXTENSIONS].some((ext) => lower.endsWith(ext));
289
+ }
290
+ function createFolder(id, title, path, thumbnail, isLeaf) {
291
+ return { type: "folder", id, title, path, thumbnail, isLeaf };
292
+ }
293
+ function createFile(id, title, url, options) {
294
+ return { type: "file", id, title, url, mediaType: options?.mediaType ?? detectMediaType(url), thumbnail: options?.thumbnail, muxPlaybackId: options?.muxPlaybackId, seconds: options?.seconds, loop: options?.loop, loopVideo: options?.loopVideo, streamUrl: options?.streamUrl };
295
+ }
296
+ function generateId() {
297
+ return "gen-" + Math.random().toString(36).substring(2, 11);
298
+ }
299
+ function instructionsToPlaylist(instructions) {
300
+ const files = [];
301
+ function extractFiles(items) {
302
+ for (const item of items) {
303
+ if (item.downloadUrl && (item.itemType === "file" || !item.children?.length)) {
304
+ files.push({ type: "file", id: item.id || item.relatedId || generateId(), title: item.label || "Untitled", mediaType: detectMediaType(item.downloadUrl), url: item.downloadUrl, downloadUrl: item.downloadUrl, seconds: item.seconds, thumbnail: item.thumbnail });
305
+ }
306
+ if (item.children) extractFiles(item.children);
307
+ }
308
+ }
309
+ extractFiles(instructions.items);
310
+ return files;
311
+ }
312
+
602
313
  // src/providers/aPlay/APlayConverters.ts
603
314
  function extractLibraryId(path) {
604
315
  const { segments, depth } = parsePath(path);
@@ -705,7 +416,7 @@ var APlayProvider = class {
705
416
  this.config = { id: "aplay", name: "APlay", apiBase: API_BASE, oauthBase: "https://api.joinamazing.com/prod/aims/oauth", clientId: "xFJFq7yNYuXXXMx0YBiQ", scopes: ["openid", "profile", "email"], endpoints: { modules: "/prod/curriculum/modules", productLibraries: (productId) => `/prod/curriculum/modules/products/${productId}/libraries`, libraryMedia: (libraryId) => `/prod/creators/libraries/${libraryId}/media` } };
706
417
  this.requiresAuth = true;
707
418
  this.authTypes = ["oauth_pkce"];
708
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: true };
419
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: true };
709
420
  }
710
421
  async apiRequest(path, auth) {
711
422
  return this.apiHelper.apiRequest(this.config, this.id, path, auth);
@@ -757,13 +468,6 @@ var APlayProvider = class {
757
468
  const mediaItems = extractArray(response, "data", "media");
758
469
  return convertMediaToFiles(mediaItems);
759
470
  }
760
- // async getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null> {
761
- // const libraryId = extractLibraryId(path);
762
- // if (!libraryId) return null;
763
- // const files = await this.getMediaFiles(libraryId, auth) as ContentFile[];
764
- // if (files.length === 0) return null;
765
- // return convertFilesToPresentations(files, libraryId).plan;
766
- // }
767
471
  async getPlaylist(path, auth, _resolution) {
768
472
  const libraryId = extractLibraryId(path);
769
473
  if (!libraryId) return null;
@@ -797,7 +501,7 @@ var SignPresenterProvider = class {
797
501
  this.config = { id: "signpresenter", name: "SignPresenter", apiBase: "https://api.signpresenter.com", oauthBase: "https://api.signpresenter.com/oauth", clientId: "lessonsscreen-tv", scopes: ["openid", "profile", "content"], supportsDeviceFlow: true, deviceAuthEndpoint: "/device/authorize", endpoints: { playlists: "/content/playlists", messages: (playlistId) => `/content/playlists/${playlistId}/messages` } };
798
502
  this.requiresAuth = true;
799
503
  this.authTypes = ["oauth_pkce", "device_flow"];
800
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: false };
504
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
801
505
  }
802
506
  async apiRequest(path, auth) {
803
507
  return this.apiHelper.apiRequest(this.config, this.id, path, auth);
@@ -866,20 +570,6 @@ var SignPresenterProvider = class {
866
570
  }
867
571
  return files;
868
572
  }
869
- // async getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null> {
870
- // const { segments, depth } = parsePath(path);
871
- // if (depth < 2 || segments[0] !== "playlists") return null;
872
- // const playlistId = segments[1];
873
- // const files = await this.getMessages(playlistId, auth) as ContentFile[];
874
- // if (files.length === 0) return null;
875
- // // Get playlist info for title
876
- // const playlists = await this.getPlaylists(auth);
877
- // const playlist = playlists.find(p => p.id === playlistId);
878
- // const title = playlist?.title || "Playlist";
879
- // const thumbnail = (playlist as Record<string, unknown> | undefined)?.image as string | undefined;
880
- // const presentations: PlanPresentation[] = files.map(f => ({ id: f.id, name: f.title, actionType: "play" as const, files: [f] }));
881
- // return { id: playlistId, name: title as string, thumbnail, sections: [{ id: `section-${playlistId}`, name: title as string, presentations }], allFiles: files };
882
- // }
883
573
  async getPlaylist(path, auth, _resolution) {
884
574
  const { segments, depth } = parsePath(path);
885
575
  if (depth < 2 || segments[0] !== "playlists") return null;
@@ -1025,7 +715,7 @@ function buildSectionActionsMap(actionsResponse, lessonImage, feedResponse) {
1025
715
  for (const section of actionsResponse.sections) {
1026
716
  if (section.id && section.actions) {
1027
717
  sectionActionsMap.set(section.id, section.actions.map((action) => {
1028
- const seconds = action.seconds ?? estimateImageDuration();
718
+ const seconds = action.seconds ?? IMAGE_DURATION_SECONDS;
1029
719
  const rawActionType = action.actionType?.toLowerCase() || "";
1030
720
  const hasFiles = rawActionType === "play" || rawActionType === "add-on";
1031
721
  const thumbnail = action.id && actionThumbnailMap.get(action.id) || lessonImage;
@@ -1131,7 +821,7 @@ var LessonsChurchProvider = class {
1131
821
  this.config = { id: "lessonschurch", name: "Lessons.church", apiBase: API_BASE2, oauthBase: "", clientId: "", scopes: [], endpoints: { programs: "/programs/public", studies: (programId) => `/studies/public/program/${programId}`, lessons: (studyId) => `/lessons/public/study/${studyId}`, venues: (lessonId) => `/venues/public/lesson/${lessonId}`, playlist: (venueId) => `/venues/playlist/${venueId}`, feed: (venueId) => `/venues/public/feed/${venueId}`, addOns: "/addOns/public", addOnDetail: (id) => `/addOns/public/${id}` } };
1132
822
  this.requiresAuth = false;
1133
823
  this.authTypes = ["none"];
1134
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: false };
824
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
1135
825
  }
1136
826
  async getPlaylist(path, _auth, resolution) {
1137
827
  const { segments } = parsePath(path);
@@ -1242,19 +932,6 @@ var LessonsChurchProvider = class {
1242
932
  const filtered = allAddOns.filter((a) => a.category === decodedCategory);
1243
933
  return filtered.map((addOn) => createFolder(addOn.id, addOn.name, `${currentPath}/${addOn.id}`, addOn.image, true));
1244
934
  }
1245
- // async getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null> {
1246
- // const venueId = getSegment(path, 4);
1247
- // if (venueId) {
1248
- // const venueData = await apiRequest<FeedVenueInterface>(`/venues/public/feed/${venueId}`);
1249
- // if (!venueData) return null;
1250
- // return convertVenueToPlan(venueData);
1251
- // }
1252
- // const { segments } = parsePath(path);
1253
- // if (segments[0] === "addons" && segments.length === 2) {
1254
- // return convertAddOnCategoryToPlan(segments[1]);
1255
- // }
1256
- // return null;
1257
- // }
1258
935
  async getInstructions(path, _auth) {
1259
936
  const venueId = getSegment(path, 4);
1260
937
  if (venueId) {
@@ -1376,42 +1053,6 @@ async function refreshTokenWithSecret(config, auth, clientSecret) {
1376
1053
  return null;
1377
1054
  }
1378
1055
  }
1379
- async function initiateDeviceFlow(config) {
1380
- if (!config.supportsDeviceFlow || !config.deviceAuthEndpoint) return null;
1381
- try {
1382
- const response = await fetch(`${config.oauthBase}${config.deviceAuthEndpoint}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ client_id: config.clientId, scope: config.scopes.join(" ") }) });
1383
- if (!response.ok) {
1384
- return null;
1385
- }
1386
- return await response.json();
1387
- } catch {
1388
- return null;
1389
- }
1390
- }
1391
- async function pollDeviceFlowToken(config, deviceCode) {
1392
- try {
1393
- const response = await fetch(`${config.oauthBase}/token`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ grant_type: "urn:ietf:params:oauth:grant-type:device_code", device_code: deviceCode, client_id: config.clientId }) });
1394
- if (response.ok) {
1395
- const data = await response.json();
1396
- return { access_token: data.access_token, refresh_token: data.refresh_token, token_type: data.token_type || "Bearer", created_at: Math.floor(Date.now() / 1e3), expires_in: data.expires_in, scope: data.scope || config.scopes.join(" ") };
1397
- }
1398
- const errorData = await response.json();
1399
- switch (errorData.error) {
1400
- case "authorization_pending":
1401
- return { error: "authorization_pending" };
1402
- case "slow_down":
1403
- return { error: "slow_down", shouldSlowDown: true };
1404
- case "expired_token":
1405
- return null;
1406
- case "access_denied":
1407
- return null;
1408
- default:
1409
- return null;
1410
- }
1411
- } catch {
1412
- return { error: "network_error" };
1413
- }
1414
- }
1415
1056
 
1416
1057
  // src/providers/b1Church/B1ChurchApi.ts
1417
1058
  var API_BASE3 = "https://api.churchapps.org";
@@ -1750,6 +1391,7 @@ function isExternalProviderItem(item) {
1750
1391
  var B1ChurchProvider = class {
1751
1392
  constructor() {
1752
1393
  this.apiHelper = new ApiHelper();
1394
+ this.deviceFlowHelper = new DeviceFlowHelper();
1753
1395
  // Unified cache for external provider data to avoid duplicate calls across methods
1754
1396
  this.externalContentCache = {
1755
1397
  plans: /* @__PURE__ */ new Map(),
@@ -1763,109 +1405,7 @@ var B1ChurchProvider = class {
1763
1405
  this.appBase = "https://admin.b1.church";
1764
1406
  this.requiresAuth = true;
1765
1407
  this.authTypes = ["oauth_pkce", "device_flow"];
1766
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: false };
1767
- // async getPresentations(path: string, authData?: ContentProviderAuthData | null): Promise<Plan | null> {
1768
- // const { segments, depth } = parsePath(path);
1769
- // if (depth < 4 || segments[0] !== "ministries") return null;
1770
- // const ministryId = segments[1];
1771
- // const planId = segments[3];
1772
- // const planTypeId = segments[2];
1773
- // // Need to fetch plan details to get churchId and contentId
1774
- // const plans = await fetchPlans(planTypeId, authData);
1775
- // const planFolder = plans.find(p => p.id === planId);
1776
- // if (!planFolder) return null;
1777
- // const churchId = planFolder.churchId;
1778
- // const venueId = planFolder.contentId;
1779
- // const planTitle = planFolder.name || "Plan";
1780
- // if (!churchId) {
1781
- // console.warn("[B1Church getPresentations] planFolder missing churchId:", planFolder.id);
1782
- // return null;
1783
- // }
1784
- // const pathFn = this.config.endpoints.planItems as (churchId: string, planId: string) => string;
1785
- // const planItems = await this.apiRequest<B1PlanItem[]>(pathFn(churchId, planId), authData);
1786
- // // If no planItems but plan has associated provider content, fetch from that provider
1787
- // if ((!planItems || planItems.length === 0) && planFolder.providerId && planFolder.providerPlanId) {
1788
- // const externalPlan = await fetchFromProviderProxy(
1789
- // "getPresentations",
1790
- // ministryId,
1791
- // planFolder.providerId,
1792
- // planFolder.providerPlanId,
1793
- // authData
1794
- // );
1795
- // if (externalPlan) {
1796
- // return { id: planId, name: planTitle, sections: externalPlan.sections, allFiles: externalPlan.allFiles };
1797
- // }
1798
- // }
1799
- // if (!planItems || !Array.isArray(planItems)) return null;
1800
- // const venueFeed = venueId ? await fetchVenueFeed(venueId) : null;
1801
- // const sections: PlanSection[] = [];
1802
- // const allFiles: ContentFile[] = [];
1803
- // for (const sectionItem of planItems) {
1804
- // const presentations: PlanPresentation[] = [];
1805
- // for (const child of sectionItem.children || []) {
1806
- // // Try external provider resolution first (cached, uses providerContentPath)
1807
- // if (isExternalProviderItem(child) && child.providerId && child.providerPath) {
1808
- // const cacheKey = `${child.providerId}:${child.providerPath}`;
1809
- // let externalPlan = this.externalContentCache.plans.get(cacheKey);
1810
- // if (externalPlan === undefined) {
1811
- // externalPlan = await fetchFromProviderProxy(
1812
- // "getPresentations",
1813
- // ministryId,
1814
- // child.providerId,
1815
- // child.providerPath,
1816
- // authData
1817
- // );
1818
- // this.externalContentCache.plans.set(cacheKey, externalPlan);
1819
- // }
1820
- // if (externalPlan) {
1821
- // if (child.providerContentPath) {
1822
- // // Fetch instructions to enable path-based lookup (with caching)
1823
- // let externalInstructions = this.externalContentCache.instructions.get(cacheKey);
1824
- // if (externalInstructions === undefined) {
1825
- // externalInstructions = await fetchFromProviderProxy(
1826
- // "getInstructions",
1827
- // ministryId,
1828
- // child.providerId,
1829
- // child.providerPath,
1830
- // authData
1831
- // );
1832
- // this.externalContentCache.instructions.set(cacheKey, externalInstructions);
1833
- // }
1834
- // // Find and use only the specific presentation
1835
- // const matchingPresentation = this.findPresentationByPath(externalPlan, externalInstructions, child.providerContentPath);
1836
- // if (matchingPresentation) {
1837
- // presentations.push(matchingPresentation);
1838
- // if (Array.isArray(matchingPresentation.files)) {
1839
- // allFiles.push(...matchingPresentation.files);
1840
- // }
1841
- // }
1842
- // } else {
1843
- // // Add all presentations from the external plan
1844
- // for (const section of externalPlan.sections || []) {
1845
- // if (Array.isArray(section.presentations)) {
1846
- // presentations.push(...section.presentations);
1847
- // }
1848
- // }
1849
- // if (Array.isArray(externalPlan.allFiles)) {
1850
- // allFiles.push(...externalPlan.allFiles);
1851
- // }
1852
- // }
1853
- // }
1854
- // } else {
1855
- // // Handle internal items (venue feed sections, link-based files, etc.)
1856
- // const presentation = await planItemToPresentation(child, venueFeed);
1857
- // if (presentation) {
1858
- // presentations.push(presentation);
1859
- // allFiles.push(...presentation.files);
1860
- // }
1861
- // }
1862
- // }
1863
- // if (presentations.length > 0 || sectionItem.label) {
1864
- // sections.push({ id: sectionItem.id, name: sectionItem.label || "Section", presentations });
1865
- // }
1866
- // }
1867
- // return { id: planId, name: planTitle, sections, allFiles };
1868
- // }
1408
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
1869
1409
  this.planTypeId = null;
1870
1410
  }
1871
1411
  async apiRequest(path, authData) {
@@ -1884,10 +1424,10 @@ var B1ChurchProvider = class {
1884
1424
  return refreshTokenWithSecret(this.config, authData, clientSecret);
1885
1425
  }
1886
1426
  async initiateDeviceFlow() {
1887
- return initiateDeviceFlow(this.config);
1427
+ return this.deviceFlowHelper.initiateDeviceFlow(this.config);
1888
1428
  }
1889
1429
  async pollDeviceFlowToken(deviceCode) {
1890
- return pollDeviceFlowToken(this.config, deviceCode);
1430
+ return this.deviceFlowHelper.pollDeviceFlowToken(this.config, deviceCode);
1891
1431
  }
1892
1432
  async browse(path, authData) {
1893
1433
  const { segments, depth } = parsePath(path);
@@ -2304,7 +1844,6 @@ var DropboxProvider = class {
2304
1844
  this.authTypes = ["oauth_pkce"];
2305
1845
  this.capabilities = {
2306
1846
  browse: true,
2307
- presentations: false,
2308
1847
  playlist: true,
2309
1848
  instructions: true,
2310
1849
  mediaLicensing: false
@@ -2516,7 +2055,7 @@ var PlanningCenterProvider = class {
2516
2055
  this.ONE_WEEK_MS = 6048e5;
2517
2056
  this.requiresAuth = true;
2518
2057
  this.authTypes = ["oauth_pkce"];
2519
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: false };
2058
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
2520
2059
  }
2521
2060
  async apiRequest(path, auth) {
2522
2061
  return this.apiHelper.apiRequest(this.config, this.id, path, auth);
@@ -2576,54 +2115,6 @@ var PlanningCenterProvider = class {
2576
2115
  if (!response?.data) return [];
2577
2116
  return response.data.map((item) => ({ type: "file", id: item.id, title: item.attributes.title || "", mediaType: "image", url: "" }));
2578
2117
  }
2579
- // async getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null> {
2580
- // const { segments, depth } = parsePath(path);
2581
- // if (depth < 3 || segments[0] !== "serviceTypes") return null;
2582
- // const serviceTypeId = segments[1];
2583
- // const planId = segments[2];
2584
- // const pathFn = this.config.endpoints.planItems as (stId: string, pId: string) => string;
2585
- // const response = await this.apiRequest<{ data: PCOPlanItem[] }>(
2586
- // `${pathFn(serviceTypeId, planId)}?per_page=100`,
2587
- // auth
2588
- // );
2589
- // if (!response?.data) return null;
2590
- // const plans = await this.getPlans(serviceTypeId, `/serviceTypes/${serviceTypeId}`, auth);
2591
- // const plan = plans.find(p => p.id === planId);
2592
- // const planTitle = plan?.title || "Plan";
2593
- // const sections: PlanSection[] = [];
2594
- // const allFiles: ContentFile[] = [];
2595
- // let currentSection: PlanSection | null = null;
2596
- // for (const item of response.data) {
2597
- // const itemType = item.attributes.item_type;
2598
- // if (itemType === "header") {
2599
- // if (currentSection && currentSection.presentations.length > 0) sections.push(currentSection);
2600
- // currentSection = { id: item.id, name: item.attributes.title || "Section", presentations: [] };
2601
- // continue;
2602
- // }
2603
- // if (!currentSection) {
2604
- // currentSection = { id: `default-${planId}`, name: "Service", presentations: [] };
2605
- // }
2606
- // const presentation = await convertToPresentation(this.config, item, auth);
2607
- // if (presentation) {
2608
- // currentSection.presentations.push(presentation);
2609
- // allFiles.push(...presentation.files);
2610
- // }
2611
- // }
2612
- // if (currentSection && currentSection.presentations.length > 0) {
2613
- // sections.push(currentSection);
2614
- // }
2615
- // return { id: planId, name: planTitle as string, sections, allFiles };
2616
- // }
2617
- // async getPlaylist(path: string, auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null> {
2618
- // const plan = await this.getPresentations(path, auth);
2619
- // if (!plan) return null;
2620
- // return plan.allFiles.length > 0 ? plan.allFiles : null;
2621
- // }
2622
- // async getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null> {
2623
- // const plan = await this.getPresentations(path, auth);
2624
- // if (!plan) return null;
2625
- // return buildInstructionsFromPlan(plan);
2626
- // }
2627
2118
  supportsDeviceFlow() {
2628
2119
  return false;
2629
2120
  }
@@ -5043,7 +4534,6 @@ var BibleProjectProvider = class {
5043
4534
  this.authTypes = ["none"];
5044
4535
  this.capabilities = {
5045
4536
  browse: true,
5046
- presentations: true,
5047
4537
  playlist: true,
5048
4538
  instructions: true,
5049
4539
  mediaLicensing: false
@@ -5096,32 +4586,6 @@ var BibleProjectProvider = class {
5096
4586
  if (!video) return [];
5097
4587
  return [createFile(video.id, video.title, video.videoUrl, { mediaType: "video", muxPlaybackId: video.muxPlaybackId, seconds: 0 })];
5098
4588
  }
5099
- // async getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null> {
5100
- // const { segments, depth } = parsePath(path);
5101
- // if (depth < 1) return null;
5102
- // const collectionSlug = segments[0];
5103
- // const collection = this.data.collections.find(c => slugify(c.name) === collectionSlug);
5104
- // if (!collection) return null;
5105
- // // For collection level (depth 1), create a plan with all videos
5106
- // if (depth === 1) {
5107
- // const allFiles: ContentFile[] = [];
5108
- // const presentations: PlanPresentation[] = collection.videos.map(video => {
5109
- // const file: ContentFile = { type: "file", id: video.id, title: video.title, mediaType: "video", url: video.videoUrl, thumbnail: this.getMuxThumbnail(video.muxPlaybackId), muxPlaybackId: video.muxPlaybackId, seconds: 0 };
5110
- // allFiles.push(file);
5111
- // return { id: video.id, name: video.title, actionType: "play" as const, files: [file] };
5112
- // });
5113
- // return { id: slugify(collection.name), name: collection.name, thumbnail: collection.image || undefined, sections: [{ id: "videos", name: "Videos", presentations }], allFiles };
5114
- // }
5115
- // // For video level (depth 2, single video), create a simple plan
5116
- // if (depth === 2) {
5117
- // const videoId = segments[1];
5118
- // const video = collection.videos.find(v => v.id === videoId);
5119
- // if (!video) return null;
5120
- // const file: ContentFile = { type: "file", id: video.id, title: video.title, mediaType: "video", url: video.videoUrl, thumbnail: this.getMuxThumbnail(video.muxPlaybackId), muxPlaybackId: video.muxPlaybackId, seconds: 0 };
5121
- // return { id: video.id, name: video.title, thumbnail: this.getMuxThumbnail(video.muxPlaybackId), sections: [{ id: "main", name: "Content", presentations: [{ id: video.id, name: video.title, actionType: "play", files: [file] }] }], allFiles: [file] };
5122
- // }
5123
- // return null;
5124
- // }
5125
4589
  async getPlaylist(path, _auth, _resolution) {
5126
4590
  const { segments, depth } = parsePath(path);
5127
4591
  if (depth < 1) return null;
@@ -12773,7 +12237,7 @@ function groupFilesIntoActions(files, thumbnail) {
12773
12237
  const flushGroup = () => {
12774
12238
  if (currentGroup.length === 0) return;
12775
12239
  const children = currentGroup.map((file) => {
12776
- const seconds = estimateDuration(file.mediaType);
12240
+ const seconds = file.mediaType === "image" ? IMAGE_DURATION_SECONDS : 0;
12777
12241
  return {
12778
12242
  id: file.id,
12779
12243
  itemType: "file",
@@ -12811,7 +12275,7 @@ function groupFilesIntoActions(files, thumbnail) {
12811
12275
  function buildStudyInstructions(study) {
12812
12276
  const lessonItems = study.lessons.map((lesson) => {
12813
12277
  const fileItems = lesson.files.map((file) => {
12814
- const seconds = estimateDuration(file.mediaType);
12278
+ const seconds = file.mediaType === "image" ? IMAGE_DURATION_SECONDS : 0;
12815
12279
  return { id: file.id, itemType: "file", label: file.title, seconds, downloadUrl: file.url, thumbnail: lesson.image };
12816
12280
  });
12817
12281
  return { id: lesson.id, itemType: "action", label: lesson.name, actionType: "play", children: fileItems };
@@ -12846,7 +12310,6 @@ var HighVoltageKidsProvider = class {
12846
12310
  this.authTypes = ["none"];
12847
12311
  this.capabilities = {
12848
12312
  browse: true,
12849
- presentations: true,
12850
12313
  playlist: true,
12851
12314
  instructions: true,
12852
12315
  mediaLicensing: false
@@ -12860,19 +12323,6 @@ var HighVoltageKidsProvider = class {
12860
12323
  if (depth === 3) return getLessonFiles(this.data, segments[0], segments[1], segments[2]);
12861
12324
  return [];
12862
12325
  }
12863
- // async getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null> {
12864
- // const { segments, depth } = parsePath(path);
12865
- // if (depth < 2) return null;
12866
- // const study = findStudy(this.data, segments[0], segments[1]);
12867
- // if (!study) return null;
12868
- // if (depth === 2) return buildStudyPlan(study);
12869
- // if (depth === 3) {
12870
- // const lesson = findLesson(this.data, segments[0], segments[1], segments[2]);
12871
- // if (!lesson) return null;
12872
- // return buildLessonPlan(lesson);
12873
- // }
12874
- // return null;
12875
- // }
12876
12326
  async getPlaylist(path, _auth, _resolution) {
12877
12327
  const { segments, depth } = parsePath(path);
12878
12328
  if (depth < 2) return null;
@@ -12938,7 +12388,6 @@ var JesusFilmProvider = class {
12938
12388
  this.authTypes = ["none"];
12939
12389
  this.capabilities = {
12940
12390
  browse: true,
12941
- presentations: true,
12942
12391
  playlist: true,
12943
12392
  instructions: true,
12944
12393
  mediaLicensing: false
@@ -13321,7 +12770,7 @@ var CbnProvider = class {
13321
12770
  };
13322
12771
  this.requiresAuth = true;
13323
12772
  this.authTypes = ["device_flow"];
13324
- this.capabilities = { browse: true, presentations: false, playlist: true, instructions: true, mediaLicensing: false };
12773
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
13325
12774
  }
13326
12775
  async apiRequest(path, auth) {
13327
12776
  return this.apiHelper.apiRequest(this.config, this.id, path, auth);
@@ -17023,7 +16472,6 @@ var LifeChurchProvider = class {
17023
16472
  this.authTypes = ["none"];
17024
16473
  this.capabilities = {
17025
16474
  browse: true,
17026
- presentations: true,
17027
16475
  playlist: true,
17028
16476
  instructions: true,
17029
16477
  mediaLicensing: false
@@ -17273,28 +16721,20 @@ var unimplementedProviders = [
17273
16721
  }
17274
16722
  ];
17275
16723
  function initializeProviders() {
17276
- const aplay = new APlayProvider();
17277
- const b1Church = new B1ChurchProvider();
17278
- const dropbox = new DropboxProvider();
17279
- const bibleProject = new BibleProjectProvider();
17280
- const highVoltageKids = new HighVoltageKidsProvider();
17281
- const lessonsChurch = new LessonsChurchProvider();
17282
- const lifeChurch = new LifeChurchProvider();
17283
- const planningCenter = new PlanningCenterProvider();
17284
- const signPresenter = new SignPresenterProvider();
17285
- const jesusFilm = new JesusFilmProvider();
17286
- const cbn = new CbnProvider();
17287
- providerRegistry.set(aplay.id, aplay);
17288
- providerRegistry.set(b1Church.id, b1Church);
17289
- providerRegistry.set(dropbox.id, dropbox);
17290
- providerRegistry.set(bibleProject.id, bibleProject);
17291
- providerRegistry.set(highVoltageKids.id, highVoltageKids);
17292
- providerRegistry.set(jesusFilm.id, jesusFilm);
17293
- providerRegistry.set(lessonsChurch.id, lessonsChurch);
17294
- providerRegistry.set(lifeChurch.id, lifeChurch);
17295
- providerRegistry.set(planningCenter.id, planningCenter);
17296
- providerRegistry.set(signPresenter.id, signPresenter);
17297
- providerRegistry.set(cbn.id, cbn);
16724
+ const providers = [
16725
+ new APlayProvider(),
16726
+ new B1ChurchProvider(),
16727
+ new DropboxProvider(),
16728
+ new BibleProjectProvider(),
16729
+ new HighVoltageKidsProvider(),
16730
+ new JesusFilmProvider(),
16731
+ new LessonsChurchProvider(),
16732
+ new LifeChurchProvider(),
16733
+ new PlanningCenterProvider(),
16734
+ new SignPresenterProvider(),
16735
+ new CbnProvider()
16736
+ ];
16737
+ for (const provider of providers) registerProvider(provider);
17298
16738
  }
17299
16739
  initializeProviders();
17300
16740
  function getProviderConfig(providerId) {
@@ -17318,7 +16758,7 @@ function getAvailableProviders(ids) {
17318
16758
  implemented: false,
17319
16759
  requiresAuth: false,
17320
16760
  authTypes: [],
17321
- capabilities: { browse: false, presentations: false, playlist: false, instructions: false, mediaLicensing: false }
16761
+ capabilities: { browse: false, playlist: false, instructions: false, mediaLicensing: false }
17322
16762
  }));
17323
16763
  const all = [...implemented, ...comingSoon];
17324
16764
  if (ids && ids.length > 0) {
@@ -17329,47 +16769,29 @@ function getAvailableProviders(ids) {
17329
16769
  }
17330
16770
 
17331
16771
  // src/index.ts
17332
- var VERSION = "0.0.5";
16772
+ var VERSION = "0.4.0";
17333
16773
  // Annotate the CommonJS export names for ESM import in node:
17334
16774
  0 && (module.exports = {
17335
16775
  APlayProvider,
17336
- ApiHelper,
17337
16776
  B1ChurchProvider,
17338
16777
  BibleProjectProvider,
17339
16778
  CbnProvider,
17340
- DEFAULT_DURATION_CONFIG,
17341
- DeviceFlowHelper,
17342
16779
  DropboxProvider,
17343
- FormatConverters,
17344
- FormatResolver,
17345
16780
  HighVoltageKidsProvider,
17346
16781
  JesusFilmProvider,
17347
16782
  LessonsChurchProvider,
17348
- OAuthHelper,
16783
+ LifeChurchProvider,
17349
16784
  PlanningCenterProvider,
17350
16785
  SignPresenterProvider,
17351
16786
  TokenHelper,
17352
16787
  VERSION,
17353
- appendToPath,
17354
- buildPath,
17355
- countWords,
17356
- createFile,
17357
- createFolder,
17358
- detectMediaType,
17359
- estimateDuration,
17360
- estimateImageDuration,
17361
- estimateTextDuration,
17362
- generatePath,
17363
16788
  getAllProviders,
17364
16789
  getAvailableProviders,
17365
16790
  getProvider,
17366
16791
  getProviderConfig,
17367
- getSegment,
17368
16792
  isContentFile,
17369
16793
  isContentFolder,
17370
- isMediaFile,
17371
16794
  navigateToPath,
17372
- parsePath,
17373
16795
  registerProvider
17374
16796
  });
17375
16797
  //# sourceMappingURL=index.cjs.map