npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@timmo001/effect-youtube

v2.1.1

Published

Effect client for YouTube: channel feeds, live and upcoming streams, oEmbed and upnext media items

Readme

@timmo001/effect-youtube

An Effect client for YouTube: channel RSS feeds, live and upcoming streams from the Data API, subscriptions through a Google sign-in, oEmbed lookups, and mapping videos to Up Next media items.

It works on its own and knows nothing about Up Next's config files or socket.

Install

bun add @timmo001/effect-youtube effect
npm install @timmo001/effect-youtube effect
npx jsr add @timmo001/effect-youtube

effect is a peer dependency, so install the same Effect v4 version your app uses.

Client

YouTubeClient.layer takes an optional Data API key and an optional access token from a Google sign-in. Feeds and oEmbed work without either; videos needs one of them, and subscriptions needs the access token.

import { YouTubeClient, toMediaItem } from "@timmo001/effect-youtube";
import { Effect, Option } from "effect";
import { FetchHttpClient } from "effect/http";

const uploads = Effect.gen(function* () {
  const youtube = yield* YouTubeClient;
  const entries = yield* youtube.channelFeed("UCxxxxxxxxxxxxxxxxxxxxxx");

  return entries.map((entry) => toMediaItem(entry, Option.none()));
}).pipe(
  Effect.provide(YouTubeClient.layer({ apiKey: Option.none() })),
  Effect.provide(FetchHttpClient.layer),
);
  • channelFeed(channelId): the latest 15 uploads from a channel's RSS feed. It takes the channel ID that starts with UC, not a handle.
  • channelUploads(channelId): the same 15 uploads, read from the channel's uploads playlist through the API, for when the RSS feeds are down. Costs 1 unit of quota and needs the API key or access token.
  • videos(videoIds): titles, live state, stream times and viewer counts, 50 videos per request. The key or token is sent as a header, so it never appears in a URL.
  • subscriptions: every channel the signed-in account subscribes to, 50 per request.
  • playlistTitle(playlistId): a playlist's title, or none when there's no such playlist. Needs the access token for a private playlist.
  • playlistItems(playlistId): every video in a playlist, 50 per request, leaving out deleted and private ones. Needs the access token.
  • addToPlaylist(playlistId, videoId) and removeFromPlaylist(itemId): change a playlist. They need a sign-in with manageScope. removeFromPlaylist takes the entry's itemId, not the video ID.
  • oembed(url): the title, channel and thumbnail for any video URL, without a key.

toMediaItem(entry, details) turns a feed entry into a MediaItem. With details from videos, live and upcoming streams get the live or upcoming kind and their start time. toSavedItem(entry) turns a playlist entry into a saved item whose URL plays the video in its playlist. videoIdFromUrl reads the video ID from watch, youtu.be, shorts, live and embed URLs, playlistIdFrom reads a playlist ID from an ID or a URL with a list parameter, and playlistUrl builds a playlist's URL.

Google sign-in

authorizeUrl, exchangeCode and refreshTokens handle a Google sign-in. authorizeUrl asks for the read-only YouTube scope, requiredScope, unless you pass scope, such as manageScope to change playlists. They take the ID and secret of a Google OAuth client of the Desktop app type, which can redirect to any loopback port. authorizeUrl asks for offline access, so exchangeCode returns a refresh token. The returned tokens include the scopes Google granted, when it says.

Failures are a YouTubeError, with the HTTP status and the API's reason when there are them, or a YouTubeAuthError when Google rejects the sign-in or refresh token, or the sign-in doesn't allow changing playlists.

Licence

Apache 2.0. See LICENSE.