docs: rewrite README with prose focus and screenshot
This commit is contained in:
117
README.md
117
README.md
@@ -1,57 +1,42 @@
|
||||
# MyAnimeList
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="/static/assets/readme-logo-dark.svg" />
|
||||
<img src="/static/assets/readme-logo-light.svg" alt="MyAnimeList logo" width="140" />
|
||||
<img src="/static/assets/readme-logo-light.svg" alt="MyAnimeList logo" width="120" />
|
||||
</picture>
|
||||
</td>
|
||||
<td>
|
||||
<strong>MyAnimeList</strong><br />
|
||||
My personal anime tracker, built because nothing else felt right.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<em>My personal anime tracker, built because nothing else felt right.</em>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img alt="Go" src="https://img.shields.io/badge/go-1.25-00ADD8?style=flat-square&logo=go" />
|
||||
<img alt="SQLite" src="https://img.shields.io/badge/database-sqlite-003B57?style=flat-square&logo=sqlite" />
|
||||
<img alt="Tailwind" src="https://img.shields.io/badge/tailwind-4-06B6D4?style=flat-square&logo=tailwindcss" />
|
||||
<img alt="Tailwind" src="https://img.shields.io/badge/tailwind-4-06D6D4?style=flat-square&logo=tailwindcss" />
|
||||
<img alt="HTMX" src="https://img.shields.io/badge/htmx-partial--updates-3366CC?style=flat-square" />
|
||||
</p>
|
||||
|
||||
---
|
||||
<img alt="MyAnimeList home page screenshot" src="/static/assets/screenshot-home.png" width="800" />
|
||||
|
||||
## Why this project exists
|
||||
I was frustrated with every anime tracker I tried. Decent UI but awkward UX. Good features but missing the ones I actually use. So I built my own: search fast, get context fast, update your status fast, and move on.
|
||||
|
||||
I built this for myself.
|
||||
This project is personal first — I put it on GitHub because I like shipping in the open. It also doubles as proof that a small, server-rendered Go app can stay reliable even when upstream anime APIs are inconsistent.
|
||||
|
||||
I was frustrated with the UI and UX of every tracker I tried. Even when something looked decent, it still felt awkward to use day-to-day, or it was missing pieces I considered essential. I wanted one place that matched how I actually watch anime: search fast, get context fast, update status fast, and move on.
|
||||
|
||||
So this project is personal first and public second. I put it on GitHub because I like shipping in the open, not because it was originally designed as a general-purpose product for everyone.
|
||||
|
||||
Technically, I also wanted to prove that a small, server-rendered Go app could stay reliable even when upstream anime APIs are inconsistent. A lot of this code exists because real APIs rate-limit, timeout, and occasionally fail at the worst possible moment.
|
||||
|
||||
## What the application offers
|
||||
|
||||
For my own workflow, MyAnimeList combines catalog browsing, seasonal discovery, quick search, detail pages with recommendations and relations, watchlist management, continue-watching, and in-app playback in one server-rendered interface.
|
||||
|
||||
The interface is minimal and functional, featuring a dark theme and quick access to tracking tools.
|
||||
- **Catalog browsing & seasonal discovery** — explore what's airing, filter by season
|
||||
- **Quick search** — find anime, get mal links, open the detail page in seconds
|
||||
- **Detail pages** — synopsis, stats, recommendations, related entries
|
||||
- **Watchlist management** — track your progress across statuses
|
||||
- **Continue watching** — pick up where you left off
|
||||
- **In-app playback** — proxy-based video player
|
||||
|
||||
## Technical approach
|
||||
|
||||
The application is written in Go and rendered on the server with `html/template`, with SQLite as the primary datastore and `sqlc` for typed query generation. Styling uses Tailwind CSS v4. HTMX and small TypeScript modules handle incremental interactions, which keeps the interface responsive without moving the entire product into a heavy client-side architecture.
|
||||
Written in Go with server-rendered `html/template`, SQLite + `sqlc` for typed queries, Tailwind CSS v4 for styling, and HTMX backed by small TypeScript modules for incremental interactions.
|
||||
|
||||
The external anime data source is Jikan (`https://api.jikan.moe/v4`). Because reliability is a first-class concern, the client layer includes request pacing, bounded retries, backoff behavior, stale-cache fallback, and a persisted retry queue for failed fetches. Playback proxying uses uTLS to bypass Cloudflare protections.
|
||||
|
||||
Upstream APIs can fail transiently with `429` and `5xx` responses, so the app favors graceful degradation over hard failure. Cached values are used when fresh requests fail, retryable failures are persisted and replayed in a background worker, and relation synchronization is incremental so one bad fetch does not block the rest of the graph.
|
||||
The external anime data source is [Jikan](https://api.jikan.moe/v4). The client layer handles request pacing, bounded retries, backoff, stale-cache fallback, and a persisted retry queue. Playback proxying uses uTLS to bypass Cloudflare. The system is built to degrade gracefully under `429` and `5xx` responses rather than fail hard.
|
||||
|
||||
## Repository structure
|
||||
|
||||
The codebase follows standard Go project layout conventions.
|
||||
|
||||
| Path | Purpose |
|
||||
| ----------------- | ------------------------------------------------ |
|
||||
| `api/*` | Feature routes: anime, auth, playback, watchlist |
|
||||
@@ -63,74 +48,18 @@ The codebase follows standard Go project layout conventions.
|
||||
| `migrations` | Schema evolution |
|
||||
| `static` / `dist` | Frontend assets |
|
||||
|
||||
## Getting started
|
||||
## Running locally
|
||||
|
||||
Requires Go `1.25+`, Bun, and [just](https://github.com/casey/just) (`brew install just`).
|
||||
Requires Go `1.25+`, Bun, and [just](https://github.com/casey/just). Migrations run on startup. Configuration lives in environment variables — see `cmd/server/main.go` for the full list.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/mkelvers/mal.git && cd mal
|
||||
openssl rand -base32 32
|
||||
PLAYBACK_PROXY_SECRET="your-32-char-secret" go run ./cmd/server
|
||||
go run ./cmd/user <username> <password>
|
||||
just dev
|
||||
```
|
||||
|
||||
The app runs at `http://localhost:3000`.
|
||||
## Contributing
|
||||
|
||||
### Tasks
|
||||
|
||||
The justfile automates common tasks:
|
||||
|
||||
```bash
|
||||
just fmt # format go code
|
||||
just lint # go fmt && go vet
|
||||
just test # run go tests
|
||||
just build # build go binary + frontend
|
||||
just check # lint, test, typecheck, build
|
||||
just dev # build and run
|
||||
just install-hooks # install pre-push hooks
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
docker build -t mal .
|
||||
docker run --rm -p 3000:3000 -e PLAYBACK_PROXY_SECRET="$(openssl rand -base32 32)" mal
|
||||
|
||||
# persistent data
|
||||
docker run --rm -p 3000:3000 \
|
||||
-e DATABASE_FILE=/app/data/mal.db \
|
||||
-e PLAYBACK_PROXY_SECRET="your-secret" \
|
||||
-v "$(pwd)/data:/app/data" \
|
||||
mal
|
||||
|
||||
docker exec mal ./cmd/user <username> <password>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
| ----------------------- | ------------------- | ----------------------------------------------------------- |
|
||||
| `PORT` | `3000` | HTTP listen port |
|
||||
| `DATABASE_FILE` | `mal.db` | SQLite database file path |
|
||||
| `ENV` | _(empty)_ | Set to `production` to enable secure session cookies |
|
||||
| `MIGRATIONS_DIR` | _(auto-discovered)_ | Optional explicit path to migration files |
|
||||
| `PLAYBACK_PROXY_SECRET` | _(required)_ | HMAC secret for signed playback proxy tokens (min 32 chars) |
|
||||
| `MAL_JIKAN_TRACE` | `false` | Log all Jikan cache/upstream timings when enabled |
|
||||
|
||||
## Testing
|
||||
|
||||
Run locally with `just check` or manually:
|
||||
|
||||
```bash
|
||||
go test ./...
|
||||
```
|
||||
|
||||
Migrations run automatically on startup.
|
||||
|
||||
## Security
|
||||
|
||||
Keep secrets out of version control, do not publish real credentials in documentation or screenshots, and report security issues privately before public disclosure.
|
||||
Bug reports and pull requests are welcome. This is a personal project, so there is no strict roadmap or issue triage cycle. If something is broken or missing, open an issue or send a PR.
|
||||
|
||||
## License
|
||||
|
||||
This project is released under the MIT License. See `LICENSE` for details.
|
||||
MIT. See `LICENSE`.
|
||||
|
||||
BIN
static/assets/screenshot-home.png
Normal file
BIN
static/assets/screenshot-home.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
Reference in New Issue
Block a user