88 lines
3.9 KiB
Markdown
88 lines
3.9 KiB
Markdown
# 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. |
|