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. Uor 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 listcollapses 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
Ratingcolumn. - 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. |