@churchapps/content-providers 0.3.1 → 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.js CHANGED
@@ -1,9 +1,3 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
1
  // src/interfaces.ts
8
2
  function isContentFolder(item) {
9
3
  return item.type === "folder";
@@ -12,64 +6,6 @@ function isContentFile(item) {
12
6
  return item.type === "file";
13
7
  }
14
8
 
15
- // src/utils.ts
16
- function slugify(text) {
17
- return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
18
- }
19
- var VIDEO_EXTENSIONS = [".mp4", ".webm", ".m3u8", ".mov", ".avi", ".mkv", ".m4v"];
20
- var IMAGE_EXTENSIONS = [
21
- ".jpg",
22
- ".jpeg",
23
- ".png",
24
- ".gif",
25
- ".bmp",
26
- ".svg",
27
- ".webp",
28
- ".tiff",
29
- ".tif"
30
- ];
31
- function detectMediaType(url, explicitType) {
32
- if (explicitType === "video" || explicitType?.startsWith("video/")) return "video";
33
- if (explicitType === "image" || explicitType?.startsWith("image/")) return "image";
34
- const lower = url.toLowerCase();
35
- if (VIDEO_EXTENSIONS.some((p) => lower.includes(p)) || lower.includes("stream.mux.com")) return "video";
36
- return "image";
37
- }
38
- function isMediaFile(filename) {
39
- const lower = filename.toLowerCase();
40
- return [...VIDEO_EXTENSIONS, ...IMAGE_EXTENSIONS].some((ext) => lower.endsWith(ext));
41
- }
42
- function createFolder(id, title, path, thumbnail, isLeaf) {
43
- return { type: "folder", id, title, path, thumbnail, isLeaf };
44
- }
45
- function createFile(id, title, url, options) {
46
- 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 };
47
- }
48
-
49
- // src/pathUtils.ts
50
- function parsePath(path) {
51
- if (!path || path === "/" || path === "") {
52
- return { segments: [], depth: 0 };
53
- }
54
- const segments = path.replace(/^\//, "").split("/").filter(Boolean);
55
- return { segments, depth: segments.length };
56
- }
57
- function getSegment(path, index) {
58
- const { segments } = parsePath(path);
59
- return segments[index] ?? null;
60
- }
61
- function buildPath(segments) {
62
- if (segments.length === 0) return "/";
63
- return "/" + segments.join("/");
64
- }
65
- function appendToPath(basePath, segment) {
66
- if (!basePath || basePath === "/" || basePath === "") {
67
- return "/" + segment;
68
- }
69
- const cleanBase = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
70
- return cleanBase + "/" + segment;
71
- }
72
-
73
9
  // src/instructionPathUtils.ts
74
10
  function navigateToPath(instructions, path) {
75
11
  if (!path || !instructions?.items) return null;
@@ -81,283 +17,6 @@ function navigateToPath(instructions, path) {
81
17
  }
82
18
  return current;
83
19
  }
84
- function generatePath(indices) {
85
- return indices.join(".");
86
- }
87
-
88
- // src/durationUtils.ts
89
- var DEFAULT_DURATION_CONFIG = {
90
- secondsPerImage: 15,
91
- wordsPerMinute: 150
92
- };
93
- function countWords(text) {
94
- if (!text || !text.trim()) return 0;
95
- return text.trim().split(/\s+/).length;
96
- }
97
- function estimateImageDuration(config = {}) {
98
- return config.secondsPerImage ?? DEFAULT_DURATION_CONFIG.secondsPerImage;
99
- }
100
- function estimateTextDuration(text, config = {}) {
101
- const words = countWords(text);
102
- const wpm = config.wordsPerMinute ?? DEFAULT_DURATION_CONFIG.wordsPerMinute;
103
- return Math.ceil(words / wpm * 60);
104
- }
105
- function estimateDuration(mediaType, options) {
106
- const config = options?.config ?? {};
107
- switch (mediaType) {
108
- case "image":
109
- return estimateImageDuration(config);
110
- case "text":
111
- if (options?.wordCount) {
112
- const wpm = config.wordsPerMinute ?? DEFAULT_DURATION_CONFIG.wordsPerMinute;
113
- return Math.ceil(options.wordCount / wpm * 60);
114
- }
115
- if (options?.text) {
116
- return estimateTextDuration(options.text, config);
117
- }
118
- return 0;
119
- case "video":
120
- default:
121
- return 0;
122
- }
123
- }
124
-
125
- // src/FormatConverters.ts
126
- var FormatConverters_exports = {};
127
- __export(FormatConverters_exports, {
128
- expandedInstructionsToPlaylist: () => expandedInstructionsToPlaylist,
129
- expandedInstructionsToPresentations: () => expandedInstructionsToPresentations,
130
- instructionsToPlaylist: () => instructionsToPlaylist,
131
- instructionsToPresentations: () => instructionsToPresentations,
132
- playlistToExpandedInstructions: () => playlistToExpandedInstructions,
133
- playlistToInstructions: () => playlistToInstructions,
134
- playlistToPresentations: () => playlistToPresentations,
135
- presentationsToExpandedInstructions: () => presentationsToExpandedInstructions,
136
- presentationsToPlaylist: () => presentationsToPlaylist
137
- });
138
- function generateId() {
139
- return "gen-" + Math.random().toString(36).substring(2, 11);
140
- }
141
- function mapItemTypeToActionType(itemType) {
142
- switch (itemType) {
143
- case "action":
144
- case "lessonAction":
145
- case "providerPresentation":
146
- case "play":
147
- case "addon":
148
- case "add-on":
149
- case "lessonAddOn":
150
- case "providerFile":
151
- return "play";
152
- default:
153
- return "other";
154
- }
155
- }
156
- function presentationsToPlaylist(plan) {
157
- if (plan.allFiles && plan.allFiles.length > 0) {
158
- return [...plan.allFiles];
159
- }
160
- const files = [];
161
- for (const section of plan.sections) {
162
- for (const presentation of section.presentations) {
163
- files.push(...presentation.files);
164
- }
165
- }
166
- return files;
167
- }
168
- function mapActionTypeToItemType(actionType) {
169
- switch (actionType) {
170
- case "play":
171
- return "action";
172
- default:
173
- return "item";
174
- }
175
- }
176
- function presentationsToExpandedInstructions(plan) {
177
- return {
178
- name: plan.name,
179
- items: plan.sections.map((section) => ({
180
- id: section.id,
181
- itemType: "section",
182
- label: section.name,
183
- children: section.presentations.map((pres) => ({
184
- id: pres.id,
185
- itemType: mapActionTypeToItemType(pres.actionType),
186
- label: pres.name,
187
- description: pres.actionType !== "other" ? pres.actionType : void 0,
188
- seconds: pres.files.reduce((sum, f) => sum + (f.seconds || 0), 0) || void 0,
189
- children: pres.files.map((f) => ({
190
- id: f.id,
191
- itemType: "file",
192
- label: f.title,
193
- seconds: f.seconds,
194
- downloadUrl: f.downloadUrl || f.url,
195
- thumbnail: f.thumbnail
196
- }))
197
- }))
198
- }))
199
- };
200
- }
201
- function instructionsToPlaylist(instructions) {
202
- const files = [];
203
- function extractFiles(items) {
204
- for (const item of items) {
205
- if (item.downloadUrl && (item.itemType === "file" || !item.children?.length)) {
206
- 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 });
207
- }
208
- if (item.children) {
209
- extractFiles(item.children);
210
- }
211
- }
212
- }
213
- extractFiles(instructions.items);
214
- return files;
215
- }
216
- var expandedInstructionsToPlaylist = instructionsToPlaylist;
217
- function instructionsToPresentations(instructions, planId) {
218
- const allFiles = [];
219
- const sections = instructions.items.filter((item) => item.children && item.children.length > 0).map((sectionItem) => {
220
- const presentations = (sectionItem.children || []).map((presItem) => {
221
- const files = [];
222
- if (presItem.children && presItem.children.length > 0) {
223
- for (const child of presItem.children) {
224
- if (child.downloadUrl) {
225
- 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 };
226
- allFiles.push(file);
227
- files.push(file);
228
- }
229
- }
230
- }
231
- if (files.length === 0 && presItem.downloadUrl) {
232
- 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 };
233
- allFiles.push(file);
234
- files.push(file);
235
- }
236
- return { id: presItem.id || presItem.relatedId || generateId(), name: presItem.label || "Presentation", actionType: mapItemTypeToActionType(presItem.itemType), files };
237
- });
238
- return { id: sectionItem.id || sectionItem.relatedId || generateId(), name: sectionItem.label || "Section", presentations };
239
- });
240
- return { id: planId || generateId(), name: instructions.name || "Plan", sections, allFiles };
241
- }
242
- var expandedInstructionsToPresentations = instructionsToPresentations;
243
- function playlistToPresentations(files, planName = "Playlist", sectionName = "Content") {
244
- const presentations = files.map((file, index) => ({ id: `pres-${index}-${file.id}`, name: file.title, actionType: "play", files: [file] }));
245
- return { id: "playlist-plan-" + generateId(), name: planName, sections: [{ id: "main-section", name: sectionName, presentations }], allFiles: [...files] };
246
- }
247
- function playlistToInstructions(files, name = "Playlist") {
248
- 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 })) }] };
249
- }
250
- var playlistToExpandedInstructions = playlistToInstructions;
251
-
252
- // src/FormatResolver.ts
253
- var FormatResolver = class {
254
- constructor(provider, options = {}) {
255
- this.provider = provider;
256
- this.options = { allowLossy: options.allowLossy ?? true };
257
- }
258
- getProvider() {
259
- return this.provider;
260
- }
261
- /** Extract the last segment from a path to use as fallback ID/title */
262
- getIdFromPath(path) {
263
- const { segments } = parsePath(path);
264
- return segments[segments.length - 1] || "content";
265
- }
266
- async getPlaylist(path, auth) {
267
- const caps = this.provider.capabilities;
268
- if (caps.playlist && this.provider.getPlaylist) {
269
- const result = await this.provider.getPlaylist(path, auth);
270
- if (result && result.length > 0) return result;
271
- }
272
- if (caps.instructions && this.provider.getInstructions) {
273
- const expanded = await this.provider.getInstructions(path, auth);
274
- if (expanded) return instructionsToPlaylist(expanded);
275
- }
276
- return null;
277
- }
278
- async getPlaylistWithMeta(path, auth) {
279
- const caps = this.provider.capabilities;
280
- if (caps.playlist && this.provider.getPlaylist) {
281
- const result = await this.provider.getPlaylist(path, auth);
282
- if (result && result.length > 0) {
283
- return { data: result, meta: { isNative: true, isLossy: false } };
284
- }
285
- }
286
- if (caps.instructions && this.provider.getInstructions) {
287
- const expanded = await this.provider.getInstructions(path, auth);
288
- if (expanded) return { data: instructionsToPlaylist(expanded), meta: { isNative: false, sourceFormat: "instructions", isLossy: false } };
289
- }
290
- return { data: null, meta: { isNative: false, isLossy: false } };
291
- }
292
- // async getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null> {
293
- // const caps = this.provider.capabilities;
294
- // const fallbackId = this.getIdFromPath(path);
295
- // if (caps.presentations) {
296
- // const result = await this.provider.getPresentations(path, auth);
297
- // if (result) return result;
298
- // }
299
- // if (caps.instructions && this.provider.getInstructions) {
300
- // const expanded = await this.provider.getInstructions(path, auth);
301
- // if (expanded) return Converters.instructionsToPresentations(expanded, fallbackId);
302
- // }
303
- // if (this.options.allowLossy && caps.playlist && this.provider.getPlaylist) {
304
- // const playlist = await this.provider.getPlaylist(path, auth);
305
- // if (playlist && playlist.length > 0) {
306
- // return Converters.playlistToPresentations(playlist, fallbackId);
307
- // }
308
- // }
309
- // return null;
310
- // }
311
- // async getPresentationsWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{ data: Plan | null; meta: ResolvedFormatMeta }> {
312
- // const caps = this.provider.capabilities;
313
- // const fallbackId = this.getIdFromPath(path);
314
- // if (caps.presentations) {
315
- // const result = await this.provider.getPresentations(path, auth);
316
- // if (result) {
317
- // return { data: result, meta: { isNative: true, isLossy: false } };
318
- // }
319
- // }
320
- // if (caps.instructions && this.provider.getInstructions) {
321
- // const expanded = await this.provider.getInstructions(path, auth);
322
- // if (expanded) return { data: Converters.instructionsToPresentations(expanded, fallbackId), meta: { isNative: false, sourceFormat: "instructions", isLossy: false } };
323
- // }
324
- // if (this.options.allowLossy && caps.playlist && this.provider.getPlaylist) {
325
- // const playlist = await this.provider.getPlaylist(path, auth);
326
- // if (playlist && playlist.length > 0) return { data: Converters.playlistToPresentations(playlist, fallbackId), meta: { isNative: false, sourceFormat: "playlist", isLossy: true } };
327
- // }
328
- // return { data: null, meta: { isNative: false, isLossy: false } };
329
- // }
330
- async getInstructions(path, auth) {
331
- const caps = this.provider.capabilities;
332
- const fallbackTitle = this.getIdFromPath(path);
333
- if (caps.instructions && this.provider.getInstructions) {
334
- const result = await this.provider.getInstructions(path, auth);
335
- if (result) return result;
336
- }
337
- if (this.options.allowLossy && caps.playlist && this.provider.getPlaylist) {
338
- const playlist = await this.provider.getPlaylist(path, auth);
339
- if (playlist && playlist.length > 0) {
340
- return playlistToInstructions(playlist, fallbackTitle);
341
- }
342
- }
343
- return null;
344
- }
345
- async getInstructionsWithMeta(path, auth) {
346
- const caps = this.provider.capabilities;
347
- const fallbackTitle = this.getIdFromPath(path);
348
- if (caps.instructions && this.provider.getInstructions) {
349
- const result = await this.provider.getInstructions(path, auth);
350
- if (result) {
351
- return { data: result, meta: { isNative: true, isLossy: false } };
352
- }
353
- }
354
- if (this.options.allowLossy && caps.playlist && this.provider.getPlaylist) {
355
- const playlist = await this.provider.getPlaylist(path, auth);
356
- if (playlist && playlist.length > 0) return { data: playlistToInstructions(playlist, fallbackTitle), meta: { isNative: false, sourceFormat: "playlist", isLossy: true } };
357
- }
358
- return { data: null, meta: { isNative: false, isLossy: false } };
359
- }
360
- };
361
20
 
362
21
  // src/helpers/OAuthHelper.ts
363
22
  var OAuthHelper = class {
@@ -521,6 +180,19 @@ var ApiHelper = class {
521
180
  }
522
181
  };
523
182
 
183
+ // src/pathUtils.ts
184
+ function parsePath(path) {
185
+ if (!path || path === "/" || path === "") {
186
+ return { segments: [], depth: 0 };
187
+ }
188
+ const segments = path.replace(/^\//, "").split("/").filter(Boolean);
189
+ return { segments, depth: segments.length };
190
+ }
191
+ function getSegment(path, index) {
192
+ const { segments } = parsePath(path);
193
+ return segments[index] ?? null;
194
+ }
195
+
524
196
  // src/providers/aPlay/APlayApi.ts
525
197
  var API_BASE = "https://api-prod.amazingkids.app";
526
198
  async function checkMediaLicense(mediaId, auth) {
@@ -541,6 +213,57 @@ async function checkMediaLicense(mediaId, auth) {
541
213
  }
542
214
  }
543
215
 
216
+ // src/utils.ts
217
+ var IMAGE_DURATION_SECONDS = 15;
218
+ function slugify(text) {
219
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
220
+ }
221
+ var VIDEO_EXTENSIONS = [".mp4", ".webm", ".m3u8", ".mov", ".avi", ".mkv", ".m4v"];
222
+ var IMAGE_EXTENSIONS = [
223
+ ".jpg",
224
+ ".jpeg",
225
+ ".png",
226
+ ".gif",
227
+ ".bmp",
228
+ ".svg",
229
+ ".webp",
230
+ ".tiff",
231
+ ".tif"
232
+ ];
233
+ function detectMediaType(url, explicitType) {
234
+ if (explicitType === "video" || explicitType?.startsWith("video/")) return "video";
235
+ if (explicitType === "image" || explicitType?.startsWith("image/")) return "image";
236
+ const lower = url.toLowerCase();
237
+ if (VIDEO_EXTENSIONS.some((p) => lower.includes(p)) || lower.includes("stream.mux.com")) return "video";
238
+ return "image";
239
+ }
240
+ function isMediaFile(filename) {
241
+ const lower = filename.toLowerCase();
242
+ return [...VIDEO_EXTENSIONS, ...IMAGE_EXTENSIONS].some((ext) => lower.endsWith(ext));
243
+ }
244
+ function createFolder(id, title, path, thumbnail, isLeaf) {
245
+ return { type: "folder", id, title, path, thumbnail, isLeaf };
246
+ }
247
+ function createFile(id, title, url, options) {
248
+ 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 };
249
+ }
250
+ function generateId() {
251
+ return "gen-" + Math.random().toString(36).substring(2, 11);
252
+ }
253
+ function instructionsToPlaylist(instructions) {
254
+ const files = [];
255
+ function extractFiles(items) {
256
+ for (const item of items) {
257
+ if (item.downloadUrl && (item.itemType === "file" || !item.children?.length)) {
258
+ 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 });
259
+ }
260
+ if (item.children) extractFiles(item.children);
261
+ }
262
+ }
263
+ extractFiles(instructions.items);
264
+ return files;
265
+ }
266
+
544
267
  // src/providers/aPlay/APlayConverters.ts
545
268
  function extractLibraryId(path) {
546
269
  const { segments, depth } = parsePath(path);
@@ -647,7 +370,7 @@ var APlayProvider = class {
647
370
  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` } };
648
371
  this.requiresAuth = true;
649
372
  this.authTypes = ["oauth_pkce"];
650
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: true };
373
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: true };
651
374
  }
652
375
  async apiRequest(path, auth) {
653
376
  return this.apiHelper.apiRequest(this.config, this.id, path, auth);
@@ -699,13 +422,6 @@ var APlayProvider = class {
699
422
  const mediaItems = extractArray(response, "data", "media");
700
423
  return convertMediaToFiles(mediaItems);
701
424
  }
702
- // async getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null> {
703
- // const libraryId = extractLibraryId(path);
704
- // if (!libraryId) return null;
705
- // const files = await this.getMediaFiles(libraryId, auth) as ContentFile[];
706
- // if (files.length === 0) return null;
707
- // return convertFilesToPresentations(files, libraryId).plan;
708
- // }
709
425
  async getPlaylist(path, auth, _resolution) {
710
426
  const libraryId = extractLibraryId(path);
711
427
  if (!libraryId) return null;
@@ -739,7 +455,7 @@ var SignPresenterProvider = class {
739
455
  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` } };
740
456
  this.requiresAuth = true;
741
457
  this.authTypes = ["oauth_pkce", "device_flow"];
742
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: false };
458
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
743
459
  }
744
460
  async apiRequest(path, auth) {
745
461
  return this.apiHelper.apiRequest(this.config, this.id, path, auth);
@@ -808,20 +524,6 @@ var SignPresenterProvider = class {
808
524
  }
809
525
  return files;
810
526
  }
811
- // async getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null> {
812
- // const { segments, depth } = parsePath(path);
813
- // if (depth < 2 || segments[0] !== "playlists") return null;
814
- // const playlistId = segments[1];
815
- // const files = await this.getMessages(playlistId, auth) as ContentFile[];
816
- // if (files.length === 0) return null;
817
- // // Get playlist info for title
818
- // const playlists = await this.getPlaylists(auth);
819
- // const playlist = playlists.find(p => p.id === playlistId);
820
- // const title = playlist?.title || "Playlist";
821
- // const thumbnail = (playlist as Record<string, unknown> | undefined)?.image as string | undefined;
822
- // const presentations: PlanPresentation[] = files.map(f => ({ id: f.id, name: f.title, actionType: "play" as const, files: [f] }));
823
- // return { id: playlistId, name: title as string, thumbnail, sections: [{ id: `section-${playlistId}`, name: title as string, presentations }], allFiles: files };
824
- // }
825
527
  async getPlaylist(path, auth, _resolution) {
826
528
  const { segments, depth } = parsePath(path);
827
529
  if (depth < 2 || segments[0] !== "playlists") return null;
@@ -967,7 +669,7 @@ function buildSectionActionsMap(actionsResponse, lessonImage, feedResponse) {
967
669
  for (const section of actionsResponse.sections) {
968
670
  if (section.id && section.actions) {
969
671
  sectionActionsMap.set(section.id, section.actions.map((action) => {
970
- const seconds = action.seconds ?? estimateImageDuration();
672
+ const seconds = action.seconds ?? IMAGE_DURATION_SECONDS;
971
673
  const rawActionType = action.actionType?.toLowerCase() || "";
972
674
  const hasFiles = rawActionType === "play" || rawActionType === "add-on";
973
675
  const thumbnail = action.id && actionThumbnailMap.get(action.id) || lessonImage;
@@ -1073,7 +775,7 @@ var LessonsChurchProvider = class {
1073
775
  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}` } };
1074
776
  this.requiresAuth = false;
1075
777
  this.authTypes = ["none"];
1076
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: false };
778
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
1077
779
  }
1078
780
  async getPlaylist(path, _auth, resolution) {
1079
781
  const { segments } = parsePath(path);
@@ -1184,19 +886,6 @@ var LessonsChurchProvider = class {
1184
886
  const filtered = allAddOns.filter((a) => a.category === decodedCategory);
1185
887
  return filtered.map((addOn) => createFolder(addOn.id, addOn.name, `${currentPath}/${addOn.id}`, addOn.image, true));
1186
888
  }
1187
- // async getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null> {
1188
- // const venueId = getSegment(path, 4);
1189
- // if (venueId) {
1190
- // const venueData = await apiRequest<FeedVenueInterface>(`/venues/public/feed/${venueId}`);
1191
- // if (!venueData) return null;
1192
- // return convertVenueToPlan(venueData);
1193
- // }
1194
- // const { segments } = parsePath(path);
1195
- // if (segments[0] === "addons" && segments.length === 2) {
1196
- // return convertAddOnCategoryToPlan(segments[1]);
1197
- // }
1198
- // return null;
1199
- // }
1200
889
  async getInstructions(path, _auth) {
1201
890
  const venueId = getSegment(path, 4);
1202
891
  if (venueId) {
@@ -1318,42 +1007,6 @@ async function refreshTokenWithSecret(config, auth, clientSecret) {
1318
1007
  return null;
1319
1008
  }
1320
1009
  }
1321
- async function initiateDeviceFlow(config) {
1322
- if (!config.supportsDeviceFlow || !config.deviceAuthEndpoint) return null;
1323
- try {
1324
- 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(" ") }) });
1325
- if (!response.ok) {
1326
- return null;
1327
- }
1328
- return await response.json();
1329
- } catch {
1330
- return null;
1331
- }
1332
- }
1333
- async function pollDeviceFlowToken(config, deviceCode) {
1334
- try {
1335
- 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 }) });
1336
- if (response.ok) {
1337
- const data = await response.json();
1338
- 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(" ") };
1339
- }
1340
- const errorData = await response.json();
1341
- switch (errorData.error) {
1342
- case "authorization_pending":
1343
- return { error: "authorization_pending" };
1344
- case "slow_down":
1345
- return { error: "slow_down", shouldSlowDown: true };
1346
- case "expired_token":
1347
- return null;
1348
- case "access_denied":
1349
- return null;
1350
- default:
1351
- return null;
1352
- }
1353
- } catch {
1354
- return { error: "network_error" };
1355
- }
1356
- }
1357
1010
 
1358
1011
  // src/providers/b1Church/B1ChurchApi.ts
1359
1012
  var API_BASE3 = "https://api.churchapps.org";
@@ -1692,6 +1345,7 @@ function isExternalProviderItem(item) {
1692
1345
  var B1ChurchProvider = class {
1693
1346
  constructor() {
1694
1347
  this.apiHelper = new ApiHelper();
1348
+ this.deviceFlowHelper = new DeviceFlowHelper();
1695
1349
  // Unified cache for external provider data to avoid duplicate calls across methods
1696
1350
  this.externalContentCache = {
1697
1351
  plans: /* @__PURE__ */ new Map(),
@@ -1705,109 +1359,7 @@ var B1ChurchProvider = class {
1705
1359
  this.appBase = "https://admin.b1.church";
1706
1360
  this.requiresAuth = true;
1707
1361
  this.authTypes = ["oauth_pkce", "device_flow"];
1708
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: false };
1709
- // async getPresentations(path: string, authData?: ContentProviderAuthData | null): Promise<Plan | null> {
1710
- // const { segments, depth } = parsePath(path);
1711
- // if (depth < 4 || segments[0] !== "ministries") return null;
1712
- // const ministryId = segments[1];
1713
- // const planId = segments[3];
1714
- // const planTypeId = segments[2];
1715
- // // Need to fetch plan details to get churchId and contentId
1716
- // const plans = await fetchPlans(planTypeId, authData);
1717
- // const planFolder = plans.find(p => p.id === planId);
1718
- // if (!planFolder) return null;
1719
- // const churchId = planFolder.churchId;
1720
- // const venueId = planFolder.contentId;
1721
- // const planTitle = planFolder.name || "Plan";
1722
- // if (!churchId) {
1723
- // console.warn("[B1Church getPresentations] planFolder missing churchId:", planFolder.id);
1724
- // return null;
1725
- // }
1726
- // const pathFn = this.config.endpoints.planItems as (churchId: string, planId: string) => string;
1727
- // const planItems = await this.apiRequest<B1PlanItem[]>(pathFn(churchId, planId), authData);
1728
- // // If no planItems but plan has associated provider content, fetch from that provider
1729
- // if ((!planItems || planItems.length === 0) && planFolder.providerId && planFolder.providerPlanId) {
1730
- // const externalPlan = await fetchFromProviderProxy(
1731
- // "getPresentations",
1732
- // ministryId,
1733
- // planFolder.providerId,
1734
- // planFolder.providerPlanId,
1735
- // authData
1736
- // );
1737
- // if (externalPlan) {
1738
- // return { id: planId, name: planTitle, sections: externalPlan.sections, allFiles: externalPlan.allFiles };
1739
- // }
1740
- // }
1741
- // if (!planItems || !Array.isArray(planItems)) return null;
1742
- // const venueFeed = venueId ? await fetchVenueFeed(venueId) : null;
1743
- // const sections: PlanSection[] = [];
1744
- // const allFiles: ContentFile[] = [];
1745
- // for (const sectionItem of planItems) {
1746
- // const presentations: PlanPresentation[] = [];
1747
- // for (const child of sectionItem.children || []) {
1748
- // // Try external provider resolution first (cached, uses providerContentPath)
1749
- // if (isExternalProviderItem(child) && child.providerId && child.providerPath) {
1750
- // const cacheKey = `${child.providerId}:${child.providerPath}`;
1751
- // let externalPlan = this.externalContentCache.plans.get(cacheKey);
1752
- // if (externalPlan === undefined) {
1753
- // externalPlan = await fetchFromProviderProxy(
1754
- // "getPresentations",
1755
- // ministryId,
1756
- // child.providerId,
1757
- // child.providerPath,
1758
- // authData
1759
- // );
1760
- // this.externalContentCache.plans.set(cacheKey, externalPlan);
1761
- // }
1762
- // if (externalPlan) {
1763
- // if (child.providerContentPath) {
1764
- // // Fetch instructions to enable path-based lookup (with caching)
1765
- // let externalInstructions = this.externalContentCache.instructions.get(cacheKey);
1766
- // if (externalInstructions === undefined) {
1767
- // externalInstructions = await fetchFromProviderProxy(
1768
- // "getInstructions",
1769
- // ministryId,
1770
- // child.providerId,
1771
- // child.providerPath,
1772
- // authData
1773
- // );
1774
- // this.externalContentCache.instructions.set(cacheKey, externalInstructions);
1775
- // }
1776
- // // Find and use only the specific presentation
1777
- // const matchingPresentation = this.findPresentationByPath(externalPlan, externalInstructions, child.providerContentPath);
1778
- // if (matchingPresentation) {
1779
- // presentations.push(matchingPresentation);
1780
- // if (Array.isArray(matchingPresentation.files)) {
1781
- // allFiles.push(...matchingPresentation.files);
1782
- // }
1783
- // }
1784
- // } else {
1785
- // // Add all presentations from the external plan
1786
- // for (const section of externalPlan.sections || []) {
1787
- // if (Array.isArray(section.presentations)) {
1788
- // presentations.push(...section.presentations);
1789
- // }
1790
- // }
1791
- // if (Array.isArray(externalPlan.allFiles)) {
1792
- // allFiles.push(...externalPlan.allFiles);
1793
- // }
1794
- // }
1795
- // }
1796
- // } else {
1797
- // // Handle internal items (venue feed sections, link-based files, etc.)
1798
- // const presentation = await planItemToPresentation(child, venueFeed);
1799
- // if (presentation) {
1800
- // presentations.push(presentation);
1801
- // allFiles.push(...presentation.files);
1802
- // }
1803
- // }
1804
- // }
1805
- // if (presentations.length > 0 || sectionItem.label) {
1806
- // sections.push({ id: sectionItem.id, name: sectionItem.label || "Section", presentations });
1807
- // }
1808
- // }
1809
- // return { id: planId, name: planTitle, sections, allFiles };
1810
- // }
1362
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
1811
1363
  this.planTypeId = null;
1812
1364
  }
1813
1365
  async apiRequest(path, authData) {
@@ -1826,10 +1378,10 @@ var B1ChurchProvider = class {
1826
1378
  return refreshTokenWithSecret(this.config, authData, clientSecret);
1827
1379
  }
1828
1380
  async initiateDeviceFlow() {
1829
- return initiateDeviceFlow(this.config);
1381
+ return this.deviceFlowHelper.initiateDeviceFlow(this.config);
1830
1382
  }
1831
1383
  async pollDeviceFlowToken(deviceCode) {
1832
- return pollDeviceFlowToken(this.config, deviceCode);
1384
+ return this.deviceFlowHelper.pollDeviceFlowToken(this.config, deviceCode);
1833
1385
  }
1834
1386
  async browse(path, authData) {
1835
1387
  const { segments, depth } = parsePath(path);
@@ -2246,7 +1798,6 @@ var DropboxProvider = class {
2246
1798
  this.authTypes = ["oauth_pkce"];
2247
1799
  this.capabilities = {
2248
1800
  browse: true,
2249
- presentations: false,
2250
1801
  playlist: true,
2251
1802
  instructions: true,
2252
1803
  mediaLicensing: false
@@ -2458,7 +2009,7 @@ var PlanningCenterProvider = class {
2458
2009
  this.ONE_WEEK_MS = 6048e5;
2459
2010
  this.requiresAuth = true;
2460
2011
  this.authTypes = ["oauth_pkce"];
2461
- this.capabilities = { browse: true, presentations: true, playlist: true, instructions: true, mediaLicensing: false };
2012
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
2462
2013
  }
2463
2014
  async apiRequest(path, auth) {
2464
2015
  return this.apiHelper.apiRequest(this.config, this.id, path, auth);
@@ -2518,54 +2069,6 @@ var PlanningCenterProvider = class {
2518
2069
  if (!response?.data) return [];
2519
2070
  return response.data.map((item) => ({ type: "file", id: item.id, title: item.attributes.title || "", mediaType: "image", url: "" }));
2520
2071
  }
2521
- // async getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null> {
2522
- // const { segments, depth } = parsePath(path);
2523
- // if (depth < 3 || segments[0] !== "serviceTypes") return null;
2524
- // const serviceTypeId = segments[1];
2525
- // const planId = segments[2];
2526
- // const pathFn = this.config.endpoints.planItems as (stId: string, pId: string) => string;
2527
- // const response = await this.apiRequest<{ data: PCOPlanItem[] }>(
2528
- // `${pathFn(serviceTypeId, planId)}?per_page=100`,
2529
- // auth
2530
- // );
2531
- // if (!response?.data) return null;
2532
- // const plans = await this.getPlans(serviceTypeId, `/serviceTypes/${serviceTypeId}`, auth);
2533
- // const plan = plans.find(p => p.id === planId);
2534
- // const planTitle = plan?.title || "Plan";
2535
- // const sections: PlanSection[] = [];
2536
- // const allFiles: ContentFile[] = [];
2537
- // let currentSection: PlanSection | null = null;
2538
- // for (const item of response.data) {
2539
- // const itemType = item.attributes.item_type;
2540
- // if (itemType === "header") {
2541
- // if (currentSection && currentSection.presentations.length > 0) sections.push(currentSection);
2542
- // currentSection = { id: item.id, name: item.attributes.title || "Section", presentations: [] };
2543
- // continue;
2544
- // }
2545
- // if (!currentSection) {
2546
- // currentSection = { id: `default-${planId}`, name: "Service", presentations: [] };
2547
- // }
2548
- // const presentation = await convertToPresentation(this.config, item, auth);
2549
- // if (presentation) {
2550
- // currentSection.presentations.push(presentation);
2551
- // allFiles.push(...presentation.files);
2552
- // }
2553
- // }
2554
- // if (currentSection && currentSection.presentations.length > 0) {
2555
- // sections.push(currentSection);
2556
- // }
2557
- // return { id: planId, name: planTitle as string, sections, allFiles };
2558
- // }
2559
- // async getPlaylist(path: string, auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null> {
2560
- // const plan = await this.getPresentations(path, auth);
2561
- // if (!plan) return null;
2562
- // return plan.allFiles.length > 0 ? plan.allFiles : null;
2563
- // }
2564
- // async getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null> {
2565
- // const plan = await this.getPresentations(path, auth);
2566
- // if (!plan) return null;
2567
- // return buildInstructionsFromPlan(plan);
2568
- // }
2569
2072
  supportsDeviceFlow() {
2570
2073
  return false;
2571
2074
  }
@@ -4985,7 +4488,6 @@ var BibleProjectProvider = class {
4985
4488
  this.authTypes = ["none"];
4986
4489
  this.capabilities = {
4987
4490
  browse: true,
4988
- presentations: true,
4989
4491
  playlist: true,
4990
4492
  instructions: true,
4991
4493
  mediaLicensing: false
@@ -5038,32 +4540,6 @@ var BibleProjectProvider = class {
5038
4540
  if (!video) return [];
5039
4541
  return [createFile(video.id, video.title, video.videoUrl, { mediaType: "video", muxPlaybackId: video.muxPlaybackId, seconds: 0 })];
5040
4542
  }
5041
- // async getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null> {
5042
- // const { segments, depth } = parsePath(path);
5043
- // if (depth < 1) return null;
5044
- // const collectionSlug = segments[0];
5045
- // const collection = this.data.collections.find(c => slugify(c.name) === collectionSlug);
5046
- // if (!collection) return null;
5047
- // // For collection level (depth 1), create a plan with all videos
5048
- // if (depth === 1) {
5049
- // const allFiles: ContentFile[] = [];
5050
- // const presentations: PlanPresentation[] = collection.videos.map(video => {
5051
- // 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 };
5052
- // allFiles.push(file);
5053
- // return { id: video.id, name: video.title, actionType: "play" as const, files: [file] };
5054
- // });
5055
- // return { id: slugify(collection.name), name: collection.name, thumbnail: collection.image || undefined, sections: [{ id: "videos", name: "Videos", presentations }], allFiles };
5056
- // }
5057
- // // For video level (depth 2, single video), create a simple plan
5058
- // if (depth === 2) {
5059
- // const videoId = segments[1];
5060
- // const video = collection.videos.find(v => v.id === videoId);
5061
- // if (!video) return null;
5062
- // 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 };
5063
- // 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] };
5064
- // }
5065
- // return null;
5066
- // }
5067
4543
  async getPlaylist(path, _auth, _resolution) {
5068
4544
  const { segments, depth } = parsePath(path);
5069
4545
  if (depth < 1) return null;
@@ -12715,7 +12191,7 @@ function groupFilesIntoActions(files, thumbnail) {
12715
12191
  const flushGroup = () => {
12716
12192
  if (currentGroup.length === 0) return;
12717
12193
  const children = currentGroup.map((file) => {
12718
- const seconds = estimateDuration(file.mediaType);
12194
+ const seconds = file.mediaType === "image" ? IMAGE_DURATION_SECONDS : 0;
12719
12195
  return {
12720
12196
  id: file.id,
12721
12197
  itemType: "file",
@@ -12753,7 +12229,7 @@ function groupFilesIntoActions(files, thumbnail) {
12753
12229
  function buildStudyInstructions(study) {
12754
12230
  const lessonItems = study.lessons.map((lesson) => {
12755
12231
  const fileItems = lesson.files.map((file) => {
12756
- const seconds = estimateDuration(file.mediaType);
12232
+ const seconds = file.mediaType === "image" ? IMAGE_DURATION_SECONDS : 0;
12757
12233
  return { id: file.id, itemType: "file", label: file.title, seconds, downloadUrl: file.url, thumbnail: lesson.image };
12758
12234
  });
12759
12235
  return { id: lesson.id, itemType: "action", label: lesson.name, actionType: "play", children: fileItems };
@@ -12788,7 +12264,6 @@ var HighVoltageKidsProvider = class {
12788
12264
  this.authTypes = ["none"];
12789
12265
  this.capabilities = {
12790
12266
  browse: true,
12791
- presentations: true,
12792
12267
  playlist: true,
12793
12268
  instructions: true,
12794
12269
  mediaLicensing: false
@@ -12802,19 +12277,6 @@ var HighVoltageKidsProvider = class {
12802
12277
  if (depth === 3) return getLessonFiles(this.data, segments[0], segments[1], segments[2]);
12803
12278
  return [];
12804
12279
  }
12805
- // async getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null> {
12806
- // const { segments, depth } = parsePath(path);
12807
- // if (depth < 2) return null;
12808
- // const study = findStudy(this.data, segments[0], segments[1]);
12809
- // if (!study) return null;
12810
- // if (depth === 2) return buildStudyPlan(study);
12811
- // if (depth === 3) {
12812
- // const lesson = findLesson(this.data, segments[0], segments[1], segments[2]);
12813
- // if (!lesson) return null;
12814
- // return buildLessonPlan(lesson);
12815
- // }
12816
- // return null;
12817
- // }
12818
12280
  async getPlaylist(path, _auth, _resolution) {
12819
12281
  const { segments, depth } = parsePath(path);
12820
12282
  if (depth < 2) return null;
@@ -12880,7 +12342,6 @@ var JesusFilmProvider = class {
12880
12342
  this.authTypes = ["none"];
12881
12343
  this.capabilities = {
12882
12344
  browse: true,
12883
- presentations: true,
12884
12345
  playlist: true,
12885
12346
  instructions: true,
12886
12347
  mediaLicensing: false
@@ -13263,7 +12724,7 @@ var CbnProvider = class {
13263
12724
  };
13264
12725
  this.requiresAuth = true;
13265
12726
  this.authTypes = ["device_flow"];
13266
- this.capabilities = { browse: true, presentations: false, playlist: true, instructions: true, mediaLicensing: false };
12727
+ this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
13267
12728
  }
13268
12729
  async apiRequest(path, auth) {
13269
12730
  return this.apiHelper.apiRequest(this.config, this.id, path, auth);
@@ -16965,7 +16426,6 @@ var LifeChurchProvider = class {
16965
16426
  this.authTypes = ["none"];
16966
16427
  this.capabilities = {
16967
16428
  browse: true,
16968
- presentations: true,
16969
16429
  playlist: true,
16970
16430
  instructions: true,
16971
16431
  mediaLicensing: false
@@ -17215,28 +16675,20 @@ var unimplementedProviders = [
17215
16675
  }
17216
16676
  ];
17217
16677
  function initializeProviders() {
17218
- const aplay = new APlayProvider();
17219
- const b1Church = new B1ChurchProvider();
17220
- const dropbox = new DropboxProvider();
17221
- const bibleProject = new BibleProjectProvider();
17222
- const highVoltageKids = new HighVoltageKidsProvider();
17223
- const lessonsChurch = new LessonsChurchProvider();
17224
- const lifeChurch = new LifeChurchProvider();
17225
- const planningCenter = new PlanningCenterProvider();
17226
- const signPresenter = new SignPresenterProvider();
17227
- const jesusFilm = new JesusFilmProvider();
17228
- const cbn = new CbnProvider();
17229
- providerRegistry.set(aplay.id, aplay);
17230
- providerRegistry.set(b1Church.id, b1Church);
17231
- providerRegistry.set(dropbox.id, dropbox);
17232
- providerRegistry.set(bibleProject.id, bibleProject);
17233
- providerRegistry.set(highVoltageKids.id, highVoltageKids);
17234
- providerRegistry.set(jesusFilm.id, jesusFilm);
17235
- providerRegistry.set(lessonsChurch.id, lessonsChurch);
17236
- providerRegistry.set(lifeChurch.id, lifeChurch);
17237
- providerRegistry.set(planningCenter.id, planningCenter);
17238
- providerRegistry.set(signPresenter.id, signPresenter);
17239
- providerRegistry.set(cbn.id, cbn);
16678
+ const providers = [
16679
+ new APlayProvider(),
16680
+ new B1ChurchProvider(),
16681
+ new DropboxProvider(),
16682
+ new BibleProjectProvider(),
16683
+ new HighVoltageKidsProvider(),
16684
+ new JesusFilmProvider(),
16685
+ new LessonsChurchProvider(),
16686
+ new LifeChurchProvider(),
16687
+ new PlanningCenterProvider(),
16688
+ new SignPresenterProvider(),
16689
+ new CbnProvider()
16690
+ ];
16691
+ for (const provider of providers) registerProvider(provider);
17240
16692
  }
17241
16693
  initializeProviders();
17242
16694
  function getProviderConfig(providerId) {
@@ -17260,7 +16712,7 @@ function getAvailableProviders(ids) {
17260
16712
  implemented: false,
17261
16713
  requiresAuth: false,
17262
16714
  authTypes: [],
17263
- capabilities: { browse: false, presentations: false, playlist: false, instructions: false, mediaLicensing: false }
16715
+ capabilities: { browse: false, playlist: false, instructions: false, mediaLicensing: false }
17264
16716
  }));
17265
16717
  const all = [...implemented, ...comingSoon];
17266
16718
  if (ids && ids.length > 0) {
@@ -17271,46 +16723,28 @@ function getAvailableProviders(ids) {
17271
16723
  }
17272
16724
 
17273
16725
  // src/index.ts
17274
- var VERSION = "0.3.1";
16726
+ var VERSION = "0.4.0";
17275
16727
  export {
17276
16728
  APlayProvider,
17277
- ApiHelper,
17278
16729
  B1ChurchProvider,
17279
16730
  BibleProjectProvider,
17280
16731
  CbnProvider,
17281
- DEFAULT_DURATION_CONFIG,
17282
- DeviceFlowHelper,
17283
16732
  DropboxProvider,
17284
- FormatConverters_exports as FormatConverters,
17285
- FormatResolver,
17286
16733
  HighVoltageKidsProvider,
17287
16734
  JesusFilmProvider,
17288
16735
  LessonsChurchProvider,
17289
- OAuthHelper,
16736
+ LifeChurchProvider,
17290
16737
  PlanningCenterProvider,
17291
16738
  SignPresenterProvider,
17292
16739
  TokenHelper,
17293
16740
  VERSION,
17294
- appendToPath,
17295
- buildPath,
17296
- countWords,
17297
- createFile,
17298
- createFolder,
17299
- detectMediaType,
17300
- estimateDuration,
17301
- estimateImageDuration,
17302
- estimateTextDuration,
17303
- generatePath,
17304
16741
  getAllProviders,
17305
16742
  getAvailableProviders,
17306
16743
  getProvider,
17307
16744
  getProviderConfig,
17308
- getSegment,
17309
16745
  isContentFile,
17310
16746
  isContentFolder,
17311
- isMediaFile,
17312
16747
  navigateToPath,
17313
- parsePath,
17314
16748
  registerProvider
17315
16749
  };
17316
16750
  //# sourceMappingURL=index.js.map