@churchapps/content-providers 0.9.3 → 0.10.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 +49 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +48 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -116,6 +116,11 @@ interface FeedFileInterface {
|
|
|
116
116
|
seconds?: number;
|
|
117
117
|
fileType?: string;
|
|
118
118
|
thumbnail?: string;
|
|
119
|
+
bytes?: number;
|
|
120
|
+
}
|
|
121
|
+
interface FeedDownloadInterface {
|
|
122
|
+
name?: string;
|
|
123
|
+
files?: FeedFileInterface[];
|
|
119
124
|
}
|
|
120
125
|
interface FeedActionInterface {
|
|
121
126
|
id?: string;
|
|
@@ -135,6 +140,7 @@ interface FeedVenueInterface {
|
|
|
135
140
|
lessonName?: string;
|
|
136
141
|
lessonDescription?: string;
|
|
137
142
|
lessonImage?: string;
|
|
143
|
+
downloads?: FeedDownloadInterface[];
|
|
138
144
|
sections?: FeedSectionInterface[];
|
|
139
145
|
}
|
|
140
146
|
interface InstructionItem {
|
|
@@ -150,9 +156,18 @@ interface InstructionItem {
|
|
|
150
156
|
thumbnail?: string;
|
|
151
157
|
mediaType?: "video" | "image" | "audio";
|
|
152
158
|
}
|
|
159
|
+
/** An extra file the teacher downloads/prints (zip, PDF, leader guide) — never part of the presented playlist. */
|
|
160
|
+
interface ContentDownload {
|
|
161
|
+
id?: string;
|
|
162
|
+
title: string;
|
|
163
|
+
url: string;
|
|
164
|
+
fileType?: string;
|
|
165
|
+
bytes?: number;
|
|
166
|
+
}
|
|
153
167
|
interface Instructions {
|
|
154
168
|
name?: string;
|
|
155
169
|
items: InstructionItem[];
|
|
170
|
+
downloads?: ContentDownload[];
|
|
156
171
|
}
|
|
157
172
|
interface MessageFileInterface {
|
|
158
173
|
id?: string;
|
|
@@ -263,10 +278,13 @@ declare function toAuthData(data: Record<string, unknown>, fallbacks?: {
|
|
|
263
278
|
}): ContentProviderAuthData & {
|
|
264
279
|
planTypeId?: string;
|
|
265
280
|
};
|
|
281
|
+
declare function authIsExpired(auth: ContentProviderAuthData | null | undefined, nowMs?: number): boolean;
|
|
266
282
|
declare class TokenHelper {
|
|
283
|
+
private static inflight;
|
|
267
284
|
isAuthValid(auth: ContentProviderAuthData | null | undefined): boolean;
|
|
268
285
|
isTokenExpired(auth: ContentProviderAuthData): boolean;
|
|
269
286
|
refreshToken(config: ContentProviderConfig, auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
|
|
287
|
+
private doRefresh;
|
|
270
288
|
}
|
|
271
289
|
|
|
272
290
|
declare class DeviceFlowHelper {
|
|
@@ -377,6 +395,8 @@ declare class LessonsChurchProvider extends BaseProvider {
|
|
|
377
395
|
private getAddOnFiles;
|
|
378
396
|
private getAddOnCategories;
|
|
379
397
|
private getAddOnsByCategory;
|
|
398
|
+
/** Flatten feed download bundles into printable files, keeping playlist media (videos already in the run-of-show) out. */
|
|
399
|
+
private convertFeedDownloads;
|
|
380
400
|
getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
381
401
|
}
|
|
382
402
|
|
|
@@ -586,4 +606,4 @@ declare function getAvailableProviders(ids?: string[]): ProviderInfo[];
|
|
|
586
606
|
*/
|
|
587
607
|
declare const VERSION: string;
|
|
588
608
|
|
|
589
|
-
export { APlayProvider, type AuthType, B1ChurchProvider, BaseProvider, BibleProjectProvider, CbnProvider, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, type CurrentPlan, type DeviceAuthorizationResponse, DeviceFlowHelper, 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, OAuthHelper, 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, setProviderSecret, toAuthData };
|
|
609
|
+
export { APlayProvider, type AuthType, B1ChurchProvider, BaseProvider, BibleProjectProvider, CbnProvider, type ContentDownload, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, type CurrentPlan, type DeviceAuthorizationResponse, DeviceFlowHelper, type DeviceFlowPollResult, type DeviceFlowState, DropboxProvider, type EndpointValue, type EndpointsConfig, type FeedActionInterface, type FeedDownloadInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, HighVoltageKidsProvider, type IProvider, type InstructionItem, type Instructions, JesusFilmProvider, LessonsChurchProvider, LifeChurchProvider, type MediaLicenseResult, type MediaLicenseStatus, type MessageFileInterface, OAuthHelper, type Plan, type PlanPresentation, type PlanSection, type PlanTimelineItem, PlanningCenterProvider, type ProviderCapabilities, type ProviderInfo, type ProviderLogos, SignPresenterProvider, TokenHelper, VERSION, type VenueActionInterface, type VenueActionsResponseInterface, type VenueSectionActionsInterface, authIsExpired, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, isContentFile, isContentFolder, navigateToPath, registerProvider, setProviderSecret, toAuthData };
|
package/dist/index.d.ts
CHANGED
|
@@ -116,6 +116,11 @@ interface FeedFileInterface {
|
|
|
116
116
|
seconds?: number;
|
|
117
117
|
fileType?: string;
|
|
118
118
|
thumbnail?: string;
|
|
119
|
+
bytes?: number;
|
|
120
|
+
}
|
|
121
|
+
interface FeedDownloadInterface {
|
|
122
|
+
name?: string;
|
|
123
|
+
files?: FeedFileInterface[];
|
|
119
124
|
}
|
|
120
125
|
interface FeedActionInterface {
|
|
121
126
|
id?: string;
|
|
@@ -135,6 +140,7 @@ interface FeedVenueInterface {
|
|
|
135
140
|
lessonName?: string;
|
|
136
141
|
lessonDescription?: string;
|
|
137
142
|
lessonImage?: string;
|
|
143
|
+
downloads?: FeedDownloadInterface[];
|
|
138
144
|
sections?: FeedSectionInterface[];
|
|
139
145
|
}
|
|
140
146
|
interface InstructionItem {
|
|
@@ -150,9 +156,18 @@ interface InstructionItem {
|
|
|
150
156
|
thumbnail?: string;
|
|
151
157
|
mediaType?: "video" | "image" | "audio";
|
|
152
158
|
}
|
|
159
|
+
/** An extra file the teacher downloads/prints (zip, PDF, leader guide) — never part of the presented playlist. */
|
|
160
|
+
interface ContentDownload {
|
|
161
|
+
id?: string;
|
|
162
|
+
title: string;
|
|
163
|
+
url: string;
|
|
164
|
+
fileType?: string;
|
|
165
|
+
bytes?: number;
|
|
166
|
+
}
|
|
153
167
|
interface Instructions {
|
|
154
168
|
name?: string;
|
|
155
169
|
items: InstructionItem[];
|
|
170
|
+
downloads?: ContentDownload[];
|
|
156
171
|
}
|
|
157
172
|
interface MessageFileInterface {
|
|
158
173
|
id?: string;
|
|
@@ -263,10 +278,13 @@ declare function toAuthData(data: Record<string, unknown>, fallbacks?: {
|
|
|
263
278
|
}): ContentProviderAuthData & {
|
|
264
279
|
planTypeId?: string;
|
|
265
280
|
};
|
|
281
|
+
declare function authIsExpired(auth: ContentProviderAuthData | null | undefined, nowMs?: number): boolean;
|
|
266
282
|
declare class TokenHelper {
|
|
283
|
+
private static inflight;
|
|
267
284
|
isAuthValid(auth: ContentProviderAuthData | null | undefined): boolean;
|
|
268
285
|
isTokenExpired(auth: ContentProviderAuthData): boolean;
|
|
269
286
|
refreshToken(config: ContentProviderConfig, auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
|
|
287
|
+
private doRefresh;
|
|
270
288
|
}
|
|
271
289
|
|
|
272
290
|
declare class DeviceFlowHelper {
|
|
@@ -377,6 +395,8 @@ declare class LessonsChurchProvider extends BaseProvider {
|
|
|
377
395
|
private getAddOnFiles;
|
|
378
396
|
private getAddOnCategories;
|
|
379
397
|
private getAddOnsByCategory;
|
|
398
|
+
/** Flatten feed download bundles into printable files, keeping playlist media (videos already in the run-of-show) out. */
|
|
399
|
+
private convertFeedDownloads;
|
|
380
400
|
getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
381
401
|
}
|
|
382
402
|
|
|
@@ -586,4 +606,4 @@ declare function getAvailableProviders(ids?: string[]): ProviderInfo[];
|
|
|
586
606
|
*/
|
|
587
607
|
declare const VERSION: string;
|
|
588
608
|
|
|
589
|
-
export { APlayProvider, type AuthType, B1ChurchProvider, BaseProvider, BibleProjectProvider, CbnProvider, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, type CurrentPlan, type DeviceAuthorizationResponse, DeviceFlowHelper, 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, OAuthHelper, 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, setProviderSecret, toAuthData };
|
|
609
|
+
export { APlayProvider, type AuthType, B1ChurchProvider, BaseProvider, BibleProjectProvider, CbnProvider, type ContentDownload, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, type CurrentPlan, type DeviceAuthorizationResponse, DeviceFlowHelper, type DeviceFlowPollResult, type DeviceFlowState, DropboxProvider, type EndpointValue, type EndpointsConfig, type FeedActionInterface, type FeedDownloadInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, HighVoltageKidsProvider, type IProvider, type InstructionItem, type Instructions, JesusFilmProvider, LessonsChurchProvider, LifeChurchProvider, type MediaLicenseResult, type MediaLicenseStatus, type MessageFileInterface, OAuthHelper, type Plan, type PlanPresentation, type PlanSection, type PlanTimelineItem, PlanningCenterProvider, type ProviderCapabilities, type ProviderInfo, type ProviderLogos, SignPresenterProvider, TokenHelper, VERSION, type VenueActionInterface, type VenueActionsResponseInterface, type VenueSectionActionsInterface, authIsExpired, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, isContentFile, isContentFolder, navigateToPath, registerProvider, setProviderSecret, toAuthData };
|
package/dist/index.js
CHANGED
|
@@ -31,18 +31,32 @@ function toAuthData(data, fallbacks) {
|
|
|
31
31
|
...planTypeId ? { planTypeId } : {}
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
function authIsExpired(auth, nowMs = Date.now()) {
|
|
35
|
+
if (!auth?.created_at || !auth.expires_in) return true;
|
|
36
|
+
const lifetimeMs = auth.expires_in * 1e3;
|
|
37
|
+
const expiresAt = (auth.created_at + auth.expires_in) * 1e3;
|
|
38
|
+
const bufferMs = Math.min(5 * 60 * 1e3, Math.floor(lifetimeMs / 10));
|
|
39
|
+
return nowMs > expiresAt - bufferMs;
|
|
40
|
+
}
|
|
41
|
+
var _TokenHelper = class _TokenHelper {
|
|
35
42
|
isAuthValid(auth) {
|
|
36
|
-
|
|
37
|
-
return !this.isTokenExpired(auth);
|
|
43
|
+
return !authIsExpired(auth);
|
|
38
44
|
}
|
|
39
45
|
isTokenExpired(auth) {
|
|
40
|
-
|
|
41
|
-
const expiresAt = (auth.created_at + auth.expires_in) * 1e3;
|
|
42
|
-
return Date.now() > expiresAt - 5 * 60 * 1e3;
|
|
46
|
+
return authIsExpired(auth);
|
|
43
47
|
}
|
|
44
48
|
async refreshToken(config, auth) {
|
|
45
49
|
if (!auth.refresh_token) return null;
|
|
50
|
+
const key = `${config.oauthBase}|${config.clientId}|${auth.refresh_token}`;
|
|
51
|
+
const existing = _TokenHelper.inflight.get(key);
|
|
52
|
+
if (existing) return existing;
|
|
53
|
+
const pending = this.doRefresh(config, auth).finally(() => {
|
|
54
|
+
_TokenHelper.inflight.delete(key);
|
|
55
|
+
});
|
|
56
|
+
_TokenHelper.inflight.set(key, pending);
|
|
57
|
+
return pending;
|
|
58
|
+
}
|
|
59
|
+
async doRefresh(config, auth) {
|
|
46
60
|
try {
|
|
47
61
|
const params = new URLSearchParams({
|
|
48
62
|
grant_type: "refresh_token",
|
|
@@ -63,6 +77,8 @@ var TokenHelper = class {
|
|
|
63
77
|
}
|
|
64
78
|
}
|
|
65
79
|
};
|
|
80
|
+
_TokenHelper.inflight = /* @__PURE__ */ new Map();
|
|
81
|
+
var TokenHelper = _TokenHelper;
|
|
66
82
|
|
|
67
83
|
// src/helpers/OAuthHelper.ts
|
|
68
84
|
function generateCodeVerifier() {
|
|
@@ -270,6 +286,12 @@ function isMediaFile(filename) {
|
|
|
270
286
|
const lower = filename.toLowerCase();
|
|
271
287
|
return [...VIDEO_EXTENSIONS, ...IMAGE_EXTENSIONS, ...AUDIO_EXTENSIONS].some((ext) => lower.endsWith(ext));
|
|
272
288
|
}
|
|
289
|
+
function isPlaylistMedia(url, fileType, name) {
|
|
290
|
+
if (fileType?.startsWith("video/") || fileType?.startsWith("audio/") || fileType === "video" || fileType === "audio") return true;
|
|
291
|
+
const haystack = `${url} ${name || ""}`.toLowerCase();
|
|
292
|
+
if (haystack.includes("stream.mux.com") || haystack.includes("externalvideos/download")) return true;
|
|
293
|
+
return [...VIDEO_EXTENSIONS, ...AUDIO_EXTENSIONS].some((ext) => haystack.includes(ext));
|
|
294
|
+
}
|
|
273
295
|
function createFolder(id, title, path, thumbnail, isLeaf) {
|
|
274
296
|
return { type: "folder", id, title, path, thumbnail, isLeaf };
|
|
275
297
|
}
|
|
@@ -943,6 +965,18 @@ var LessonsChurchProvider = class extends BaseProvider {
|
|
|
943
965
|
const filtered = allAddOns.filter((a) => a.category === decodedCategory);
|
|
944
966
|
return filtered.map((addOn) => createFolder(addOn.id, addOn.name, `${currentPath}/${addOn.id}`, addOn.image, true));
|
|
945
967
|
}
|
|
968
|
+
/** Flatten feed download bundles into printable files, keeping playlist media (videos already in the run-of-show) out. */
|
|
969
|
+
convertFeedDownloads(bundles) {
|
|
970
|
+
const result = [];
|
|
971
|
+
for (const bundle of bundles || []) {
|
|
972
|
+
const files = (bundle.files || []).filter((f) => f.url && !isPlaylistMedia(f.url, f.fileType, f.name));
|
|
973
|
+
for (const file of files) {
|
|
974
|
+
const title = (files.length === 1 ? bundle.name || file.name : file.name || bundle.name) || "Download";
|
|
975
|
+
result.push({ id: file.id, title, url: file.url, fileType: file.fileType, bytes: file.bytes });
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
return result;
|
|
979
|
+
}
|
|
946
980
|
async getInstructions(path, _auth) {
|
|
947
981
|
const venueId = getSegment(path, 4);
|
|
948
982
|
if (venueId) {
|
|
@@ -954,7 +988,8 @@ var LessonsChurchProvider = class extends BaseProvider {
|
|
|
954
988
|
if (!planItemsResponse) return null;
|
|
955
989
|
const lessonImage = feedResponse?.lessonImage;
|
|
956
990
|
const sectionActionsMap = buildSectionActionsMap(actionsResponse, lessonImage, feedResponse);
|
|
957
|
-
|
|
991
|
+
const downloads = this.convertFeedDownloads(feedResponse?.downloads);
|
|
992
|
+
return { name: planItemsResponse.venueName, items: (planItemsResponse.items || []).map((item) => processInstructionItem(item, sectionActionsMap, lessonImage)), downloads: downloads.length > 0 ? downloads : void 0 };
|
|
958
993
|
}
|
|
959
994
|
const { segments } = parsePath(path);
|
|
960
995
|
if (segments[0] === "addons" && segments.length === 3) {
|
|
@@ -17724,7 +17759,10 @@ var GoCurriculumProvider = class extends BaseProvider {
|
|
|
17724
17759
|
if (!files) return null;
|
|
17725
17760
|
const collection = (await this.getData()).catalog.find((c) => c.id === segments[0]);
|
|
17726
17761
|
const lesson = collection?.lessons.find((l) => l.id === segments[1]);
|
|
17727
|
-
|
|
17762
|
+
const instructions = filesToInstructions(lesson?.name || "Lesson", files);
|
|
17763
|
+
const downloads = (lesson?.resources || []).filter((r) => r.url && !isPlaylistMedia(r.url, void 0, r.file)).map((r) => ({ id: slugify(r.file || r.title), title: r.title || r.file, url: r.url }));
|
|
17764
|
+
if (downloads.length > 0) instructions.downloads = downloads;
|
|
17765
|
+
return instructions;
|
|
17728
17766
|
}
|
|
17729
17767
|
generateCodeVerifier() {
|
|
17730
17768
|
return this.oauthHelper.generateCodeVerifier();
|
|
@@ -17971,7 +18009,7 @@ function getAvailableProviders(ids) {
|
|
|
17971
18009
|
}
|
|
17972
18010
|
|
|
17973
18011
|
// src/index.ts
|
|
17974
|
-
var VERSION = true ? "0.
|
|
18012
|
+
var VERSION = true ? "0.10.0" : "dev";
|
|
17975
18013
|
export {
|
|
17976
18014
|
APlayProvider,
|
|
17977
18015
|
B1ChurchProvider,
|
|
@@ -17989,6 +18027,7 @@ export {
|
|
|
17989
18027
|
SignPresenterProvider,
|
|
17990
18028
|
TokenHelper,
|
|
17991
18029
|
VERSION,
|
|
18030
|
+
authIsExpired,
|
|
17992
18031
|
getAllProviders,
|
|
17993
18032
|
getAvailableProviders,
|
|
17994
18033
|
getProvider,
|