Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copy to .env and set values for production.
# Never commit .env. The default compose password is fine for localhost ONLY.

POSTGRES_PASSWORD=change-me-to-a-long-random-string

# Comma-separated API keys. Empty + AUTH_DISABLED=false → all non-public endpoints return 401.
API_KEYS=

# Set AUTH_DISABLED=true to run without keys (local dev only).
AUTH_DISABLED=false

# Set to true only when you're behind a trusted reverse proxy (nginx, Traefik, ALB).
# Required for X-Forwarded-For to be honoured for rate-limit client IP detection.
TRUSTED_PROXY=false

# Model + translation (see README). Default is mock.
MODEL_PROVIDER=mock
TRANSLATION_PROVIDER=mock

# Do NOT enable in production. Silent mock fallback hides real outages.
MODEL_FALLBACK_ON_ERROR=false
48 changes: 48 additions & 0 deletions COOKIES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Cookie policy

Last updated: 2026-04-16

## Short version

At the time of this writing, **self-hosted Accessibility Lite sets no cookies by default**. The pages served by this server do not set tracking cookies, analytics cookies, or advertising cookies. The only time you will ever see a cookie from this service is if the operator of a deployment explicitly enables one of the categories below.

## Full version

### What a cookie is, in one sentence

A cookie is a small piece of text your browser stores on behalf of a site and sends back on future requests to that site. It is the mechanism behind sign-in, shopping carts, and a great deal of tracking.

### Cookies this service may set

The only cookies a standard deployment of this service should ever set are in the first two categories below. Anything else is the decision of whoever is operating your particular deployment.

1. **Strictly necessary (no consent required, cannot be disabled).**
- `session` — HttpOnly, Secure, SameSite=Lax. Keeps a signed-in operator signed in across requests. Only set after authentication. **Not present in the public open-source release; will appear when user accounts ship.**
- `csrf` — Protects state-changing HTML forms against cross-site request forgery. Paired with a matching header on submission. **Not present in the current release.**

2. **Functional (opt-in).**
- `ui_prefs` — Remembers your player UI choices (caption font size, high-contrast mode, preferred language). Not sent to any third party. Can be cleared from the player page.

3. **Analytics (opt-in, off by default).**
- If and only if the operator enables analytics, an anonymous identifier may be set with a 90-day lifetime. The identifier is not linked to your name, email, IP address, or any account. It is used only to count usage of features (e.g. "how many people downloaded a VTT file this week"). **Never shared with advertising networks. Never sold.**

4. **Advertising.**
- Never. This service does not support advertising cookies, never has, and never will in its open-source form.

### Consent and control

Under the EU ePrivacy Directive, UK PECR, and state laws in the US (e.g. California CCPA/CPRA, Colorado, Connecticut), analytics cookies require opt-in consent from residents of those jurisdictions. The hosted deployment of Accessibility Lite shows a consent banner the first time a visitor loads a page that would set an analytics cookie. Declining keeps the cookie off. Changing your mind is one click from the footer link "Cookie preferences".

Strictly-necessary cookies do not require consent and cannot be turned off without breaking sign-in.

### Third parties

A standard self-hosted Accessibility Lite deployment makes no outbound requests to third parties from the browser. If you have enabled an optional integration (Sentry, PostHog, DeepL, LibreTranslate), your browser may make requests that involve cookies or similar technologies operated by those vendors. Each of them publishes their own cookie policy.

### Changes to this policy

We'll note changes in the repository changelog and update the "last updated" date above.

### Contact

Open an issue at [github.com/dedmonwalkin/accessibility-lite](https://github.com/dedmonwalkin/accessibility-lite) or email the address in [SECURITY.md](SECURITY.md).
17 changes: 15 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
# node:20-alpine — pin by digest before shipping a release tag. Example:
# FROM node:20-alpine@sha256:<digest>
# Floating tags are accepted here during development only.
FROM node:20-alpine

RUN apk add --no-cache ffmpeg
RUN apk add --no-cache ffmpeg tini

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --omit=dev

COPY src/ src/
COPY README.md LIMITATIONS.md COOKIES.md PRIVACY.md SECURITY.md ./

RUN mkdir -p uploads
# Run as a non-root user. If an attacker ever achieves RCE via ffmpeg or
# Node, they do not have container root and cannot escalate to write
# outside the uploads volume.
RUN addgroup -S app && adduser -S app -G app \
&& mkdir -p uploads \
&& chown -R app:app /app uploads

USER app

EXPOSE 3000

# tini is PID 1 so SIGTERM / SIGINT reach Node for graceful shutdown.
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "src/server.js"]
57 changes: 57 additions & 0 deletions LIMITATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Limitations

Accessibility Lite is an open-source draft-assist tool. It automates the parts of media accessibility where automation is useful today, and it is explicit about the parts where automation is not. Please read this document before relying on any output for legal compliance or for users who depend on the output.

## What it does well

- **Captions from clear speech.** When the default provider is swapped for [whisper.cpp](https://github.com/ggerganov/whisper.cpp) (or a comparable Whisper deployment), word-error rates are typically in the 5–10% range for clean English speech and degrade predictably with noise, accent, overlapping speakers, and domain-specific vocabulary. That is good enough to *seed* a human captioning workflow and, in low-stakes contexts, good enough as-is.
- **Format fidelity.** WebVTT and TTML outputs conform to the spec well enough for major media players, LMS systems, and broadcast delivery platforms.
- **Translation.** With DeepL or LibreTranslate wired up, caption translation quality matches the underlying service. It is not better and not worse.
- **Self-hosting.** The pipeline runs entirely offline against whisper.cpp + Ollama + LibreTranslate with no outbound network traffic — a requirement for many EU public-sector buyers.

## What is *draft-quality* and requires human review

### Audio Description ("AD Draft Assist")

Vision-language models can produce a first-pass description of what is visible on screen during dialogue gaps. That is not the same as writing an audio description that works for a blind audience.

- Timing is approximate. The model does not know when dialogue will resume, so descriptions frequently overrun and talk over returning speech.
- Tone, voice, and narrative choice (what to describe, what to omit) are the craft of professional describers. Model output reliably fails on these.
- Blind users surveyed in public studies (AMI, RNIB) consistently reject generic LLM-produced AD when it is presented as finished product.

**How to use the AD output:** as the first draft a sighted describer polishes in a tool like YouDescribe or a professional describer reviews in Amara. The UI labels these outputs as drafts and the JSON download includes a `requires_human_review: true` field.

### Transcript quality on hard audio

Whisper degrades sharply on: heavy accents the model has not seen, whispered or shouted speech, sustained background noise, music under dialogue, and speaker overlap. If your content includes these, expect meaningful manual correction. The captions endpoint does not guarantee WCAG "equivalent" quality on adversarial audio.

### Simplified captions

The `caption_style: "simplified"` mode truncates and compresses per-segment text. It is intended for readers who find verbatim text fast-moving. It is **not** a plain-language adaptation in the technical sense (CEFR A2, Easy Read, Leichte Sprache). Do not market it as such.

## What is **not in this release**

### Sign language

Earlier drafts of this project included a "sign language overlay" feature generated from gloss tokens. We have removed it from the public surface for v0.2.

Gloss is a written linguistic annotation; it is not a sign language. Signing avatars driven by gloss or by English text have been opposed by the [World Federation of the Deaf and WASLI since 2018](https://wfdeaf.org/news/resources/wfd-wasli-statement-use-signing-avatars/) and by NAD, BDA, and EUD. Shipping avatar overlays labelled as "ASL / AUSLAN / LIBRAS / HKSL" that are in fact word-for-word transliterations of English is not accessibility — it is inaccessible output presented as accessibility, and the Deaf community has been clear that it causes harm.

If we revisit sign language in a future version, it will be:

1. Led by Deaf signers and a Deaf-led organization.
2. Using human-signed video clips, not generated avatars.
3. Scoped to a small number of languages at a time, curated in partnership with that community.
4. Marketed honestly.

We will not ship avatar-based sign output before then. If you fork the project and add it back, please read the WFD statement first.

## Compliance note

Nothing in this repository is legal advice. Accessibility Lite can *help* you meet WCAG 2.2 A captions (Success Criterion 1.2.2) and AA audio description (Success Criterion 1.2.5) obligations when combined with appropriate human review. It does not by itself make a site or service conformant, and it does not produce outputs that should be labelled as "WCAG AA captions" without the review step for anything beyond the lowest-stakes content.

For EU buyers subject to EN 301 549 or the European Accessibility Act: use outputs as drafts and keep the human-in-the-loop step in your procurement requirement.

## Reporting problems with outputs

If an output is actively harmful — mistranscribed in a way that changes meaning, or describes a scene in a way that misleads a blind listener — please open an issue labelled `output-quality` with the input source (if you can share it) and the output. These reports directly inform provider configuration defaults.
52 changes: 52 additions & 0 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Privacy notice

Last updated: 2026-04-16

This notice describes how a deployment of Accessibility Lite handles personal data. This file is a template; the operator of the specific deployment you are using may publish their own version. Always check the `/privacy` page of the site you are actually using.

## Who is the controller

You are reading this from a self-hostable, open-source project. When you upload a file to a hosted deployment, the **operator of that deployment** is the data controller. The original authors of this project ([Isabella & Tan](https://github.com/dedmonwalkin)) are not controllers of any data you submit to a third-party deployment. The authors are controllers only of the data submitted directly to deployments we operate, if and when any exist.

## What we process and why

| Category | Purpose | Legal basis (GDPR) | Retention |
|---|---|---|---|
| Uploaded media (video/audio) | Transcription, description, caption generation | Contract / consent | Default 24 hours, then deleted |
| Transcripts & derived captions | Deliver the output you asked for | Contract / consent | Same as uploaded media |
| API key (if configured) | Authenticate requests | Contract / legitimate interests | Until revoked |
| Request IP | Rate limiting, abuse prevention | Legitimate interests | Rolling 60-second window in memory; not persisted |
| Audit log (operation, timestamp, job id) | Debugging, support | Legitimate interests | Same as job retention |
| Anonymous analytics (if operator enables) | Improve the product | Consent | 90 days |

**What we do not process:** We do not sell personal data. We do not transmit your media to advertising networks. We do not share your content with model vendors beyond the inference step you configured.

## Your rights

If you are in the EU / UK: you have the right to access, rectify, erase, restrict, port, and object. Contact the operator of the deployment you are using. If they do not respond, you can lodge a complaint with your data protection authority.

If you are in California: you have the right to know, delete, correct, and opt out of any sale or share. We do not sell or share in the CCPA sense.

## International transfers

A self-hosted deployment that runs entirely locally performs no international transfer of your data. A hosted deployment may. Any hosted deployment we offer will publish its transfer basis (Standard Contractual Clauses and a transfer impact assessment for EU transfers).

## Subprocessors

A standard self-hosted deployment has no subprocessors. A hosted deployment, if offered, will publish its subprocessor list here and notify users before adding new ones.

## Children

This service is not directed at children under 16. Do not upload media of children unless you have parental consent and a lawful basis for processing.

## Security

See [SECURITY.md](SECURITY.md) for our responsible-disclosure process and for the technical measures in place.

## Changes

Material changes are announced in the repository changelog with a minimum 30-day notice for the hosted tier.

## Contact

Open an issue at [github.com/dedmonwalkin/accessibility-lite](https://github.com/dedmonwalkin/accessibility-lite) for general questions. Use the contact in [SECURITY.md](SECURITY.md) for anything sensitive.
Loading