Repository navigation
Releases
v5.0.0
5.0.0
Cinemory learns which episodes of a series you have actually watched, lets
you pin what you are in the middle of, and gives Add title more to choose
from. Five pull requests since 4.0.0.
Updating from 4.0.0 needs one step on the database — see the bottom.
Episodes, not just seasons
Adding a series as watched, or editing one already in the catalog, now
shows its seasons from TMDB: how many episodes each has, the year, and how
many are out so far. Open a season to see its episodes with their title,
runtime, air date and a short synopsis.
- Ticking a season ticks it and every season before it.
- Ticking an episode ticks everything before it as well.
- Unticking clears only what you clicked, and Clear asks before
unticking the lot. - Episodes that have not aired yet cannot be ticked.
The season count on the card now follows from the episodes: a season counts
once everything released in it is watched. The card also says how far you
got, for example "2 of 5 seasons · S3 · E4". Series already tracked by season
open with those seasons ticked, so nothing recorded is lost, and the −/+ on
a card keeps the episodes in step.
Picking episodes is optional: a series added without any works as before.
Pin what you are watching
Right-click a card (or long-press on a phone) and choose Pin. Pinned
titles stay at the top of Watched or To watch whatever the sort,
most recently pinned first, and carry a small pin in the top-right corner.
Unpin from the same menu.
More in Add title
Popular now and New releases now hold up to 30 titles each, in rows
that scroll sideways: six at a time on a wide screen, with the mouse wheel,
the trackpad or a swipe.
Fixes
- The selection ring on a suggestion poster is no longer clipped by its row.
- A confirmation opened over another dialog answers Escape and keeps the
keyboard on its own, without closing the dialog underneath.
Under the hood
- 252 tests, with new coverage for the episode rules and for pinning.
- Backups and restores carry the watched episodes and the pin.
- The package version is
5.0.0.
Updating from 4.0.0
Run npm install after updating the checkout.
This release adds two columns. In the Turso SQL console, run:
ALTER TABLE "Title" ADD COLUMN "watchedEpisodes" TEXT;
ALTER TABLE "Title" ADD COLUMN "pinnedAt" DATETIME;Or, with the repository checked out and the two Turso values in a .env:
npm run db:migrate-tursoThe migration command is safe to re-run. Apply the migration before the
new code goes live: the app expects the columns to exist.
v4.0.0
4.0.0
Cinemory gives each title a proper details view, learns to search by
description, and keeps browsing your catalog separate from finding something
new. Twenty-one commits since 3.0.0.
Updating from 3.0.0 needs one step on the database — see the bottom.
A closer look at a title
A title now has a details view: a poster and header above a reading column,
with the description, ratings, viewing information and links together.
Cast, directors, creators and writers are fetched from TMDB when you open
it. Missing credits are left out rather than turned into empty rows.
Search what you have
The search in both Watched and To watch now filters that part of your
saved catalog. Searching the watchlist used to browse TMDB instead, which
made it hard to find something you had already saved.
An Add title card carries what you typed into TMDB search when you want
to look beyond the catalog.
Search by description
When a title search finds nothing, a local semantic search can look through
saved descriptions, genres, years, types and platforms. Try “melancholy
movies set in space” rather than remembering the name.
It uses words and small groups of related concepts in English and Italian,
runs inside Cinemory, and needs no AI key. Its results depend on the metadata
already saved with your titles. Claude remains an optional deeper fallback.
More to find in Add title
- Popular now and New releases give you somewhere to start before
you type. - Opening Add title from Watched or To watch selects that destination
for you. The navigation bar’s + leaves the choice open. - Suggestion rows scroll sideways on a phone and respond to the mouse wheel
on desktop.
Your name at the door
Setup now asks what Cinemory should call you, and the sign-in screen uses
that name. Change it later in Settings → Your name, or clear it to go
without.
Better on a phone
- Dialogs fit the screen and keep the page behind them still, without making
it disappear. - Opening a dialog on a touch screen no longer raises the keyboard before
you ask to type. - Cards reveal their information on tap where there is no hover.
- The sign-in screen, settings and tablet navigation make better use of
the available space.
Fixes
- Different works with the same name are handled more carefully across
imports, restores, recommendations and catalog writes. Matching uses the
TMDB ID together with movie or series type; titles without an ID use the
name, type and year, and ambiguous matches are left separate. - Streaming availability is cached by region, media type and TMDB ID,
with missing entries fetched in batches. - Failed catalog actions use a compact notification inside the app.
The persistent offline status returns after the message clears. - Dialog panels stay readable without depending on background blur,
and their close controls remain visible. - Missing posters have a Cinemory placeholder.
- Moving titles between Watched and To watch gets more consistent
pixel dissolve animations.
Under the hood
- Tests run against temporary SQLite databases, isolated from local and
hosted catalog data. - Added coverage for title identity, streaming providers and local semantic
search. - The package version and lockfile now agree on
4.0.0, and the MCP server
reads its version directly from the package.
Updating from 3.0.0
Run npm install after updating the checkout.
This release adds one column. In the Turso SQL console, run:
sql
ALTER TABLE "Settings" ADD COLUMN "displayName" TEXT NOT NULL DEFAULT '';
Or, with the repository checked out and the two Turso values in a .env:
sh
npm run db:migrate-turso
The migration command is safe to re-run. Apply the migration before
the new code goes live: the app expects the column to exist.
Existing installations start with an empty display name. Choose one in
Settings whenever you like; your saved titles stay as they are.
v3.0.0
3.0.0
Cinemory learns to talk to an assistant, to be read without a mouse, and to
show you where the things on your watchlist actually are. Fifty commits since
2.0.0.
Updating from 2.0.0 needs one step on the database — see the bottom.
An MCP connector
An assistant can now read this catalog during an ordinary chat: what you have
watched, what is waiting, and the numbers behind it — no pasting exports, no
guessing. Off until you switch it on in Settings, and revocable in a click.
- The credential travels in an
AuthorizationorX-API-Keyheader, or in the
URL for connectors that store nothing else. It is hashed at rest and shown
once. - A read-only token is the default. A write-capable one can add to the
watchlist, mark something watched, and correct where and when — never delete.
The scope is part of the hashed string, so it cannot be edited in the URL. - A missing or wrong credential gets
401with a challenge on the plain
address, and a plain404on the URL-with-token form, where the address is
the credential.
See docs/mcp.md.
Import from Letterboxd
The one export that knows more than the streaming services do: the release
year, your star rating, and the day you actually watched something rather than
the day you logged it. diary.csv, ratings.csv, watched.csv and
watchlist.csv are all read. Rewatches fold into one row, keeping the most
recent viewing.
Keep the file names Letterboxd gave them: watched.csv and watchlist.csv are
identical inside, and the name is the only thing that says which half of the
catalog a title belongs in.
Where to watch what is waiting
Every title in "To watch" now says where it is streaming right now in your
region, from TMDB. Asked a screenful at a time and remembered for half a day,
so a long watchlist costs one request rather than hundreds. Rentals and
purchases are left out — that is not an answer to what to watch tonight.
Restore a backup
The export has always written a full JSON dump and nothing could read it back.
Now Settings → Restore from a backup does: it adds the titles the catalog
does not have and leaves the rest alone, so it rebuilds an empty instance and
merges into a live one without overwriting anything.
A new sign-in screen
- Your own posters drift past in columns behind a glass card — the catalog is
recognisable before you are in, and does nothing until you are. A catalog
with fewer than 50 posters gets an animated terminal instead, and Settings
→ Sign-in screen forces either. - The code is six boxes, one per digit, and submits itself on the sixth.
- Sign out, which was not possible before: it clears the session and the
offline copy of the catalog with it. - Use a different authenticator — a new phone, a lost one, a QR code that
was photographed. It asks for a code from the authenticator in use before it
will hand out a new secret, and writes nothing until a code from the new app
comes back.
Offline, and saying so
Browsing without a network already worked; now the app admits it. A status line
says the catalog on screen is the saved copy, and writes that cannot reach the
database say so instead of failing silently.
Keyboard and screen readers
The grid was a pointer-only surface. Now:
Tabwalks the page (it used to be captured and sent to the search field on
every press, which left the cards, the filters and the settings link
unreachable without a mouse),/jumps to the search from anywhere.- A card takes focus, has a name, and answers to
Enter— which opens its
actions — andShift+Enter, which picks it out for a batch. - Dialogs keep the keyboard inside them and hand it back where it came from.
Also new
- Finish an interrupted import from Settings: a closed tab or a lost
connection used to leave the rest of the catalog without posters for good. - Search by words: every word has to appear, in any order — "wars empire"
finds The Empire Strikes Back — and typing a title with its accents works. - Marking something watched breaks the card into pixels on its way out, and
the same in reverse when it goes back to the watchlist. - Series seasons are edited from the dialog, with the total fetched from
TMDB rather than typed. - Setup moved out of the README into docs/, written to be
followable without a terminal, plus a security policy, contributing
guidelines and a code of conduct.
Fixes
- Missing posters showed nothing while there was plenty to fix: the filter
that skips "ignored" titles was written asNOT (tmdbId = -1), which in SQL
is null rather than true for a title TMDB never matched — so exactly the
titles that needed linking by hand were the ones hidden. - The genre filter answered confidently with nothing when the catalog held
no genres. - The genre and sort dropdowns could not be used in the desktop filter
panel: the panel closed on the way to an option and unmounted the list before
the click landed. - The sideways rows of platform pills would not move with a mouse wheel.
- The header turned into the compact layout at the width where the desktop
one stopped fitting, instead of wrapping onto two rows. - A date that is not a date is refused on the app's own write routes, not
only on the MCP ones:new Date("some time in 2021")is the first of January
2021, not an error. - The poster routes answer 404 rather than 500 when given an id that is not
there.
Under the hood
- 199 tests, up from 68. The API routes that write are covered now — every
test asserts the database did not move when a request was refused. - The catalog page is three times smaller: it only sends the columns the
grid reads. Measured on a 1,366-title catalog, 227 KB → 75 KB gzipped. - An error boundary, so a crash is a page with a way back rather than
Next's bare "Application error". docs/schema.sqlis generated from the migrations, and a test fails if it
goes stale — it is what someone with no checkout pastes into their database.- The code, its comments and the database schema are English throughout.
Updating from 2.0.0
npm install first: this release adds ogl, mcp-handler and the MCP SDK.
Two migrations landed since 2.0.0. If your database has neither, run both — in
the Turso SQL console:
ALTER TABLE "Settings" ADD COLUMN "mcpTokenHash" TEXT;
ALTER TABLE "Settings" ADD COLUMN "mcpTokenCreatedAt" DATETIME;
ALTER TABLE "Settings" ADD COLUMN "loginBackground" TEXT NOT NULL DEFAULT 'auto';Or, with the repository checked out and the two Turso values in a .env:
npm run db:migrate-turso, which is safe to re-run. Pasting
docs/schema.sql again works too: it stops harmlessly at what
already exists.
Do this before the new code goes live — until the columns are there, the
app errors on every page load. Nothing else is needed: your catalog is
untouched by this release.
v2.0.0
Cinemory 1.0 was a catalog of what you had already watched. 2.0 is about what
you watch next: Claude reads your catalog and suggests titles, the plain search
falls back to asking it in your own words, and a watchlist sits alongside the
watched half.
87 commits since v1.0.0.
Ask Claude
- Recommendations — suggestions based on your catalog, each with a reason,
refreshed automatically every 5 days and kept as history. Watch the trailer
from the suggestion, add it to the watchlist in one click, or say "not
interested" and it never comes back. Nothing you have already watched is ever
suggested. - Search with AI — when you cannot remember a title, describe it. "The long
fantasy trilogy about a ring" finds it. Offered whenever the plain search
comes up empty in Watched, and always in "To watch", where it searches all of
TMDB rather than only your catalog. - Both are optional and off unless
ANTHROPIC_API_KEYis set. A search costs
roughly 300 input tokens: the catalog is never sent to the model, which names
works from its own knowledge and is matched against your library locally.
A watchlist
- A Watched / To watch switch. In "To watch" the search browses all of TMDB,
hiding what you have already seen, and a click adds it. - Move titles either way: "Mark as watched" with an editable date, or back to
"To watch" from the context menu. - The AI suggestions appear there as a strip you can add from directly.
Statistics
A new page: how much you have watched and where, movies against series, top
genres, titles per year, which decades they come from, first and most recent on
record, and your best-rated titles.
Import
- One dialog per service. Pick where you are coming from and it shows what to
click, what the file should look like, and whether the titles land in your
watched half or in "To watch". - IMDb — your ratings export, now uploadable from the app rather than only
through a script. It is the only source that knows what you made of a title,
so your ratings come across with it. - Disney+ — Disney publishes no export and no API, so a bundled browser
script reads your watchlist page and saves a CSV. It runs in your own browser
and sends nothing anywhere. Watchlist only: a Disney+ watch history exists
solely inside Disney and needs a GDPR request. - Re-importing the same file still changes nothing.
Catalog
- Select several titles with shift-click and mark them watched, move them to
"To watch", or delete them together. - Genre filter, and platform and sort moved into a proper filter dropdown.
- New season available — series are checked automatically and flagged when
TMDB's count goes up. - Export the whole catalog as JSON from Settings, as a backup independent of
the database. - The grid now grows as you scroll instead of rendering everything at once. On a
2000-title catalog a long-press took 18.9s before and 0.96s after.
Mobile and PWA
- The long-press menu works on iOS and in the installed PWA — it no longer
vanishes on release, its items no longer ignore taps, and two fingers on two
posters open one menu rather than two. - Turn the phone sideways during a trailer and it fills the screen; everywhere
else stays portrait. - A bigger, glass watch-mode switch, haptic feedback on long-press where the
browser allows it, and no pinch-zoom on desktop either.
Polish
- Native
<select>dropdowns are gone: the list a native select opens belongs
to the operating system, so on a dark page it arrived as a white macOS menu or
a full-height iOS wheel. All eight are drawn now, with keyboard support intact. - Modals open with a short entrance instead of appearing in one frame, and the
blur behind a context menu carries over to the dialog it opens rather than
flashing. - Titles arrive in a quick wave as they come into view, on the first screen, on a
switch between halves, and on each batch scrolled to. - The settings page had drifted into four designs stacked up; every section now
shares one shape.
Upgrading
- Run the migrations. Four were added since 1.0:
2_recommendations,
3_recommendations_history,4_dismissed_recommendationsand
5_new_season_check. Docker applies them on start. On Turso run
npm run db:migrate-tursobefore deploying —prisma migrate deploytalks to
a SQLite file, not to Turso. ANTHROPIC_API_KEYis new and optional. Without it the app behaves as it
did in 1.0; the AI features simply do not appear.- The "Deploy with Vercel" button is gone from the README. The Vercel + Turso
instructions are unchanged — import the repository and set the four variables.
Nothing else needs changing: no existing variable was renamed, and the schema
additions default for rows already in your catalog.
v1.0.0
First tagged release. Cinemory has grown from a personal script into a complete, documented, self-hostable app.
Highlights
- First-run setup wizard — no
TOTP_SECRETenv var to generate up front: pick your TMDB content language/region and scan a QR code into your authenticator app, right from the browser. - Import from Netflix, Prime Video and IMDb — incremental, deduplicated import from your watch-history exports, enriched with posters/ratings/genres from TMDB.
- Season tracking — series show "3 of 5 seasons" instead of raw episode counts, editable by hand.
- Right-click / long-press menu — Edit or Delete a title directly from its card, with a proper confirmation dialog.
- Installable PWA — offline fallback, cached posters, iOS splash screens.
- Two deploy paths — Docker (self-hosted SQLite) or Vercel + Turso, with a one-click "Deploy with Vercel" button.
- AGPLv3 licensed.