@churchapps/content-providers 0.9.1 → 0.9.2
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 +45 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +45 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -64,7 +64,7 @@ interface ContentFile {
|
|
|
64
64
|
type: "file";
|
|
65
65
|
id: string;
|
|
66
66
|
title: string;
|
|
67
|
-
mediaType: "video" | "image";
|
|
67
|
+
mediaType: "video" | "image" | "audio";
|
|
68
68
|
thumbnail?: string;
|
|
69
69
|
url: string;
|
|
70
70
|
downloadUrl?: string;
|
|
@@ -148,7 +148,7 @@ interface InstructionItem {
|
|
|
148
148
|
children?: InstructionItem[];
|
|
149
149
|
downloadUrl?: string;
|
|
150
150
|
thumbnail?: string;
|
|
151
|
-
mediaType?: "video" | "image";
|
|
151
|
+
mediaType?: "video" | "image" | "audio";
|
|
152
152
|
}
|
|
153
153
|
interface Instructions {
|
|
154
154
|
name?: string;
|
|
@@ -331,7 +331,11 @@ declare class SignPresenterProvider extends BaseProvider {
|
|
|
331
331
|
browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
332
332
|
private extractList;
|
|
333
333
|
private getPlaylists;
|
|
334
|
+
/** image and video/stream slides play directly; web slides only when the url is itself a media file. html/pdf/multi_zone and generic web pages aren't playable in ChurchApps. */
|
|
335
|
+
private slideMediaType;
|
|
336
|
+
/** The documented player contract; /content/playlists/:id/messages only covers templates 1 and 3 so most playlists come back empty there. */
|
|
334
337
|
private getMessages;
|
|
338
|
+
private getLegacyMessages;
|
|
335
339
|
getPlaylist(path: string, auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
|
|
336
340
|
getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
337
341
|
generateCodeVerifier(): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ interface ContentFile {
|
|
|
64
64
|
type: "file";
|
|
65
65
|
id: string;
|
|
66
66
|
title: string;
|
|
67
|
-
mediaType: "video" | "image";
|
|
67
|
+
mediaType: "video" | "image" | "audio";
|
|
68
68
|
thumbnail?: string;
|
|
69
69
|
url: string;
|
|
70
70
|
downloadUrl?: string;
|
|
@@ -148,7 +148,7 @@ interface InstructionItem {
|
|
|
148
148
|
children?: InstructionItem[];
|
|
149
149
|
downloadUrl?: string;
|
|
150
150
|
thumbnail?: string;
|
|
151
|
-
mediaType?: "video" | "image";
|
|
151
|
+
mediaType?: "video" | "image" | "audio";
|
|
152
152
|
}
|
|
153
153
|
interface Instructions {
|
|
154
154
|
name?: string;
|
|
@@ -331,7 +331,11 @@ declare class SignPresenterProvider extends BaseProvider {
|
|
|
331
331
|
browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
332
332
|
private extractList;
|
|
333
333
|
private getPlaylists;
|
|
334
|
+
/** image and video/stream slides play directly; web slides only when the url is itself a media file. html/pdf/multi_zone and generic web pages aren't playable in ChurchApps. */
|
|
335
|
+
private slideMediaType;
|
|
336
|
+
/** The documented player contract; /content/playlists/:id/messages only covers templates 1 and 3 so most playlists come back empty there. */
|
|
334
337
|
private getMessages;
|
|
338
|
+
private getLegacyMessages;
|
|
335
339
|
getPlaylist(path: string, auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
|
|
336
340
|
getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
337
341
|
generateCodeVerifier(): string;
|
package/dist/index.js
CHANGED
|
@@ -191,7 +191,8 @@ var ApiHelper = class {
|
|
|
191
191
|
const options = { method, headers, ...body ? { body: JSON.stringify(body) } : {} };
|
|
192
192
|
const response = await fetch(url, options);
|
|
193
193
|
if (!response.ok) {
|
|
194
|
-
|
|
194
|
+
const detail = await response.text().catch(() => "");
|
|
195
|
+
console.warn(`[${providerId}] apiRequest failed: ${method} ${url} \u2192 HTTP ${response.status} ${response.statusText}${detail ? ` ${detail.slice(0, 500)}` : ""}`);
|
|
195
196
|
return null;
|
|
196
197
|
}
|
|
197
198
|
return await response.json();
|
|
@@ -252,16 +253,19 @@ var IMAGE_EXTENSIONS = [
|
|
|
252
253
|
".tiff",
|
|
253
254
|
".tif"
|
|
254
255
|
];
|
|
256
|
+
var AUDIO_EXTENSIONS = [".mp3", ".m4a", ".aac", ".wav", ".flac", ".oga"];
|
|
255
257
|
function detectMediaType(url, explicitType) {
|
|
256
258
|
if (explicitType === "video" || explicitType?.startsWith("video/")) return "video";
|
|
257
259
|
if (explicitType === "image" || explicitType?.startsWith("image/")) return "image";
|
|
260
|
+
if (explicitType === "audio" || explicitType?.startsWith("audio/")) return "audio";
|
|
258
261
|
const lower = url.toLowerCase();
|
|
259
262
|
if (VIDEO_EXTENSIONS.some((p) => lower.includes(p)) || lower.includes("stream.mux.com")) return "video";
|
|
263
|
+
if (AUDIO_EXTENSIONS.some((p) => lower.includes(p))) return "audio";
|
|
260
264
|
return "image";
|
|
261
265
|
}
|
|
262
266
|
function isMediaFile(filename) {
|
|
263
267
|
const lower = filename.toLowerCase();
|
|
264
|
-
return [...VIDEO_EXTENSIONS, ...IMAGE_EXTENSIONS].some((ext) => lower.endsWith(ext));
|
|
268
|
+
return [...VIDEO_EXTENSIONS, ...IMAGE_EXTENSIONS, ...AUDIO_EXTENSIONS].some((ext) => lower.endsWith(ext));
|
|
265
269
|
}
|
|
266
270
|
function createFolder(id, title, path, thumbnail, isLeaf) {
|
|
267
271
|
return { type: "folder", id, title, path, thumbnail, isLeaf };
|
|
@@ -541,13 +545,45 @@ var SignPresenterProvider = class extends BaseProvider {
|
|
|
541
545
|
isLeaf: true
|
|
542
546
|
}));
|
|
543
547
|
}
|
|
548
|
+
/** image and video/stream slides play directly; web slides only when the url is itself a media file. html/pdf/multi_zone and generic web pages aren't playable in ChurchApps. */
|
|
549
|
+
slideMediaType(slideType, url) {
|
|
550
|
+
if (slideType === "image") return "image";
|
|
551
|
+
if (slideType === "video" || slideType === "stream") return "video";
|
|
552
|
+
if (slideType === "web" && isMediaFile(url)) return detectMediaType(url);
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
/** The documented player contract; /content/playlists/:id/messages only covers templates 1 and 3 so most playlists come back empty there. */
|
|
544
556
|
async getMessages(playlistId, auth) {
|
|
557
|
+
const response = await this.apiRequest(`/v2/playlists/${playlistId}`, auth);
|
|
558
|
+
const messages = this.extractList(response, "messages");
|
|
559
|
+
if (messages.length === 0) return this.getLegacyMessages(playlistId, auth);
|
|
560
|
+
const files = [];
|
|
561
|
+
messages.forEach((msg, messageIndex) => {
|
|
562
|
+
const slides = Array.isArray(msg.slides) ? msg.slides : [];
|
|
563
|
+
slides.forEach((slide, slideIndex) => {
|
|
564
|
+
const data = slide.data || {};
|
|
565
|
+
const url = typeof data.url === "string" ? data.url.trim() : "";
|
|
566
|
+
const mediaType = url ? this.slideMediaType(slide.type, url) : null;
|
|
567
|
+
if (!mediaType) return;
|
|
568
|
+
const file = createFile(`${playlistId}-${messageIndex}-${slideIndex}`, msg.name, url, {
|
|
569
|
+
mediaType,
|
|
570
|
+
thumbnail: msg.thumbnail,
|
|
571
|
+
seconds: slide.seconds,
|
|
572
|
+
loop: data.loop
|
|
573
|
+
});
|
|
574
|
+
file.downloadUrl = url;
|
|
575
|
+
files.push(file);
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
return files;
|
|
579
|
+
}
|
|
580
|
+
async getLegacyMessages(playlistId, auth) {
|
|
545
581
|
const response = await this.apiRequest(`/content/playlists/${playlistId}/messages`, auth);
|
|
546
582
|
if (!response) return [];
|
|
547
583
|
const files = [];
|
|
548
584
|
for (const msg of this.extractList(response, "messages")) {
|
|
549
|
-
|
|
550
|
-
|
|
585
|
+
const url = [msg.url, msg.thumbnail, msg.image].map((v) => typeof v === "string" ? v.trim() : "").find(Boolean) || "";
|
|
586
|
+
if (!url) continue;
|
|
551
587
|
const file = createFile(msg.id, msg.name, url, {
|
|
552
588
|
mediaType: detectMediaType(url, msg.mediaType),
|
|
553
589
|
thumbnail: msg.thumbnail || msg.image,
|
|
@@ -17761,7 +17797,9 @@ var GoogleDriveProvider = class extends BaseProvider {
|
|
|
17761
17797
|
orderBy: "folder,name_natural",
|
|
17762
17798
|
pageSize: "1000",
|
|
17763
17799
|
supportsAllDrives: "true",
|
|
17764
|
-
includeItemsFromAllDrives
|
|
17800
|
+
// corpora=user (not includeItemsFromAllDrives) — "root" is only meaningful in the user's own corpus, and
|
|
17801
|
+
// combining it with an all-drives search makes Google reject the query, which browse saw as an empty folder.
|
|
17802
|
+
corpora: "user"
|
|
17765
17803
|
});
|
|
17766
17804
|
if (pageToken) params.set("pageToken", pageToken);
|
|
17767
17805
|
const response = await this.apiRequest(`/files?${params.toString()}`, auth);
|
|
@@ -17775,7 +17813,7 @@ var GoogleDriveProvider = class extends BaseProvider {
|
|
|
17775
17813
|
async childItems(folderId, auth) {
|
|
17776
17814
|
const entries = await this.listFiles(`'${folderId}' in parents and trashed=false`, auth);
|
|
17777
17815
|
const folders = entries.filter((e) => e.mimeType === FOLDER_MIME);
|
|
17778
|
-
const mediaFiles = entries.filter((e) => e.mimeType.startsWith("video/")
|
|
17816
|
+
const mediaFiles = entries.filter((e) => e.mimeType !== FOLDER_MIME && !e.mimeType.startsWith("application/vnd.google-apps") && (["video/", "image/", "audio/"].some((prefix) => e.mimeType.startsWith(prefix)) || isMediaFile(e.name)));
|
|
17779
17817
|
return { folders, mediaFiles };
|
|
17780
17818
|
}
|
|
17781
17819
|
/** One batched query marks which sibling folders have subfolders; null = unknown (isLeaf omitted). */
|
|
@@ -17932,7 +17970,7 @@ function getAvailableProviders(ids) {
|
|
|
17932
17970
|
}
|
|
17933
17971
|
|
|
17934
17972
|
// src/index.ts
|
|
17935
|
-
var VERSION = true ? "0.9.
|
|
17973
|
+
var VERSION = true ? "0.9.2" : "dev";
|
|
17936
17974
|
export {
|
|
17937
17975
|
APlayProvider,
|
|
17938
17976
|
B1ChurchProvider,
|