{"id":50782409,"url":"https://github.com/jchirayath/mediahound","last_synced_at":"2026-06-12T05:00:28.525Z","repository":{"id":363671869,"uuid":"1264392739","full_name":"jchirayath/mediahound","owner":"jchirayath","description":"Turn photos of your movie \u0026 music collection (DVD/VHS/Blu-ray, CD/vinyl/cassette) into a sleek, searchable web catalog — offline-first, zero-key.","archived":false,"fork":false,"pushed_at":"2026-06-10T06:36:14.000Z","size":1163,"stargazers_count":0,"open_issues_count":5,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T07:25:16.373Z","etag":null,"topics":["catalog","cd","collection","dvd","movies","music","musicbrainz","ocr","records","self-hosted","static-site","vhs","vinyl"],"latest_commit_sha":null,"homepage":"https://jchirayath.github.io/mediahound/","language":"Python","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/jchirayath.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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-09T21:00:21.000Z","updated_at":"2026-06-10T06:36:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jchirayath/mediahound","commit_stats":null,"previous_names":["jchirayath/reelshelf","jchirayath/mediahound"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jchirayath/mediahound","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchirayath%2Fmediahound","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchirayath%2Fmediahound/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchirayath%2Fmediahound/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchirayath%2Fmediahound/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jchirayath","download_url":"https://codeload.github.com/jchirayath/mediahound/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchirayath%2Fmediahound/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34229624,"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-12T02:00:06.859Z","response_time":109,"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":["catalog","cd","collection","dvd","movies","music","musicbrainz","ocr","records","self-hosted","static-site","vhs","vinyl"],"created_at":"2026-06-12T05:00:20.063Z","updated_at":"2026-06-12T05:00:28.517Z","avatar_url":"https://github.com/jchirayath.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"MediaHound\" src=\"docs/brand/mediahound-logo.png\" height=\"150\"\u003e\n\u003c/p\u003e\n\n# 🎬🎵 MediaHound\n\n[![CI](https://github.com/jchirayath/mediahound/actions/workflows/ci.yml/badge.svg)](https://github.com/jchirayath/mediahound/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/jchirayath/mediahound/actions/workflows/codeql.yml/badge.svg)](https://github.com/jchirayath/mediahound/actions/workflows/codeql.yml)\n[![PyPI](https://img.shields.io/pypi/v/mediahound.svg)](https://pypi.org/project/mediahound/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)\n[![Live demo](https://img.shields.io/badge/live-demo-e97b0c.svg)](https://jchirayath.github.io/mediahound/)\n\n**Turn photos of your movie *and* music collection into a sleek, searchable web catalog.**\n\nPoint MediaHound at a folder of cover photos — DVDs, VHS, Blu-ray, **CDs, vinyl, cassettes** — or\n**import a CSV**. It identifies each item, pulls in cover art, genres, cast/artist, studio/label,\nruntime/tracklist and ratings, writes a short enticing intro, estimates the used resale value, links\nwhere to **watch** (movies), **listen** (music) or **find** (books), and generates a polished static\nwebsite you can search, filter by **🎬 Movies / 🎵 Music / 📚 Books**, sort, and curate — with a\npassword-protected admin mode.\n\nMovies are identified/enriched via TMDB / OMDb / Wikidata + JustWatch; music via **MusicBrainz +\nCover Art Archive**; books via **Open Library** (open, zero-key) — scan a book's **ISBN** for an exact\nmatch. Keyless Spotify / Apple Music / YouTube Music + Open Library / Goodreads links throughout.\n\n**▶ [Live demo](https://jchirayath.github.io/mediahound/)** — explore a sample catalog in your browser (admin password: `changeme`).\n\n**🖥️ Download the desktop app — no Python, no terminal:**\n\u0026nbsp; **[⬇ macOS](https://github.com/jchirayath/mediahound/releases/latest/download/MediaHound-macOS.zip)**\n\u0026nbsp; **[⬇ Windows](https://github.com/jchirayath/mediahound/releases/latest/download/MediaHound-Windows.zip)**\n\u0026nbsp; — unzip and open. *(Or `pip install mediahound` — see below.)*\n\n[![MediaHound screenshot](docs/screenshot.jpg)](https://jchirayath.github.io/mediahound/)\n\n\u003e ℹ️ The demo shows **real movie posters and album covers** (hotlinked from IMDb/OMDb and Cover Art\n\u003e Archive / Apple) so you can see what a finished catalog looks like — no cover images are stored in\n\u003e this repo. Extra gallery photos are generated placeholders standing in for *your own* photos. Your\n\u003e real catalog pulls art from TMDB / OMDb / Wikidata (movies) and MusicBrainz / Cover Art Archive\n\u003e (music), or falls back to the photos you take.\n\n- **Runs for anybody with zero API keys** — open-source OCR + open data by default.\n- **Offline-first** — never contacts the internet unless you explicitly ask (`--online`).\n- **Static output** — deploy anywhere (Netlify, GitHub Pages, S3, Vercel) or just open the HTML file.\n- **No secrets in the repo** — keys live in a gitignored `.env`; your catalog is generated output.\n\n\u003e MIT-licensed. Your photos, keys and catalog never get committed to this tool's repo.\n\n---\n\n## See it in 30 seconds (no photos, no keys)\n\n```bash\npip install mediahound\n\nmediahound init demo\nmediahound build --config demo/config.toml --mock   # generates a sample catalog\ncd demo \u0026\u0026 python3 -m http.server 8000              # open http://localhost:8000\n```\n\nThat's the screenshot above. Click **🔒 Admin** and sign in with **`changeme`** to try the\nread/write admin tools. Everything you see is generated by `--mock` — no internet, no API keys.\n\n\u003e Prefer the bleeding edge or want to hack on it? Install from source instead:\n\u003e `git clone https://github.com/jchirayath/mediahound \u0026\u0026 cd mediahound \u0026\u0026 pip install -e .`\n\u003e (Maintainers: see [RELEASING.md](RELEASING.md) for the publish flow.)\n\n---\n\n## Cataloguing your own collection\n\n### The easy way — one command, no terminal after that\n\n```bash\npip install mediahound\nmediahound app          # sets up a library and opens the editor in your browser\n```\n\n`mediahound app` creates a library folder (if needed), opens the catalog, and you click\n**➕ Add photos** to **drag-and-drop** your cover pics — they're saved and identified automatically.\nNo config files, no separate build/serve commands. Everything stays on your computer.\n\n**Snap covers on your phone:**\n\n```bash\nmediahound app --phone   # opens to your Wi-Fi and prints a QR code\n```\n\nScan the QR with your phone (on the same Wi-Fi), tap **➕ Add photos → Take Photo**, and they upload\nstraight into your catalog. Uploads are **token-protected** (only the phone that scanned the code can\nadd photos) and nothing leaves your network — use it on a network you trust.\n\n### Desktop app (no Python, no terminal)\n\nPrefer to double-click an icon? A native app opens the editor in its own window:\n\n- **Download:** **[⬇ macOS (.app)](https://github.com/jchirayath/mediahound/releases/latest/download/MediaHound-macOS.zip)**\n  · **[⬇ Windows (.exe)](https://github.com/jchirayath/mediahound/releases/latest/download/MediaHound-Windows.zip)**\n  — or pick a specific version on the [Releases](https://github.com/jchirayath/mediahound/releases)\n  page. Unzip, and open. *(Unsigned builds show a Gatekeeper/SmartScreen prompt the first time —\n  right-click → **Open** on macOS, or **More info → Run anyway** on Windows.)* To ship builds that\n  open with no warning, see [SIGNING.md](SIGNING.md).\n- **Or, if you've got Python:** `pip install \"mediahound[desktop]\"` then `mediahound gui` opens the\n  same native window. (Without the `[desktop]` extra it falls back to opening your browser.)\n- **Build it yourself:** `bash packaging/build-desktop.sh` (uses PyInstaller; build on the OS you\n  want). CI builds the macOS + Windows apps automatically — see `.github/workflows/desktop.yml`.\n\nThe app keeps your library in **`~/MediaHound Library`** and works fully offline.\n\n### Share it — one-click Publish\n\nWhen your catalog's ready, click **🌐 Publish** in the admin console to deploy it to **Netlify** (free) and get a shareable link. Paste a Netlify access token once (stored in your OS keychain); only the finished site is uploaded — your source photos and config never leave your computer.\n\n### The CLI way (more control)\n\n```bash\npip install \"mediahound[ocr]\"   # adds the default OCR identifier\n# Install the Tesseract engine for OCR:\n#   macOS:  brew install tesseract\n#   Debian: sudo apt-get install tesseract-ocr\n\nmediahound init mysite      # scaffolds mysite/ (RawImages/{video,audio}/, config.toml, web template)\n\n# Sort your cover photos by media type:\ncp ~/Pictures/dvd-covers/*.jpg   mysite/RawImages/video/    # 🎬 movies (DVD/VHS/Blu-ray/LaserDisc)\ncp ~/Pictures/album-covers/*.jpg mysite/RawImages/audio/    # 🎵 music  (CD/vinyl/cassette)\n\nmediahound build --config mysite/config.toml --online   # identify + enrich (see Providers below)\ncd mysite \u0026\u0026 python3 -m http.server 8000\n```\n\n#### Raw-image folder convention\n\nPhotos are sorted into **media-type subfolders** so MediaHound knows how to identify each item:\n\n| Folder | Media type | Identified/enriched via |\n|---|---|---|\n| `RawImages/video/` | 🎬 movies | TMDB / OMDb / Wikidata + JustWatch |\n| `RawImages/audio/` | 🎵 music | MusicBrainz + Cover Art Archive + listen links |\n| `RawImages/` (root) | defaults to movies | — |\n\n(`movies/` and `music/` are accepted aliases.) Add more photos anytime and re-run `build` — only the\n**new** ones are processed (state is tracked by content hash in `data/manifest.json`).\n\n### Or import from a CSV (no photos)\n\n```bash\nmediahound import catalog.csv --config mysite/config.toml          # add rows offline\nmediahound import catalog.csv --config mysite/config.toml --online # …and fetch cover art + metadata\nmediahound export --config mysite/config.toml -o backup.csv        # dump the whole catalog back to CSV\n```\n\nColumns (case-insensitive; extras ignored): `media_type, title, artist, director, year, format,\nlabel, studio, genres, rating, barcode, cover_url, intro`. **Only `title` is required** — any missing\nfields are left blank (or filled by `--online`); even a one-column list of titles works. `media_type`\nis inferred (`music` if an `artist` is given, else `movie`). See\n[`examples/sample-import.csv`](examples/sample-import.csv).\n\nPrefer a UI? Under **`mediahound serve --admin`** the admin screen has an **⬆ Import list** button —\npaste or upload the same CSV, optionally tick *enrich online*, and the titles are added and the site\nrebuilt in place.\n\n---\n\n## Features\n\n### The catalog\n- **Search** title / genre / cast / studio / intro, **sort** by title, year, recently-added, value or rating.\n- **Filters**: format, genre, studio, **streaming service**, language, category, seen / unseen.\n- **Dense, aligned cards** showing poster, title·year, ★rating · format · runtime · language,\n  genres, director + cast, studio, where-to-watch, intro hook, and estimated resale value.\n- **Clickable everything**: a genre, person, or studio filters the grid to matching titles.\n- **Adjustable density** — viewers pick how many movies per row; responsive on web \u0026 mobile.\n\n### Photos\n- **Multi-photo galleries** — flip through every photo of a title with ‹ › arrows.\n- **Click-to-zoom** lightbox; set any photo as the default; rotate photos (baked in on rebuild).\n- Auto-uprights sideways/landscape cover photos to portrait.\n\n### Where to watch \u0026 resale\n- **Where to watch** — is it on Netflix / Amazon Prime / Hulu? A clickable ▶ badge + pills link\n  straight to the title (via JustWatch, no key). A filter narrows to a specific service.\n- **Resale value** — a heuristic estimate plus a live link to eBay sold/completed listings. For music\n  with a Discogs release id, a condition-based **Discogs price suggestion** (token-gated).\n\n### 📷 Barcode scanning (exact, not fuzzy)\n- Identify the **exact release** from the UPC/EAN barcode instead of fuzzy OCR. In the admin view,\n  **📷 Scan barcode** opens your camera (or type the digits); on `mediahound build --online` a barcode\n  found in a cover photo is preferred over OCR. Music → MusicBrainz/Discogs; movies → UPCItemDB →\n  the normal identify-by-title path. Local decode needs the optional extra: `pip install \"mediahound[barcode]\"`.\n\n### 💿 Discogs (records \u0026 CDs)\n- **Import an existing Discogs collection** in one step: `mediahound import-discogs \u003cusername\u003e` (or the\n  **💿 Discogs** admin button). Selectable as a music metadata provider (`[music.metadata] provider = \"discogs\"`).\n  Token stored in your keychain via **Settings → API keys**.\n\n### ⭐ Your personal catalog (admin-only, never published)\n- **Rate** (★1–10), **note**, and **tag/shelve** any item; track **lending** (loan out → badge →\n  returned), filter **On loan / Available**, and hit **🎲 Surprise me** to pick something for tonight.\n  All of this is **stripped from the published site** — it shows only in your local admin view.\n\n### 🛟 Backup, export \u0026 feeds\n- **`mediahound backup` / `restore`** zip up (and re-create) your whole library — `--no-photos` for a\n  quick curation-only backup; secrets are never included. A **⬇ Backup** button does the same from the app.\n- **Export** to **Letterboxd** (movies) or **JSON**: `mediahound export --format letterboxd|json`\n  (or the **🎬 Letterboxd** button). The published site also emits **`feed.json` + `feed.xml`** of\n  recently-added items so anyone can subscribe.\n- **📚 Library switcher** — keep separate catalogs (e.g. movies vs. music, or per-family-member) and\n  **open / create / switch between them from the admin UI** with no restart (a recents list lives in\n  `~/.config/mediahound/`). Each library's **data directory** is set by its own `config.toml` `[paths]`.\n\n### Two views\n- **Default view** — public, read-only.\n- **Admin view** — password-protected, read/write. Edit a title's name, year, format, studio \u0026\n  distributor; **move a title between 🎬 Movies and 🎵 Music**; mark seen; rotate / set-default /\n  delete a photo; delete a title; and configure the **library name, description, logo, which fields\n  are shown, and default columns**.\n\n### Editing \u0026 persisting your changes\n\nYour edits are recorded as small **corrections** (keyed by title id). There are two ways to make\nthem permanent so they **survive every future `mediahound build`** — pick one:\n\n**A. Live admin server (recommended — zero manual steps)**\n\n```bash\nmediahound serve --admin          # serves the site at http://127.0.0.1:8765\n```\n\nOpen the site, unlock admin, and edit. Every change is written **straight into\n`data/corrections.json`** (and `seen-overrides.json`) as you go — the badge shows\n*“✓ Saved to disk.”* Click **↻ Rebuild** to re-bake the catalog and reload. Because the edit is\nalready in `data/`, the next `mediahound build` (and any re-query) keeps it — **edits never revert.**\nThe write API is **localhost-only** and refuses cross-origin requests; never expose it publicly.\n\n**B. Static export (for read-only/CDN hosting like Netlify or GitHub Pages)**\n\nWhen the site is served as plain files (no admin server), edits live in your browser. Click\n**Export changes** / **Export seen** — the download is **merged with the site's existing\n`data/corrections.json`** so nothing already saved is lost — then drop the file into `data/` and run\n`mediahound build`.\n\n\u003e Either way the source of truth is `data/corrections.json`. A title you fix only in the browser\n\u003e (without server-admin or an export) shows locally but **reverts on the next rebuild**, because the\n\u003e build regenerates the catalog from `data/`.\n\n### Manual identification\n- Covers that couldn't be read are grouped on `identify.html`, where you **name** them (queued for\n  discovery on the next online build) or **discard** them (e.g. blank tapes).\n\n---\n\n## How it compares\n\nMost movie-collection tools add items by **barcode scan or manual entry** and keep your catalog in\n**their cloud** or a dated desktop app. MediaHound is the only one that identifies titles from\n**photos of the covers** and generates a **modern static website you own and host for free** —\noffline-first and open-source. It's also one of the few that handles **VHS** (which usually has no\nscannable barcode in the disc databases others rely on).\n\n| | MediaHound | CLZ / Libib | Tellico / GCstar | Plex / Jellyfin |\n|---|---|---|---|---|\n| Add by **photo of cover** | ✅ OCR/AI | ❌ barcode/manual | ❌ search/manual | ❌ scans video files |\n| Modern **website you host free** | ✅ | ❌ their cloud | ◻︎ dated HTML export | ❌ private server |\n| Open-source / offline / no account | ✅ | ❌ | ✅ desktop | ✅ (Jellyfin) |\n| For a **physical** shelf | ✅ | ✅ | ✅ | ❌ digital files |\n\nSee **[COMPARISON.md](COMPARISON.md)** for the full, honest analysis — including when a barcode app\n(CLZ/Libib), an OSS desktop cataloger (Tellico/Data Crow), or a media server (Plex/Jellyfin) is the\nbetter choice.\n\n---\n\n## Providers (how titles get identified \u0026 enriched)\n\nBoth paths are first-class — pick them per-site in `config.toml`. The default needs **zero keys**.\n\n| Concern | Default (no key) | Optional upgrade |\n|---|---|---|\n| **Identify** title from a cover | `tesseract` — open-source OCR | `claude` (Anthropic vision, also writes the intro) · `ollama` (local model) |\n| **Movie** metadata + poster | `wikidata` — Wikidata + Wikipedia + Wikimedia | `tmdb` (free key) · `omdb` (free key) |\n| **Music** metadata + cover art | `musicbrainz` — MusicBrainz + Cover Art Archive | `discogs` *(planned)* |\n| **Where to watch / listen** | `justwatch` (movies) · keyless Spotify/Apple/YouTube search (music) | Spotify / Apple Music keys *(planned)* |\n| **Resale** | eBay sold-listings link + estimate | Discogs price *(planned, music)* |\n\nSwitch to a premium provider in `config.toml`:\n\n```toml\n[identify]\nprovider = \"claude\"      # needs ANTHROPIC_API_KEY\n[metadata]\nprovider = \"tmdb\"        # needs TMDB_API_KEY (or use \"omdb\" + OMDB_API_KEY)\n```\n\n…and create a **gitignored** `.env` next to `config.toml`:\n\n```\nANTHROPIC_API_KEY=sk-ant-...\nTMDB_API_KEY=...\n```\n\nRobustness built in: results are cached (`data/.metadata-cache.json`) so rebuilds never re-hit a\nrate-limited free key, providers fail soft (a bad lookup never drops a title), and a fuzzy match\nthat returns the wrong film is rejected so it can't corrupt your names.\n\n---\n\n## Offline by default\n\n`mediahound build` is **offline** — it regenerates the site from existing data and never contacts\nthe internet. Add `--online` to allow identification / metadata / where-to-watch lookups:\n\n```bash\nmediahound build --config mysite/config.toml              # offline: just rebuild the site\nmediahound build --config mysite/config.toml --online     # online: identify + enrich new titles\nmediahound build --config mysite/config.toml --online --refresh-streaming   # also re-check where-to-watch\n```\n\nUseful flags: `--mock` (demo data), `--force` (reprocess everything), `--limit N`, `--reidentify \u003csha256\u003e`.\n\n---\n\n## Deploy\n\nThe generated site folder (`mysite/`) is plain static files (`index.html`, `identify.html`,\n`assets/`, `data/`, `posters/`, `originals/`). It's just static files, so you can **host it free**\non **GitHub Pages, Cloudflare Pages, Netlify, Vercel, Render, or Surge.sh** — no server, database,\nor build step required. Quickest:\n\n```bash\ncd mysite \u0026\u0026 npx netlify deploy --prod          # Netlify\ncd mysite \u0026\u0026 npx wrangler pages deploy .         # Cloudflare Pages\ncd mysite \u0026\u0026 npx surge .                         # Surge.sh\n```\n\nSee **[DEPLOYMENT.md](DEPLOYMENT.md)** for the full free-hosting comparison plus GitHub Pages, Vercel\nand S3 instructions. The live demo above is itself hosted free on GitHub Pages via a workflow.\n\nIt even works by **double-clicking `index.html`** — the build embeds the catalog in `data/bundle.js`\nso it loads without a web server.\n\n### 📱 Install it on your phone (PWA)\n\nA published catalog is a **Progressive Web App**. Open it in your phone's browser and **Add to Home\nScreen** (on iPhone: the **Share** button in Safari) — you get an app icon, a full-screen view, and\n**offline** access (the catalog is cached). It **auto-updates** every time you republish. Browsing is\nread-only; editing happens in the local app (`mediahound app`) and is then published.\n\n---\n\n## Architecture\n\nSee **[ARCHITECTURE.md](ARCHITECTURE.md)** for the full picture. In short:\n\n```\nRawImages/*.jpg ─▶ identify (OCR / vision) ─▶ enrich (poster, genres, cast, studio, rating)\n                                                    │\n                          confidence too low? ──────┴─▶ data/unidentified.json → identify.html\n                                                    ▼\n   + intro + resale + where-to-watch ─▶ data/collection.json ─▶ static site (index.html)\n```\n\nPython CLI (`mediahound/`) builds the data; a dependency-free vanilla-JS frontend (`mediahound/web/`) renders it.\n\n---\n\n## Attribution \u0026 licensing\n\n- Code: **MIT** (see [LICENSE](LICENSE)).\n- Default data: **Wikidata** (CC0), **Wikipedia** text (CC BY-SA), images via **Wikimedia Commons**.\n- If you enable **TMDB**: uses the TMDB API but is not endorsed or certified by TMDB.\n- Where-to-watch data via **JustWatch**; resale links to **eBay** sold listings (estimates are heuristics).\n\n## Security\n\nMediaHound output is a **static site** — read-only to everyone, with no server to attack. The admin\npassword is a convenience gate, **not** an access-control boundary (the published catalog can't be\nchanged without rebuilding + redeploying). API keys stay in a gitignored `.env`; only the password\nhash ships. All rendered data is HTML-escaped and links are scheme-restricted. See\n**[SECURITY.md](SECURITY.md)** for the full threat model and reporting instructions.\n\n**Privacy:** MediaHound is offline-first with **no account and no telemetry** — your photos, catalog,\nand keys stay on your computer; data leaves only when you opt into online metadata, Publish, or phone\nupload. See **[PRIVACY.md](PRIVACY.md)**.\n\n**Roadmap:** what's next (barcode scanning, Discogs, backup/exports, personal catalog) is designed in\n[docs/design/](docs/design/); the full backlog is in [docs/ROADMAP.md](docs/ROADMAP.md).\n\nContributions welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjchirayath%2Fmediahound","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjchirayath%2Fmediahound","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjchirayath%2Fmediahound/lists"}