@churchapps/content-providers 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -542,13 +542,18 @@ var ApiHelper = class {
542
542
  const headers = { Accept: "application/json" };
543
543
  if (auth) headers["Authorization"] = `Bearer ${auth.access_token}`;
544
544
  if (body) headers["Content-Type"] = "application/json";
545
+ console.log(`[B1Church] apiRequest: ${method} ${url}`);
545
546
  const options = { method, headers, ...body ? { body: JSON.stringify(body) } : {} };
546
547
  const response = await fetch(url, options);
547
548
  if (!response.ok) {
549
+ console.warn(`[B1Church] apiRequest failed: ${method} ${url} \u2192 HTTP ${response.status} ${response.statusText}`);
548
550
  return null;
549
551
  }
550
- return await response.json();
551
- } catch {
552
+ const data = await response.json();
553
+ console.log(`[B1Church] apiRequest OK: ${method} ${url} \u2192 ${Array.isArray(data) ? data.length + " items" : typeof data}`);
554
+ return data;
555
+ } catch (err) {
556
+ console.error(`[B1Church] apiRequest error: ${method} ${config.apiBase}${path}`, err);
552
557
  return null;
553
558
  }
554
559
  }
@@ -1423,10 +1428,17 @@ async function authFetch(url, auth) {
1423
1428
  if (auth) {
1424
1429
  headers["Authorization"] = `Bearer ${auth.access_token}`;
1425
1430
  }
1431
+ console.log(`[B1Church] authFetch: ${url}`);
1426
1432
  const response = await fetch(url, { method: "GET", headers });
1427
- if (!response.ok) return null;
1428
- return await response.json();
1429
- } catch {
1433
+ if (!response.ok) {
1434
+ console.warn(`[B1Church] authFetch failed: ${url} \u2192 HTTP ${response.status} ${response.statusText}`);
1435
+ return null;
1436
+ }
1437
+ const data = await response.json();
1438
+ console.log(`[B1Church] authFetch OK: ${url} \u2192 ${Array.isArray(data) ? data.length + " items" : typeof data}`);
1439
+ return data;
1440
+ } catch (err) {
1441
+ console.error(`[B1Church] authFetch error: ${url}`, err);
1430
1442
  return null;
1431
1443
  }
1432
1444
  }
@@ -1445,20 +1457,34 @@ async function fetchPlans(planTypeId, auth) {
1445
1457
  async function fetchVenueFeed(venueId) {
1446
1458
  try {
1447
1459
  const url = `${LESSONS_API_BASE}/venues/public/feed/${venueId}`;
1460
+ console.log(`[B1Church] fetchVenueFeed: ${url}`);
1448
1461
  const response = await fetch(url, { method: "GET", headers: { Accept: "application/json" } });
1449
- if (!response.ok) return null;
1450
- return await response.json();
1451
- } catch {
1462
+ if (!response.ok) {
1463
+ console.warn(`[B1Church] fetchVenueFeed failed: HTTP ${response.status} ${response.statusText} for venueId=${venueId}`);
1464
+ return null;
1465
+ }
1466
+ const data = await response.json();
1467
+ console.log(`[B1Church] fetchVenueFeed OK: venueId=${venueId}, sections=${data?.sections?.length ?? "none"}`);
1468
+ return data;
1469
+ } catch (err) {
1470
+ console.error(`[B1Church] fetchVenueFeed error: venueId=${venueId}`, err);
1452
1471
  return null;
1453
1472
  }
1454
1473
  }
1455
1474
  async function fetchVenueActions(venueId) {
1456
1475
  try {
1457
1476
  const url = `${LESSONS_API_BASE}/venues/public/actions/${venueId}`;
1477
+ console.log(`[B1Church] fetchVenueActions: ${url}`);
1458
1478
  const response = await fetch(url, { method: "GET", headers: { Accept: "application/json" } });
1459
- if (!response.ok) return null;
1460
- return await response.json();
1461
- } catch {
1479
+ if (!response.ok) {
1480
+ console.warn(`[B1Church] fetchVenueActions failed: HTTP ${response.status} ${response.statusText} for venueId=${venueId}`);
1481
+ return null;
1482
+ }
1483
+ const data = await response.json();
1484
+ console.log(`[B1Church] fetchVenueActions OK: venueId=${venueId}`);
1485
+ return data;
1486
+ } catch (err) {
1487
+ console.error(`[B1Church] fetchVenueActions error: venueId=${venueId}`, err);
1462
1488
  return null;
1463
1489
  }
1464
1490
  }
@@ -1474,14 +1500,21 @@ async function fetchFromProviderProxy(method, ministryId, providerId, path, auth
1474
1500
  }
1475
1501
  const body = { ministryId, providerId, path };
1476
1502
  if (resolution !== void 0) body.resolution = resolution;
1503
+ console.log(`[B1Church] providerProxy: ${method} providerId=${providerId} path=${path}`);
1477
1504
  const response = await fetch(url, {
1478
1505
  method: "POST",
1479
1506
  headers,
1480
1507
  body: JSON.stringify(body)
1481
1508
  });
1482
- if (!response.ok) return null;
1483
- return await response.json();
1484
- } catch {
1509
+ if (!response.ok) {
1510
+ console.warn(`[B1Church] providerProxy failed: ${method} \u2192 HTTP ${response.status} ${response.statusText}`);
1511
+ return null;
1512
+ }
1513
+ const data = await response.json();
1514
+ console.log(`[B1Church] providerProxy OK: ${method} \u2192 ${Array.isArray(data) ? data.length + " items" : typeof data}`);
1515
+ return data;
1516
+ } catch (err) {
1517
+ console.error(`[B1Church] providerProxy error: ${method}`, err);
1485
1518
  return null;
1486
1519
  }
1487
1520
  }
@@ -1909,23 +1942,35 @@ var B1ChurchProvider = class {
1909
1942
  return null;
1910
1943
  }
1911
1944
  async getPlaylist(path, authData, resolution) {
1945
+ console.log(`[B1Church] getPlaylist called with path=${path}`);
1912
1946
  const { segments, depth } = parsePath(path);
1913
- if (depth < 4 || segments[0] !== "ministries") return null;
1947
+ if (depth < 4 || segments[0] !== "ministries") {
1948
+ console.warn(`[B1Church] getPlaylist: invalid path depth=${depth} segments=${JSON.stringify(segments)}`);
1949
+ return null;
1950
+ }
1914
1951
  const ministryId = segments[1];
1915
1952
  const planId = segments[3];
1916
1953
  const planTypeId = segments[2];
1954
+ console.log(`[B1Church] getPlaylist: ministryId=${ministryId}, planTypeId=${planTypeId}, planId=${planId}`);
1917
1955
  const plans = await fetchPlans(planTypeId, authData);
1956
+ console.log(`[B1Church] getPlaylist: fetchPlans returned ${plans.length} plans`);
1918
1957
  const planFolder = plans.find((p) => p.id === planId);
1919
- if (!planFolder) return null;
1958
+ if (!planFolder) {
1959
+ console.warn(`[B1Church] getPlaylist: plan ${planId} not found in ${plans.length} plans (ids: ${plans.map((p) => p.id).join(", ")})`);
1960
+ return null;
1961
+ }
1920
1962
  const churchId = planFolder.churchId;
1921
1963
  const venueId = planFolder.contentId;
1964
+ console.log(`[B1Church] getPlaylist: planFolder found \u2014 churchId=${churchId}, venueId=${venueId}, providerId=${planFolder.providerId}, providerPlanId=${planFolder.providerPlanId}`);
1922
1965
  if (!churchId) {
1923
1966
  console.warn("[B1Church getPlaylist] planFolder missing churchId:", planFolder.id);
1924
1967
  return null;
1925
1968
  }
1926
1969
  const pathFn = this.config.endpoints.planItems;
1927
1970
  const planItems = await this.apiRequest(pathFn(churchId, planId), authData);
1971
+ console.log(`[B1Church] getPlaylist: planItems=${planItems ? Array.isArray(planItems) ? planItems.length + " sections" : typeof planItems : "null"}`);
1928
1972
  if ((!planItems || planItems.length === 0) && planFolder.providerId && planFolder.providerPlanId) {
1973
+ console.log(`[B1Church] getPlaylist: no planItems, trying external provider ${planFolder.providerId} with path ${planFolder.providerPlanId}`);
1929
1974
  const externalFiles = await fetchFromProviderProxy(
1930
1975
  "getPlaylist",
1931
1976
  ministryId,
@@ -1934,17 +1979,30 @@ var B1ChurchProvider = class {
1934
1979
  authData,
1935
1980
  resolution
1936
1981
  );
1982
+ console.log(`[B1Church] getPlaylist: external provider returned ${externalFiles ? Array.isArray(externalFiles) ? externalFiles.length + " files" : typeof externalFiles : "null"}`);
1937
1983
  return externalFiles || null;
1938
1984
  }
1939
- if (!planItems || !Array.isArray(planItems)) return null;
1985
+ if (!planItems || !Array.isArray(planItems)) {
1986
+ console.warn(`[B1Church] getPlaylist: planItems is null/not-array and no external provider fallback. providerId=${planFolder.providerId}, providerPlanId=${planFolder.providerPlanId}`);
1987
+ return null;
1988
+ }
1989
+ console.log(`[B1Church] getPlaylist: processing ${planItems.length} sections, venueId=${venueId || "none"}`);
1940
1990
  const venueFeed = venueId ? await fetchVenueFeed(venueId) : null;
1991
+ if (venueId && !venueFeed) {
1992
+ console.warn(`[B1Church] getPlaylist: venueFeed is null for venueId=${venueId}`);
1993
+ }
1941
1994
  const files = [];
1942
1995
  for (const sectionItem of planItems) {
1996
+ console.log(`[B1Church] getPlaylist: section "${sectionItem.label || sectionItem.id}" has ${sectionItem.children?.length || 0} children`);
1943
1997
  for (const child of sectionItem.children || []) {
1944
1998
  const childItemType = child.itemType;
1999
+ console.log(`[B1Church] getPlaylist: child itemType=${childItemType}, relatedId=${child.relatedId}, providerId=${child.providerId}, providerPath=${child.providerPath}, link=${child.link ? "yes" : "no"}`);
1945
2000
  const isSectionType = childItemType === "section" || childItemType === "lessonSection" || childItemType === "providerSection";
1946
2001
  const canExpandLocally = isSectionType && venueFeed && child.relatedId;
1947
- if (isExternalProviderItem(child) && child.providerId && child.providerPath) {
2002
+ if (canExpandLocally) {
2003
+ const itemFiles = getFilesFromVenueFeed(venueFeed, childItemType, child.relatedId);
2004
+ files.push(...itemFiles);
2005
+ } else if (isExternalProviderItem(child) && child.providerId && child.providerPath) {
1948
2006
  const cacheKey = `${child.providerId}:${child.providerPath}`;
1949
2007
  if (child.providerContentPath) {
1950
2008
  let externalPlan = this.externalContentCache.plans.get(cacheKey);
@@ -1992,9 +2050,6 @@ var B1ChurchProvider = class {
1992
2050
  files.push(...externalFiles);
1993
2051
  }
1994
2052
  }
1995
- } else if (canExpandLocally) {
1996
- const itemFiles = getFilesFromVenueFeed(venueFeed, childItemType, child.relatedId);
1997
- files.push(...itemFiles);
1998
2053
  } else if ((childItemType === "providerFile" || childItemType === "providerPresentation") && child.link) {
1999
2054
  const file = getFileFromProviderFileItem(child);
2000
2055
  if (file) files.push(file);
@@ -2004,6 +2059,10 @@ var B1ChurchProvider = class {
2004
2059
  }
2005
2060
  }
2006
2061
  }
2062
+ console.log(`[B1Church] getPlaylist: total files collected = ${files.length}`);
2063
+ if (files.length === 0) {
2064
+ console.warn(`[B1Church] getPlaylist: returning null \u2014 no files found for path=${path}`);
2065
+ }
2007
2066
  return files.length > 0 ? files : null;
2008
2067
  }
2009
2068
  supportsDeviceFlow() {
@@ -12497,13 +12556,13 @@ var JesusFilmProvider = class {
12497
12556
  const { segments, depth } = parsePath(path);
12498
12557
  if (depth === 0) return this.getCategories();
12499
12558
  if (depth === 1) return this.getItemsInCategory(segments[0]);
12500
- if (depth === 2) {
12501
- const category = segments[0];
12502
- if (category === "feature-films") return this.getVideoFile(segments[1]);
12503
- return this.getContainerChildren(segments[1], category);
12504
- }
12505
- if (depth === 3) return this.getVideoFile(segments[2]);
12506
- return [];
12559
+ const category = segments[0];
12560
+ const lastId = segments[depth - 1];
12561
+ if (depth === 2 && category === "feature-films") return this.getVideoFile(lastId);
12562
+ const pathPrefix = "/" + segments.join("/");
12563
+ const children = await this.getContainerChildren(lastId, pathPrefix);
12564
+ if (children.length > 0) return children;
12565
+ return this.getVideoFile(lastId);
12507
12566
  }
12508
12567
  getCategories() {
12509
12568
  return [
@@ -12552,7 +12611,7 @@ var JesusFilmProvider = class {
12552
12611
  })
12553
12612
  ];
12554
12613
  }
12555
- async getContainerChildren(containerId, category) {
12614
+ async getContainerChildren(containerId, pathPrefix) {
12556
12615
  const linksData = await this.fetchApi(
12557
12616
  `/media-component-links/${containerId}`
12558
12617
  );
@@ -12566,9 +12625,9 @@ var JesusFilmProvider = class {
12566
12625
  return childrenData._embedded.mediaComponents.map((item) => createFolder(
12567
12626
  item.mediaComponentId,
12568
12627
  item.title,
12569
- `/${category}/${containerId}/${item.mediaComponentId}`,
12628
+ `${pathPrefix}/${item.mediaComponentId}`,
12570
12629
  item.imageUrls.mobileCinematicHigh || item.imageUrls.videoStill || item.imageUrls.thumbnail,
12571
- true
12630
+ item.containsCount === 0
12572
12631
  ));
12573
12632
  }
12574
12633
  extractMuxPlaybackId(url) {
@@ -12579,10 +12638,13 @@ var JesusFilmProvider = class {
12579
12638
  const { segments, depth } = parsePath(path);
12580
12639
  if (depth < 1) return null;
12581
12640
  const category = segments[0];
12582
- if (depth === 3) {
12583
- const items = await this.getVideoFile(segments[2]);
12584
- if (items.length === 0) return null;
12585
- return items.filter((item) => item.type === "file");
12641
+ if (depth >= 3) {
12642
+ const lastId = segments[depth - 1];
12643
+ const items = await this.getVideoFile(lastId);
12644
+ const files2 = items.filter((item) => item.type === "file");
12645
+ if (files2.length > 0) return files2;
12646
+ const containerFiles = await this.fetchContainerVideoFiles(lastId);
12647
+ return containerFiles.length > 0 ? containerFiles : null;
12586
12648
  }
12587
12649
  if (depth === 2) {
12588
12650
  if (category === "feature-films") {
@@ -12598,7 +12660,7 @@ var JesusFilmProvider = class {
12598
12660
  const data = await this.fetchApi(
12599
12661
  `/media-components?filter=master&subTypes=${subType}&languageIds=${LANGUAGE_ID}&limit=100`
12600
12662
  );
12601
- const contentComponents = data._embedded.mediaComponents.filter((item) => item.componentType === "content");
12663
+ const contentComponents = data._embedded.mediaComponents.filter((item) => item.containsCount === 0);
12602
12664
  const files = await this.fetchVideoFiles(contentComponents);
12603
12665
  return files.length > 0 ? files : null;
12604
12666
  }
@@ -12637,7 +12699,14 @@ var JesusFilmProvider = class {
12637
12699
  `/media-components?ids=${idsParam}&languageIds=${LANGUAGE_ID}`
12638
12700
  );
12639
12701
  if (!childrenData._embedded?.mediaComponents) return [];
12640
- return this.fetchVideoFiles(childrenData._embedded.mediaComponents);
12702
+ const contentItems = childrenData._embedded.mediaComponents.filter((c) => c.containsCount === 0);
12703
+ const containerItems = childrenData._embedded.mediaComponents.filter((c) => c.containsCount > 0);
12704
+ const files = await this.fetchVideoFiles(contentItems);
12705
+ for (const container of containerItems) {
12706
+ const nested = await this.fetchContainerVideoFiles(container.mediaComponentId);
12707
+ files.push(...nested);
12708
+ }
12709
+ return files;
12641
12710
  }
12642
12711
  async buildVideoInstructions(mediaComponentId, category) {
12643
12712
  const items = await this.getVideoFile(mediaComponentId);
@@ -12712,7 +12781,7 @@ var JesusFilmProvider = class {
12712
12781
  const actionItems = await Promise.all(
12713
12782
  data._embedded.mediaComponents.map(async (component) => {
12714
12783
  let downloadUrl;
12715
- if (component.componentType === "content") {
12784
+ if (component.containsCount === 0) {
12716
12785
  try {
12717
12786
  const variant = await this.fetchApi(
12718
12787
  `/media-components/${component.mediaComponentId}/languages/${LANGUAGE_ID}?platform=web`
@@ -12750,7 +12819,12 @@ var JesusFilmProvider = class {
12750
12819
  if (category === "feature-films") return this.buildVideoInstructions(segments[1], category);
12751
12820
  return this.buildContainerInstructions(segments[1], category);
12752
12821
  }
12753
- if (depth === 3) return this.buildVideoInstructions(segments[2], category);
12822
+ if (depth >= 3) {
12823
+ const lastId = segments[depth - 1];
12824
+ const videoResult = await this.buildVideoInstructions(lastId, category);
12825
+ if (videoResult) return videoResult;
12826
+ return this.buildContainerInstructions(lastId, category);
12827
+ }
12754
12828
  return null;
12755
12829
  }
12756
12830
  supportsDeviceFlow() {