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

youtube-mpv-shim

v1.0.6

Published

Cast YouTube to mpv: your PC appears as a YouTube cast target and plays videos in a local mpv window

Readme

youtube-mpv-shim

Cast YouTube to a local mpv window. A small daemon makes your PC show up as a cast target in YouTube (the same way a smart TV does, via the DIAL protocol and YouTube's Lounge API). Hit the cast button, pick your PC, and the video plays in mpv instead of the browser. Your browser or phone stays connected as a remote: pause, seek, volume, queue and autoplay all work.

For browsers without a working cast button there are companion extensions for both browser families (Firefox/LibreWolf and Chromium/Chrome/Brave/Edge) that send the current video, including your position in it, straight to the daemon.

Features

  • Appears in the YouTube cast menu on the phone app and cast-enabled desktop browsers
  • Full remote control from the sender: play/pause, seek, volume, queue, autoplay ("up next")
  • In-player menu on the Enter key: recommendations, subtitles, audio tracks, playback speed, quality, Stable Volume, SponsorBlock
  • Stable Volume: consistent loudness across videos using YouTube's own per-video loudness data
  • SponsorBlock: auto-skips sponsor segments, "seek forward to skip" prompts for intros, outros, self-promo and interaction reminders
  • Browser extensions for Firefox-family and Chromium-family browsers
  • Settings and player state persist across restarts and updates
  • Works on Linux, Windows and macOS (see macOS notes)

Requirements

  • Node.js >= 22.13
  • mpv (on PATH, or set mpv.binary in the config)
  • yt-dlp on PATH (keep it current - it is the most common cause of playback breakage: yt-dlp -U or your package manager)

Setup

npm install -g youtube-mpv-shim
youtube-mpv-shim

(Running from source instead: clone the repo, npm install, npm run build, node dist/index.js.)

You should see "mpv on <hostname>" is discoverable. Then:

  • Google Chrome / Edge (branded builds): open youtube.com, play a video, click the cast icon in the player, pick your PC.
  • Phone YouTube app (same network): pick your PC from the cast menu.
  • Firefox/LibreWolf and plain Chromium: install the extension (below) and click its toolbar button on any YouTube page. Un-branded Chromium builds (distro packages) usually ship without Google's cast integration, so the in-player cast button never appears there; the extension is the reliable path.

The first cast spawns mpv; closing the mpv window is fine, the next cast respawns it.

macOS notes

  • Safari cannot cast. Google's cast integration is proprietary to Chrome-family browsers; there is no Safari extension either. Use branded Chrome/Edge's in-player cast button, or the extension in Firefox/Chromium.
  • Chrome's global cast menu (toolbar / three-dot menu) lists the device as "Available for specific video sites" and won't let you pick it. That menu only launches Chromecast (mDNS) devices; this daemon is a DIAL device, which only the cast button inside the YouTube player can launch. This is expected, not a failure.
  • Local Network permission (macOS 15+): only the cast path needs it; the extension talks to the daemon over loopback and is unaffected. Cast discovery uses SSDP multicast, which macOS gates per app - if the device never shows up in a cast menu, grant "Local Network" access (System Settings → Privacy & Security → Local Network) to your browser and to whatever runs the daemon (Terminal, or node for a launchd agent).
  • Homebrew PATH: launchd agents and GUI-launched apps get a minimal PATH without /opt/homebrew/bin. The daemon appends /opt/homebrew/bin and /usr/local/bin automatically when spawning mpv and yt-dlp; if your mpv lives elsewhere, set mpv.binary to an absolute path in the config.
  • Autostart: a sample LaunchAgent ships in autostart/youtube-mpv-shim.plist. Adjust the node and youtube-mpv-shim paths inside (see which node / which youtube-mpv-shim), copy it to ~/Library/LaunchAgents/ and run launchctl load ~/Library/LaunchAgents/youtube-mpv-shim.plist.

Browser extensions

Both variants do the same: the toolbar button sends the current tab's video to mpv (resuming at your position, pausing the browser player), right-clicking a YouTube link offers Play link in mpv, and the options page sets the daemon port (default 9909).

Firefox / LibreWolf (Manifest V2): download ytshim-firefox.xpi from the latest release and open it with Firefox. It is AMO-signed and installs permanently.

Chromium / Chrome / Brave / Edge (Manifest V3): download and extract ytshim-chromium.zip from the latest release, then load the folder as an unpacked extension on the chrome://extensions page (developer mode).

From source instead: the variants live in extension/firefox/ (load as a temporary add-on on about:debugging) and extension/chromium/ (load unpacked).

The daemon's API binds to 127.0.0.1 and rejects requests from web pages, so only the extensions and local tools can use it:

curl -X POST http://127.0.0.1:9909/api/play -d '{"url":"https://youtu.be/dQw4w9WgXcQ","time":42}'
curl http://127.0.0.1:9909/api/status

In-player menu

Press Enter in the mpv window (arrows navigate, Enter selects, left goes back, Esc closes):

  • Up next / recommendations: pick a related video to play it
  • Subtitles / Audio track
  • Playback speed: 0.25x to 2x
  • Quality: best down to 360p; reloads the video at the current position
  • Stable Volume: consistent loudness across videos, using YouTube's own per-video loudness data (realtime loudnorm fallback when a video has none). Runs as its own filter; af=... from your mpv.conf is untouched.
  • SponsorBlock: off by default. Sponsor segments auto-skip; self-promo, interaction reminders, intros, outros and previews show a "seek forward to skip" prompt where any forward seek jumps past the segment. Per-category behavior ("skip", "seek", "none") is set via sponsorBlockBehavior in the config. Lookups only ever send a 4-character hash prefix, never the video id.

Disable the whole menu with "menu": false in the config.

Theming

The menu is plain text through mpv's native OSD with a background box, selected entry wrapped in **asterisks**. It uses your OSD font (osd-font in mpv.conf) automatically. While the menu is open three OSD properties are overridden and restored on close; their menu values can be changed in ~/.config/mpv/script-opts/ytshim_menu.conf (defaults shown):

back_color=#CC333333     # #AARRGGBB background box color
font_size=40
max_visible_items=10     # long lists scroll around the selection

Configuration

Everything lives in one per-platform folder and survives updates:

  • Linux: ~/.config/youtube-mpv-shim/
  • Windows: %APPDATA%\youtube-mpv-shim\
  • macOS: ~/Library/Application Support/youtube-mpv-shim/

Files: config.json (yours, hand-edited), player-state.json (auto-written: volume, mute, speed, quality, Stable Volume and SponsorBlock toggles), store.json (cast session identity, so senders remember the device).

config.json (all keys optional):

{
  "deviceName": "mpv on mybox",   // name in the cast menu
  "dialPort": 8098,               // DIAL discovery port
  "httpPort": 9909,               // local API for the extensions; 0 disables
  "mpv": {
    "binary": "mpv",
    "extraArgs": [],              // e.g. ["--fs"] for fullscreen
    "socketPath": "..."           // mpv IPC socket/pipe; sensible per-OS default
  },
  "autoplay": true,               // "up next" autoplay for extension/menu plays
  "autoplayOnConnect": true,      // "up next" autoplay for cast sessions
  "menu": true,                   // in-mpv menu on the Enter key
  "persistState": true,           // remember volume/mute/speed/quality/toggles
  "stableVolumeFilter": "lavfi=[loudnorm=I=-14:TP=-1.5:LRA=11]",
  "browserProfile": null,         // daemon youtube cookies: null, "auto" or a profile path
  "sponsorBlockBehavior": {       // per category: "skip", "seek" or "none"
    "sponsor": "skip",
    "selfpromo": "seek",
    "interaction": "seek",
    "intro": "seek",
    "outro": "seek",
    "preview": "seek",
    "music_offtopic": "none",
    "filler": "none"
  },
  "sponsorBlockApiUrl": "https://sponsor.ajay.app",
  "showPairingCode": false,       // log "Link with TV code" codes
  "logLevel": "info"
}

A partial sponsorBlockBehavior map merges over the defaults. CLI flags override the file: --name, --dial-port, --http-port, --config, --log-level, --pairing-code.

With autoplay the mpv window closes at the end of each video and reopens for the next one; add "--force-window=yes" to mpv.extraArgs if you prefer a persistent window.

Video quality starts as whatever your mpv.conf says (ytdl-format=...). A quality chosen in the menu takes precedence and persists.

Persistence: volume, mute, playback speed, the menu quality choice and the Stable Volume / SponsorBlock toggles survive mpv restarts and daemon restarts (player-state.json). Set "persistState": false to turn this off, or delete the state file to reset.

YouTube bot check / age-restricted videos

If videos fail to load and the log mentions yt-dlp errors, YouTube is likely bot-checking your IP (very common on VPNs). The fix is to let yt-dlp use your browser's YouTube cookies. Add to config.json:

{
  "mpv": {
    "extraArgs": ["--ytdl-raw-options=cookies-from-browser=firefox:/home/you/.config/librewolf/librewolf/<profile-dir>"]
  }
}

For actual Firefox, plain cookies-from-browser=firefox finds the profile automatically; for Chromium use cookies-from-browser=chromium. Putting it here instead of mpv.conf keeps the cookie usage scoped to the shim. The same fix covers age-restricted videos.

The daemon's own metadata calls (Stable Volume loudness data in particular; YouTube withholds the player response from bot-checked anonymous requests) can also use cookies, but this is off by default: the daemon never reads your browser data unless you opt in via browserProfile:

  • "auto": reuse the profile from the cookies-from-browser=firefox:<path> entry above
  • "/path/to/profile": a specific Firefox-family profile directory
  • omit the key (or null): no cookie usage (default)

Only the essential YouTube auth cookies are read from the profile's cookies.sqlite, and requests then count as your account (same as watching in the browser). Without cookies everything still works, with two degradations on bot-checked IPs: Stable Volume falls back to realtime loudnorm instead of YouTube's exact per-video gain, and the recommendations menu may occasionally come up empty.

Credits

License

MIT, see LICENSE.