Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mikf
GitHub Repository: mikf/gallery-dl
Path: blob/master/scripts/man.py
5457 views
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
# Copyright 2019-2020 Mike Fährmann
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License version 2 as
8
# published by the Free Software Foundation.
9
10
"""Generate man pages"""
11
12
import re
13
import datetime
14
15
import util
16
import gallery_dl.option
17
import gallery_dl.version
18
19
20
def build_gallery_dl_1(path=None):
21
22
OPTS_FMT = """.TP\n.B "{}" {}\n{}"""
23
24
TEMPLATE = r"""
25
.TH "GALLERY-DL" "1" "%(date)s" "%(version)s" "gallery-dl Manual"
26
.\" disable hyphenation
27
.nh
28
29
.SH NAME
30
gallery-dl \- download image-galleries and -collections
31
32
.SH SYNOPSIS
33
.B gallery-dl
34
[OPTION]... URL...
35
36
.SH DESCRIPTION
37
.B gallery-dl
38
is a command-line program to download image-galleries and -collections
39
from several image hosting sites. It is a cross-platform tool
40
with many configuration options and powerful filenaming capabilities.
41
42
.SH OPTIONS
43
%(options)s
44
45
.SH EXAMPLES
46
.TP
47
gallery-dl \f[I]URL\f[]
48
Download images from \f[I]URL\f[].
49
.TP
50
gallery-dl -g -u <username> -p <password> \f[I]URL\f[]
51
Print direct URLs from a site that requires authentication.
52
.TP
53
gallery-dl --filter 'type == "ugoira"' --range '2-4' \f[I]URL\f[]
54
Apply filter and range expressions. This will only download
55
the second, third, and fourth file where its type value is equal to "ugoira".
56
.TP
57
gallery-dl r:\f[I]URL\f[]
58
Scan \f[I]URL\f[] for other URLs and invoke \f[B]gallery-dl\f[] on them.
59
.TP
60
gallery-dl oauth:\f[I]SITE\-NAME\f[]
61
Gain OAuth authentication tokens for
62
.IR deviantart ,
63
.IR flickr ,
64
.IR reddit ,
65
.IR smugmug ", and"
66
.IR tumblr .
67
68
.SH FILES
69
.TP
70
.I /etc/gallery-dl.conf
71
The system wide configuration file.
72
.TP
73
.I ~/.config/gallery-dl/config.json
74
Per user configuration file.
75
.TP
76
.I ~/.gallery-dl.conf
77
Alternate per user configuration file.
78
79
.SH BUGS
80
https://github.com/mikf/gallery-dl/issues
81
82
.SH AUTHORS
83
Mike Fährmann <[email protected]>
84
.br
85
and https://github.com/mikf/gallery-dl/graphs/contributors
86
87
.SH "SEE ALSO"
88
.BR gallery-dl.conf (5)
89
"""
90
91
options = []
92
for action in gallery_dl.option.build_parser()._actions:
93
if action.help.startswith("=="):
94
continue
95
options.append(OPTS_FMT.format(
96
", ".join(action.option_strings).replace("-", r"\-"),
97
r"\f[I]{}\f[]".format(action.metavar) if action.metavar else "",
98
action.help,
99
))
100
101
if not path:
102
path = util.path("data/man/gallery-dl.1")
103
with util.lazy(path) as fp:
104
fp.write(TEMPLATE.lstrip() % {
105
"options": "\n".join(options),
106
"version": gallery_dl.version.__version__,
107
"date" : datetime.datetime.now().strftime("%Y-%m-%d"),
108
})
109
110
111
def build_gallery_dl_conf_5(path=None):
112
113
TEMPLATE = r"""
114
.TH "GALLERY-DL.CONF" "5" "%(date)s" "%(version)s" "gallery-dl Manual"
115
.\" disable hyphenation
116
.nh
117
.\" disable justification (adjust text to left margin only)
118
.ad l
119
120
.SH NAME
121
gallery-dl.conf \- gallery-dl configuration file
122
123
.SH DESCRIPTION
124
gallery-dl will search for configuration files in the following places
125
every time it is started, unless
126
.B --ignore-config
127
is specified:
128
.PP
129
.RS 4
130
.nf
131
.I /etc/gallery-dl.conf
132
.I $HOME/.config/gallery-dl/config.json
133
.I $HOME/.gallery-dl.conf
134
.fi
135
.RE
136
.PP
137
It is also possible to specify additional configuration files with the
138
.B -c/--config
139
command-line option or to add further option values with
140
.B -o/--option
141
as <key>=<value> pairs,
142
143
Configuration files are JSON-based and therefore don't allow any ordinary
144
comments, but, since unused keys are simply ignored, it is possible to utilize
145
those as makeshift comments by settings their values to arbitrary strings.
146
147
.SH EXAMPLE
148
{
149
.RS 4
150
"base-directory": "/tmp/",
151
.br
152
"extractor": {
153
.RS 4
154
"pixiv": {
155
.RS 4
156
"directory": ["Pixiv", "Works", "{user[id]}"],
157
.br
158
"filename": "{id}{num}.{extension}",
159
.br
160
"username": "foo",
161
.br
162
"password": "bar"
163
.RE
164
},
165
.br
166
"flickr": {
167
.RS 4
168
"_comment": "OAuth keys for account 'foobar'",
169
.br
170
"access-token": "0123456789-0123456789abcdef",
171
.br
172
"access-token-secret": "fedcba9876543210"
173
.RE
174
}
175
.RE
176
},
177
.br
178
"downloader": {
179
.RS 4
180
"retries": 3,
181
.br
182
"timeout": 2.5
183
.RE
184
}
185
.RE
186
}
187
188
%(options)s
189
190
.SH BUGS
191
https://github.com/mikf/gallery-dl/issues
192
193
.SH AUTHORS
194
Mike Fährmann <[email protected]>
195
.br
196
and https://github.com/mikf/gallery-dl/graphs/contributors
197
198
.SH "SEE ALSO"
199
.BR gallery-dl (1)
200
"""
201
202
sections = parse_docs_configuration()
203
content = []
204
205
for sec_name, section in sections.items():
206
content.append(".SH " + sec_name.upper())
207
208
for opt_name, option in section.items():
209
content.append(".SS " + opt_name)
210
211
for field, text in option.items():
212
if field in ("Type", "Default"):
213
content.append('.IP "{}:" {}'.format(field, len(field)+2))
214
content.append(strip_rst(text))
215
else:
216
content.append('.IP "{}:" 4'.format(field))
217
content.append(strip_rst(text, field != "Example"))
218
219
if not path:
220
path = util.path("data/man/gallery-dl.conf.5")
221
with util.lazy(path) as fp:
222
fp.write(TEMPLATE.lstrip() % {
223
"options": "\n".join(content),
224
"version": gallery_dl.version.__version__,
225
"date" : datetime.datetime.now().strftime("%Y-%m-%d"),
226
})
227
228
229
def parse_docs_configuration():
230
231
path = util.path("docs", "configuration.rst")
232
with util.open(path) as fp:
233
doc_lines = fp.readlines()
234
235
sections = {}
236
sec_name = None
237
options = None
238
opt_name = None
239
opt_desc = None
240
name = None
241
last = None
242
for line in doc_lines:
243
244
if line[0] == ".":
245
continue
246
247
# start of new section
248
elif re.match(r"^=+$", line):
249
if sec_name and options:
250
sections[sec_name] = options
251
sec_name = last.strip()
252
options = {}
253
254
# start of new option block
255
elif re.match(r"^-+$", line):
256
opt_name = last.strip()
257
opt_desc = {}
258
259
# end of option block
260
elif opt_name and opt_desc and line == "\n" and not last:
261
options[opt_name] = opt_desc
262
opt_name = None
263
name = None
264
265
# inside option block
266
elif opt_name:
267
if line[0].isalpha():
268
name = line.strip()
269
opt_desc[name] = ""
270
else:
271
line = line.strip()
272
if line.startswith(("* ", "- ")):
273
# list item
274
line = ".br\n" + line
275
elif line.startswith("| "):
276
# line block
277
line = line[2:] + "\n.br"
278
opt_desc[name] += line + "\n"
279
280
last = line
281
sections[sec_name] = options
282
283
return sections
284
285
286
def strip_rst(text, extended=True, *, ITALIC=r"\\f[I]\1\\f[]", REGULAR=r"\1"):
287
288
text = text.replace("\\", "\\\\")
289
290
# ``foo``
291
repl = ITALIC if extended else REGULAR
292
text = re.sub(r"``([^`]+)``", repl, text)
293
# |foo|_
294
text = re.sub(r"\|([^|]+)\|_*", ITALIC, text)
295
# `foo <bar>`__
296
text = re.sub(r"`([^`<]+) <[^>`]+>`_+", ITALIC, text)
297
# `foo`_
298
text = re.sub(r"`([^`]+)`_+", ITALIC, text)
299
# `foo`
300
text = re.sub(r"`([^`]+)`", REGULAR, text)
301
# foo_
302
text = re.sub(r"([A-Za-z0-9-]+)_+(?=\s)", ITALIC, text)
303
# -------
304
text = re.sub(r"---+", "", text)
305
306
return text
307
308
309
if __name__ == "__main__":
310
build_gallery_dl_1()
311
build_gallery_dl_conf_5()
312
313