{"id":50945909,"url":"https://github.com/smark91/limbo","last_synced_at":"2026-06-17T20:06:03.222Z","repository":{"id":361212682,"uuid":"1248845827","full_name":"smark91/limbo","owner":"smark91","description":"Limbo — a Go‑based Docker service that tracks Seerr‑approved media requests, auto‑updates their status, and sends Discord notifications, with a sleek glass‑morphic PWA UI.","archived":false,"fork":false,"pushed_at":"2026-06-14T12:23:10.000Z","size":4760,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T16:16:45.337Z","etag":null,"topics":["docker","go","media-request","radarr","seerr","sonarr","tailwindcss"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smark91.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-25T05:28:07.000Z","updated_at":"2026-06-14T12:23:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/smark91/limbo","commit_stats":null,"previous_names":["smark91/limbo"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/smark91/limbo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smark91%2Flimbo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smark91%2Flimbo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smark91%2Flimbo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smark91%2Flimbo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smark91","download_url":"https://codeload.github.com/smark91/limbo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smark91%2Flimbo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34463563,"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-17T02:00:05.408Z","response_time":127,"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":["docker","go","media-request","radarr","seerr","sonarr","tailwindcss"],"created_at":"2026-06-17T20:06:02.552Z","updated_at":"2026-06-17T20:06:03.213Z","avatar_url":"https://github.com/smark91.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"frontend/assets/logo.svg\" alt=\"Limbo Logo\" width=\"64\" height=\"64\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e\u003cfont size=\"7\"\u003eLimbo\u003c/font\u003e\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eA lightweight, self-hosted Go dashboard and background notifier that tracks approved but unfulfilled requests from Seerr.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#-features\"\u003eFeatures\u003c/a\u003e \u0026bull;\n  \u003ca href=\"#-tech-stack\"\u003eTech Stack\u003c/a\u003e \u0026bull;\n  \u003ca href=\"#️-configuration\"\u003eConfiguration\u003c/a\u003e \u0026bull;\n  \u003ca href=\"#-quick-start\"\u003eQuick Start\u003c/a\u003e \u0026bull;\n  \u003ca href=\"#-testing\"\u003eTesting\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\nLimbo is a lightweight, self-hosted Go dashboard and background notifier that tracks approved but unfulfilled requests from **Seerr** (Overseerr/Jellyseerr). It features a beautiful, responsive, glassmorphic Single-Page Application (SPA) web UI to browse and triage requests, while handling release date evaluation and Discord notifications.\n\n\u003e [!NOTE]\n\u003e This project was built with significant AI assistance (Google Gemini). All feature decisions, architecture choices, and code reviews were made by the author — the AI acted as a pair programmer, not an autonomous agent.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".github/screenshots/dashboard-dark.png\" alt=\"Limbo Dashboard Dark Mode\" width=\"800\"\u003e\n\u003c/p\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e📸 View Light Mode \u0026 Maintenance Screens\u003c/summary\u003e\n  \u003cbr\u003e\n  \u003cp align=\"center\"\u003e\n    \u003cstrong\u003eLight Mode Dashboard\u003c/strong\u003e\u003cbr\u003e\u003cbr\u003e\n    \u003cimg src=\".github/screenshots/dashboard-light.png\" alt=\"Limbo Dashboard Light Mode\" width=\"800\"\u003e\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003cstrong\u003eMaintenance Operations\u003c/strong\u003e\u003cbr\u003e\u003cbr\u003e\n    \u003cimg src=\".github/screenshots/maintenance.png\" alt=\"Limbo Triage \u0026 Maintenance Details\" width=\"800\"\u003e\n  \u003c/p\u003e\n\u003c/details\u003e\n\n---\n\n## ✨ Features\n\n- **Automated Sync \u0026 State Machine**: Periodically checks Seerr for approved requests, transitioning entries through statuses.\n- **Smart Release Evaluation**:\n  - **Movies**: Evaluates release dates using priority: `Digital \u003e Physical \u003e Theatrical` based on country codes.\n  - **TV Shows**: Parses show status and tracks individual season air dates.\n- **Manual State Overrides \u0026 Reasons**: Manage and override request statuses (e.g., parking a request as `UNAVAILABLE` or reverting to `PENDING`) and add administrator cancellation/unavailable reasons.\n- **Maintenance \u0026 Cache Operations**: Purge stale requests older than a specific threshold (clearing them from both Limbo and Seerr), refresh the TMDB poster and release date cache, and trigger test Discord notifications.\n- **Discord Notifications**: Sends rich webhook embeds within a configurable release window.\n- **Premium User Experience**: Designed using a modern glassmorphic dark theme, featuring subtle micro-animations, poster image loading, status badges, and full mobile responsiveness (PWA-ready).\n- **Ultra-lightweight**: Written in Go with standard routing (`chi`), `gorm` (SQLite/PostgreSQL support), and embedded frontend assets—resulting in a tiny, performant Docker container (~15MB).\n\n---\n\n## 📂 Tech Stack\n\n- **Backend**: Go 1.26.3, Chi Router, GORM\n- **Database**: SQLite (default, WAL mode optimized) or PostgreSQL\n- **Frontend**: Vanilla JS (SPA), Vanilla CSS (Glassmorphism \u0026 animations)\n- **Asset Delivery**: HTML, JS, CSS embedded directly into the Go executable via `//go:embed`\n- **Containerization**: Multi-stage CGO Alpine Dockerfile (local development) and lightweight runtime release Dockerfile (packaging static host-compiled binaries for CI/CD)\n\n---\n\n## ⚙️ Configuration\n\nAll settings are configured using environment variables:\n\n| Environment Variable | Description | Default | Required |\n|----------------------|-------------|---------|----------|\n| `DB_DRIVER` | Database engine (`sqlite` or `postgres`) | `sqlite` | No |\n| `POSTGRES_URL` | PostgreSQL connection URL (e.g. `postgresql://user:pass@host:5432/db`) | None | Yes (only if `DB_DRIVER` is `postgres`) |\n| `SQLITE_PATH` | SQLite database file path | `/data/limbo.db` | No |\n| `SEERR_URL` | Internal Seerr API address | `http://localhost:5055` | No |\n| `SEERR_PUBLIC_URL` | User-facing Seerr external address | `http://localhost:5055` | No |\n| `SEERR_API_KEY` | Authenticated Seerr API key | None | **Yes** |\n| `DISCORD_WEBHOOK_URL`| Destination webhook for release embeds | None | No |\n| `RELEASE_COUNTRY` | 2-letter ISO country code for release priority | `US` | No |\n| `SCAN_INTERVAL_MINUTES` | Frequency of background Seerr sync scans | `10` | No |\n| `ALERT_DELAY_MINUTES` | Minimum request age (in minutes) before Discord notification (gives automation time to download first) | `10` | No |\n| `ALERT_MAX_AGE_MINUTES` | Maximum request age (in minutes) to qualify for notifications (prevents spamming old requests) | `1440` | No |\n| `LIMBO_PORT` | Port for the HTTP web server | `3000` | No |\n| `LOG_LEVEL` | Log verbosity (`debug`, `info`, `warn`, `error`) | `info` | No |\n\n### 🔒 Secrets \u0026 `_FILE` Environment Variables\n\nFor sensitive configuration fields, you can append `_FILE` to the variable name to load its value from a file (e.g. Docker Secrets or Kubernetes secrets).\nSupported variables:\n- `POSTGRES_URL_FILE` (defaults to `/run/secrets/postgres_url`)\n- `SEERR_API_KEY_FILE` (defaults to `/run/secrets/seerr_api_key`)\n- `DISCORD_WEBHOOK_URL_FILE` (defaults to `/run/secrets/discord_webhook_url`)\n\n**Note**: Either the direct variable or the `_FILE` variable must be used. If both are set simultaneously, the application will fail validation on startup. If neither is set, the application automatically attempts to load the default `/run/secrets/...` file path.\n\n---\n\n## 🚀 Quick Start\n\n### 1. Docker Compose (Recommended)\n\nAdd Limbo to your `docker-compose.yaml` stack:\n\n```yaml\nservices:\n  limbo:\n    image: ghcr.io/smark91/limbo:latest\n    container_name: limbo\n    restart: unless-stopped\n    volumes:\n      - ./config:/data\n    ports:\n      - \"${LIMBO_PORT:-3000}:${LIMBO_PORT:-3000}\"\n    env_file:\n      - .env\n    # BELOW CONFIG ONLY IF USING FILE SECRETS\n    secrets:\n      - seerr_api_key\n      - postgres_url\n      - discord_webhook_url\n\nsecrets:\n  seerr_api_key:\n    file: ./secrets/seerr_api_key\n  postgres_url:\n    file: ./secrets/postgres_url\n  discord_webhook_url:\n    file: ./secrets/discord_webhook_url\n```\n\n\u003e [!WARNING]\n\u003e If you change the internal `LIMBO_PORT` (for example, to `8080`), the container's internal service port changes. In this case, you must also update the `HEALTHCHECK` port defined in the `Dockerfile` (or override it in `docker-compose.yaml`) to match the new port so the health check endpoint remains reachable:\n\u003e \n\u003e ```yaml\n\u003e     healthcheck:\n\u003e       test: wget -qO- \"http://127.0.0.1:${LIMBO_PORT:-3000}/api/health\" | grep '\"status\":\"ok\"' || exit 1\n\u003e       interval: 30s\n\u003e       timeout: 10s\n\u003e       retries: 3\n\u003e ```\n\nCopy the example environment file to create your own configuration:\n\n```bash\ncp .env.example .env\n```\n\nEdit `.env` as needed to set your values.\n\nRun the container:\n```bash\ndocker compose up -d\n```\n\n### 2. Local Development\n\nEnsure Go 1.26+ is installed:\n\n\n```bash\n# Clone and enter the app directory\ncd app\n\n# Copy environment example\ncp .env.example .env\n\n# Run the app\ngo run main.go\n```\n\nThe server will start on `http://localhost:3000`.\n\n---\n\n## 🧪 Testing\n\nTo run the automated test suite within a clean Docker environment:\n\n```bash\ndocker build --target tester .\n```\n\n---\n\n## 📄 License\n\nThis project is licensed under the GNU Affero General Public License v3 - see the `LICENSE` file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmark91%2Flimbo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmark91%2Flimbo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmark91%2Flimbo/lists"}