{"id":47277572,"url":"https://github.com/suitux/tagr","last_synced_at":"2026-04-12T13:29:58.270Z","repository":{"id":341173934,"uuid":"1161649036","full_name":"suitux/Tagr","owner":"suitux","description":"Self-hosted web app for browsing, playing, and editing    music file metadata. Features a three-panel UI to navigate       your library, listen to tracks, and write tag changes directly    back to audio files.                                                Built with Next.js, React, Prisma + SQLite, and                  node-taglib-sharp.","archived":false,"fork":false,"pushed_at":"2026-04-02T16:22:57.000Z","size":8318,"stargazers_count":59,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-04-03T02:45:30.325Z","etag":null,"topics":["audio","docker","headless","jellyfin","metadata-management","music","music-player","self-hosted","tag"],"latest_commit_sha":null,"homepage":"https://tagr-demo.fly.dev/","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/suitux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/funding.yml","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},"funding":{"buy_me_a_coffee":"suitux"}},"created_at":"2026-02-19T11:00:27.000Z","updated_at":"2026-04-02T22:00:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/suitux/Tagr","commit_stats":null,"previous_names":["suitux/tagr"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/suitux/Tagr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suitux%2FTagr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suitux%2FTagr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suitux%2FTagr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suitux%2FTagr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/suitux","download_url":"https://codeload.github.com/suitux/Tagr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suitux%2FTagr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31494177,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T17:22:55.647Z","status":"ssl_error","status_checked_at":"2026-04-06T17:22:54.741Z","response_time":112,"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":["audio","docker","headless","jellyfin","metadata-management","music","music-player","self-hosted","tag"],"created_at":"2026-03-15T19:49:26.615Z","updated_at":"2026-04-07T00:01:57.269Z","avatar_url":"https://github.com/suitux.png","language":"TypeScript","funding_links":["https://buymeacoffee.com/suitux"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/tagr-logo.webp\" alt=\"Tagr Logo\" width=\"120\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eTagr\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eA self-hosted music metadata editor with a modern, intuitive web UI.\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://buymeacoffee.com/suitux\"\u003e\u003cimg src=\"https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge\u0026logo=buy-me-a-coffee\u0026logoColor=black\" alt=\"Buy Me a Coffee\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://tagr-demo.fly.dev/\"\u003e\u003cstrong\u003eLive Demo\u003c/strong\u003e\u003c/a\u003e — login with \u003ccode\u003edemo\u003c/code\u003e / \u003ccode\u003edemo\u003c/code\u003e\u003cbr\u003e\n  \u003csub\u003eHosted on Fly.io with auto-stop to save costs. First load may take ~30s while the machine wakes up.\u003cbr\u003eDemo is read-only: you can browse, filter, scan, view song edit history, and play songs, but metadata editing is disabled.\u003c/sub\u003e\n\u003c/p\u003e\n\nTagr lets you browse, edit, and manage audio file tags from any browser — desktop or mobile. Just point it at your music folders, and get a clean three-panel interface for organizing your library — no desktop apps, no CLI wizardry.\n\n![Tagr Main Screen](docs/main-screen.png)\n\n---\n\n## Features\n\n### Metadata Editing\n\n- Edit **40+ metadata fields** inline — title, artist, album, year, genre, composer, BPM, lyrics, and more\n- **Custom metadata** — add, edit, and remove your own custom tags beyond the standard fields\n- **Album art** management — view, replace, and upload cover images directly\n- **Star ratings** (1–5) with a visual widget\n- Support for track/disc numbering, sort fields, catalog numbers, barcodes, and extended tags\n- Read-only display of audio properties (codec, bitrate, sample rate, channels, bits per sample)\n\n![Search and metadata editing](docs/basic-search.png)\n\n### Change History\n\n- **Full audit trail** of every metadata change with old and new values\n- **Revert** individual changes or bulk-select and undo multiple edits at once\n- Searchable history with shift+click and ctrl+click multi-selection\n- Per-song and per-folder history views\n\n![Song change history](docs/song-history.png)\n\n### Music Player\n\n- **Built-in audio player** with interactive waveform visualization (WaveSurfer.js)\n- Play/pause, previous/next track navigation\n- Click-to-seek on the waveform\n- Auto-advance to next song\n- Collapsible sidebar player with album art, title, and artist display\n\n\u003cp\u003e\n  \u003cimg src=\"docs/player-big.png\" alt=\"Player expanded\" height=\"400\" /\u003e\n  \u0026nbsp;\u0026nbsp;\n  \u003cimg src=\"docs/player-mini.png\" alt=\"Player mini\" /\u003e\n\u003c/p\u003e\n\n### Library Browsing\n\n- **Three-panel layout** — folder tree, song list, and detail editor side by side\n- **Folder tree** with hierarchical navigation and real-time search\n- **Sorting** on any column — title, artist, album, year, duration, bitrate, date added, and dozens more\n- **Advanced filtering** — text, numeric ranges, date ranges, and boolean filters across all fields\n- **Customizable columns** — show/hide any of 40+ columns to match your workflow\n- Virtual scrolling and infinite pagination for large libraries\n\n\u003cp\u003e\n  \u003cimg src=\"docs/rescan-history-context-menu.png\" alt=\"Folder tree with context menu\" height=\"350\" /\u003e\n  \u0026nbsp;\u0026nbsp;\n  \u003cimg src=\"docs/columns.png\" alt=\"Customizable columns\" height=\"350\" /\u003e\n\u003c/p\u003e\n\n### File Support\n\n| Format | Supported |\n|--------|-----------|\n| MP3    | Yes       |\n| FLAC   | Yes       |\n| WAV    | Yes       |\n| AAC    | Yes       |\n| OGG    | Yes       |\n| M4A    | Yes       |\n| WMA    | Yes       |\n| AIFF   | Yes       |\n| Opus   | Yes       |\n\nLossless formats are automatically detected and displayed with a badge.\n\n### Mobile Support\n\nTagr is fully responsive and works on phones and tablets. The mobile UI adapts to smaller screens with:\n\n- **Full-screen panels** with swipe gestures to navigate between folders, song list, and detail editor\n- **Expanded music player** with album art, waveform, and playback controls\n- **Touch-friendly editing** — all edit actions are always visible (no hover required)\n\n\u003cp\u003e\n  \u003cimg src=\"docs/mobile-list.png\" alt=\"Mobile song list\" height=\"400\" /\u003e\n  \u0026nbsp;\u0026nbsp;\n  \u003cimg src=\"docs/mobile-list-song.png\" alt=\"Mobile player expanded\" height=\"400\" /\u003e\n  \u0026nbsp;\u0026nbsp;\n  \u003cimg src=\"docs/mobile-song.png\" alt=\"Mobile song detail\" height=\"400\" /\u003e\n  \u0026nbsp;\u0026nbsp;\n  \u003cimg src=\"docs/mobile-musicbrainz-metadata-pick.png\" alt=\"Mobile MusicBrainz metadata comparison\" height=\"400\" /\u003e\n\u003c/p\u003e\n\n### Additional\n\n- **Single-user authentication** — password-protected access\n- **Resizable panels** — drag to resize the three-panel layout to your liking\n- **Dark theme** by default\n- **Toast notifications** for operation feedback\n- **URL-based state** — bookmarkable views with folder, song, sort, and filter state preserved in the URL\n\n![Rescan warning dialog](docs/scan%20warning.png)\n\n---\n\n## Quick Start with Docker\n\n### 1. Clone the repository\n\n```bash\nwget https://raw.githubusercontent.com/suitux/Tagr/main/docker-compose.yml\n```\n\n### 2. Generate a secret key\n\n```bash\nopenssl rand -hex 32\n```\n\nCopy the output — you'll use it as `AUTH_SECRET` in the next step.\n\n### 3. Configure `docker-compose.yml`\n\n```yaml\nservices:\n  tagr:\n    image: ghcr.io/suitux/tagr:latest\n    container_name: tagr\n    restart: unless-stopped\n    ports:\n      - \"3000:3000\"\n    environment:\n      - PUID=1000\n      - PGID=1000\n      - NODE_ENV=production\n      - DATABASE_URL=file:/data/tagr.db\n      - AUTH_SECRET=paste-your-generated-secret-here\n      - AUTH_USER=admin\n      - AUTH_PASSWORD=your-password-here\n      - AUTH_URL=https://your-domain.com\n    volumes:\n      - sqlite_data:/data\n      # Mount your music folder into the container:\n      - /path/to/your/music:/music\n\nvolumes:\n  sqlite_data:\n```\n\n\u003e **Multiple folders:** If your music is spread across different host paths, mount them as subdirectories under `/music`. Tagr scans `/music` recursively, so all subdirectories are included automatically:\n\u003e\n\u003e ```yaml\n\u003e volumes:\n\u003e   - /home/user/Music:/music/library\n\u003e   - /mnt/nas/Music:/music/nas\n\u003e ```\n\u003e\n\u003e Set `MUSIC_FOLDERS` only if you want to **restrict** scanning to specific subdirectories (e.g., scan `/music/library` but skip `/music/podcasts`).\n\n### 4. Build and run\n\n```bash\ndocker compose up -d\n```\n\n### 5. Open your browser\n\nNavigate to [http://localhost:3000](http://localhost:3000), log in with your credentials, and hit the **scan** button to index your library.\n\n---\n\n## Manual Installation\n\nRequirements: **Node.js 22+**.\n\n```bash\ngit clone https://github.com/suitux/Tagr.git\ncd tagr\npnpm install\n```\n\nCreate a `.env` file in the project root:\n\n```env\nDATABASE_URL=file:./data/tagr.db\nAUTH_SECRET=\"c5398a60cfd61607192d74ae8db237aaeaa07a98cd8ecdb8776c86eb87376ba3\"\n\nAUTH_USER=\"admin\"\nAUTH_PASSWORD=\"admin\"\n\n# Music folders (comma-separated paths)\n# Example: /Users/youruser/Music,/Volumes/External/Music\nMUSIC_FOLDERS=\"/Users/youruser/Music,/Volumes/External/Music\"\n```\n\nThen start:\n\n```bash\npnpm build \u0026\u0026 pnpm start # Production\n# or\npnpm dev                 # Development mode\n```\n\n---\n\n## Environment Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `DATABASE_URL` | Yes | SQLite database path. Use `file:/data/tagr.db` in Docker or `file:./data/tagr.db` locally. |\n| `AUTH_SECRET` | Yes | Secret for signing JWT sessions. Generate with `openssl rand -hex 32`. |\n| `AUTH_USER` | Yes | Login username. |\n| `AUTH_PASSWORD` | Yes | Login password (plain text). |\n| `MUSIC_FOLDERS` | No | Comma-separated list of paths to music directories. Defaults to `/music` if not set. |\n| `PUID` | No | User ID for the container process. Defaults to `1000`. (Docker only) |\n| `PGID` | No | Group ID for the container process. Defaults to `1000`. (Docker only) |\n\n---\n\n## Docker Volumes\n\n| Container Path | Purpose |\n|----------------|---------|\n| `/data` | SQLite database. Persist with a named volume to avoid data loss. |\n| `/music/*` | Mount points for your music libraries. |\n\n---\n\n## Architecture\n\n```\nBrowser (React Query) --\u003e Next.js API Routes --\u003e Prisma --\u003e SQLite\n                                                   |\n                                          node-taglib-sharp --\u003e audio files on disk\n```\n\n| Layer | Technology |\n|-------|------------|\n| Frontend | React 19, TanStack Query, Shadcn UI, Tailwind CSS 4 |\n| Backend | Next.js 16 App Router (route handlers) |\n| Database | SQLite via Prisma 7 + LibSQL |\n| Auth | NextAuth 5 (credentials provider, JWT sessions) |\n| Metadata Read | music-metadata |\n| Metadata Write | node-taglib-sharp |\n| Audio Player | WaveSurfer.js |\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuitux%2Ftagr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuitux%2Ftagr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuitux%2Ftagr/lists"}