overleaf-comments-export 0.2.0__tar.gz → 0.4.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.
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/PKG-INFO +74 -11
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/README.md +72 -10
- overleaf_comments_export-0.4.0/overleaf_comments_export/__init__.py +8 -0
- overleaf_comments_export-0.4.0/overleaf_comments_export/__main__.py +239 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export/client.py +179 -19
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export/export.py +82 -14
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export/gui.py +159 -23
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export/render.py +120 -7
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export.egg-info/PKG-INFO +74 -11
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export.egg-info/SOURCES.txt +4 -1
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/pyproject.toml +6 -2
- overleaf_comments_export-0.4.0/tests/test_errors_and_auth.py +157 -0
- overleaf_comments_export-0.4.0/tests/test_replies_and_changes.py +156 -0
- overleaf_comments_export-0.4.0/tests/test_response_letter.py +111 -0
- overleaf_comments_export-0.2.0/overleaf_comments_export/__init__.py +0 -1
- overleaf_comments_export-0.2.0/overleaf_comments_export/__main__.py +0 -143
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/LICENSE +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export/anchors.py +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export/model.py +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export/sections.py +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export.egg-info/dependency_links.txt +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export.egg-info/entry_points.txt +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export.egg-info/requires.txt +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/overleaf_comments_export.egg-info/top_level.txt +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/setup.cfg +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/tests/test_anchors_sections.py +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/tests/test_client.py +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/tests/test_export.py +0 -0
- {overleaf_comments_export-0.2.0 → overleaf_comments_export-0.4.0}/tests/test_render.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: overleaf-comments-export
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Export comment threads and tracked changes from an Overleaf project to Markdown + JSON, optimized for AI-agent consumption.
|
|
5
5
|
Author: Shivang
|
|
6
6
|
License: MIT
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
23
|
Classifier: Topic :: Text Processing :: Markup :: LaTeX
|
|
23
24
|
Classifier: Topic :: Scientific/Engineering
|
|
24
25
|
Requires-Python: >=3.10
|
|
@@ -69,7 +70,13 @@ an Overleaf project URL and a logged-in browser session.
|
|
|
69
70
|
pip install overleaf-comments-export
|
|
70
71
|
```
|
|
71
72
|
|
|
72
|
-
Requires Python 3.10
|
|
73
|
+
Requires Python 3.10 or newer (tested up to 3.14). Works on macOS, Linux, and
|
|
74
|
+
Windows.
|
|
75
|
+
|
|
76
|
+
The graphical window needs Python's Tk toolkit, which most Linux distributions
|
|
77
|
+
package separately (`sudo apt install python3-tk` on Debian/Ubuntu). The
|
|
78
|
+
command line never needs it, and `--gui` tells you what to install if it is
|
|
79
|
+
missing.
|
|
73
80
|
|
|
74
81
|
## Quick start
|
|
75
82
|
|
|
@@ -104,6 +111,7 @@ In your output folder, by default:
|
|
|
104
111
|
| `comments.json` | Structured data — `summary`, top-level `threads`, `files`, `comments`, `tracked_changes`, etc. Schema described in `agents.md`. |
|
|
105
112
|
| `comments.jsonl` | One self-contained JSON record per comment for streaming/pipelines. |
|
|
106
113
|
| `agents.md` | A brief instruction file telling an AI agent how to consume the batch. |
|
|
114
|
+
| `response-letter.md` | (Optional, `--response-letter`) A point-by-point reply document, pre-filled with every open comment grouped by who raised it, with blanks for your response. |
|
|
107
115
|
| `by-reviewer/<name>.md` | (Optional, `--per-reviewer`) One Markdown per reviewer with only their threads. |
|
|
108
116
|
| `comments.log` | Diagnostic log for the run. |
|
|
109
117
|
|
|
@@ -121,6 +129,9 @@ overleaf-comments-export --project-url … --out ./out --render-mode detailed
|
|
|
121
129
|
|
|
122
130
|
# Per-reviewer sub-reports under ./out/by-reviewer/
|
|
123
131
|
overleaf-comments-export --project-url … --out ./out --per-reviewer
|
|
132
|
+
|
|
133
|
+
# Draft a point-by-point response letter for the open comments
|
|
134
|
+
overleaf-comments-export --project-url … --out ./out --response-letter
|
|
124
135
|
```
|
|
125
136
|
|
|
126
137
|
Full flag reference: `overleaf-comments-export --help`.
|
|
@@ -137,19 +148,71 @@ by browser on macOS:
|
|
|
137
148
|
| Chrome / Edge / Brave | Cookies are AES-encrypted with a Keychain-stored key; **you'll get a Keychain password prompt every run.** Hidden behind an opt-in in the GUI. |
|
|
138
149
|
|
|
139
150
|
On Windows, Chrome 127+ uses App-Bound Encryption that `browser-cookie3`
|
|
140
|
-
|
|
151
|
+
can't decrypt. On Linux, snap-packaged browsers sandbox their cookie stores.
|
|
141
152
|
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
**If reading the cookie from your browser fails, paste it instead** — this
|
|
154
|
+
works on every OS and browser:
|
|
144
155
|
|
|
145
|
-
|
|
156
|
+
```bash
|
|
157
|
+
overleaf-comments-export --project-url <url> --out ./out --cookie "PASTE_HERE"
|
|
158
|
+
```
|
|
146
159
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
Pull requests are welcome; issues may or may not be acted upon.
|
|
160
|
+
Or set it once: `export OVERLEAF_SESSION="PASTE_HERE"`. In the GUI, choose
|
|
161
|
+
**"Paste the cookie myself"** and click **How?** for step-by-step instructions.
|
|
150
162
|
|
|
151
|
-
|
|
152
|
-
|
|
163
|
+
To find it: open Overleaf, press F12, go to Application (or Storage) →
|
|
164
|
+
Cookies → `https://www.overleaf.com`, and copy the Value of `overleaf_session2`.
|
|
165
|
+
Treat it like a password; it stops working when you sign out.
|
|
166
|
+
|
|
167
|
+
## Troubleshooting
|
|
168
|
+
|
|
169
|
+
| What you see | What it means |
|
|
170
|
+
|---|---|
|
|
171
|
+
| "Could not look up www.overleaf.com" | This computer is offline, or a VPN/DNS problem. Not an Overleaf issue. |
|
|
172
|
+
| "Overleaf refused the request (not signed in)" | Your session expired. Sign in again in the browser, then re-run. |
|
|
173
|
+
| "Could not read Overleaf cookies from chrome" | Use the paste-the-cookie method above. |
|
|
174
|
+
| "Overleaf could not find that project" | Wrong link, or this account has no access. |
|
|
175
|
+
|
|
176
|
+
## Feedback, questions, and contributing
|
|
177
|
+
|
|
178
|
+
This tool is actively maintained, and feedback shapes what gets built next.
|
|
179
|
+
|
|
180
|
+
- **Something broke, or the output was wrong?**
|
|
181
|
+
[Open an issue.](https://github.com/Mangluu/overleaf-comments-export/issues/new/choose)
|
|
182
|
+
You do not need to be a programmer — paste what the tool said and that is
|
|
183
|
+
plenty. If Overleaf changes something, everything here stops working at once,
|
|
184
|
+
and you may be the first person to notice.
|
|
185
|
+
- **Want it to do something it doesn't?**
|
|
186
|
+
[Suggest a feature.](https://github.com/Mangluu/overleaf-comments-export/issues/new/choose)
|
|
187
|
+
Tell me what you are trying to do, not just the feature — the real task
|
|
188
|
+
usually leads somewhere better.
|
|
189
|
+
- **Just a question, or want to show what you built with it?**
|
|
190
|
+
[Discussions.](https://github.com/Mangluu/overleaf-comments-export/discussions)
|
|
191
|
+
- **Want to contribute code?** See [CONTRIBUTING.md](CONTRIBUTING.md). It takes
|
|
192
|
+
about two minutes to get the tests running, and there are items marked
|
|
193
|
+
*help wanted* in [ROADMAP.md](ROADMAP.md).
|
|
194
|
+
|
|
195
|
+
Never include your session cookie in an issue — it is a password for your
|
|
196
|
+
Overleaf account, and nobody needs it to fix a bug.
|
|
197
|
+
|
|
198
|
+
Maintained by [Shivang Gupta](https://github.com/Mangluu), who wrote it to deal
|
|
199
|
+
with the review comments on his own papers.
|
|
200
|
+
|
|
201
|
+
## What's coming next
|
|
202
|
+
|
|
203
|
+
See [ROADMAP.md](ROADMAP.md). Short version: a response-letter scaffold,
|
|
204
|
+
writing out the full source so an AI can see more than a snippet, and a diff
|
|
205
|
+
between two exports so you can work through review comments in waves.
|
|
206
|
+
|
|
207
|
+
Changes are recorded in [CHANGELOG.md](CHANGELOG.md).
|
|
208
|
+
|
|
209
|
+
## A caution
|
|
210
|
+
|
|
211
|
+
This tool uses Overleaf's internal endpoints, which are undocumented and can
|
|
212
|
+
change without notice. It identifies itself honestly in every request, backs
|
|
213
|
+
off when asked to, and only ever reads — it cannot modify your project. Even
|
|
214
|
+
so, it may stop working the day Overleaf changes something. If that happens,
|
|
215
|
+
please say so in an issue.
|
|
153
216
|
|
|
154
217
|
## License
|
|
155
218
|
|
|
@@ -33,7 +33,13 @@ an Overleaf project URL and a logged-in browser session.
|
|
|
33
33
|
pip install overleaf-comments-export
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
Requires Python 3.10
|
|
36
|
+
Requires Python 3.10 or newer (tested up to 3.14). Works on macOS, Linux, and
|
|
37
|
+
Windows.
|
|
38
|
+
|
|
39
|
+
The graphical window needs Python's Tk toolkit, which most Linux distributions
|
|
40
|
+
package separately (`sudo apt install python3-tk` on Debian/Ubuntu). The
|
|
41
|
+
command line never needs it, and `--gui` tells you what to install if it is
|
|
42
|
+
missing.
|
|
37
43
|
|
|
38
44
|
## Quick start
|
|
39
45
|
|
|
@@ -68,6 +74,7 @@ In your output folder, by default:
|
|
|
68
74
|
| `comments.json` | Structured data — `summary`, top-level `threads`, `files`, `comments`, `tracked_changes`, etc. Schema described in `agents.md`. |
|
|
69
75
|
| `comments.jsonl` | One self-contained JSON record per comment for streaming/pipelines. |
|
|
70
76
|
| `agents.md` | A brief instruction file telling an AI agent how to consume the batch. |
|
|
77
|
+
| `response-letter.md` | (Optional, `--response-letter`) A point-by-point reply document, pre-filled with every open comment grouped by who raised it, with blanks for your response. |
|
|
71
78
|
| `by-reviewer/<name>.md` | (Optional, `--per-reviewer`) One Markdown per reviewer with only their threads. |
|
|
72
79
|
| `comments.log` | Diagnostic log for the run. |
|
|
73
80
|
|
|
@@ -85,6 +92,9 @@ overleaf-comments-export --project-url … --out ./out --render-mode detailed
|
|
|
85
92
|
|
|
86
93
|
# Per-reviewer sub-reports under ./out/by-reviewer/
|
|
87
94
|
overleaf-comments-export --project-url … --out ./out --per-reviewer
|
|
95
|
+
|
|
96
|
+
# Draft a point-by-point response letter for the open comments
|
|
97
|
+
overleaf-comments-export --project-url … --out ./out --response-letter
|
|
88
98
|
```
|
|
89
99
|
|
|
90
100
|
Full flag reference: `overleaf-comments-export --help`.
|
|
@@ -101,19 +111,71 @@ by browser on macOS:
|
|
|
101
111
|
| Chrome / Edge / Brave | Cookies are AES-encrypted with a Keychain-stored key; **you'll get a Keychain password prompt every run.** Hidden behind an opt-in in the GUI. |
|
|
102
112
|
|
|
103
113
|
On Windows, Chrome 127+ uses App-Bound Encryption that `browser-cookie3`
|
|
104
|
-
|
|
114
|
+
can't decrypt. On Linux, snap-packaged browsers sandbox their cookie stores.
|
|
105
115
|
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
**If reading the cookie from your browser fails, paste it instead** — this
|
|
117
|
+
works on every OS and browser:
|
|
108
118
|
|
|
109
|
-
|
|
119
|
+
```bash
|
|
120
|
+
overleaf-comments-export --project-url <url> --out ./out --cookie "PASTE_HERE"
|
|
121
|
+
```
|
|
110
122
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Pull requests are welcome; issues may or may not be acted upon.
|
|
123
|
+
Or set it once: `export OVERLEAF_SESSION="PASTE_HERE"`. In the GUI, choose
|
|
124
|
+
**"Paste the cookie myself"** and click **How?** for step-by-step instructions.
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
|
|
126
|
+
To find it: open Overleaf, press F12, go to Application (or Storage) →
|
|
127
|
+
Cookies → `https://www.overleaf.com`, and copy the Value of `overleaf_session2`.
|
|
128
|
+
Treat it like a password; it stops working when you sign out.
|
|
129
|
+
|
|
130
|
+
## Troubleshooting
|
|
131
|
+
|
|
132
|
+
| What you see | What it means |
|
|
133
|
+
|---|---|
|
|
134
|
+
| "Could not look up www.overleaf.com" | This computer is offline, or a VPN/DNS problem. Not an Overleaf issue. |
|
|
135
|
+
| "Overleaf refused the request (not signed in)" | Your session expired. Sign in again in the browser, then re-run. |
|
|
136
|
+
| "Could not read Overleaf cookies from chrome" | Use the paste-the-cookie method above. |
|
|
137
|
+
| "Overleaf could not find that project" | Wrong link, or this account has no access. |
|
|
138
|
+
|
|
139
|
+
## Feedback, questions, and contributing
|
|
140
|
+
|
|
141
|
+
This tool is actively maintained, and feedback shapes what gets built next.
|
|
142
|
+
|
|
143
|
+
- **Something broke, or the output was wrong?**
|
|
144
|
+
[Open an issue.](https://github.com/Mangluu/overleaf-comments-export/issues/new/choose)
|
|
145
|
+
You do not need to be a programmer — paste what the tool said and that is
|
|
146
|
+
plenty. If Overleaf changes something, everything here stops working at once,
|
|
147
|
+
and you may be the first person to notice.
|
|
148
|
+
- **Want it to do something it doesn't?**
|
|
149
|
+
[Suggest a feature.](https://github.com/Mangluu/overleaf-comments-export/issues/new/choose)
|
|
150
|
+
Tell me what you are trying to do, not just the feature — the real task
|
|
151
|
+
usually leads somewhere better.
|
|
152
|
+
- **Just a question, or want to show what you built with it?**
|
|
153
|
+
[Discussions.](https://github.com/Mangluu/overleaf-comments-export/discussions)
|
|
154
|
+
- **Want to contribute code?** See [CONTRIBUTING.md](CONTRIBUTING.md). It takes
|
|
155
|
+
about two minutes to get the tests running, and there are items marked
|
|
156
|
+
*help wanted* in [ROADMAP.md](ROADMAP.md).
|
|
157
|
+
|
|
158
|
+
Never include your session cookie in an issue — it is a password for your
|
|
159
|
+
Overleaf account, and nobody needs it to fix a bug.
|
|
160
|
+
|
|
161
|
+
Maintained by [Shivang Gupta](https://github.com/Mangluu), who wrote it to deal
|
|
162
|
+
with the review comments on his own papers.
|
|
163
|
+
|
|
164
|
+
## What's coming next
|
|
165
|
+
|
|
166
|
+
See [ROADMAP.md](ROADMAP.md). Short version: a response-letter scaffold,
|
|
167
|
+
writing out the full source so an AI can see more than a snippet, and a diff
|
|
168
|
+
between two exports so you can work through review comments in waves.
|
|
169
|
+
|
|
170
|
+
Changes are recorded in [CHANGELOG.md](CHANGELOG.md).
|
|
171
|
+
|
|
172
|
+
## A caution
|
|
173
|
+
|
|
174
|
+
This tool uses Overleaf's internal endpoints, which are undocumented and can
|
|
175
|
+
change without notice. It identifies itself honestly in every request, backs
|
|
176
|
+
off when asked to, and only ever reads — it cannot modify your project. Even
|
|
177
|
+
so, it may stop working the day Overleaf changes something. If that happens,
|
|
178
|
+
please say so in an issue.
|
|
117
179
|
|
|
118
180
|
## License
|
|
119
181
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Export Overleaf comment threads and tracked changes."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("overleaf-comments-export")
|
|
7
|
+
except PackageNotFoundError: # running from a source checkout
|
|
8
|
+
__version__ = "0.0.0-dev"
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import traceback
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from . import __version__
|
|
11
|
+
from .client import OverleafClient, UserFacingError
|
|
12
|
+
from .export import ExportResult, run_export
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _no_tkinter_message() -> str:
|
|
16
|
+
"""Platform-specific instructions for installing Python's GUI toolkit."""
|
|
17
|
+
if sys.platform == "darwin":
|
|
18
|
+
fix = (
|
|
19
|
+
"Install Python from python.org (it includes the GUI toolkit), or\n"
|
|
20
|
+
"with Homebrew run:\n\n"
|
|
21
|
+
" brew install python-tk"
|
|
22
|
+
)
|
|
23
|
+
elif sys.platform.startswith("win"):
|
|
24
|
+
fix = (
|
|
25
|
+
"Re-run the Python installer from python.org, choose \"Modify\", and\n"
|
|
26
|
+
"tick \"tcl/tk and IDLE\"."
|
|
27
|
+
)
|
|
28
|
+
else:
|
|
29
|
+
fix = (
|
|
30
|
+
"Install it with your package manager, for example:\n\n"
|
|
31
|
+
" Debian/Ubuntu : sudo apt install python3-tk\n"
|
|
32
|
+
" Fedora : sudo dnf install python3-tkinter\n"
|
|
33
|
+
" Arch : sudo pacman -S tk"
|
|
34
|
+
)
|
|
35
|
+
return (
|
|
36
|
+
"The window cannot open because this Python has no GUI toolkit "
|
|
37
|
+
"installed.\n\n"
|
|
38
|
+
f"{fix}\n\n"
|
|
39
|
+
"Or skip the window entirely and use the command line:\n\n"
|
|
40
|
+
" overleaf-comments-export --project-url <your project link> --out ./comments"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def main(argv: list[str] | None = None) -> int:
|
|
45
|
+
parser = argparse.ArgumentParser(
|
|
46
|
+
prog="overleaf-comments-export",
|
|
47
|
+
description="Export Overleaf comment threads and tracked changes to Markdown.",
|
|
48
|
+
)
|
|
49
|
+
parser.add_argument(
|
|
50
|
+
"--gui",
|
|
51
|
+
action="store_true",
|
|
52
|
+
help="Launch the graphical interface (default if no other args).",
|
|
53
|
+
)
|
|
54
|
+
parser.add_argument(
|
|
55
|
+
"--project-url",
|
|
56
|
+
help="Full Overleaf project URL, e.g. https://www.overleaf.com/project/<24-hex-id>.",
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"--out",
|
|
60
|
+
type=Path,
|
|
61
|
+
help="Directory to write comments-<date>.md, comments.json, and comments.log into.",
|
|
62
|
+
)
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--project-title",
|
|
65
|
+
default=None,
|
|
66
|
+
help="Optional human-readable title for the report header. Defaults to the project id.",
|
|
67
|
+
)
|
|
68
|
+
parser.add_argument(
|
|
69
|
+
"--browser",
|
|
70
|
+
default="auto",
|
|
71
|
+
choices=list(OverleafClient.SUPPORTED_BROWSERS),
|
|
72
|
+
help="Which browser to read cookies from. Default: auto-detect.",
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"--cookie",
|
|
76
|
+
default=None,
|
|
77
|
+
metavar="VALUE",
|
|
78
|
+
help="Overleaf session cookie, pasted from your browser (DevTools → "
|
|
79
|
+
"Application → Cookies → overleaf_session2). Use this when reading "
|
|
80
|
+
"cookies from the browser fails. Also read from the OVERLEAF_SESSION "
|
|
81
|
+
"environment variable.",
|
|
82
|
+
)
|
|
83
|
+
parser.add_argument(
|
|
84
|
+
"--base-url",
|
|
85
|
+
default="https://www.overleaf.com",
|
|
86
|
+
help="Override the Overleaf base URL (for self-hosted instances).",
|
|
87
|
+
)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"-v", "--verbose", action="store_true", help="More logging."
|
|
90
|
+
)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--version", action="version", version=f"%(prog)s {__version__}"
|
|
93
|
+
)
|
|
94
|
+
parser.add_argument(
|
|
95
|
+
"--render-mode",
|
|
96
|
+
choices=["compact", "detailed"],
|
|
97
|
+
default="compact",
|
|
98
|
+
help="Markdown layout: 'compact' (one line per comment, default) or "
|
|
99
|
+
"'detailed' (multi-line code-fence with anchor highlighted).",
|
|
100
|
+
)
|
|
101
|
+
parser.add_argument(
|
|
102
|
+
"--no-open",
|
|
103
|
+
dest="include_open",
|
|
104
|
+
action="store_false",
|
|
105
|
+
help="Skip open (unresolved) comments.",
|
|
106
|
+
)
|
|
107
|
+
parser.add_argument(
|
|
108
|
+
"--no-resolved",
|
|
109
|
+
dest="include_resolved",
|
|
110
|
+
action="store_false",
|
|
111
|
+
help="Skip resolved comments.",
|
|
112
|
+
)
|
|
113
|
+
parser.add_argument(
|
|
114
|
+
"--no-changes",
|
|
115
|
+
dest="include_changes",
|
|
116
|
+
action="store_false",
|
|
117
|
+
help="Skip tracked changes.",
|
|
118
|
+
)
|
|
119
|
+
parser.add_argument(
|
|
120
|
+
"--reviewer",
|
|
121
|
+
action="append",
|
|
122
|
+
default=[],
|
|
123
|
+
metavar="NAME",
|
|
124
|
+
help="Only include threads/changes touching this reviewer "
|
|
125
|
+
"(case-insensitive substring match against name and email). "
|
|
126
|
+
"Pass multiple times for OR-of-reviewers.",
|
|
127
|
+
)
|
|
128
|
+
parser.add_argument(
|
|
129
|
+
"--include-raw",
|
|
130
|
+
action="store_true",
|
|
131
|
+
help="Embed the unprocessed Overleaf API payloads inside comments.json.",
|
|
132
|
+
)
|
|
133
|
+
parser.add_argument(
|
|
134
|
+
"--no-jsonl",
|
|
135
|
+
dest="write_jsonl",
|
|
136
|
+
action="store_false",
|
|
137
|
+
help="Skip writing comments.jsonl (the streaming-friendly companion).",
|
|
138
|
+
)
|
|
139
|
+
parser.add_argument(
|
|
140
|
+
"--response-letter",
|
|
141
|
+
action="store_true",
|
|
142
|
+
help="Also write response-letter.md: a point-by-point reply document "
|
|
143
|
+
"pre-filled with every open comment, grouped by who raised it, with "
|
|
144
|
+
"blanks for your response.",
|
|
145
|
+
)
|
|
146
|
+
parser.add_argument(
|
|
147
|
+
"--per-reviewer",
|
|
148
|
+
action="store_true",
|
|
149
|
+
help="Also write one Markdown per reviewer into by-reviewer/.",
|
|
150
|
+
)
|
|
151
|
+
parser.set_defaults(
|
|
152
|
+
include_open=True,
|
|
153
|
+
include_resolved=True,
|
|
154
|
+
include_changes=True,
|
|
155
|
+
write_jsonl=True,
|
|
156
|
+
)
|
|
157
|
+
args = parser.parse_args(argv)
|
|
158
|
+
|
|
159
|
+
if args.gui or (not args.project_url and not args.out):
|
|
160
|
+
try:
|
|
161
|
+
from .gui import launch_gui
|
|
162
|
+
except ImportError:
|
|
163
|
+
# tkinter is NOT bundled with Python everywhere — most Linux
|
|
164
|
+
# distributions ship it as a separate system package, and it is
|
|
165
|
+
# missing from some minimal/conda builds.
|
|
166
|
+
print(_no_tkinter_message(), file=sys.stderr)
|
|
167
|
+
return 1
|
|
168
|
+
try:
|
|
169
|
+
return launch_gui()
|
|
170
|
+
except Exception as e:
|
|
171
|
+
# Typically TclError on a headless machine (SSH, server, container).
|
|
172
|
+
if "display" in str(e).lower() or type(e).__name__ == "TclError":
|
|
173
|
+
print(
|
|
174
|
+
"There is no screen to open a window on.\n\n"
|
|
175
|
+
"This looks like a computer without a desktop (a server, or "
|
|
176
|
+
"a remote session). Use the command line instead, for "
|
|
177
|
+
"example:\n\n"
|
|
178
|
+
" overleaf-comments-export --project-url <your project link> "
|
|
179
|
+
"--out ./comments\n\n"
|
|
180
|
+
"Run with --help to see every option.",
|
|
181
|
+
file=sys.stderr,
|
|
182
|
+
)
|
|
183
|
+
return 1
|
|
184
|
+
raise
|
|
185
|
+
|
|
186
|
+
if not args.project_url or not args.out:
|
|
187
|
+
parser.error("--project-url and --out are required in CLI mode (or pass --gui).")
|
|
188
|
+
|
|
189
|
+
logging.basicConfig(
|
|
190
|
+
level=logging.DEBUG if args.verbose else logging.INFO,
|
|
191
|
+
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
|
|
192
|
+
stream=sys.stderr,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
cookie_value = args.cookie or os.environ.get("OVERLEAF_SESSION") or None
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
result: ExportResult = run_export(
|
|
199
|
+
project_url=args.project_url,
|
|
200
|
+
out_dir=args.out,
|
|
201
|
+
project_title=args.project_title,
|
|
202
|
+
base_url=args.base_url,
|
|
203
|
+
browser=args.browser,
|
|
204
|
+
cookie_value=cookie_value,
|
|
205
|
+
verbose=args.verbose,
|
|
206
|
+
include_raw=args.include_raw,
|
|
207
|
+
include_open=args.include_open,
|
|
208
|
+
include_resolved=args.include_resolved,
|
|
209
|
+
include_changes=args.include_changes,
|
|
210
|
+
reviewer_filter=args.reviewer,
|
|
211
|
+
render_mode=args.render_mode,
|
|
212
|
+
write_jsonl=args.write_jsonl,
|
|
213
|
+
per_reviewer_reports=args.per_reviewer,
|
|
214
|
+
response_letter=args.response_letter,
|
|
215
|
+
progress=lambda msg: print(msg, file=sys.stderr),
|
|
216
|
+
)
|
|
217
|
+
except UserFacingError as e:
|
|
218
|
+
# Expected, explainable failures: no traceback, just what to do next.
|
|
219
|
+
print(f"\n{e}", file=sys.stderr)
|
|
220
|
+
return 1
|
|
221
|
+
except Exception:
|
|
222
|
+
# Unexpected: show the traceback, but also tell people where to send it.
|
|
223
|
+
# The moment something breaks is the only moment we have their attention.
|
|
224
|
+
traceback.print_exc()
|
|
225
|
+
print(
|
|
226
|
+
f"\nThat looks like a bug in overleaf-comments-export {__version__}.\n"
|
|
227
|
+
"Please report it (copy the lines above) at\n"
|
|
228
|
+
" https://github.com/Mangluu/overleaf-comments-export/issues/new/choose\n"
|
|
229
|
+
"It probably affects other people too, and it cannot be fixed if "
|
|
230
|
+
"nobody says anything.",
|
|
231
|
+
file=sys.stderr,
|
|
232
|
+
)
|
|
233
|
+
return 2
|
|
234
|
+
print(f"\nDone. Open: {result.markdown_path}")
|
|
235
|
+
return 0
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
if __name__ == "__main__":
|
|
239
|
+
sys.exit(main())
|