{"id":28664181,"url":"https://github.com/ericboehs/yt","last_synced_at":"2026-04-18T14:05:39.582Z","repository":{"id":298597326,"uuid":"1000468977","full_name":"ericboehs/yt","owner":"ericboehs","description":"Offline YouTube video viewer with metadata management and interactive   playback controls","archived":false,"fork":false,"pushed_at":"2025-09-19T17:11:35.000Z","size":198,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-12T03:55:38.958Z","etag":null,"topics":["iina","media-server","offline-video","ruby","self-hosted","sinatra","video-library","video-management","web-app","youtube"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/ericboehs.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":"2025-06-11T20:45:21.000Z","updated_at":"2025-09-19T17:11:38.000Z","dependencies_parsed_at":"2025-06-11T23:35:36.524Z","dependency_job_id":"a026839d-28d5-4827-8a18-174d195e27d3","html_url":"https://github.com/ericboehs/yt","commit_stats":null,"previous_names":["ericboehs/yt"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ericboehs/yt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fyt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fyt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fyt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fyt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ericboehs","download_url":"https://codeload.github.com/ericboehs/yt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fyt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31971500,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"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":["iina","media-server","offline-video","ruby","self-hosted","sinatra","video-library","video-management","web-app","youtube"],"created_at":"2025-06-13T12:12:21.447Z","updated_at":"2026-04-18T14:05:34.573Z","avatar_url":"https://github.com/ericboehs.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Offline YouTube Viewer\n\nA self-hosted web application for managing and viewing offline YouTube videos downloaded via Downie, featuring metadata processing, search/filtering, and seamless IINA integration.\n\n## Features\n\n- 🎬 **Offline Video Management** - Browse and play locally downloaded YouTube videos\n- 🔍 **Smart Search \u0026 Filtering** - Real-time search by title/author, filter by watch status\n- 🖼️ **Interactive Thumbnails** - Hover overlays with play icons and automatic thumbnail generation\n- ▶️ **IINA Integration** - Seamless video playback with bidirectional progress sync\n- 📊 **Progress Tracking** - Visual progress bars with real-time sync between web and IINA\n- 🔗 **YouTube Integration** - Mark videos as watched, sync timestamps, maintain algorithm tracking\n- 📱 **Responsive Design** - Clean, modern Netflix-style interface with full dark mode support\n- 🗂️ **Channel Management** - Automatic channel URL resolution and intelligent caching\n- 🎭 **Theater Mode** - Immersive fullscreen viewing with persistent preferences\n- 📝 **Rich Descriptions** - Collapsible video descriptions with proper formatting\n\n## Screenshots\n\nThe app provides a Netflix-style grid interface for browsing your offline video collection with thumbnails, progress indicators, and interactive controls.\n\n## Requirements\n\n- **Ruby** (any recent version)\n- **[IINA](https://iina.io/)** - Required for video playback\n- **[Downie](https://software.charliemonroe.net/downie/)** - For downloading YouTube videos with metadata\n- **ffprobe** (optional) - For improved video duration detection\n\n## Installation\n\n1. **Install IINA**:\n  ```bash\n  brew install --cask iina\n  ```\n\n2. **Clone and run**:\n  ```bash\n  git clone https://github.com/ericboehs/yt.git\n  cd yt\n  ./yt\n  ```\n\nThe app will automatically install required Ruby gems and start the web server at `http://localhost:7777` (or the port specified by the `PORT` environment variable).\n\n## Usage\n\n### Running as a Service (macOS)\n\nTo run the application automatically on startup using macOS Launch Agents:\n\n1. **Create a launch agent plist file** at `~/Library/LaunchAgents/com.ericboehs.yt.plist`:\n  ```xml\n  \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n  \u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n  \u003cplist version=\"1.0\"\u003e\n    \u003cdict\u003e\n      \u003ckey\u003eEnvironmentVariables\u003c/key\u003e\n      \u003cdict\u003e\n        \u003ckey\u003ePATH\u003c/key\u003e\n        \u003cstring\u003e/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\u003c/string\u003e\n        \u003ckey\u003ePORT\u003c/key\u003e\n        \u003cstring\u003e7777\u003c/string\u003e\n        \u003ckey\u003eRACK_ENV\u003c/key\u003e\n        \u003cstring\u003eproduction\u003c/string\u003e\n      \u003c/dict\u003e\n      \u003ckey\u003eKeepAlive\u003c/key\u003e\n      \u003ctrue/\u003e\n      \u003ckey\u003eLabel\u003c/key\u003e\n      \u003cstring\u003ecom.ericboehs.yt\u003c/string\u003e\n      \u003ckey\u003eProgramArguments\u003c/key\u003e\n      \u003carray\u003e\n        \u003cstring\u003eruby\u003c/string\u003e\n        \u003cstring\u003e/path/to/your/yt/script\u003c/string\u003e\n      \u003c/array\u003e\n      \u003ckey\u003eRunAtLoad\u003c/key\u003e\n      \u003ctrue/\u003e\n      \u003ckey\u003eStandardErrorPath\u003c/key\u003e\n      \u003cstring\u003e/Users/yourname/Library/Logs/com.ericboehs.yt/stdout.log\u003c/string\u003e\n      \u003ckey\u003eStandardOutPath\u003c/key\u003e\n      \u003cstring\u003e/Users/yourname/Library/Logs/com.ericboehs.yt/stdout.log\u003c/string\u003e\n      \u003ckey\u003eWorkingDirectory\u003c/key\u003e\n      \u003cstring\u003e/path/to/your/yt/directory\u003c/string\u003e\n    \u003c/dict\u003e\n  \u003c/plist\u003e\n  ```\n\n2. **Create the log directory**:\n  ```bash\n  mkdir -p ~/Library/Logs/com.ericboehs.yt\n  ```\n\n3. **Load the service**:\n  ```bash\n  launchctl load -w ~/Library/LaunchAgents/com.ericboehs.yt.plist\n  ```\n\n4. **Manage the service**:\n  ```bash\n  # Restart the service\n  launchctl unload ~/Library/LaunchAgents/com.ericboehs.yt.plist\n  launchctl load -w ~/Library/LaunchAgents/com.ericboehs.yt.plist\n   \n  # View logs\n  tail -f ~/Library/Logs/com.ericboehs.yt/stdout.log\n   \n  # Stop the service\n  launchctl unload ~/Library/LaunchAgents/com.ericboehs.yt.plist\n  ```\n\n**Important notes:**\n- Update the paths to match your system (replace `/path/to/your/` and `yourname` with actual paths)\n- Ensure your `PATH` includes the directory where Ruby is installed\n- The service will automatically restart if it crashes (`KeepAlive`)\n- Logs are written to the specified log file for debugging\n\n### Downloading Videos\n\n1. Use Downie to download YouTube videos to `~/Downloads/YouTube/`\n2. Ensure Downie is configured to save JSON metadata files\n3. The app will automatically process metadata and generate thumbnails\n\n### Video Management\n\n- **Play Videos**: Click thumbnails or use hover overlay play button to start videos\n- **Theater Mode**: Toggle fullscreen viewing with T key or theater button\n- **Progress Sync**: Seamless progress tracking between web player and IINA\n- **Mark as Watched**: Click the ✓ button (also opens YouTube at video end)\n- **Delete Videos**: Click the trash icon (opens YouTube at video end and deletes files)\n- **Search**: Real-time search from any page, with YouTube fallback suggestions\n- **Filter**: Sort by download/upload date, filter by watch status (unwatched/partial/watched)\n\n### Channel Management\n\nVisit `/channels` to manage cached channel URLs. The app automatically tries to resolve YouTube channel URLs and falls back to search URLs when needed.\n\n## Configuration\n\nThe app uses these default paths:\n- **Download Directory**: `~/Downloads/YouTube/`\n- **Cache File**: `~/Downloads/YouTube/channel_cache.json`\n- **Server**: `http://0.0.0.0:7777` (configurable via `PORT` env var)\n\n## Development\n\n### Running Tests\n\n```bash\nbin/yt-test\n```\n\n### Linting and Quality Checks\n\n```bash\nbin/ci\n```\n\nThis runs:\n- editorconfig-checker\n- rubocop (code style)\n- test suite with coverage\n- coverage reporting\n\n### Pre-commit Hooks\n\nThe repository includes pre-commit hooks that automatically run the CI pipeline:\n\n```bash\n# Hooks are automatically installed when you run the app\n# They run bin/ci before each commit\n```\n\n## Architecture\n\n- **Backend**: Ruby/Sinatra web application\n- **Frontend**: ERB templates with Tailwind CSS\n- **Video Processing**: Integration with IINA for playback, ffprobe for metadata\n- **File Management**: JSON metadata processing with automatic updates\n- **Caching**: Channel URL resolution with persistent caching\n\n## API Endpoints\n\n- `GET /` - Main video grid interface with search and filtering\n- `GET /video` - Individual video player view with theater mode\n- `GET /channels` - Channel management interface\n- `POST /sync-progress` - Bidirectional progress sync between web player and IINA\n- `POST /mark-watched` - Mark video as watched (with YouTube timestamp)\n- `DELETE /video` - Delete video and associated files\n- `GET /thumbnails/:file` - Serve thumbnail images\n- `GET /video-file/:file` - Serve video files for web playback\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Run `bin/ci` to ensure all checks pass\n5. Submit a pull request\n\n## License\n\nThis project is licensed under the [MIT License](https://opensource.org/licenses/MIT). Feel free to use, modify, and distribute as needed.\n\n## Acknowledgments\n\n- Built for use with [Downie](https://software.charliemonroe.net/downie/) by Charlie Monroe\n- Designed for [IINA](https://iina.io/) video player integration\n- Uses [Tailwind CSS](https://tailwindcss.com/) for styling\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericboehs%2Fyt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fericboehs%2Fyt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericboehs%2Fyt/lists"}