{"id":51079061,"url":"https://github.com/maxgfr/feedreel","last_synced_at":"2026-06-23T16:33:08.571Z","repository":{"id":362965781,"uuid":"1261266520","full_name":"maxgfr/feedreel","owner":"maxgfr","description":"Local-first generator of daily short videos (Remotion). Auto per-platform captions/hashtags + opt-in publishing to YouTube Shorts, TikTok \u0026 Instagram Reels with automatic token refresh. Multilingual.","archived":false,"fork":false,"pushed_at":"2026-06-06T18:11:44.000Z","size":3521,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-06T20:08:49.441Z","etag":null,"topics":["ai","automation","content-automation","ffmpeg","instagram-reels","local-first","remotion","rss","short-form-video","social-media","tiktok","typescript","video-generation","youtube-shorts"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxgfr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-06T13:09:56.000Z","updated_at":"2026-06-06T18:11:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/maxgfr/feedreel","commit_stats":null,"previous_names":["maxgfr/feedreel"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/maxgfr/feedreel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Ffeedreel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Ffeedreel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Ffeedreel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Ffeedreel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxgfr","download_url":"https://codeload.github.com/maxgfr/feedreel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Ffeedreel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34698696,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","automation","content-automation","ffmpeg","instagram-reels","local-first","remotion","rss","short-form-video","social-media","tiktok","typescript","video-generation","youtube-shorts"],"created_at":"2026-06-23T16:33:08.149Z","updated_at":"2026-06-23T16:33:08.566Z","avatar_url":"https://github.com/maxgfr.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FeedReel\n\n**Local-first generator of one daily vertical short video from RSS feeds.**\nFeedReel turns RSS feeds into a single 1080×1920 vertical video (YouTube Shorts /\nTikTok / Instagram Reels format), music only, with an auto \"subscribe\" outro — and\na ready-to-paste **title + description + hashtags** you post manually.\n\nEverything runs locally. The pipeline pulls your RSS feeds, deduplicates against\npast videos, and renders a fully code-generated video with\n[Remotion](https://www.remotion.dev/). The editorial work (selecting items,\nwriting the script/title/description) is done by the bundled **Claude Code skill**.\n\n|  |  |\n|---|---|\n| Output | one `output/\u003cdate\u003e.mp4` (1080×1920 @ 30 fps, H.264/AAC) + `output/\u003cdate\u003e.txt` |\n| Rendering | [Remotion](https://www.remotion.dev/) (React/TSX), no external images |\n| Audio | CC0 background music ([SoundSafari/CC0-1.0-Music](https://github.com/SoundSafari/CC0-1.0-Music)), fixed scene durations |\n| Script \u0026 caption | written by the **`feedreel`** Claude Code skill |\n| Publishing | none — you post the MP4 manually using the generated caption |\n\n## How it works\n\n```\nfeedreel prepare  → fetch RSS + dedup (SQLite) → cache/items/\u003cdate\u003e.json   (local, deterministic)\n   ↓  (the \"feedreel\" skill reads the items and writes the script)\ncache/scripts/\u003cdate\u003e.json   { date, title, description, hashtags, segments[intro,item…] }\n   ↓\nfeedreel render   → music + Remotion → output/\u003cdate\u003e.mp4\n                                     → output/\u003cdate\u003e.txt  (title + description + hashtags + sources)\n                                     + prints the caption to the terminal\n```\n\nThe closing \"subscribe\" scene is appended automatically — you don't write it.\n\n## Requirements\n\n- **macOS / Apple Silicon.**\n- **Node.js \u003e= 20** and **pnpm**.\n- **ffmpeg / ffprobe** on the `PATH` (music trim + mux).\n- **Claude Code** (to run the bundled skill).\n\n## Installation\n\n```bash\npnpm setup\n```\n\n`scripts/setup.sh` is **idempotent**: it checks Node \u003e= 20, installs dependencies,\ndownloads the CC0 music tracks, vendors the OFL fonts, prepares the Remotion\nheadless browser, creates the working directories, and creates\n`config/feedreel.yaml` from the example template if missing.\n\n## Configuration (private)\n\nYour feeds live in **`config/feedreel.yaml`**, which is **gitignored** (your RSS\nfeeds stay private). Start from the committed template:\n\n```bash\ncp config/feedreel.example.yaml config/feedreel.yaml   # then edit your feeds\n```\n\nThe config describes a single video: format, language identity, editorial\nidentity (`label`, `emoji`, `accentColor`, `maxItems`, `subscribeText`), the\n`feeds` list, the background `music`, and the `scene` durations\n(`introSec` / `itemSec` / `outroSec`).\n\nKeep alternate feed sets in their own gitignored files and switch with\n`FEEDREEL_CONFIG`, e.g. `FEEDREEL_CONFIG=config/feedreel.tech.yaml pnpm feedreel prepare`.\n\n## Usage\n\nJust tell Claude Code **\"generate me the video\"** (or _\"génère moi la vidéo\"_). The\n**`feedreel`** skill drives the whole flow locally: prepare → write the script →\nrender → report the MP4 and the copy-paste caption. Nothing leaves your machine\nexcept fetching the RSS feeds.\n\nUnder the hood it runs two commands (both accept `--date YYYY-MM-DD`, default today):\n\n```bash\n# 1) Fetch + dedup today's items → cache/items/\u003cdate\u003e.json\npnpm feedreel prepare\n\n# 2) The skill reads the items and writes cache/scripts/\u003cdate\u003e.json\n\n# 3) Build the video + caption → output/\u003cdate\u003e.mp4 + output/\u003cdate\u003e.txt\npnpm feedreel render\n```\n\nDeduplication is persisted in SQLite (`feedreel.db`): items are marked seen only\nafter a successful `render`, so a second run on the same day won't repeat the same\nnews, while re-running `prepare` before rendering is safe.\n\n## Configuration (environment variables)\n\nAll have defaults (see `config/index.ts`). Relative paths resolve from the project root.\n\n| Variable | Default | Role |\n|---|---|---|\n| `FEEDREEL_CONFIG` | `config/feedreel.yaml` | Active config file |\n| `FEEDREEL_OUTPUT_DIR` | `output` | Rendered videos directory |\n| `FEEDREEL_CACHE_DIR` | `cache` | items / scripts / audio cache |\n| `FEEDREEL_DB_PATH` | `feedreel.db` | SQLite dedup database |\n| `FEEDREEL_MUSIC_TRACK` | (config) | Override the background track |\n| `FEEDREEL_FPS` / `FEEDREEL_WIDTH` / `FEEDREEL_HEIGHT` | `30` / `1080` / `1920` | Video format |\n| `FEEDREEL_FEED_TIMEOUT_MS` | `12000` | Per-feed RSS timeout (ms) |\n| `FEEDREEL_LOG_FILE` | — | If set, also logs to this file |\n\n## Project layout\n\n```\nfeedreel/\n  config/        feedreel.yaml (private) · feedreel.example.yaml · schema.ts · load.ts · index.ts\n  src/\n    types.ts · log.ts · exec.ts · util.ts · cli.ts\n    pipeline/    fetchRss · dedup · script · music · render · orchestrate\n    remotion/    FeedReelVideo.tsx · scenes/{Intro,Item,Outro} · components/* · theme · fonts\n  scripts/       setup.sh · vendor-*.mjs\n  .claude/skills/feedreel/   the skill that drives generation\n```\n\n## Licenses\n\n| Component | License |\n|---|---|\n| TypeScript, Node, `tsx`, `vitest`, `rss-parser`, `better-sqlite3`, `zod`, `commander` | MIT |\n| ffmpeg / ffprobe | LGPL |\n| Remotion | source-available (free for solo use; see Remotion's terms) |\n| Fonts **Unbounded**, **Hanken Grotesk**, **JetBrains Mono** | SIL Open Font License (OFL) |\n| Music | CC0 (SoundSafari/CC0-1.0-Music) |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxgfr%2Ffeedreel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxgfr%2Ffeedreel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxgfr%2Ffeedreel/lists"}