@churchapps/content-providers 0.3.1 → 0.4.1

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.d.cts CHANGED
@@ -193,7 +193,6 @@ interface VenueActionsResponseInterface {
193
193
  }
194
194
  interface ProviderCapabilities {
195
195
  browse: boolean;
196
- presentations: boolean;
197
196
  playlist: boolean;
198
197
  instructions: boolean;
199
198
  mediaLicensing: boolean;
@@ -235,158 +234,11 @@ interface IProvider {
235
234
  checkMediaLicense?(mediaId: string, auth?: ContentProviderAuthData | null): Promise<MediaLicenseResult | null>;
236
235
  }
237
236
 
238
- declare function detectMediaType(url: string, explicitType?: string): "video" | "image";
239
- declare function isMediaFile(filename: string): boolean;
240
- declare function createFolder(id: string, title: string, path: string, thumbnail?: string, isLeaf?: boolean): ContentFolder;
241
- declare function createFile(id: string, title: string, url: string, options?: {
242
- mediaType?: "video" | "image";
243
- thumbnail?: string;
244
- muxPlaybackId?: string;
245
- seconds?: number;
246
- loop?: boolean;
247
- loopVideo?: boolean;
248
- streamUrl?: string;
249
- }): ContentFile;
250
-
251
- /**
252
- * Path parsing utilities for content providers.
253
- * Paths follow the format: /segment1/segment2/segment3/...
254
- * Example: /lessons/programId/studyId/lessonId/venueId
255
- */
256
- interface ParsedPath {
257
- segments: string[];
258
- depth: number;
259
- }
260
- /**
261
- * Parse a path string into segments and depth.
262
- * @param path - The path to parse (e.g., "/lessons/abc123/def456")
263
- * @returns Object with segments array and depth count
264
- */
265
- declare function parsePath(path: string | null | undefined): ParsedPath;
266
- /**
267
- * Get a specific segment from a path by index.
268
- * @param path - The path to parse
269
- * @param index - Zero-based index of the segment to retrieve
270
- * @returns The segment at the given index, or null if not found
271
- */
272
- declare function getSegment(path: string | null | undefined, index: number): string | null;
273
- /**
274
- * Build a path string from segments.
275
- * @param segments - Array of path segments
276
- * @returns Path string with leading slash
277
- */
278
- declare function buildPath(segments: string[]): string;
279
- /**
280
- * Append a segment to an existing path.
281
- * @param basePath - The base path
282
- * @param segment - The segment to append
283
- * @returns New path with segment appended
284
- */
285
- declare function appendToPath(basePath: string | null | undefined, segment: string): string;
286
-
287
237
  /**
288
238
  * Navigate to a specific item using a dot-notation path.
289
239
  * Path format: "0.2.1" means items[0].children[2].children[1]
290
240
  */
291
241
  declare function navigateToPath(instructions: Instructions, path: string): InstructionItem | null;
292
- /**
293
- * Generate a path string for an item given its position in the tree.
294
- * Used when selecting an item to store its path.
295
- */
296
- declare function generatePath(indices: number[]): string;
297
-
298
- interface DurationEstimationConfig {
299
- secondsPerImage: number;
300
- wordsPerMinute: number;
301
- }
302
- declare const DEFAULT_DURATION_CONFIG: DurationEstimationConfig;
303
- /**
304
- * Count words in text (splits on whitespace)
305
- */
306
- declare function countWords(text: string): number;
307
- /**
308
- * Estimate duration for image content
309
- * @returns Duration in seconds (default: 15)
310
- */
311
- declare function estimateImageDuration(config?: Partial<DurationEstimationConfig>): number;
312
- /**
313
- * Estimate duration for text content based on word count
314
- * @param text - The text content
315
- * @param config - Optional configuration overrides
316
- * @returns Duration in seconds
317
- */
318
- declare function estimateTextDuration(text: string, config?: Partial<DurationEstimationConfig>): number;
319
- /**
320
- * Estimate duration based on media type
321
- * @param mediaType - "video" | "image" | "text"
322
- * @param options - Text content or word count for text estimation
323
- * @returns Duration in seconds (0 for video/unknown)
324
- */
325
- declare function estimateDuration(mediaType: "video" | "image" | "text", options?: {
326
- text?: string;
327
- wordCount?: number;
328
- config?: Partial<DurationEstimationConfig>;
329
- }): number;
330
-
331
- declare function presentationsToPlaylist(plan: Plan): ContentFile[];
332
- declare function presentationsToExpandedInstructions(plan: Plan): Instructions;
333
- declare function instructionsToPlaylist(instructions: Instructions): ContentFile[];
334
- declare const expandedInstructionsToPlaylist: typeof instructionsToPlaylist;
335
- declare function instructionsToPresentations(instructions: Instructions, planId?: string): Plan;
336
- declare const expandedInstructionsToPresentations: typeof instructionsToPresentations;
337
- declare function playlistToPresentations(files: ContentFile[], planName?: string, sectionName?: string): Plan;
338
- declare function playlistToInstructions(files: ContentFile[], name?: string): Instructions;
339
- declare const playlistToExpandedInstructions: typeof playlistToInstructions;
340
-
341
- declare const FormatConverters_expandedInstructionsToPlaylist: typeof expandedInstructionsToPlaylist;
342
- declare const FormatConverters_expandedInstructionsToPresentations: typeof expandedInstructionsToPresentations;
343
- declare const FormatConverters_instructionsToPlaylist: typeof instructionsToPlaylist;
344
- declare const FormatConverters_instructionsToPresentations: typeof instructionsToPresentations;
345
- declare const FormatConverters_playlistToExpandedInstructions: typeof playlistToExpandedInstructions;
346
- declare const FormatConverters_playlistToInstructions: typeof playlistToInstructions;
347
- declare const FormatConverters_playlistToPresentations: typeof playlistToPresentations;
348
- declare const FormatConverters_presentationsToExpandedInstructions: typeof presentationsToExpandedInstructions;
349
- declare const FormatConverters_presentationsToPlaylist: typeof presentationsToPlaylist;
350
- declare namespace FormatConverters {
351
- export { FormatConverters_expandedInstructionsToPlaylist as expandedInstructionsToPlaylist, FormatConverters_expandedInstructionsToPresentations as expandedInstructionsToPresentations, FormatConverters_instructionsToPlaylist as instructionsToPlaylist, FormatConverters_instructionsToPresentations as instructionsToPresentations, FormatConverters_playlistToExpandedInstructions as playlistToExpandedInstructions, FormatConverters_playlistToInstructions as playlistToInstructions, FormatConverters_playlistToPresentations as playlistToPresentations, FormatConverters_presentationsToExpandedInstructions as presentationsToExpandedInstructions, FormatConverters_presentationsToPlaylist as presentationsToPlaylist };
352
- }
353
-
354
- interface FormatResolverOptions {
355
- allowLossy?: boolean;
356
- }
357
- interface ResolvedFormatMeta {
358
- isNative: boolean;
359
- sourceFormat?: "playlist" | "presentations" | "instructions";
360
- isLossy: boolean;
361
- }
362
- declare class FormatResolver {
363
- private provider;
364
- private options;
365
- constructor(provider: IProvider, options?: FormatResolverOptions);
366
- getProvider(): IProvider;
367
- /** Extract the last segment from a path to use as fallback ID/title */
368
- private getIdFromPath;
369
- getPlaylist(path: string, auth?: ContentProviderAuthData | null): Promise<ContentFile[] | null>;
370
- getPlaylistWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
371
- data: ContentFile[] | null;
372
- meta: ResolvedFormatMeta;
373
- }>;
374
- getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
375
- getInstructionsWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
376
- data: Instructions | null;
377
- meta: ResolvedFormatMeta;
378
- }>;
379
- }
380
-
381
- declare class OAuthHelper {
382
- generateCodeVerifier(): string;
383
- generateCodeChallenge(verifier: string): Promise<string>;
384
- buildAuthUrl(config: ContentProviderConfig, codeVerifier: string, redirectUri: string, state?: string): Promise<{
385
- url: string;
386
- challengeMethod: string;
387
- }>;
388
- exchangeCodeForTokens(config: ContentProviderConfig, _providerId: string, code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
389
- }
390
242
 
391
243
  declare class TokenHelper {
392
244
  isAuthValid(auth: ContentProviderAuthData | null | undefined): boolean;
@@ -394,18 +246,6 @@ declare class TokenHelper {
394
246
  refreshToken(config: ContentProviderConfig, auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
395
247
  }
396
248
 
397
- declare class DeviceFlowHelper {
398
- supportsDeviceFlow(config: ContentProviderConfig): boolean;
399
- initiateDeviceFlow(config: ContentProviderConfig): Promise<DeviceAuthorizationResponse | null>;
400
- pollDeviceFlowToken(config: ContentProviderConfig, deviceCode: string): Promise<DeviceFlowPollResult>;
401
- calculatePollDelay(baseInterval?: number, slowDownCount?: number): number;
402
- }
403
-
404
- declare class ApiHelper {
405
- createAuthHeaders(auth: ContentProviderAuthData | null | undefined): Record<string, string> | null;
406
- apiRequest<T>(config: ContentProviderConfig, providerId: string, path: string, auth?: ContentProviderAuthData | null, method?: "GET" | "POST", body?: unknown): Promise<T | null>;
407
- }
408
-
409
249
  /**
410
250
  * APlay Provider
411
251
  *
@@ -512,6 +352,7 @@ declare class LessonsChurchProvider implements IProvider {
512
352
 
513
353
  declare class B1ChurchProvider implements IProvider {
514
354
  private readonly apiHelper;
355
+ private readonly deviceFlowHelper;
515
356
  private readonly externalContentCache;
516
357
  private apiRequest;
517
358
  readonly id = "b1church";
@@ -721,6 +562,52 @@ declare class CbnProvider implements IProvider {
721
562
  pollDeviceFlowToken(deviceCode: string): Promise<DeviceFlowPollResult>;
722
563
  }
723
564
 
565
+ /**
566
+ * Life.Church Provider
567
+ *
568
+ * Browses the Life.Church kids curriculum from a static catalog generated by
569
+ * scripts/scrape-lifechurch.ts (sourced from life.church/media/* + the
570
+ * open.life.church weekly calendar).
571
+ *
572
+ * Path structure:
573
+ * / -> "scheduled" folder + 4 series
574
+ * /scheduled -> this Sunday's scheduled lessons (one per age group)
575
+ * /scheduled/{scheduledId} -> single video file (leaf)
576
+ * /{seriesId} -> units within the series
577
+ * /{seriesId}/{unitId} -> lessons within the unit
578
+ * /{seriesId}/{unitId}/{lessonId} -> single video file (leaf)
579
+ *
580
+ * Video delivery: ContentFile.url is a direct mp4 on Life.Church's CDN
581
+ * (https://d.life.church/.../{slug}_720p.mp4). Public, no auth, supports
582
+ * range requests — plays in any standard mp4 player including
583
+ * react-native-video.
584
+ */
585
+ declare class LifeChurchProvider implements IProvider {
586
+ readonly id = "lifechurch";
587
+ readonly name = "Life.Church";
588
+ readonly logos: ProviderLogos;
589
+ readonly config: ContentProviderConfig;
590
+ readonly requiresAuth = false;
591
+ readonly authTypes: AuthType[];
592
+ readonly capabilities: ProviderCapabilities;
593
+ private data;
594
+ private findSeries;
595
+ private findUnit;
596
+ private findLesson;
597
+ private findScheduled;
598
+ /** Resolve a scheduled-lesson reference to the underlying lesson + unit + series. */
599
+ private resolveScheduled;
600
+ private lessonToFile;
601
+ browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
602
+ getPlaylist(path: string, _auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
603
+ getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
604
+ /**
605
+ * Returns the most recent scheduled lesson from data.scheduledLessons.
606
+ */
607
+ getCurrentPlan(_auth?: ContentProviderAuthData | null): Promise<CurrentPlan | null>;
608
+ supportsDeviceFlow(): boolean;
609
+ }
610
+
724
611
  declare function getProvider(providerId: string): IProvider | null;
725
612
  declare function getAllProviders(): IProvider[];
726
613
  declare function registerProvider(provider: IProvider): void;
@@ -742,4 +629,4 @@ declare function getAvailableProviders(ids?: string[]): ProviderInfo[];
742
629
  */
743
630
  declare const VERSION: string;
744
631
 
745
- export { APlayProvider, ApiHelper, type AuthType, B1ChurchProvider, BibleProjectProvider, CbnProvider, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, type CurrentPlan, DEFAULT_DURATION_CONFIG, type DeviceAuthorizationResponse, DeviceFlowHelper, type DeviceFlowPollResult, type DeviceFlowState, DropboxProvider, type DurationEstimationConfig, type EndpointValue, type EndpointsConfig, type FeedActionInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, FormatConverters, FormatResolver, type FormatResolverOptions, HighVoltageKidsProvider, type IProvider, type InstructionItem, type Instructions, JesusFilmProvider, LessonsChurchProvider, type MediaLicenseResult, type MediaLicenseStatus, type MessageFileInterface, OAuthHelper, type Plan, type PlanPresentation, type PlanSection, type PlanTimelineItem, PlanningCenterProvider, type ProviderCapabilities, type ProviderInfo, type ProviderLogos, type ResolvedFormatMeta, SignPresenterProvider, TokenHelper, VERSION, type VenueActionInterface, type VenueActionsResponseInterface, type VenueSectionActionsInterface, appendToPath, buildPath, countWords, createFile, createFolder, detectMediaType, estimateDuration, estimateImageDuration, estimateTextDuration, generatePath, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, getSegment, isContentFile, isContentFolder, isMediaFile, navigateToPath, parsePath, registerProvider };
632
+ export { APlayProvider, type AuthType, B1ChurchProvider, BibleProjectProvider, CbnProvider, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, type CurrentPlan, type DeviceAuthorizationResponse, type DeviceFlowPollResult, type DeviceFlowState, DropboxProvider, type EndpointValue, type EndpointsConfig, type FeedActionInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, HighVoltageKidsProvider, type IProvider, type InstructionItem, type Instructions, JesusFilmProvider, LessonsChurchProvider, LifeChurchProvider, type MediaLicenseResult, type MediaLicenseStatus, type MessageFileInterface, type Plan, type PlanPresentation, type PlanSection, type PlanTimelineItem, PlanningCenterProvider, type ProviderCapabilities, type ProviderInfo, type ProviderLogos, SignPresenterProvider, TokenHelper, VERSION, type VenueActionInterface, type VenueActionsResponseInterface, type VenueSectionActionsInterface, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, isContentFile, isContentFolder, navigateToPath, registerProvider };
package/dist/index.d.ts CHANGED
@@ -193,7 +193,6 @@ interface VenueActionsResponseInterface {
193
193
  }
194
194
  interface ProviderCapabilities {
195
195
  browse: boolean;
196
- presentations: boolean;
197
196
  playlist: boolean;
198
197
  instructions: boolean;
199
198
  mediaLicensing: boolean;
@@ -235,158 +234,11 @@ interface IProvider {
235
234
  checkMediaLicense?(mediaId: string, auth?: ContentProviderAuthData | null): Promise<MediaLicenseResult | null>;
236
235
  }
237
236
 
238
- declare function detectMediaType(url: string, explicitType?: string): "video" | "image";
239
- declare function isMediaFile(filename: string): boolean;
240
- declare function createFolder(id: string, title: string, path: string, thumbnail?: string, isLeaf?: boolean): ContentFolder;
241
- declare function createFile(id: string, title: string, url: string, options?: {
242
- mediaType?: "video" | "image";
243
- thumbnail?: string;
244
- muxPlaybackId?: string;
245
- seconds?: number;
246
- loop?: boolean;
247
- loopVideo?: boolean;
248
- streamUrl?: string;
249
- }): ContentFile;
250
-
251
- /**
252
- * Path parsing utilities for content providers.
253
- * Paths follow the format: /segment1/segment2/segment3/...
254
- * Example: /lessons/programId/studyId/lessonId/venueId
255
- */
256
- interface ParsedPath {
257
- segments: string[];
258
- depth: number;
259
- }
260
- /**
261
- * Parse a path string into segments and depth.
262
- * @param path - The path to parse (e.g., "/lessons/abc123/def456")
263
- * @returns Object with segments array and depth count
264
- */
265
- declare function parsePath(path: string | null | undefined): ParsedPath;
266
- /**
267
- * Get a specific segment from a path by index.
268
- * @param path - The path to parse
269
- * @param index - Zero-based index of the segment to retrieve
270
- * @returns The segment at the given index, or null if not found
271
- */
272
- declare function getSegment(path: string | null | undefined, index: number): string | null;
273
- /**
274
- * Build a path string from segments.
275
- * @param segments - Array of path segments
276
- * @returns Path string with leading slash
277
- */
278
- declare function buildPath(segments: string[]): string;
279
- /**
280
- * Append a segment to an existing path.
281
- * @param basePath - The base path
282
- * @param segment - The segment to append
283
- * @returns New path with segment appended
284
- */
285
- declare function appendToPath(basePath: string | null | undefined, segment: string): string;
286
-
287
237
  /**
288
238
  * Navigate to a specific item using a dot-notation path.
289
239
  * Path format: "0.2.1" means items[0].children[2].children[1]
290
240
  */
291
241
  declare function navigateToPath(instructions: Instructions, path: string): InstructionItem | null;
292
- /**
293
- * Generate a path string for an item given its position in the tree.
294
- * Used when selecting an item to store its path.
295
- */
296
- declare function generatePath(indices: number[]): string;
297
-
298
- interface DurationEstimationConfig {
299
- secondsPerImage: number;
300
- wordsPerMinute: number;
301
- }
302
- declare const DEFAULT_DURATION_CONFIG: DurationEstimationConfig;
303
- /**
304
- * Count words in text (splits on whitespace)
305
- */
306
- declare function countWords(text: string): number;
307
- /**
308
- * Estimate duration for image content
309
- * @returns Duration in seconds (default: 15)
310
- */
311
- declare function estimateImageDuration(config?: Partial<DurationEstimationConfig>): number;
312
- /**
313
- * Estimate duration for text content based on word count
314
- * @param text - The text content
315
- * @param config - Optional configuration overrides
316
- * @returns Duration in seconds
317
- */
318
- declare function estimateTextDuration(text: string, config?: Partial<DurationEstimationConfig>): number;
319
- /**
320
- * Estimate duration based on media type
321
- * @param mediaType - "video" | "image" | "text"
322
- * @param options - Text content or word count for text estimation
323
- * @returns Duration in seconds (0 for video/unknown)
324
- */
325
- declare function estimateDuration(mediaType: "video" | "image" | "text", options?: {
326
- text?: string;
327
- wordCount?: number;
328
- config?: Partial<DurationEstimationConfig>;
329
- }): number;
330
-
331
- declare function presentationsToPlaylist(plan: Plan): ContentFile[];
332
- declare function presentationsToExpandedInstructions(plan: Plan): Instructions;
333
- declare function instructionsToPlaylist(instructions: Instructions): ContentFile[];
334
- declare const expandedInstructionsToPlaylist: typeof instructionsToPlaylist;
335
- declare function instructionsToPresentations(instructions: Instructions, planId?: string): Plan;
336
- declare const expandedInstructionsToPresentations: typeof instructionsToPresentations;
337
- declare function playlistToPresentations(files: ContentFile[], planName?: string, sectionName?: string): Plan;
338
- declare function playlistToInstructions(files: ContentFile[], name?: string): Instructions;
339
- declare const playlistToExpandedInstructions: typeof playlistToInstructions;
340
-
341
- declare const FormatConverters_expandedInstructionsToPlaylist: typeof expandedInstructionsToPlaylist;
342
- declare const FormatConverters_expandedInstructionsToPresentations: typeof expandedInstructionsToPresentations;
343
- declare const FormatConverters_instructionsToPlaylist: typeof instructionsToPlaylist;
344
- declare const FormatConverters_instructionsToPresentations: typeof instructionsToPresentations;
345
- declare const FormatConverters_playlistToExpandedInstructions: typeof playlistToExpandedInstructions;
346
- declare const FormatConverters_playlistToInstructions: typeof playlistToInstructions;
347
- declare const FormatConverters_playlistToPresentations: typeof playlistToPresentations;
348
- declare const FormatConverters_presentationsToExpandedInstructions: typeof presentationsToExpandedInstructions;
349
- declare const FormatConverters_presentationsToPlaylist: typeof presentationsToPlaylist;
350
- declare namespace FormatConverters {
351
- export { FormatConverters_expandedInstructionsToPlaylist as expandedInstructionsToPlaylist, FormatConverters_expandedInstructionsToPresentations as expandedInstructionsToPresentations, FormatConverters_instructionsToPlaylist as instructionsToPlaylist, FormatConverters_instructionsToPresentations as instructionsToPresentations, FormatConverters_playlistToExpandedInstructions as playlistToExpandedInstructions, FormatConverters_playlistToInstructions as playlistToInstructions, FormatConverters_playlistToPresentations as playlistToPresentations, FormatConverters_presentationsToExpandedInstructions as presentationsToExpandedInstructions, FormatConverters_presentationsToPlaylist as presentationsToPlaylist };
352
- }
353
-
354
- interface FormatResolverOptions {
355
- allowLossy?: boolean;
356
- }
357
- interface ResolvedFormatMeta {
358
- isNative: boolean;
359
- sourceFormat?: "playlist" | "presentations" | "instructions";
360
- isLossy: boolean;
361
- }
362
- declare class FormatResolver {
363
- private provider;
364
- private options;
365
- constructor(provider: IProvider, options?: FormatResolverOptions);
366
- getProvider(): IProvider;
367
- /** Extract the last segment from a path to use as fallback ID/title */
368
- private getIdFromPath;
369
- getPlaylist(path: string, auth?: ContentProviderAuthData | null): Promise<ContentFile[] | null>;
370
- getPlaylistWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
371
- data: ContentFile[] | null;
372
- meta: ResolvedFormatMeta;
373
- }>;
374
- getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
375
- getInstructionsWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
376
- data: Instructions | null;
377
- meta: ResolvedFormatMeta;
378
- }>;
379
- }
380
-
381
- declare class OAuthHelper {
382
- generateCodeVerifier(): string;
383
- generateCodeChallenge(verifier: string): Promise<string>;
384
- buildAuthUrl(config: ContentProviderConfig, codeVerifier: string, redirectUri: string, state?: string): Promise<{
385
- url: string;
386
- challengeMethod: string;
387
- }>;
388
- exchangeCodeForTokens(config: ContentProviderConfig, _providerId: string, code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
389
- }
390
242
 
391
243
  declare class TokenHelper {
392
244
  isAuthValid(auth: ContentProviderAuthData | null | undefined): boolean;
@@ -394,18 +246,6 @@ declare class TokenHelper {
394
246
  refreshToken(config: ContentProviderConfig, auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
395
247
  }
396
248
 
397
- declare class DeviceFlowHelper {
398
- supportsDeviceFlow(config: ContentProviderConfig): boolean;
399
- initiateDeviceFlow(config: ContentProviderConfig): Promise<DeviceAuthorizationResponse | null>;
400
- pollDeviceFlowToken(config: ContentProviderConfig, deviceCode: string): Promise<DeviceFlowPollResult>;
401
- calculatePollDelay(baseInterval?: number, slowDownCount?: number): number;
402
- }
403
-
404
- declare class ApiHelper {
405
- createAuthHeaders(auth: ContentProviderAuthData | null | undefined): Record<string, string> | null;
406
- apiRequest<T>(config: ContentProviderConfig, providerId: string, path: string, auth?: ContentProviderAuthData | null, method?: "GET" | "POST", body?: unknown): Promise<T | null>;
407
- }
408
-
409
249
  /**
410
250
  * APlay Provider
411
251
  *
@@ -512,6 +352,7 @@ declare class LessonsChurchProvider implements IProvider {
512
352
 
513
353
  declare class B1ChurchProvider implements IProvider {
514
354
  private readonly apiHelper;
355
+ private readonly deviceFlowHelper;
515
356
  private readonly externalContentCache;
516
357
  private apiRequest;
517
358
  readonly id = "b1church";
@@ -721,6 +562,52 @@ declare class CbnProvider implements IProvider {
721
562
  pollDeviceFlowToken(deviceCode: string): Promise<DeviceFlowPollResult>;
722
563
  }
723
564
 
565
+ /**
566
+ * Life.Church Provider
567
+ *
568
+ * Browses the Life.Church kids curriculum from a static catalog generated by
569
+ * scripts/scrape-lifechurch.ts (sourced from life.church/media/* + the
570
+ * open.life.church weekly calendar).
571
+ *
572
+ * Path structure:
573
+ * / -> "scheduled" folder + 4 series
574
+ * /scheduled -> this Sunday's scheduled lessons (one per age group)
575
+ * /scheduled/{scheduledId} -> single video file (leaf)
576
+ * /{seriesId} -> units within the series
577
+ * /{seriesId}/{unitId} -> lessons within the unit
578
+ * /{seriesId}/{unitId}/{lessonId} -> single video file (leaf)
579
+ *
580
+ * Video delivery: ContentFile.url is a direct mp4 on Life.Church's CDN
581
+ * (https://d.life.church/.../{slug}_720p.mp4). Public, no auth, supports
582
+ * range requests — plays in any standard mp4 player including
583
+ * react-native-video.
584
+ */
585
+ declare class LifeChurchProvider implements IProvider {
586
+ readonly id = "lifechurch";
587
+ readonly name = "Life.Church";
588
+ readonly logos: ProviderLogos;
589
+ readonly config: ContentProviderConfig;
590
+ readonly requiresAuth = false;
591
+ readonly authTypes: AuthType[];
592
+ readonly capabilities: ProviderCapabilities;
593
+ private data;
594
+ private findSeries;
595
+ private findUnit;
596
+ private findLesson;
597
+ private findScheduled;
598
+ /** Resolve a scheduled-lesson reference to the underlying lesson + unit + series. */
599
+ private resolveScheduled;
600
+ private lessonToFile;
601
+ browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
602
+ getPlaylist(path: string, _auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
603
+ getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
604
+ /**
605
+ * Returns the most recent scheduled lesson from data.scheduledLessons.
606
+ */
607
+ getCurrentPlan(_auth?: ContentProviderAuthData | null): Promise<CurrentPlan | null>;
608
+ supportsDeviceFlow(): boolean;
609
+ }
610
+
724
611
  declare function getProvider(providerId: string): IProvider | null;
725
612
  declare function getAllProviders(): IProvider[];
726
613
  declare function registerProvider(provider: IProvider): void;
@@ -742,4 +629,4 @@ declare function getAvailableProviders(ids?: string[]): ProviderInfo[];
742
629
  */
743
630
  declare const VERSION: string;
744
631
 
745
- export { APlayProvider, ApiHelper, type AuthType, B1ChurchProvider, BibleProjectProvider, CbnProvider, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, type CurrentPlan, DEFAULT_DURATION_CONFIG, type DeviceAuthorizationResponse, DeviceFlowHelper, type DeviceFlowPollResult, type DeviceFlowState, DropboxProvider, type DurationEstimationConfig, type EndpointValue, type EndpointsConfig, type FeedActionInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, FormatConverters, FormatResolver, type FormatResolverOptions, HighVoltageKidsProvider, type IProvider, type InstructionItem, type Instructions, JesusFilmProvider, LessonsChurchProvider, type MediaLicenseResult, type MediaLicenseStatus, type MessageFileInterface, OAuthHelper, type Plan, type PlanPresentation, type PlanSection, type PlanTimelineItem, PlanningCenterProvider, type ProviderCapabilities, type ProviderInfo, type ProviderLogos, type ResolvedFormatMeta, SignPresenterProvider, TokenHelper, VERSION, type VenueActionInterface, type VenueActionsResponseInterface, type VenueSectionActionsInterface, appendToPath, buildPath, countWords, createFile, createFolder, detectMediaType, estimateDuration, estimateImageDuration, estimateTextDuration, generatePath, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, getSegment, isContentFile, isContentFolder, isMediaFile, navigateToPath, parsePath, registerProvider };
632
+ export { APlayProvider, type AuthType, B1ChurchProvider, BibleProjectProvider, CbnProvider, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, type CurrentPlan, type DeviceAuthorizationResponse, type DeviceFlowPollResult, type DeviceFlowState, DropboxProvider, type EndpointValue, type EndpointsConfig, type FeedActionInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, HighVoltageKidsProvider, type IProvider, type InstructionItem, type Instructions, JesusFilmProvider, LessonsChurchProvider, LifeChurchProvider, type MediaLicenseResult, type MediaLicenseStatus, type MessageFileInterface, type Plan, type PlanPresentation, type PlanSection, type PlanTimelineItem, PlanningCenterProvider, type ProviderCapabilities, type ProviderInfo, type ProviderLogos, SignPresenterProvider, TokenHelper, VERSION, type VenueActionInterface, type VenueActionsResponseInterface, type VenueSectionActionsInterface, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, isContentFile, isContentFolder, navigateToPath, registerProvider };