- Rust 96.2%
- SCSS 3.6%
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: If49e784ce4c704538529a41a237d6a7c6a6a6964 |
||
|---|---|---|
| crates | ||
| migrations | ||
| nix | ||
| .envrc | ||
| Cargo.lock | ||
| Cargo.toml | ||
| flake.lock | ||
| flake.nix | ||
| pinakes.toml.example | ||
| README.md | ||
Pinakes
A media cataloging and library management system written in Rust. Pinakes indexes files across configured directories, extracts metadata from audio, video, document, and text files, and provides full-text search with tagging, collections, and audit logging. It supports both SQLite and PostgreSQL backends.
Building
# Build all compilable crates
cargo build -p pinakes-core -p pinakes-server -p pinakes-tui
# The Dioxus UI requires GTK3 and libsoup system libraries:
# On Debian/Ubuntu: apt install libgtk-3-dev libsoup-3.0-dev libwebkit2gtk-4.1-dev
# On Fedora: dnf install gtk3-devel libsoup3-devel webkit2gtk4.1-devel
# On Nix: Use the dev shell, everything is provided :)
cargo build -p pinakes-ui
Configuration
Copy the example config and edit it:
cp pinakes.toml.example pinakes.toml
Key settings:
storage.backend--"sqlite"or"postgres"storage.sqlite.path-- Path to the SQLite database filestorage.postgres.*-- PostgreSQL connection parametersdirectories.roots-- Directories to scan for media filesscanning.watch-- Enable filesystem watching for automatic importsscanning.ignore_patterns-- Patterns to skip during scanning (e.g.,".*","node_modules")server.host/server.port-- Server bind address
Running
Server
cargo run -p pinakes-server -- pinakes.toml
# or
cargo run -p pinakes-server -- --config pinakes.toml
The server starts on the configured host:port (default 127.0.0.1:3000).
TUI
cargo run -p pinakes-tui
# or with a custom server URL:
cargo run -p pinakes-tui -- --server http://localhost:3000
Keybindings:
| Key | Action |
|---|---|
q / Ctrl-C |
Quit |
j / k |
Navigate down / up |
Enter |
Select / confirm |
Esc |
Back |
/ |
Search |
i |
Import file |
o |
Open file |
d |
Delete (media in library, tag/collection in their views) |
t |
Tags view |
c |
Collections view |
a |
Audit log view |
s |
Trigger scan |
r |
Refresh current view |
n |
Create new tag (in tags view) |
+ |
Tag selected media (in detail view) |
- |
Untag selected media (in detail view) |
Tab / Shift-Tab |
Next / previous tab |
PageUp / PageDown |
Paginate |
Desktop/Web UI
cargo run -p pinakes-ui
Set PINAKES_SERVER_URL to point at the server if it is not on
localhost:3000.
API
All endpoints are under /api/v1.
Media
| Method | Path | Description |
|---|---|---|
POST |
/media/import |
Import a file ({"path": "..."}) |
GET |
/media |
List media (query: offset, limit) |
GET |
/media/{id} |
Get media item |
PATCH |
/media/{id} |
Update metadata |
DELETE |
/media/{id} |
Delete media item |
GET |
/media/{id}/stream |
Stream file content |
POST |
/media/{id}/open |
Open with system viewer |
Search
| Method | Path | Description |
|---|---|---|
GET |
/search?q=... |
Search (query: q, sort, offset, limit) |
Search syntax: term, "exact phrase", field:value, type:pdf, tag:music,
prefix*, fuzzy~, -excluded, a b (AND), a OR b, (grouped).
Tags
| Method | Path | Description |
|---|---|---|
POST |
/tags |
Create tag ({"name": "...", "parent_id": ...}) |
GET |
/tags |
List all tags |
GET |
/tags/{id} |
Get tag |
DELETE |
/tags/{id} |
Delete tag |
POST |
/media/{id}/tags |
Tag media ({"tag_id": "..."}) |
GET |
/media/{id}/tags |
List media's tags |
DELETE |
/media/{id}/tags/{tag_id} |
Untag media |
Collections
| Method | Path | Description |
|---|---|---|
POST |
/collections |
Create collection |
GET |
/collections |
List collections |
GET |
/collections/{id} |
Get collection |
DELETE |
/collections/{id} |
Delete collection |
POST |
/collections/{id}/members |
Add member |
GET |
/collections/{id}/members |
List members |
DELETE |
/collections/{cid}/members/{mid} |
Remove member |
Virtual collections (kind "virtual") evaluate their filter_query as a search
query when listing members, returning results dynamically.
Audit & Scanning
| Method | Path | Description |
|---|---|---|
GET |
/audit |
List audit log (query: offset, limit) |
POST |
/scan |
Trigger directory scan ({"path": "/..."} or {"path": null} for all roots) |
Testing
# Unit and integration tests for the core library (SQLite in-memory)
cargo test -p pinakes-core
# API integration tests for the server
cargo test -p pinakes-server
Supported Media Types
| Category | Formats |
|---|---|
| Audio | MP3, FLAC, OGG, WAV, AAC, Opus |
| Video | MP4, MKV, AVI, WebM |
| Document | PDF, EPUB, DjVu |
| Text | Markdown, Plain text |
| Image | JPEG, PNG, GIF, WebP, SVG, AVIF |
Metadata extraction uses lofty (audio, MP4), matroska (MKV), lopdf (PDF), epub (EPUB), and gray_matter (Markdown frontmatter).
Storage Backends
SQLite (default) -- Single-file database with WAL mode and FTS5 full-text search. Bundled SQLite guarantees FTS5 availability.
PostgreSQL -- Native async with connection pooling (deadpool-postgres). Uses
tsvector with weighted columns for full-text search and pg_trgm for fuzzy
matching. Requires the pg_trgm extension.