1
0
Fork
You've already forked sub2pod
0
Turns a ytdl-sub output directory into a valid, servable podcast RSS feed.
  • Python 97.3%
  • Just 2.7%
2026年07月10日 10:30:02 +10:00
.forgejo/workflows 👷 add weekly checks workflow on Codeberg shared runner 2026年07月10日 08:45:11 +10:00
docs 📝 set up MkDocs docs deployment to grebedoc 2026年07月10日 08:49:36 +10:00
src/sub2pod feat: print program name and version on startup 2026年06月19日 17:13:15 +10:00
tests feat: print program name and version on startup 2026年06月19日 17:13:15 +10:00
.gitignore 🙈 added site folder to gitignore 2026年07月10日 09:35:27 +10:00
.gitleaks.toml 👷 migrate CI from Woodpecker to Forgejo Actions 2026年07月10日 08:42:29 +10:00
.pre-commit-config.yaml ⬆️ bump deps 2026年07月10日 08:40:17 +10:00
.python-version 🐛 parse <description> and <upload_date> from ytdl-sub episode NFOs 2026年06月18日 12:38:53 +10:00
CHANGELOG.md 📝 docs: update changelog for 0.3.1 2026年07月10日 09:49:42 +10:00
CLAUDE.md 📝 update CLAUDE.md with gitmoji note, release process, and release notes 2026年07月10日 08:55:37 +10:00
concept.md Initial commit with concept 2026年06月17日 09:52:09 +10:00
docs_hooks.py 📝 set up MkDocs docs deployment to grebedoc 2026年07月10日 08:49:36 +10:00
improvements.md 📝 document potential future improvments 2026年07月10日 10:29:52 +10:00
justfile ♻️ replace git-cliff with Release-Notes.md-based changelog generation 2026年07月10日 08:53:01 +10:00
mkdocs.yml 📝 set up MkDocs docs deployment to grebedoc 2026年07月10日 08:49:36 +10:00
noxfile.py 🔧 bootstrap: add pyproject.toml, noxfile.py, cliff.toml, uv venv 2026年06月17日 10:22:48 +10:00
pylock.toml ♻️ replace git-cliff with Release-Notes.md-based changelog generation 2026年07月10日 08:53:01 +10:00
pyproject.toml 📝 document potential future improvments 2026年07月10日 10:29:52 +10:00
README.md 📝 replace stale Woodpecker CI badge with Forgejo Actions badge 2026年07月10日 09:00:59 +10:00
Release-Notes.md 📝 reset Release-Notes.md for next release 2026年07月10日 10:30:02 +10:00
Release-Notes.md.template 🔍 change tags for release notes 2026年07月10日 09:27:13 +10:00
uv.lock 🔧 bump: version 0.3.0 → 0.3.1 2026年07月10日 09:49:44 +10:00

sub2pod

Licence: AGPL-3.0-or-later Python 3.12+ CI Codestyle: Ruff

Convert ytdl-sub output directories into standards-compliant podcast RSS feeds. Point it at a directory full of downloaded audio, and it writes feed.xml into each channel subdirectory — ready to serve or submit to podcast directories.

What it does

  • Reads Kodi tvshow.nfo and per-episode .nfo sidecars produced by ytdl-sub
  • Discovers date-prefixed audio files (YYYY-MM-DD - <title>.<ext>) in each channel directory
  • Generates RSS 2.0 + iTunes namespace feed.xml per channel
  • Emits correct MIME types for .opus, .mp3, and .m4a enclosures
  • Produces an opml.xml index at the root level for one-click feed import
  • Falls back to filename parsing when .nfo sidecars are absent

What it does not do

  • No download or subscription management (that's ytdl-sub's job)
  • No web server — feed files are static XML; serve them however you like
  • No podcast client or player

Installation

From PyPI

pip install sub2pod

From source

git clone https://codeberg.org/marvin8/sub2pod.git
cd sub2pod
uv sync
uv run sub2pod --help

Usage

sub2pod /path/to/ytdl-sub/output https://podcast.example.com

This walks the parent directory looking for subdirectories containing tvshow.nfo and generates:

Output Location Description
feed.xml Each channel subdirectory RSS 2.0 + iTunes podcast feed
opml.xml Parent directory root OPML index of all feeds

Options

--dry-run Print paths without writing any files
--verbose Log per-episode details during generation

Example

# After ytdl-sub downloads new episodes:
sub2pod /home/NAS/ytdl-sub/mark/podcast https://podcasts.example.com
# Preview without writing:
sub2pod /home/NAS/ytdl-sub/mark/podcast https://podcasts.example.com --dry-run
# See what's being generated:
sub2pod /home/NAS/ytdl-sub/mark/podcast https://podcasts.example.com --verbose

How it works

  1. Channel discovery — Walks the parent directory for subdirectories containing tvshow.nfo
  2. Metadata parsing — Reads channel title and genre from tvshow.nfo; reads per-episode title, description, date, runtime, and source URL from .nfo sidecars
  3. Episode discovery — Finds all date-prefixed audio files, pairs them with their .nfo sidecars, sorts newest-first
  4. Feed generation — Builds RSS 2.0 XML with iTunes podcast namespace elements (<itunes:image>, <itunes:duration>, <itunes:category>), writes feed.xml
  5. OPML index — Writes opml.xml at the root listing every channel feed

Input format

Each channel directory is expected to contain:

Links with Friends/
├── tvshow.nfo ← Channel metadata (title, genre)
├── poster.jpg ← Podcast artwork → <itunes:image>
├── 2026年05月19日 - Episode Title.opus ← Audio file
├── 2026年05月19日 - Episode Title.nfo ← Episode metadata sidecar
└── 2026年05月19日 - Episode Title-thumb.jpg ← Episode thumbnail

Documentation

  • ytdl-sub Integration Guide — Configuring ytdl-sub to produce sub2pod-compatible output: NFO tags, episode thumbnails, trigger strategies, and Opus MIME type guidance.

Licence

Copyright (C) 2026 Marvin8

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.