This repository has been archived on 2026-06-15. You can view files and clone it, but cannot push or open issues or pull requests.
Files
MediaLore/README.md
2026-03-25 16:40:01 -04:00

131 lines
5.6 KiB
Markdown

# MediaLore
A self-hosted web UI for browsing media libraries on a NAS or local filesystem. Configure folders as typed libraries — currently supporting **Games** and **Mixed Media** library types.
## Features
- **Games library** — displays a grid of game cover art scanned from folders. Each game folder is expected to contain a `.zip` archive and optional artwork (`cover.*`, `widecover.*`). Clicking a game opens a detail modal with a download link for the zip.
- **Mixed media library** — a folder-navigable browser that mirrors the directory structure on disk. Videos open in an inline player (with full seek support via HTTP range requests). Images open in a lightbox. Other files are opened in a new tab.
- **Library management UI** — add and remove libraries at `/manage` without touching any config files. Configuration persists across restarts in `libraries.json`.
- **Path-jailed file serving** — all file access is verified to stay within the configured library root before being served.
## Project Structure
```
MediaLoreWeb/
├── libraries.json # Runtime library config (managed via UI, do not edit by hand)
├── data/ # Example media (not committed to production)
├── src/
│ ├── app/
│ │ ├── layout.tsx
│ │ ├── page.tsx # Home — library cards (redirects to /manage if empty)
│ │ ├── manage/page.tsx # Library management — add/remove libraries
│ │ ├── library/[id]/page.tsx # Library view (games or mixed)
│ │ └── api/
│ │ ├── libraries/route.ts # GET /api/libraries, POST /api/libraries
│ │ ├── libraries/[id]/route.ts # DELETE /api/libraries/:id
│ │ ├── games/route.ts # GET /api/games?libraryId=
│ │ ├── browse/route.ts # GET /api/browse?libraryId=&path=
│ │ └── file/route.ts # GET /api/file?libraryId=&path=
│ ├── components/
│ │ ├── LibraryCard.tsx
│ │ ├── NavLink.tsx
│ │ ├── games/
│ │ │ ├── GamesView.tsx
│ │ │ └── GameDetailModal.tsx
│ │ └── mixed/
│ │ ├── MixedView.tsx
│ │ ├── VideoPlayerModal.tsx
│ │ └── ImageLightbox.tsx
│ ├── lib/
│ │ ├── libraries.ts # Config read/write, path resolution, add/remove helpers
│ │ ├── games.ts # Games library scanner
│ │ └── files.ts # Mixed library directory scanner
│ └── types/
│ └── index.ts
```
## Developer Setup
**Requirements:** Node.js 18+
```bash
# 1. Install dependencies
npm install
# 2. Start the development server
npm run dev
```
Open [http://localhost:3000](http://localhost:3000).
Other available commands:
```bash
npm run build # Production build
npm run start # Start production server (run build first)
npm run lint # Run ESLint
```
## Library Configuration
Libraries are managed through the **Manage Libraries** screen at `/manage` in the app. No manual file editing is required.
When you add a library via the UI, you provide:
| Field | Description |
|--------|-------------|
| Name | Display name shown in the UI |
| Path | Absolute or project-relative path to the library root folder on disk |
| Type | `Games` or `Mixed Media` |
The app validates that the path exists as a directory before saving. Configuration is stored in `libraries.json` at the project root and persists across restarts.
If no libraries are configured, navigating to `/` automatically redirects to `/manage`.
Paths can point anywhere on the filesystem — they do not need to be inside the project directory.
## Library Folder Conventions
### Games (`"type": "games"`)
Each game is a subdirectory containing:
```
Games/
└── My Game Title/
├── My Game Title.zip # Required — the downloadable archive
├── cover.png # Optional — portrait cover art (case-insensitive)
└── widecover.jpg # Optional — landscape/hero cover art (case-insensitive)
```
- The `.zip` filename can be anything; the first `.zip` found in the folder is used.
- Cover art filenames are matched case-insensitively against `cover.*` and `widecover.*`. Any image extension is accepted.
### Mixed Media (`"type": "mixed"`)
No specific structure is required. The UI mirrors the directory tree exactly as it exists on disk. Supported media types:
- **Video:** `.mp4`, `.mov`, `.mkv`, `.avi`, `.webm`, `.m4v`
- **Image:** `.jpg`, `.jpeg`, `.png`, `.gif`, `.webp`, `.bmp`, `.tiff`
## API Reference
All API routes are server-side. File paths are never exposed in client-side state — only opaque `/api/file?...` URLs are sent to the browser.
| Route | Method | Description |
|-------|--------|-------------|
| `/api/libraries` | GET | Returns the full configured library list |
| `/api/libraries` | POST | Adds a library. Body: `{ name, path, type }`. Validates the path exists. |
| `/api/libraries/:id` | DELETE | Removes a library by id |
| `/api/games?libraryId=<id>` | GET | Scans the games library and returns structured game entries |
| `/api/browse?libraryId=<id>&path=<subpath>` | GET | Lists the contents of a directory within a mixed library |
| `/api/file?libraryId=<id>&path=<relpath>` | GET | Streams a file; supports HTTP `Range` requests for seekable video playback |
## Tech Stack
- [Next.js 15](https://nextjs.org/) (App Router)
- [React 19](https://react.dev/)
- [TypeScript 5](https://www.typescriptlang.org/)
- [Tailwind CSS 4](https://tailwindcss.com/)