{"id":47636285,"url":"https://github.com/jakejarvis/sofa","last_synced_at":"2026-04-02T00:09:17.781Z","repository":{"id":341883903,"uuid":"1170069482","full_name":"jakejarvis/sofa","owner":"jakejarvis","description":"🍿 Self-hosted movie and TV show scrobbler for web, iOS, and Android","archived":false,"fork":false,"pushed_at":"2026-03-25T01:03:08.000Z","size":7119,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-25T16:39:52.820Z","etag":null,"topics":["better-auth","bun","crowdin","docker","drizzle-orm","expo","homelab","hono","jellyfin","media","movies","plex","react","react-native","self-hosted","tanstack-router","tmdb","tv","typescript","watchlist"],"latest_commit_sha":null,"homepage":"https://sofa.watch","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jakejarvis.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":null,"dco":null,"cla":null}},"created_at":"2026-03-01T16:51:41.000Z","updated_at":"2026-03-25T01:34:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jakejarvis/sofa","commit_stats":null,"previous_names":["jakejarvis/sofa"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/jakejarvis/sofa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakejarvis%2Fsofa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakejarvis%2Fsofa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakejarvis%2Fsofa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakejarvis%2Fsofa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jakejarvis","download_url":"https://codeload.github.com/jakejarvis/sofa/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakejarvis%2Fsofa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31293284,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["better-auth","bun","crowdin","docker","drizzle-orm","expo","homelab","hono","jellyfin","media","movies","plex","react","react-native","self-hosted","tanstack-router","tmdb","tv","typescript","watchlist"],"created_at":"2026-04-02T00:09:17.057Z","updated_at":"2026-04-02T00:09:17.762Z","avatar_url":"https://github.com/jakejarvis.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://sofa.watch\"\u003e\u003cimg width=\"72\" height=\"72\" alt=\"Sofa\" src=\"https://sofa.watch/icon.svg\" /\u003e\u003c/a\u003e\u003cbr /\u003e\n  \u003ca href=\"https://sofa.watch\"\u003e\u003cstrong\u003eSofa\u003c/strong\u003e\u003c/a\u003e — Self-hosted movie \u0026 TV tracker\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg alt=\"GitHub License\" src=\"https://img.shields.io/github/license/jakejarvis/sofa\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/jakejarvis/sofa/actions/workflows/docker.yml\"\u003e\u003cimg alt=\"GitHub Actions Workflow Status\" src=\"https://img.shields.io/github/actions/workflow/status/jakejarvis/sofa/docker.yml\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/jakejarvis/sofa/releases/latest\"\u003e\u003cimg alt=\"GitHub Release\" src=\"https://img.shields.io/github/v/release/jakejarvis/sofa\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/jakejarvis/sofa\"\u003e\u003cimg alt=\"GitHub top language\" src=\"https://img.shields.io/github/languages/top/jakejarvis/sofa\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/jakejarvis/sofa\"\u003e\u003cimg alt=\"Codecov\" src=\"https://img.shields.io/codecov/c/github/jakejarvis/sofa?token=KJIUQAG94F\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://crowdin.com/project/sofa\"\u003e\u003cimg alt=\"Crowdin\" src=\"https://badges.crowdin.net/sofa/localized.svg\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://apps.apple.com/us/app/sofa-tv-movie-tracker/id6760432427\"\u003e\u003cimg alt=\"App Store\" src=\"https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg\" height=\"40\" width=\"120\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://play.google.com/store/apps/details?id=com.jakejarvis.sofa\"\u003e\u003cimg alt=\"GetItOnGooglePlay_Badge_Web_color_English\" src=\"https://github.com/user-attachments/assets/f04efab4-a129-4392-be95-90c97372231f\" height=\"40\" width=\"135\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n[Sofa](https://sofa.watch) is a self-hosted movie and TV tracker for nerds. Track what you've watched, discover what's next, and plug your data into your existing home media stack. All without anything leaving your homelab. 🍿\n\n![Title page screenshot](screenshot.png)\n\n## What it does\n\n- Track episode-level progress for TV series and pick shows back up from a dedicated \"Continue Watching\" view\n- Mark movies as watched to discover more like them\n- Rate titles, browse cast and crew, and get recommendations based on what you are already tracking\n- Search TMDB and explore trending movies and shows without leaving your own instance\n- Show streaming availability from TMDB's US provider data\n- Automatically log completed watches from Plex, Jellyfin, or Emby webhooks\n- Import existing watch history, ratings, and watchlists from Trakt, Simkl, or Letterboxd\n- Expose your watchlist as import lists for Sonarr and Radarr\n- Runs on SQLite with local image caching, built-in backups, and no external database requirement\n- Supports local accounts or OIDC SSO for private instances\n\n\u003e [!NOTE]\n\u003e Sofa is extremely US-centric right now, in terms of streaming providers, content rating systems, etc. Contributions to address this are more than welcome!\n\n## Quick start\n\n### Self-hosted\n\nA minimal [`docker-compose.yml`](./docker-compose.yml) is provided in this repo. For most setups, the shortest path is:\n\n1. Copy the example environment file:\n\n```bash\ncp .env.example .env\n```\n\n2. Fill in the required values:\n\n```env\nTMDB_API_READ_ACCESS_TOKEN=your_tmdb_read_access_token\nBETTER_AUTH_SECRET=generate_a_long_random_secret\nBETTER_AUTH_URL=http://localhost:3000\n```\n\n3. Start the container:\n\n```bash\ndocker compose up -d\n```\n\n4. Open `http://localhost:3000` and create the first account. The first account becomes the admin automatically, and registration closes after that by default.\n\n\u003e The included Compose file uses `ghcr.io/jakejarvis/sofa:edge`. If you prefer to pin releases, switch to a published version tag like `ghcr.io/jakejarvis/sofa:\u003cversion\u003e` or use the matching `jakejarvis/sofa:\u003cversion\u003e` image on Docker Hub. Multi-arch images are published for `linux/amd64` and `linux/arm64`.\n\n### Cloud\n\nIf you prefer to deploy Sofa to the cloud, there are several great options. All you'll need is the ability to run Docker containers and mount some form of persistent storage volume to `/data` within the container.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://railway.com/deploy/sofa\"\u003e\u003cimg alt=\"Deploy on Railway\" src=\"https://railway.com/button.svg\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Required setup\n\n### TMDB\n\nSofa uses [TMDB](https://www.themoviedb.org/) for metadata, posters, cast, recommendations, and streaming availability. You need a TMDB API Read Access Token before the app can do anything useful.\n\nCreate one here:\n\n- [TMDB signup](https://www.themoviedb.org/signup)\n- [API settings](https://www.themoviedb.org/settings/api)\n\n\u003e [!TIP]\n\u003e We want the **API Read Access Token**, not the shorter API key.\n\n### Auth secret\n\n`BETTER_AUTH_SECRET` should be a long random string. To generate one:\n\n```bash\nnpx @better-auth/cli@latest secret\n# or\nopenssl rand -base64 32\n```\n\n### Public URL\n\nSet `BETTER_AUTH_URL` to the real external URL of your instance. This especially matters for login flows and OIDC callbacks behind a reverse proxy (like nginx or Traefik).\n\n## Configuration\n\n| Variable                     | Required | Notes                                                                                           |\n| ---------------------------- | -------- | ----------------------------------------------------------------------------------------------- |\n| `TMDB_API_READ_ACCESS_TOKEN` | Yes      | TMDB metadata and discovery                                                                     |\n| `BETTER_AUTH_SECRET`         | Yes      | Session and auth secret                                                                         |\n| `BETTER_AUTH_URL`            | Yes      | Public base URL of the app                                                                      |\n| `DATA_DIR`                   | No       | Root data directory. Defaults to `/data` in the container                                       |\n| `IMAGE_CACHE_ENABLED`        | No       | Defaults to enabled. Set to `false` to use TMDB images directly instead of caching them locally |\n| `LOG_LEVEL`                  | No       | `error`, `warn`, `info`, or `debug`                                                             |\n| `OIDC_CLIENT_ID`             | No       | Enable OIDC when set with the matching secret and issuer                                        |\n| `OIDC_CLIENT_SECRET`         | No       | OIDC client secret                                                                              |\n| `OIDC_ISSUER_URL`            | No       | OIDC issuer URL                                                                                 |\n| `OIDC_PROVIDER_NAME`         | No       | Login button label. Defaults to `SSO`                                                           |\n| `OIDC_AUTO_REGISTER`         | No       | Defaults to `true`                                                                              |\n| `DISABLE_PASSWORD_LOGIN`     | No       | Set to `true` to hide email/password login when OIDC is configured                              |\n\nSee [`.env.example`](./.env.example) for the full list.\n\n## Integrations\n\nSofa ships with two kinds of integrations (for now): incoming watch activity and outgoing import lists.\n\n### Incoming watch activity\n\n- Plex: logs completed watches through a webhook URL generated in Sofa. Requires an active [Plex Pass](https://www.plex.tv/plex-pass/) license.\n- Jellyfin: works through the Jellyfin Webhook plugin.\n- Emby: logs completed watches through webhooks. Requires Emby Server 4.7.9+ and an [Emby Premiere](https://emby.media/premiere.html) subscription.\n\nThese integrations are user-specific, so each user can connect their own media server account and watch history.\n\n### Outgoing import lists\n\n- Sonarr: expose your Sofa TV watchlist as a custom import list\n- Radarr: expose your Sofa movie watchlist as a custom import list\n\n## Development\n\nFor local development:\n\n```bash\nbun install\ncp .env.example .env\nbun run dev\n```\n\nUseful commands:\n\n- `bun run test`\n- `bun run lint`\n- `bun run format`\n- `bun run check-types`\n- `cd packages/db \u0026\u0026 bun run db:generate`\n- `cd packages/db \u0026\u0026 bun run db:migrate`\n\n## TMDB notice\n\nThis product uses the TMDB API but is not endorsed or certified by TMDB.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjakejarvis%2Fsofa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjakejarvis%2Fsofa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjakejarvis%2Fsofa/lists"}