Published: 2025-02-17 Mon 19:55
Updated: 2025-02-17 Mon 19:55

Migrating my YouTube workflow to RSS

Table of Contents

1. Intro

YouTube - the platform - sucks to use no matter where you're using it. Outside of the browser, without ad blockers, you're spammed with so many ads it becomes a challenge to actually use. When you can actually use an ad blocker, there's often issues with videos getting stuck, or occasional weird performance issues on the website itself (this might be an Nvidia on Linux thing, it's always an Nvidia on Linux thing).

However, I still very much want to watch YouTube - the videos. People have suggested to me in the past I use an alternate front-end like Invidious, but my watch time is split (very roughly, not actually) 50/50 between browser and Android box, so anything browser-only is a no-go.

2. ytdl-sub & Issues

For a while, I happily used ytdl-sub in a Docker container, running on my home server. This worked great for a time, downloading all my subscriptions alongside writing the metadata for Jellyfin to group them by channel, and write the video descriptions, etc.

Even while it worked well, however, Jellyfin's interface for browsing these videos wasn't perfect. Browsing each channel as a separate contained show is useful every now and again, but mostly you just want a big list of videos, sorted by date added.

Then, things started breaking. Every so often, I'd realised "hey, it's been a couple days since I last had a video download…", and then days would turn into weeks. I'd check the repo, and there'd be no updates, nor workarounds documented in the issue tracker, so would have to manually start downloading the missing videos by going through my sub box, and copy-pasting a lot of URLs to a yt-dlp command.

This was quickly becoming untenable.

And I'm not sure if this is an issue with ytdl-sub, or if my Docker-fu is just not up to snuff, but I found it really hard to get any readable logs to even figure out what the issue was. Whenever I'd check, it'd seem to be processing just fine, when in reality it was failing to be able to download anything. This was different whenever I ran the command manually, but then if it did download videos correctly, the file permissions would be screwed up, and I'd have to start SSH'ing in and sudo rm'ing 10 minute YouTube vids. Which - as you could imagine - was not something I wanted to have to do.

3. Enter RSS

I have actually tried to use RSS for YouTube before, but it never stuck, precisely because of the aforementioned (rough) 50/50 split of watching on browser vs watching on Android box. It is a hard requirement for me to be able to watch a chunk of a long video on one, and then resume that video on the other. If you don't have that requirement, it's a lot easier, but there's still a lot of info here that you might benefit from.

Another issue I thought I might as well solve while I was at it, was that it's rare I actually want to watch every video from a given sub. This would often lead to a lot of deleting videos in Jellyfin I wasn't going to watch, meaning I spent all that time and bandwidth downloading them for no reason. The manual review process of going through my YouTube subscriptions in my feed reader would alleviate this completely.

4. Getting an OPML of my YouTube subscriptions

Getting an individual RSS feed from a YouTube channel was as simple for me as installing a browser addon to sniff out feeds form a given page (https://github.com/aureliendavid/rsspreview), and then navigating to a channel (occasionally having to refresh the page a couple times).

However, wanting this RSS workflow to stick this time, I wanted a solution to get all of my subscriptions into RSS.

Enter OPML.

Both methods involve navigating to https://www.youtube.com/feed/channels, scrolling down the bottom to make sure everything has loaded, then pasting a script into the browser dev console.

4.1. Attempt 1

First, I tried the method described in https://dhariri.com/blog/youtube-sub-download/.

This worked - and worked fast - but didn't have the feeds titled, which lead to an awkward import with elfeed-org. This might be more than enough for other readers, however.

4.2. Attempt 2

Next, I tried the method described in https://github.com/jeb5/YouTube-Subscriptions-RSS.

This ran SLOW, with a cute little progress dialog on screen. This filled me with more hope, and I was right to be hopeful! At the end, I got a nicely formatted OPML complete with subscriptions.

5. Importing OPML into elfeed-org

From here, I was able to run elfeed-org-import-opml on the generated OPML file, and add that to my feed tree.

A little bit of manual tagging later, I was done!

6. elfeed review 'n' queue workflow

Now, with all of my YouTube subscriptions in elfeed, the only step left was to set up my ideal "review 'n' queue" workflow.

This ended up being extremely simple. With a small elisp function bound to an easy-to-reach key in elfeed-search-mode-map, I can quickly alternate between marking read to skip or adding to a download queue.

(defun my/elfeed-queue-yt-dl ()
  "Add yt-dlp of link of item at point to task queue."
  (interactive)
  (shell-command (concat "ts yt-dlp -P ~/server/raid/archive/media/vid/yt "
                       (shell-quote-argument (elfeed-entry-link (elfeed-search-selected t)))))
  (elfeed-search-untag-all-unread))

The important part here is ts, as this adds the command to a task spooler queue (ts may be tsp in your distribution). This allows me to rapid fire go through my subscriptions, avoiding the awkward step of filtering out the ones I want to skip, then adding a big yt-dlp call to async-shell-command with all of the URLs. You could do this if you wanted, though.

7. Future steps

For now, I'm happy with this new workflow. I do have the following ideas of things to improve, however:

  1. Writing a yt-dlp wrapper script to write the video's description and URL to Jellyfin metadata, like ytdl-sub did.
  2. A way to quickly add new RSS feeds, probably using org-capture.