Skip to content

YouTube Channels & Captions ​

xnews follows YouTube channels through their public per-channel Atom feeds, which are free and need no Google account or API key, and reads transcripts from a video's caption tracks.

Subscribe to channels ​

ts
import { fetchYoutubeChannelVideos, fetchYoutubeSubscriptions } from "@xbbg/xnews";

const subs = await fetchYoutubeSubscriptions(["@CNBCtelevision", "@YahooFinance"], {
  hideShorts: true, // read each channel's long-form uploads playlist instead
  limit: 50, // caps the merged list, not each channel
});

console.log(subs.items.length); // merged videos, newest first, kind "video"
console.log(subs.partial); // true when any channel failed

for (const channel of subs.channels) {
  console.log(channel.channel, channel.channelId, channel.items.length, channel.error ?? "");
}

const one = await fetchYoutubeChannelVideos("UCrp_UI8XtuYfpiqluWLD7Lw", { limit: 5 });
console.log(one.map((video) => `${video.publishedAt} ${video.title}`));
  • Channel references. Pass UC… channel ids, HTTPS youtube.com channel URLs, or @handles. Handles and URLs are resolved to canonical ids by reading the channel page once; UC… ids need no lookup.
  • Feed depth. Each feed carries only the 15 or so most recent uploads. Poll on an interval and keep your own history if you need more.
  • Independent failures. One bad channel never breaks the batch: its error lands in channels[i].error and partial becomes true. YouTube's feed endpoint intermittently answers 404 for every channel during certain hours; treat that as an upstream outage and keep cached results until it recovers.
  • Shorts. hideShorts: true swaps a UC… channel id for its long-form uploads playlist, which excludes Shorts at the source.
  • Date windows. since and until are enforced locally.

The youtube provider id exists in NewsProvider, but YouTube is channel-based rather than subject-based. Requesting it in a company or topic feed reports unsupported; use the functions above instead.

COMPANY_COMMENTARY_YOUTUBE_CHANNELS lists verified channels where executives speak in their own words. See Earnings Calls & Commentary.

Read a transcript ​

fetchYoutubeTranscript accepts a video URL or id, for example any item from a subscription feed:

ts
import { fetchYoutubeSubscriptions, fetchYoutubeTranscript } from "@xbbg/xnews";

const subs = await fetchYoutubeSubscriptions(["@CNBCtelevision"], { hideShorts: true, limit: 5 });
const video = subs.items[0];

if (video) {
  const transcript = await fetchYoutubeTranscript(video.url, { languages: ["en"] });
  console.log(transcript.videoId, transcript.languageCode, transcript.generated);
  console.log(transcript.segments[0]); // { text, startMs, durationMs }
  console.log(transcript.text.slice(0, 500)); // the whole transcript as one string
}

How it works:

  • Caption tracks are listed through YouTube's player API, with the watch page as a fallback, and both timed-text formats (srv1 and srv3) are parsed.
  • Track choice: an exact language match first, then the same base language (en matches en-US), manual captions over auto-generated ones, then any available track. generated tells you whether you got automatic captions.
  • No captions: the call throws when the video advertises no caption tracks or the caption payload is gated. Use Realtime Transcription to transcribe the audio instead.
  • Caption URL safety: the caption URL comes from YouTube's response, so before following it xnews requires HTTPS, no embedded credentials, and a host under youtube.com, youtube-nocookie.com, or googlevideo.com. Anything else is rejected (this check shipped in 0.2.1).

Lower-level helpers ​

FunctionPurpose
resolveYoutubeChannelId(channel)Resolve a handle or channel URL to a UC… id
isYoutubeChannelId(value)Check whether a string is already a channel id
extractYoutubeVideoId(video)Get the 11-character id from a bare id, a watch, Shorts, embed, or live URL, or a youtu.be link
youtubeChannelFeedUrl(channelId, { hideShorts })The Atom feed URL (network-free, in /catalog)
parseYoutubeChannelVideos(xml)Parse feed XML you fetched yourself (in /parsers)
parseYoutubeCaptionTracks, pickYoutubeCaptionTrack, parseYoutubeTranscriptSegmentsThe caption pipeline, step by step

xbbg is independent open-source software and is not affiliated with, endorsed by, sponsored by, or approved by Bloomberg Finance L.P.