Skip to content

Latest commit

Β 

History

1,154 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Quotinator 🎬

CI CodeQL License Release .NET Supports amd64 Architecture Supports aarch64 Architecture

"I'll be back... with a quote."

A self-hosted quote REST API with MCP support, built in C# / ASP.NET Core, deployable as a Docker container. Designed for homelab and self-hosted environments β€” serves real, verified quotes from films, books, and famous people over a clean REST API, with a Blazor management frontend and MCP tool support for AI assistants.


Project Goals

  • Serve real, accurately attributed quotes via a clean REST API
  • Source types: films, television, books, and famous people
  • Quotes stored in their original language with optional curated translations
  • Support the Model Context Protocol (MCP) so AI assistants can fetch quotes as a tool
  • Ship as a Docker image (amd64 + arm64)
  • Include a Blazor Server web frontend for managing quotes, users, and settings
  • Stay maintainable by a single developer with standard .NET skills

Architecture Overview

Quotinator/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ Quotinator.Api/          # ASP.NET Core β€” REST endpoints + Blazor Server UI (combined)
β”‚   β”œβ”€β”€ Quotinator.Changelog/    # Changelog library β€” models, schema validation, formatters
β”‚   β”œβ”€β”€ Quotinator.Constants/    # Route strings, tag names, error message keys (no dependencies)
β”‚   β”œβ”€β”€ Quotinator.Core/         # Domain models, interfaces, and the SQLite-backed service implementation
β”‚   β”œβ”€β”€ Quotinator.Data/         # Generic, reusable SQLite/Dapper infrastructure (domain-agnostic)
β”‚   └── Quotinator.Data.Testing/ # Test helper library β€” stubs, fakes, and disposable SQLite DB
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ Quotinator.Api.Tests/         # Endpoint integration tests (WebApplicationFactory)
β”‚   β”œβ”€β”€ Quotinator.Changelog.Tests/   # Changelog schema and generation tests
β”‚   β”œβ”€β”€ Quotinator.Constants.Tests/   # Tests for route and constant definitions
β”‚   β”œβ”€β”€ Quotinator.Core.Tests/        # Unit tests for domain logic, integration tests for the SQLite-backed implementation
β”‚   β”œβ”€β”€ Quotinator.Data.Example/      # Concrete example implementations of Data patterns (not a test runner)
β”‚   β”œβ”€β”€ Quotinator.Data.Testing.Tests/ # Tests for the Data.Testing helper library
β”‚   └── Quotinator.Data.Tests/        # Integration tests for Data infrastructure (real SQLite, no fakes)
β”œβ”€β”€ addon/                       # Home Assistant add-on manifest, config, and translations β€” stable channel
β”œβ”€β”€ addon-beta/                  # Same as addon/, for the beta channel (same image, different slug/version)
β”œβ”€β”€ data/
β”‚   └── sources/                 # Bundled source files (one JSON per dataset) + manifest
β”œβ”€β”€ docker/
β”‚   β”œβ”€β”€ Dockerfile
β”‚   └── docker-compose.yml
β”œβ”€β”€ docs/                        # Architecture decisions, workflow, security, and reference docs
β”œβ”€β”€ schemas/                     # JSON Schema files for source file validation and editor IntelliSense
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ SOURCES.md                # Workflow for adding a new quote source via a converter plugin
β”‚   β”œβ”€β”€ changelog.csx            # Changelog markdown generator (keepachangelog + HA add-on formats)
β”‚   β”œβ”€β”€ changelog-import.csx     # Import tool for adding new changelog entries
β”‚   └── changelog-upgrade.csx   # Schema upgrade tool for changelog format migrations
β”œβ”€β”€ SOURCES.md                   # Attribution for seed data sources
β”œβ”€β”€ CLAUDE.md                    # AI assistant context (read this first)
└── README.md

Tech Stack

Layer Technology
Language C# (.NET 10)
API ASP.NET Core Minimal API
Frontend Blazor Server
Data SQLite (Dapper β€” no EF Core)
Logging Serilog (programmatic configuration β€” HA container compatible)
Protocol REST (MCP planned)
Container Docker (linux/amd64 + linux/arm64)
Auth API key required for admin endpoints; quote endpoints are public

Quote Data

Quotinator's quote data lives in data/sources/ β€” one JSON file per dataset, normalised to the canonical schema. The bundled sources are:

  • quotinator-curated.json β€” manually verified entries with enriched metadata (character names, genres, conversations)
  • quotinator-series-universe.json β€” curated Series/Universe groupings for Sources already present in the other bundled files (e.g. linking Star Wars films into a "Star Wars" Series/Universe); carries no quotes of its own
  • vilaboim/movie-quotes β€” AFI Top 100 movie quotes (~99 entries)
  • NikhilNamal17/popular-movie-quotes β€” popular movie, TV, and anime quotes (~732 entries)

All external sources are MIT licensed. See SOURCES.md for full attribution and JSON Schema documentation.

The canonical quote schema is:

{
  "id": "uuid-v4",
  "quote": "Here's looking at you, kid.",
  "originalLanguage": "en",
  "source": "Casablanca",
  "date": "1942",
  "character": "Rick Blaine",
  "author": null,
  "type": "movie",
  "genres": ["drama", "romance"],
  "translations": {
    "nl": { "quote": "Hier kijk ik naar je, kind.", "source": "Casablanca" }
  }
}
  • originalLanguage β€” ISO 639-1 code; most entries are "en" (American English)
  • source β€” film/show title, book title, or speech occasion
  • date β€” ISO 8601, as precise as the source has it: "1942", "1940-06", or "1940-06-04"
  • character β€” fictional character (movie/tv/anime/book fiction)
  • author β€” book's author, or the real person for person type quotes
  • type β€” movie, tv, anime, book, or person
  • genres β€” filter tags; standard values: action, adventure, animation, comedy, drama, fantasy, fiction, horror, mystery, non-fiction, romance, sci-fi, thriller
  • translations β€” manually curated only; never auto-generated

API responses include language, originalLanguage, and isTranslated so consumers always know whether they received a translation or the original.


REST API Endpoints

All endpoints accept an optional lang query parameter (ISO 639-1) to request a specific language. Responses always include language, originalLanguage, and isTranslated so consumers know whether they received a translation or the original. See docs/localisation.md for details.

See docs/api-endpoints.md for the full endpoint reference β€” every route, its query parameters, and a description of its behavior. For an interactive, always-current view of the same API on a running instance, use the Scalar reference at /scalar/v1 or the raw OpenAPI spec at /openapi/v1.json.

The web UI includes a language selector in the navbar. It overrides the browser's automatic language detection (English, Deutsch, Nederlands) and persists the choice as a cookie for one year. Selecting "Auto-detect" clears the override and returns to browser language detection.


Home Assistant Add-on

Quotinator can be installed directly as a Home Assistant add-on. Click the button below to open your Home Assistant instance's app store with this repository pre-filled:

Open your Home Assistant instance and show the app store with this repository pre-filled.

Then find Quotinator (stable) or Quotinator (BETA) in the store and click Install β€” both are independently installable, published from the same repository and image. See addon/DOCS.md for configuration options once installed (identical for both channels).

Docker

docker run -d \
  -p 8080:8080 \
  -v ./data:/data \
  -e Quotinator__DataDir=/data \
  ghcr.io/dutchjafo/quotinator:latest

A docker-compose.yml example is included in the docker/ directory.

Data directory

Always mount the persistent volume at /data and set Quotinator__DataDir=/data β€” never mount it at /app/data. Bundled quote sources are baked into the image at /app/data/sources/, and standalone Docker's data-directory default (when Quotinator__DataDir is unset) is that same /app/data path. Mounting a volume there hides the bundled sources under whatever is on the host (usually nothing on a first run), so the app starts with no quotes at all. See docs/docker.md for details.

The volume at /data contains everything Quotinator persists across restarts:

Path Purpose Safe to delete?
quotinatordata.db SQLite database β€” the live data store No β€” this is your data
backups/ Pre-migration database snapshots, named quotinatordata_v{N}_{timestamp}Z.db Yes β€” old backups can be pruned freely
keys/ ASP.NET Core Data Protection keys β€” used to sign antiforgery tokens and Blazor session descriptors No β€” deleting this invalidates all active browser sessions; the app recovers on restart but users will need to reload

Note: Authentication is not yet implemented. The API is read-only and requires no credentials.

HTTPS / SSL

SSL is disabled by default. To enable HTTPS on port 8080, mount a certificate and key and pass the paths via environment variables:

docker run -d \
  -p 8080:8080 \
  -v ./data:/data \
  -e Quotinator__DataDir=/data \
  -v ./certs:/ssl:ro \
  -e Quotinator__Ssl=true \
  -e Quotinator__SslCertFile=/ssl/fullchain.pem \
  -e Quotinator__SslKeyFile=/ssl/privkey.pem \
  ghcr.io/dutchjafo/quotinator:latest

When running behind a reverse proxy (NGINX, Caddy, Traefik) that terminates TLS, leave Quotinator__Ssl=false β€” the app reads X-Forwarded-Proto and sets cookies correctly.


Development Setup

Prerequisites

  • .NET 10 SDK
  • Docker Desktop (optional, for container testing)

Run locally

git clone https://github.com/DutchJaFO/Quotinator.git
cd quotinator
dotnet run --project src/Quotinator.Api

The API will be available at https://localhost:7028. See docs/running-locally.md for all available URLs.


Roadmap

Upcoming work is tracked in GitHub Milestones.


Changelog

See CHANGELOG.md for the full release history.


License

MIT. See LICENSE for details. Quote data attribution: see SOURCES.md.

About

I'll be back... with a quote.

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages