Files
letterboxd-rating-sorter/README.md
2026-09-22 23:01:56 +02:00

3.9 KiB

Letterboxd Pairwise Ranker

Turns a Letterboxd ratings.csv export into a ranked order by asking you to pick between two films at a time, then converts that order back into 0.5-5 star ratings.

Normal use

Double-click Rank films.cmd.

The page opens in your browser. Drop your ratings.csv on it and start picking. Box art is fetched for you in the background and cached in posters.json, so later runs are instant. Closing the console window stops the server.

Rankings you have started are listed under the drop zone as Continue where you left off, with their film count, progress and when you last answered something. Continuing needs no csv: the session stores each film's original row, so it can also export a correct file on its own. Delete forgets one. Note that a saved session holds the film list from the export you dropped at the time - to include films watched since, drop a fresh csv and start a new one.

Needs python on your PATH; the launcher says so if it is missing. Same thing from a terminal, if you prefer:

python serve.py

Without the server

ranker.html also opens straight from disk by double-click. It cannot fetch box art on its own, because a browser blocks a file:// page from calling letterboxd.com. Resolve the posters first, then drop both files on the page:

python fetch_posters.py path/to/ratings.csv

--retry-failed retries the URIs that came back empty last time.

Ranking

Bottom-up merge sort, so the number of questions stays near the minimum: about 25 for 10 films, 90 for 25, 1,310 for 200. No ties, every pair has a winner.

Each round merges pairs of groups, and the groups take turns, so consecutive questions normally show two films you have not just seen. The exception is the last couple of rounds, where only one or two groups are left and a film has to be held against several opponents in a row to find its place.

  • Click a poster, or press 1 / 2, or the arrow keys.
  • U or Backspace undoes.
  • The panel on the right shows everything established so far: each ordered group, best at the top, with a dashed break wherever the order across it is still unknown. The two films on screen are highlighted in place. Films you have not been asked about yet are left out, so it starts at just the current pair and fills in as you go. Hide list collapses it, and it stays collapsed.
  • Progress is saved after every answer, keyed to the film set. Close the tab and the page offers to resume where you left off. A different export starts its own session.

Dark by default. The button in the top right switches to light and remembers the choice. The system theme is ignored on purpose.

Progress lives in browser storage for 127.0.0.1:8791, so it is tied to that browser and that port. Clearing site data for it, or running on a different port with --port, means no resume. If 8791 is ever busy the server moves up and says so.

Stars and export

When the order is complete, the result screen splits it into the ten half-star bands. Set how many films land in each band with the + / - buttons or by typing a count, or use a preset:

  • Match old ratings keeps the shape of your existing ratings, so only which film sits where changes. This is the default when the export has a Rating column.
  • Even split and Top heavy are starting points to adjust from.

Download rated CSV writes your export back out unchanged - same header, same columns, Date included - in ranking order, with Rating replaced by the new star value.

Files

File What it is
Rank films.cmd Double-click launcher. Runs python serve.py.
ranker.html The whole app. No dependencies, no build step.
serve.py Serves the page and resolves posters on its behalf.
fetch_posters.py Standalone poster resolver, also the module serve.py uses.
posters.json Poster URL cache. Safe to delete, it rebuilds.
sample.csv Eight rows for a quick smoke test.