lichess-study-to-pdf 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lichess_study_to_pdf-0.1.0/LICENSE +21 -0
- lichess_study_to_pdf-0.1.0/PKG-INFO +546 -0
- lichess_study_to_pdf-0.1.0/README.md +507 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/__init__.py +3 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/cli.py +354 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/evals.py +418 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/fetch.py +343 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/fonts.py +153 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/notation.py +147 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/parse.py +329 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/paths.py +82 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/pdf.py +1082 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/pdf_acrobat.py +316 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/pdf_latex.py +520 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/render.py +188 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/server.py +552 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/sidelines.py +132 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/studies.py +195 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/web/app.js +1032 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/web/index.html +184 -0
- lichess_study_to_pdf-0.1.0/lichess_study_pdf/web/style.css +355 -0
- lichess_study_to_pdf-0.1.0/lichess_study_to_pdf.egg-info/PKG-INFO +546 -0
- lichess_study_to_pdf-0.1.0/lichess_study_to_pdf.egg-info/SOURCES.txt +28 -0
- lichess_study_to_pdf-0.1.0/lichess_study_to_pdf.egg-info/dependency_links.txt +1 -0
- lichess_study_to_pdf-0.1.0/lichess_study_to_pdf.egg-info/entry_points.txt +2 -0
- lichess_study_to_pdf-0.1.0/lichess_study_to_pdf.egg-info/requires.txt +12 -0
- lichess_study_to_pdf-0.1.0/lichess_study_to_pdf.egg-info/top_level.txt +1 -0
- lichess_study_to_pdf-0.1.0/pyproject.toml +56 -0
- lichess_study_to_pdf-0.1.0/setup.cfg +4 -0
- lichess_study_to_pdf-0.1.0/tests/test_study.py +609 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shubhro Dev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lichess-study-to-pdf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn a Lichess study into a PDF you can step through move by move.
|
|
5
|
+
Author-email: Shubhro Dev <shubhro2004@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/spearb0lt/Lichess-Essentials
|
|
8
|
+
Project-URL: Repository, https://github.com/spearb0lt/Lichess-Essentials
|
|
9
|
+
Project-URL: Issues, https://github.com/spearb0lt/Lichess-Essentials/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/spearb0lt/Lichess-Essentials/blob/main/Lichess-Study-to-PDF/README.md
|
|
11
|
+
Keywords: chess,lichess,study,pdf,pgn,export,printable
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Framework :: FastAPI
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Games/Entertainment :: Board Games
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: chess>=1.11
|
|
28
|
+
Requires-Dist: reportlab>=4.0
|
|
29
|
+
Requires-Dist: svglib>=1.5
|
|
30
|
+
Requires-Dist: pikepdf>=8.0
|
|
31
|
+
Requires-Dist: requests>=2.31
|
|
32
|
+
Requires-Dist: fastapi>=0.110
|
|
33
|
+
Requires-Dist: uvicorn[standard]>=0.27
|
|
34
|
+
Requires-Dist: pydantic>=2.0
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pypdfium2>=4.0; extra == "dev"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# Lichess Study to PDF
|
|
41
|
+
|
|
42
|
+
[](https://pypi.org/project/lichess-study-to-pdf/)
|
|
43
|
+
[](https://pypi.org/project/lichess-study-to-pdf/)
|
|
44
|
+
[](https://pepy.tech/project/lichess-study-to-pdf)
|
|
45
|
+
[](https://pepy.tech/project/lichess-study-to-pdf)
|
|
46
|
+
[](LICENSE)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
Turn a Lichess study into a PDF worth reading, plus a browser interface for
|
|
50
|
+
working through it first.
|
|
51
|
+
|
|
52
|
+
Everything in the study makes it into the export: main line, sidelines nested
|
|
53
|
+
to any depth, comments, NAG symbols (`!`, `?!`, `□`), and the coloured square
|
|
54
|
+
markers and arrows Lichess stores in the PGN.
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install lichess-study-to-pdf
|
|
64
|
+
lichess-study-pdf serve
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or take all five at once with `pip install lichess-essentials`. Installed this
|
|
68
|
+
way your files live in the usual per-user folder for your platform, and the
|
|
69
|
+
app prints the path in its startup banner. To run it from a checkout instead,
|
|
70
|
+
see [the repository README](https://github.com/spearb0lt/Lichess-Essentials/blob/main/README.md#setup-from-a-checkout).
|
|
71
|
+
|
|
72
|
+
## Running the app
|
|
73
|
+
|
|
74
|
+
### Step 1 — set up, once
|
|
75
|
+
|
|
76
|
+
The virtualenv lives at the **repository root**, one level above this folder,
|
|
77
|
+
and is shared by every app in the repo.
|
|
78
|
+
|
|
79
|
+
<details open>
|
|
80
|
+
<summary><b>Windows (PowerShell)</b></summary>
|
|
81
|
+
|
|
82
|
+
```powershell
|
|
83
|
+
cd "C:\Users\<you>\Documents\GitHub\Lichess-Essentials"
|
|
84
|
+
python -m venv .lichess
|
|
85
|
+
.\.lichess\Scripts\python.exe -m pip install -r Lichess-Study-to-PDF\requirements.txt
|
|
86
|
+
```
|
|
87
|
+
</details>
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary><b>Windows (Git Bash) / macOS / Linux</b></summary>
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cd ~/Documents/GitHub/Lichess-Essentials
|
|
94
|
+
python -m venv .lichess
|
|
95
|
+
|
|
96
|
+
# Git Bash on Windows
|
|
97
|
+
./.lichess/Scripts/python.exe -m pip install -r Lichess-Study-to-PDF/requirements.txt
|
|
98
|
+
|
|
99
|
+
# macOS / Linux
|
|
100
|
+
./.lichess/bin/python -m pip install -r Lichess-Study-to-PDF/requirements.txt
|
|
101
|
+
```
|
|
102
|
+
</details>
|
|
103
|
+
|
|
104
|
+
You only ever do this once.
|
|
105
|
+
|
|
106
|
+
### Step 2 — start the web app
|
|
107
|
+
|
|
108
|
+
**Run it from inside the `Lichess-Study-to-PDF` folder** — that is where the
|
|
109
|
+
`lichess_study_pdf` package lives, and Python needs to see it.
|
|
110
|
+
|
|
111
|
+
```powershell
|
|
112
|
+
# Windows PowerShell
|
|
113
|
+
cd "C:\Users\<you>\Documents\GitHub\Lichess-Essentials\Lichess-Study-to-PDF"
|
|
114
|
+
& "..\.lichess\Scripts\python.exe" -m lichess_study_pdf.cli serve
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Git Bash on Windows
|
|
119
|
+
cd ~/Documents/GitHub/Lichess-Essentials/Lichess-Study-to-PDF
|
|
120
|
+
../.lichess/Scripts/python.exe -m lichess_study_pdf.cli serve
|
|
121
|
+
|
|
122
|
+
# macOS / Linux
|
|
123
|
+
cd ~/Documents/GitHub/Lichess-Essentials/Lichess-Study-to-PDF
|
|
124
|
+
../.lichess/bin/python -m lichess_study_pdf.cli serve
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
You should see:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
Lichess Study to PDF is running.
|
|
131
|
+
Open http://127.0.0.1:8777 in your browser.
|
|
132
|
+
engine : ...\engine\stockfish-windows-x86-64-bmi2.exe
|
|
133
|
+
LaTeX : ...\MiKTeX\miktex\bin\x64\pdflatex.EXE
|
|
134
|
+
Press Ctrl+C to stop.
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Those two lines tell you what will work: no engine means blank eval bars, no
|
|
138
|
+
LaTeX means the book mode is greyed out. Neither stops the app running.
|
|
139
|
+
|
|
140
|
+
### Step 3 — use it
|
|
141
|
+
|
|
142
|
+
1. Open <http://127.0.0.1:8777>. It opens on **My studies** — your own list
|
|
143
|
+
of studies as clickable cards, named, so you can see what you are opening.
|
|
144
|
+
See [Your studies list](#your-studies-list) below.
|
|
145
|
+
2. Click one, or paste a study URL and press **Load study**.
|
|
146
|
+
For a **private** study, paste a *chapter* URL
|
|
147
|
+
(`https://lichess.org/study/i7hMEq7h/0KOpBPyc`) — every other chapter is
|
|
148
|
+
found automatically, no token needed. See the next section.
|
|
149
|
+
3. Click chapters on the left; step through with **Space**, the arrow keys, or
|
|
150
|
+
by **scrolling the mouse wheel over the board** — down goes forward, up goes
|
|
151
|
+
back, and either one stops the autoplay.
|
|
152
|
+
Click any move — including inside a sideline — to jump there.
|
|
153
|
+
Pick up a piece to play your own moves from that position.
|
|
154
|
+
4. **Export PDF** on the bottom left, choose a style, **Build PDF**.
|
|
155
|
+
|
|
156
|
+

|
|
157
|
+
|
|
158
|
+
Handy: `http://127.0.0.1:8777/?url=<study-url>` loads a study straight away,
|
|
159
|
+
so you can bookmark a study you open often.
|
|
160
|
+
|
|
161
|
+
### Your studies list
|
|
162
|
+
|
|
163
|
+

|
|
164
|
+
|
|
165
|
+
The home page is built from **`studies.txt`**, in this folder. One study per
|
|
166
|
+
line:
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
## Openings
|
|
170
|
+
Fried Liver Attack Full Guide | https://lichess.org/study/i7hMEq7h/T5rBUcOn
|
|
171
|
+
Anti-Sicilian Repertoire | https://lichess.org/study/UYLsUjvy
|
|
172
|
+
https://lichess.org/study/EY8AUyPd
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- `Name | URL` — the name is what the card says, the URL is what it opens.
|
|
176
|
+
- The name is optional: a bare URL works, the card just shows the study id.
|
|
177
|
+
- `## Something` starts a section, `#` starts a comment, blank lines are
|
|
178
|
+
ignored.
|
|
179
|
+
- A line that is neither a comment nor a study is reported under the list
|
|
180
|
+
rather than throwing the rest of it away, so one typo costs you nothing.
|
|
181
|
+
- Put a **chapter** URL in for a private study, as the Fried Liver line does:
|
|
182
|
+
that is what lets it open without a token.
|
|
183
|
+
|
|
184
|
+
Two ways to add to it:
|
|
185
|
+
|
|
186
|
+
- **Edit the file.** The page re-reads it on every refresh — no restart.
|
|
187
|
+
- **Press ☆ Save** in the header while a study is open. It appends the study
|
|
188
|
+
under a `## Saved from the app` section with its real name filled in.
|
|
189
|
+
Saving one twice does nothing.
|
|
190
|
+
|
|
191
|
+
`LICHESS_STUDIES_FILE=/some/other/path.txt` points the app at a different
|
|
192
|
+
list, if you would rather keep yours outside the repository.
|
|
193
|
+
|
|
194
|
+
There is no Lichess API for the studies you have *liked*, so the list cannot
|
|
195
|
+
be filled from your Lichess favourites automatically. What Lichess does expose
|
|
196
|
+
is every study belonging to an account (`/api/study/by/<username>`), so a list
|
|
197
|
+
of your own studies can be generated if you want one.
|
|
198
|
+
|
|
199
|
+
### Step 4 — stop it
|
|
200
|
+
|
|
201
|
+
`Ctrl+C` in the terminal you started it in.
|
|
202
|
+
|
|
203
|
+
### Other ports
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
... cli serve --port 8899 # if 8777 is taken
|
|
207
|
+
... cli serve --host 0.0.0.0 # reachable from other devices on your LAN
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`--host 0.0.0.0` exposes the app to your whole network and there is no
|
|
211
|
+
authentication — only do it on a network you trust.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Without the browser: straight to a PDF
|
|
216
|
+
|
|
217
|
+
Same folder, same interpreter, no server involved:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
cd Lichess-Study-to-PDF
|
|
221
|
+
|
|
222
|
+
# the default: twelve small boards to a page
|
|
223
|
+
../.lichess/Scripts/python.exe -m lichess_study_pdf.cli \
|
|
224
|
+
"https://lichess.org/study/i7hMEq7h/0KOpBPyc" -o repertoire.pdf
|
|
225
|
+
|
|
226
|
+
# a typeset chess book
|
|
227
|
+
../.lichess/Scripts/python.exe -m lichess_study_pdf.cli \
|
|
228
|
+
"https://lichess.org/study/i7hMEq7h/0KOpBPyc" --mode book -o book.pdf
|
|
229
|
+
|
|
230
|
+
# one big board per page, steps with the arrow keys
|
|
231
|
+
../.lichess/Scripts/python.exe -m lichess_study_pdf.cli \
|
|
232
|
+
"https://lichess.org/study/ByhlXnmM" --mode slideshow -o study.pdf
|
|
233
|
+
|
|
234
|
+
# what engine did it find?
|
|
235
|
+
../.lichess/Scripts/python.exe -m lichess_study_pdf.cli engine-info
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Full option list: `... cli export --help`, or the CLI reference further down.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## If something goes wrong
|
|
243
|
+
|
|
244
|
+
| Symptom | Cause and fix |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `No module named lichess_study_pdf` | You are in the wrong directory. `cd` into `Lichess-Study-to-PDF` first. |
|
|
247
|
+
| `Port 8777 is already in use` | The app is probably already running — open the browser, or `--port 8899`. |
|
|
248
|
+
| `No module named 'chess'` (or `fastapi`, `reportlab`, …) | You ran the system Python instead of the venv one. Use the full `..\.lichess\Scripts\python.exe` path. |
|
|
249
|
+
| Eval bars are blank | No Stockfish. Run `engine-info` and drop a binary in `engine/`. |
|
|
250
|
+
| Book mode greyed out | No `pdflatex`. Install MiKTeX or TeX Live, or use Slideshow. |
|
|
251
|
+
| `403 ... study is private` | Paste a **chapter** URL instead of the study URL, or supply a token. |
|
|
252
|
+
| PDF looks blank except the first position of each chapter | You exported in **Acrobat** mode. Re-export as Book or Slideshow. |
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Private studies work without a token
|
|
257
|
+
|
|
258
|
+
Lichess is inconsistent about study privacy, and this tool exploits that:
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
GET /api/study/<study>.pgn -> 403 for a private study
|
|
262
|
+
GET /api/study/<study>/<chapter>.pgn -> 200, full PGN, no token
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
The per-chapter endpoint does not enforce the study's privacy. So **paste a
|
|
266
|
+
chapter URL** and the whole study comes down:
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
https://lichess.org/study/i7hMEq7h <- 403, private
|
|
270
|
+
https://lichess.org/study/i7hMEq7h/0KOpBPyc <- works, and finds the other 12
|
|
271
|
+
chapters automatically
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
The chapter's own page lists every chapter in the study, so one chapter URL is
|
|
275
|
+
enough to rebuild all of it. Open your study on Lichess, click any chapter,
|
|
276
|
+
copy that address.
|
|
277
|
+
|
|
278
|
+
A token is still supported and is the documented route — create one with the
|
|
279
|
+
`study:read` scope at
|
|
280
|
+
<https://lichess.org/account/oauth/token/create?scopes[]=study:read>, then
|
|
281
|
+
`--token`, `LICHESS_TOKEN`, or `~/.lichess_token`.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## The four export styles
|
|
286
|
+
|
|
287
|
+
Every chapter starts on a fresh page in all of them, and every sideline is
|
|
288
|
+
given its own colour, so two alternatives to the same move never look alike.
|
|
289
|
+
|
|
290
|
+
Each colour arrives in three matching tones: a **bar** down the left edge of
|
|
291
|
+
the board or notation block, a mild **wash** behind it, and the **ink** of its
|
|
292
|
+
moves. Numbering is chapter-wide — a branch point hands its alternatives a
|
|
293
|
+
consecutive run of colours (which the palette spaces ~105° apart on the wheel),
|
|
294
|
+
and a sideline nested inside another gets one of its own, so nothing that a
|
|
295
|
+
reader sees at once shares a colour. The palette holds 24; after that colours
|
|
296
|
+
repeat, which only ever affects sidelines pages apart.
|
|
297
|
+
|
|
298
|
+
Every sideline also carries its number — `s1`, `s2`, … printed where it opens,
|
|
299
|
+
in the grid cell, in the breadcrumb — so the colour has a name. That, the bar,
|
|
300
|
+
the indent and the depth dots are all shape rather than hue, which is what
|
|
301
|
+
keeps nesting and identity readable in a greyscale print or for a colour-blind
|
|
302
|
+
reader. Grid pages carry a legend of the sidelines shown on them along the
|
|
303
|
+
footer.
|
|
304
|
+
|
|
305
|
+

|
|
306
|
+
|
|
307
|
+
### `--mode grid` (default) — twelve boards to a page
|
|
308
|
+
|
|
309
|
+
A contact sheet: every position gets its own diagram, twelve to a page, in
|
|
310
|
+
reading order, each with its move, evaluation and comment underneath. Same
|
|
311
|
+
coverage as the slideshow with a twelfth of the diagram pages — measured on a
|
|
312
|
+
237-position study, 20 pages instead of 237.
|
|
313
|
+
|
|
314
|
+

|
|
315
|
+
|
|
316
|
+
Comments are trimmed to two lines in a grid cell; the notation section, which
|
|
317
|
+
is on by default, still carries every comment in full.
|
|
318
|
+
|
|
319
|
+
Two things that make a page hold fewer than twelve:
|
|
320
|
+
|
|
321
|
+
* **Short chapters.** Chapters always start on a fresh page, so a chapter with
|
|
322
|
+
six positions gets a page with six boards. That is the direct cost of the
|
|
323
|
+
one-chapter-per-page rule.
|
|
324
|
+
* **The notation section.** It is a separate, text-only section — it does not
|
|
325
|
+
put boards on its pages in grid mode, because the grid already shows every
|
|
326
|
+
position. `--no-notation` drops it entirely if you only want diagrams.
|
|
327
|
+
|
|
328
|
+
`--diagrams` controls diagrams *inside the notation section* only, never the
|
|
329
|
+
grid. It defaults to automatic: `none` in grid mode, `every:6` elsewhere.
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
--grid-columns 4 --grid-rows 3 # the default 12 per page
|
|
333
|
+
--grid-columns 3 --grid-rows 2 # 6 bigger boards per page
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### `--mode book` — a typeset chess book
|
|
337
|
+
|
|
338
|
+
Compiled with LaTeX (`xskak` + `chessboard`): portrait, two columns,
|
|
339
|
+
justified Computer Modern, figurine notation (`♘f3`), printed-book diagrams
|
|
340
|
+
with hatched squares and a side-to-move marker, arrows and circles from the
|
|
341
|
+
study's own annotations, and optional `[+0.42]` evaluations beside each move.
|
|
342
|
+
|
|
343
|
+
A 13-chapter study lands in about 16 pages. This is the mode to use for
|
|
344
|
+
reading and printing.
|
|
345
|
+
|
|
346
|
+

|
|
347
|
+
|
|
348
|
+
Needs `pdflatex` (MiKTeX or TeX Live) with `xskak`, `chessboard`, `skak`.
|
|
349
|
+
Without it the mode is disabled in the UI and the CLI says so.
|
|
350
|
+
|
|
351
|
+
### `--mode slideshow` — one big board per page
|
|
352
|
+
|
|
353
|
+
One position per page, so your reader's ordinary next-page key — space,
|
|
354
|
+
arrow, PageDown, a presentation remote, a tap on a phone — steps the board
|
|
355
|
+
forward one move. No scripting, so it behaves identically in every viewer.
|
|
356
|
+
|
|
357
|
+
Each page carries the board, the eval bar, the current line with the move
|
|
358
|
+
boxed, upcoming moves greyed ahead of it, and the comment. It is long by
|
|
359
|
+
nature — use `grid` unless you specifically want to step move by move.
|
|
360
|
+
|
|
361
|
+
### `--mode acrobat` — layered, Adobe Reader only
|
|
362
|
+
|
|
363
|
+
Each chapter is a single page holding every position as a PDF optional-content
|
|
364
|
+
layer, switched by embedded JavaScript.
|
|
365
|
+
|
|
366
|
+
**Only Adobe Acrobat Reader executes PDF JavaScript.** Everywhere else you see
|
|
367
|
+
the first position of each chapter and the buttons do nothing. The file now
|
|
368
|
+
carries a full-page warning saying exactly that, because this mode is easy to
|
|
369
|
+
pick by accident and the result looks broken rather than limited.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Evaluation bars
|
|
374
|
+
|
|
375
|
+
Two sources, in order:
|
|
376
|
+
|
|
377
|
+
1. **Lichess cloud eval** — instant, but only for positions already in its
|
|
378
|
+
cache (in practice, openings), and **firmly rate limited**: a few hundred
|
|
379
|
+
lookups earns a `429` that lasts minutes. So the cloud is only asked about
|
|
380
|
+
positions up to move 20, paced about a second apart, and a `429` is
|
|
381
|
+
recorded and skipped rather than waited on. It never blocks the UI.
|
|
382
|
+
2. **Local Stockfish** — full coverage, and what actually evaluates a personal
|
|
383
|
+
repertoire.
|
|
384
|
+
|
|
385
|
+
Put a Stockfish binary in `engine/`, on `PATH`, or at `$STOCKFISH_PATH`;
|
|
386
|
+
`engine-info` tells you what it found. Results are cached in
|
|
387
|
+
`~/.cache/lichess-study-pdf/evals.json`, keyed so cloud results are reused
|
|
388
|
+
regardless of engine settings.
|
|
389
|
+
|
|
390
|
+
**Export evaluations are computed on the server** for every position being
|
|
391
|
+
exported. Earlier versions shipped whatever the browser happened to have,
|
|
392
|
+
which meant most positions came out blank — that is fixed. Expect roughly
|
|
393
|
+
30 s for a 240-position study.
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## The web interface
|
|
398
|
+
|
|
399
|
+
Modelled on [chesspaper.me](https://chesspaper.me/), with the gaps filled in:
|
|
400
|
+
|
|
401
|
+
| | chesspaper.me | this |
|
|
402
|
+
|---|---|---|
|
|
403
|
+
| Sidelines and comments | need per-node toggling | all visible from the start |
|
|
404
|
+
| Board stepping | no next control | **Space / arrow keys / Next button** |
|
|
405
|
+
| Which line you step | — | follows whichever line you clicked into |
|
|
406
|
+
| Eval bar | — | live for the position you are on, ~150 ms |
|
|
407
|
+
| Play your own moves | — | pick any piece up, from any position |
|
|
408
|
+
| Diagrams in the PDF | manual toggle per node | one setting for the whole study |
|
|
409
|
+
|
|
410
|
+
**Free play.** Click a piece and its legal moves light up; click a destination
|
|
411
|
+
and you are off the study line, with a banner telling you how many moves deep
|
|
412
|
+
you are and a button back. Evaluations keep coming for every move you invent.
|
|
413
|
+
Left arrow takes back, Escape returns to the line. Legality is checked
|
|
414
|
+
server-side by python-chess, so there is no chess library in the browser.
|
|
415
|
+
|
|
416
|
+
**Hover preview.** Hovering any move in the notation pops up a small board of
|
|
417
|
+
that position, so you can scan a sideline without leaving where you are.
|
|
418
|
+
|
|
419
|
+
Keyboard: `Space`/`→`/`↓` next, `←`/`↑` back, `Home`/`End` first/last,
|
|
420
|
+
`F` flip, `P` autoplay, `Esc` cancel selection or leave free play.
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## CLI reference
|
|
425
|
+
|
|
426
|
+
```
|
|
427
|
+
lichess-study-pdf <study-url|chapter-url> [options]
|
|
428
|
+
|
|
429
|
+
-o, --output PATH output file
|
|
430
|
+
--token TOKEN Lichess API token (study:read)
|
|
431
|
+
--pgn FILE read a local PGN instead of calling the API
|
|
432
|
+
--chapter-only with a chapter URL, export only that chapter
|
|
433
|
+
--save-pgn FILE also save the downloaded PGN
|
|
434
|
+
|
|
435
|
+
--mode MODE grid (default) | book | slideshow | acrobat
|
|
436
|
+
--grid-columns N boards across the page in grid mode (default 4)
|
|
437
|
+
--grid-rows N boards down the page in grid mode (default 3)
|
|
438
|
+
--latex PATH pdflatex binary for --mode book
|
|
439
|
+
--keep-tex PATH also write the generated .tex
|
|
440
|
+
--no-notation skip the read-through notation section
|
|
441
|
+
--no-steps skip the one-page-per-position section
|
|
442
|
+
--chapters SPEC subset, 1-based, e.g. 1,3,5-8
|
|
443
|
+
--max-depth N drop sidelines nested deeper than N
|
|
444
|
+
--diagrams POLICY none | comments | all | every:N (default every:6)
|
|
445
|
+
--page-size SIZE a4 | a3 | letter
|
|
446
|
+
--portrait portrait pages (book mode is always portrait)
|
|
447
|
+
|
|
448
|
+
--no-evals no evaluation bars
|
|
449
|
+
--no-cloud engine only, skip the Lichess cloud
|
|
450
|
+
--engine PATH Stockfish binary
|
|
451
|
+
--movetime SEC seconds per position (default 0.25)
|
|
452
|
+
--depth N fixed depth instead of a time budget
|
|
453
|
+
|
|
454
|
+
lichess-study-pdf serve [--host H] [--port P]
|
|
455
|
+
lichess-study-pdf engine-info
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## Hosting it for free
|
|
461
|
+
|
|
462
|
+
This is a plain FastAPI/Uvicorn app with one runtime dependency worth caring
|
|
463
|
+
about: Stockfish, invoked as a subprocess and kept warm for the life of the
|
|
464
|
+
process ([server.py](https://github.com/spearb0lt/Lichess-Essentials/blob/main/Lichess-Study-to-PDF/lichess_study_pdf/server.py)). That rules out anything
|
|
465
|
+
serverless (Vercel, AWS Lambda-style hosts) — you need something that runs a
|
|
466
|
+
real, long-lived container. Two that do it for free:
|
|
467
|
+
|
|
468
|
+
| | Hugging Face Spaces | Render.com |
|
|
469
|
+
|---|---|---|
|
|
470
|
+
| Cost | Free, no card required | Free tier — check current signup terms, this has changed before |
|
|
471
|
+
| Runtime | Docker | Docker |
|
|
472
|
+
| Idle behaviour | Sleeps, wakes on the next visit | Spins down after ~15 min idle; cold start on the next request |
|
|
473
|
+
|
|
474
|
+
[`Dockerfile`](https://github.com/spearb0lt/Lichess-Essentials/blob/main/Lichess-Study-to-PDF/Dockerfile) in this folder installs Stockfish via `apt-get`
|
|
475
|
+
(Debian's package, not a manual binary download) and deliberately skips
|
|
476
|
+
LaTeX — a full texlive install is several GB and not worth it unless you
|
|
477
|
+
specifically want book mode. It sets `STOCKFISH_PATH` to the apt package's
|
|
478
|
+
install location so `find_stockfish()` finds it without relying on `PATH`.
|
|
479
|
+
|
|
480
|
+
### Render
|
|
481
|
+
|
|
482
|
+
1. Push this repo to GitHub.
|
|
483
|
+
2. **New Web Service** → connect the repo → **Root Directory**:
|
|
484
|
+
`Lichess-Study-to-PDF` → Render auto-detects the Dockerfile → **Free**
|
|
485
|
+
instance type → deploy.
|
|
486
|
+
3. You get a URL like `https://<name>.onrender.com`.
|
|
487
|
+
|
|
488
|
+
### Hugging Face Spaces
|
|
489
|
+
|
|
490
|
+
Spaces are their own separate git repo (not this GitHub repo), so:
|
|
491
|
+
|
|
492
|
+
1. **New Space** → **SDK: Docker** → **Hardware: CPU basic (free)**.
|
|
493
|
+
2. Clone the Space's repo locally, then copy this folder's **contents**
|
|
494
|
+
(`Dockerfile`, `requirements.txt`, `lichess_study_pdf/`, etc.) into its
|
|
495
|
+
root — not the `Lichess-Study-to-PDF` folder itself, what's inside it.
|
|
496
|
+
3. Add this to the top of the Space's `README.md`:
|
|
497
|
+
```yaml
|
|
498
|
+
---
|
|
499
|
+
title: Lichess Study to PDF
|
|
500
|
+
sdk: docker
|
|
501
|
+
app_port: 7860
|
|
502
|
+
---
|
|
503
|
+
```
|
|
504
|
+
4. Commit and push (a Hugging Face access token as the git password).
|
|
505
|
+
|
|
506
|
+
### Before you make it public
|
|
507
|
+
|
|
508
|
+
- **Don't set `LICHESS_TOKEN` on a public deployment.** It would be shared by
|
|
509
|
+
every visitor — anyone with the URL could pull whatever private studies
|
|
510
|
+
that token can see. Leave it unset; paste a token into the UI per session
|
|
511
|
+
instead, the same as running it locally.
|
|
512
|
+
- There is no password wall here by default — anyone with the link can use
|
|
513
|
+
the tool (not access your Lichess account, just use the app). If you want
|
|
514
|
+
one, the sibling app has it wired up — see
|
|
515
|
+
[Repertoire Creator's hosting section](https://github.com/spearb0lt/Lichess-Essentials/blob/main/Repertoire-Creator/README.md#hosting-it-for-free)
|
|
516
|
+
for the pattern; it is not implemented in this app.
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## Layout
|
|
521
|
+
|
|
522
|
+
```
|
|
523
|
+
lichess_study_pdf/
|
|
524
|
+
fetch.py URL -> PGN, token handling, private-study chapter fallback
|
|
525
|
+
parse.py PGN -> chapters -> depth-first list of positions
|
|
526
|
+
notation.py notation blocks and move-tree helpers
|
|
527
|
+
render.py board SVG -> vector drawing, eval bar
|
|
528
|
+
fonts.py Unicode font resolution (□ ± ∞ would break Helvetica)
|
|
529
|
+
pdf.py grid + slideshow writers, title/contents/notation
|
|
530
|
+
pdf_latex.py the LaTeX chess book
|
|
531
|
+
pdf_acrobat.py optional-content layers + embedded JavaScript
|
|
532
|
+
evals.py cloud eval, Stockfish, non-blocking back-off, disk cache
|
|
533
|
+
cli.py command line
|
|
534
|
+
server.py FastAPI backend, warm engine singleton
|
|
535
|
+
web/ browser interface (no build step, plain JS)
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
`../.lichess/Scripts/python -m pytest tests -q` runs the suite. The test that
|
|
539
|
+
matters most replays every position's recorded line and asserts it reaches
|
|
540
|
+
that position's FEN — that is what guarantees no sideline is misattached.
|
|
541
|
+
|
|
542
|
+
## Licence
|
|
543
|
+
|
|
544
|
+
MIT. Chess piece artwork in the SVG boards comes from python-chess (Colin
|
|
545
|
+
M.L. Burnett's Cburnett set, CC BY-SA 3.0); the book mode's diagrams come from
|
|
546
|
+
the LaTeX `chessboard` package.
|