mirror of
https://github.com/mikf/gallery-dl.git
synced 2024-11-22 02:32:33 +01:00
improve docs/options.md
- use non-breaking hyphens - don't replace '…' in examples - don't force width for long option column
This commit is contained in:
parent
6f6af36cad
commit
f1a715dbcd
242
docs/options.md
242
docs/options.md
@ -8,63 +8,75 @@
|
||||
<table>
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td><code>-h</code></td>
|
||||
<td width="28%"><code>--help</code></td>
|
||||
<td><code>‑h</code></td>
|
||||
<td><code>‑‑help</code></td>
|
||||
<td></td>
|
||||
<td>Print this help message and exit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--version</code></td>
|
||||
<td><code>‑‑version</code></td>
|
||||
<td></td>
|
||||
<td>Print program version and exit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-i</code></td>
|
||||
<td><code>--input-file</code></td>
|
||||
<td><code>‑i</code></td>
|
||||
<td><code>‑‑input‑file</code></td>
|
||||
<td><code>FILE</code></td>
|
||||
<td>Download URLs found in FILE (<code>-</code> for stdin). More than one --input-file can be specified</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-d</code></td>
|
||||
<td><code>--destination</code></td>
|
||||
<td><code>‑d</code></td>
|
||||
<td><code>‑‑destination</code></td>
|
||||
<td><code>PATH</code></td>
|
||||
<td>Target location for file downloads</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-D</code></td>
|
||||
<td><code>--directory</code></td>
|
||||
<td><code>‑D</code></td>
|
||||
<td><code>‑‑directory</code></td>
|
||||
<td><code>PATH</code></td>
|
||||
<td>Exact location for file downloads</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-f</code></td>
|
||||
<td><code>--filename</code></td>
|
||||
<td><code>‑f</code></td>
|
||||
<td><code>‑‑filename</code></td>
|
||||
<td><code>FORMAT</code></td>
|
||||
<td>Filename format string for downloaded files (<code>/O</code> for "original" filenames)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--proxy</code></td>
|
||||
<td><code>‑‑proxy</code></td>
|
||||
<td><code>URL</code></td>
|
||||
<td>Use the specified proxy</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--source-address</code></td>
|
||||
<td><code>‑‑source‑address</code></td>
|
||||
<td><code>IP</code></td>
|
||||
<td>Client-side IP address to bind to</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--user-agent</code></td>
|
||||
<td><code>‑‑user‑agent</code></td>
|
||||
<td><code>UA</code></td>
|
||||
<td>User-Agent request header</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--clear-cache</code></td>
|
||||
<td><code>‑‑clear‑cache</code></td>
|
||||
<td><code>MODULE</code></td>
|
||||
<td>Delete cached login sessions, cookies, etc. for MODULE (ALL to delete everything)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--cookies</code></td>
|
||||
<td><code>‑‑cookies</code></td>
|
||||
<td><code>FILE</code></td>
|
||||
<td>File to load additional cookies from</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--cookies-from-browser</code></td>
|
||||
<td><code>‑‑cookies‑from‑browser</code></td>
|
||||
<td><code>BROWSER</code></td>
|
||||
<td>Name of the browser to load cookies from, with optional keyring name prefixed with <code>+</code>, profile prefixed with <code>:</code>, and container prefixed with <code>::</code> (<code>none</code> for no container)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -76,68 +88,81 @@
|
||||
<table>
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td><code>-q</code></td>
|
||||
<td width="28%"><code>--quiet</code></td>
|
||||
<td><code>‑q</code></td>
|
||||
<td><code>‑‑quiet</code></td>
|
||||
<td></td>
|
||||
<td>Activate quiet mode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-v</code></td>
|
||||
<td><code>--verbose</code></td>
|
||||
<td><code>‑v</code></td>
|
||||
<td><code>‑‑verbose</code></td>
|
||||
<td></td>
|
||||
<td>Print various debugging information</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-g</code></td>
|
||||
<td><code>--get-urls</code></td>
|
||||
<td><code>‑g</code></td>
|
||||
<td><code>‑‑get‑urls</code></td>
|
||||
<td></td>
|
||||
<td>Print URLs instead of downloading</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-G</code></td>
|
||||
<td><code>--resolve-urls</code></td>
|
||||
<td><code>‑G</code></td>
|
||||
<td><code>‑‑resolve‑urls</code></td>
|
||||
<td></td>
|
||||
<td>Print URLs instead of downloading; resolve intermediary URLs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-j</code></td>
|
||||
<td><code>--dump-json</code></td>
|
||||
<td><code>‑j</code></td>
|
||||
<td><code>‑‑dump‑json</code></td>
|
||||
<td></td>
|
||||
<td>Print JSON information</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-s</code></td>
|
||||
<td><code>--simulate</code></td>
|
||||
<td><code>‑s</code></td>
|
||||
<td><code>‑‑simulate</code></td>
|
||||
<td></td>
|
||||
<td>Simulate data extraction; do not download anything</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-E</code></td>
|
||||
<td><code>--extractor-info</code></td>
|
||||
<td><code>‑E</code></td>
|
||||
<td><code>‑‑extractor‑info</code></td>
|
||||
<td></td>
|
||||
<td>Print extractor defaults and settings</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-K</code></td>
|
||||
<td><code>--list-keywords</code></td>
|
||||
<td><code>‑K</code></td>
|
||||
<td><code>‑‑list‑keywords</code></td>
|
||||
<td></td>
|
||||
<td>Print a list of available keywords and example values for the given URLs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--list-modules</code></td>
|
||||
<td><code>‑‑list‑modules</code></td>
|
||||
<td></td>
|
||||
<td>Print a list of available extractor modules</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--list-extractors</code></td>
|
||||
<td><code>‑‑list‑extractors</code></td>
|
||||
<td></td>
|
||||
<td>Print a list of extractor classes with description, (sub)category and example URL</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--write-log</code></td>
|
||||
<td><code>‑‑write‑log</code></td>
|
||||
<td><code>FILE</code></td>
|
||||
<td>Write logging output to FILE</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--write-unsupported</code></td>
|
||||
<td><code>‑‑write‑unsupported</code></td>
|
||||
<td><code>FILE</code></td>
|
||||
<td>Write URLs, which get emitted by other extractors but cannot be handled, to FILE</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--write-pages</code></td>
|
||||
<td><code>‑‑write‑pages</code></td>
|
||||
<td></td>
|
||||
<td>Write downloaded intermediary pages to files in the current directory to debug problems</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -149,78 +174,93 @@
|
||||
<table>
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td><code>-r</code></td>
|
||||
<td width="28%"><code>--limit-rate</code></td>
|
||||
<td><code>‑r</code></td>
|
||||
<td><code>‑‑limit‑rate</code></td>
|
||||
<td><code>RATE</code></td>
|
||||
<td>Maximum download rate (e.g. 500k or 2.5M)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-R</code></td>
|
||||
<td><code>--retries</code></td>
|
||||
<td><code>‑R</code></td>
|
||||
<td><code>‑‑retries</code></td>
|
||||
<td><code>N</code></td>
|
||||
<td>Maximum number of retries for failed HTTP requests or -1 for infinite retries (default: 4)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--http-timeout</code></td>
|
||||
<td><code>‑‑http‑timeout</code></td>
|
||||
<td><code>SECONDS</code></td>
|
||||
<td>Timeout for HTTP connections (default: 30.0)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--sleep</code></td>
|
||||
<td><code>‑‑sleep</code></td>
|
||||
<td><code>SECONDS</code></td>
|
||||
<td>Number of seconds to wait before each download. This can be either a constant value or a range (e.g. 2.7 or 2.0-3.5)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--sleep-request</code></td>
|
||||
<td><code>‑‑sleep‑request</code></td>
|
||||
<td><code>SECONDS</code></td>
|
||||
<td>Number of seconds to wait between HTTP requests during data extraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--sleep-extractor</code></td>
|
||||
<td><code>‑‑sleep‑extractor</code></td>
|
||||
<td><code>SECONDS</code></td>
|
||||
<td>Number of seconds to wait before starting data extraction for an input URL</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--filesize-min</code></td>
|
||||
<td><code>‑‑filesize‑min</code></td>
|
||||
<td><code>SIZE</code></td>
|
||||
<td>Do not download files smaller than SIZE (e.g. 500k or 2.5M)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--filesize-max</code></td>
|
||||
<td><code>‑‑filesize‑max</code></td>
|
||||
<td><code>SIZE</code></td>
|
||||
<td>Do not download files larger than SIZE (e.g. 500k or 2.5M)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--chunk-size</code></td>
|
||||
<td><code>‑‑chunk‑size</code></td>
|
||||
<td><code>SIZE</code></td>
|
||||
<td>Size of in-memory data chunks (default: 32k)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--no-part</code></td>
|
||||
<td><code>‑‑no‑part</code></td>
|
||||
<td></td>
|
||||
<td>Do not use .part files</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--no-skip</code></td>
|
||||
<td><code>‑‑no‑skip</code></td>
|
||||
<td></td>
|
||||
<td>Do not skip downloads; overwrite existing files</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--no-mtime</code></td>
|
||||
<td><code>‑‑no‑mtime</code></td>
|
||||
<td></td>
|
||||
<td>Do not set file modification times according to Last-Modified HTTP response headers</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--no-download</code></td>
|
||||
<td><code>‑‑no‑download</code></td>
|
||||
<td></td>
|
||||
<td>Do not download any files</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--no-postprocessors</code></td>
|
||||
<td><code>‑‑no‑postprocessors</code></td>
|
||||
<td></td>
|
||||
<td>Do not run any post processors</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--no-check-certificate</code></td>
|
||||
<td><code>‑‑no‑check‑certificate</code></td>
|
||||
<td></td>
|
||||
<td>Disable HTTPS certificate validation</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -232,18 +272,21 @@
|
||||
<table>
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td><code>-c</code></td>
|
||||
<td width="28%"><code>--config</code></td>
|
||||
<td><code>‑c</code></td>
|
||||
<td><code>‑‑config</code></td>
|
||||
<td><code>FILE</code></td>
|
||||
<td>Additional configuration files</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-o</code></td>
|
||||
<td><code>--option</code></td>
|
||||
<td><code>‑o</code></td>
|
||||
<td><code>‑‑option</code></td>
|
||||
<td><code>OPT</code></td>
|
||||
<td>Additional <code><key>=<value></code> option values</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--ignore-config</code></td>
|
||||
<td><code>‑‑ignore‑config</code></td>
|
||||
<td></td>
|
||||
<td>Do not read default configuration files</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -255,18 +298,21 @@
|
||||
<table>
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td><code>-u</code></td>
|
||||
<td width="28%"><code>--username</code></td>
|
||||
<td><code>‑u</code></td>
|
||||
<td><code>‑‑username</code></td>
|
||||
<td><code>USER</code></td>
|
||||
<td>Username to login with</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-p</code></td>
|
||||
<td><code>--password</code></td>
|
||||
<td><code>‑p</code></td>
|
||||
<td><code>‑‑password</code></td>
|
||||
<td><code>PASS</code></td>
|
||||
<td>Password belonging to the given username</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--netrc</code></td>
|
||||
<td><code>‑‑netrc</code></td>
|
||||
<td></td>
|
||||
<td>Enable .netrc authentication data</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -279,37 +325,44 @@
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td width="28%"><code>--download-archive</code></td>
|
||||
<td><code>‑‑download‑archive</code></td>
|
||||
<td><code>FILE</code></td>
|
||||
<td>Record all downloaded or skipped files in FILE and skip downloading any file already in it</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-A</code></td>
|
||||
<td><code>--abort</code></td>
|
||||
<td><code>‑A</code></td>
|
||||
<td><code>‑‑abort</code></td>
|
||||
<td><code>N</code></td>
|
||||
<td>Stop current extractor run after N consecutive file downloads were skipped</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-T</code></td>
|
||||
<td><code>--terminate</code></td>
|
||||
<td><code>‑T</code></td>
|
||||
<td><code>‑‑terminate</code></td>
|
||||
<td><code>N</code></td>
|
||||
<td>Stop current and parent extractor runs after N consecutive file downloads were skipped</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--range</code></td>
|
||||
<td><code>‑‑range</code></td>
|
||||
<td><code>RANGE</code></td>
|
||||
<td>Index range(s) specifying which files to download. These can be either a constant value, range, or slice (e.g. <code>5</code>, <code>8-20</code>, or <code>1:24:3</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--chapter-range</code></td>
|
||||
<td><code>‑‑chapter‑range</code></td>
|
||||
<td><code>RANGE</code></td>
|
||||
<td>Like <code>--range</code>, but applies to manga chapters and other delegated URLs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--filter</code></td>
|
||||
<td>Python expression controlling which files to download. Files for which the expression evaluates to False are ignored. Available keys are the filename-specific ones listed by <code>-K</code>. Example: --filter "image_width >= 1000 and rating in (<code>s</code>, <code>q</code>)"</td>
|
||||
<td><code>‑‑filter</code></td>
|
||||
<td><code>EXPR</code></td>
|
||||
<td>Python expression controlling which files to download. Files for which the expression evaluates to False are ignored. Available keys are the filename-specific ones listed by <code>-K</code>. <br />Example: --filter "image_width >= 1000 and rating in ('s', 'q')"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--chapter-filter</code></td>
|
||||
<td><code>‑‑chapter‑filter</code></td>
|
||||
<td><code>EXPR</code></td>
|
||||
<td>Like <code>--filter</code>, but applies to manga chapters and other delegated URLs</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -322,57 +375,68 @@
|
||||
<tbody valign="top">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td width="28%"><code>--zip</code></td>
|
||||
<td><code>‑‑zip</code></td>
|
||||
<td></td>
|
||||
<td>Store downloaded files in a ZIP archive</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--ugoira-conv</code></td>
|
||||
<td><code>‑‑ugoira‑conv</code></td>
|
||||
<td></td>
|
||||
<td>Convert Pixiv Ugoira to WebM (requires FFmpeg)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--ugoira-conv-lossless</code></td>
|
||||
<td><code>‑‑ugoira‑conv‑lossless</code></td>
|
||||
<td></td>
|
||||
<td>Convert Pixiv Ugoira to WebM in VP9 lossless mode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--ugoira-conv-copy</code></td>
|
||||
<td><code>‑‑ugoira‑conv‑copy</code></td>
|
||||
<td></td>
|
||||
<td>Convert Pixiv Ugoira to MKV without re-encoding any frames</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--write-metadata</code></td>
|
||||
<td><code>‑‑write‑metadata</code></td>
|
||||
<td></td>
|
||||
<td>Write metadata to separate JSON files</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--write-info-json</code></td>
|
||||
<td><code>‑‑write‑info‑json</code></td>
|
||||
<td></td>
|
||||
<td>Write gallery metadata to a info.json file</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--write-tags</code></td>
|
||||
<td><code>‑‑write‑tags</code></td>
|
||||
<td></td>
|
||||
<td>Write image tags to separate text files</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--mtime-from-date</code></td>
|
||||
<td><code>‑‑mtime‑from‑date</code></td>
|
||||
<td></td>
|
||||
<td>Set file modification times according to <code>date</code> metadata</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--exec</code></td>
|
||||
<td>Execute CMD for each downloaded file. Example: --exec <code>convert {} {}.png && rm {}</code></td>
|
||||
<td><code>‑‑exec</code></td>
|
||||
<td><code>CMD</code></td>
|
||||
<td>Execute CMD for each downloaded file. <br />Example: --exec "convert {} {}.png && rm {}"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><code>--exec-after</code></td>
|
||||
<td>Execute CMD after all files were downloaded successfully. Example: --exec-after <code>cd {} && convert * ../doc.pdf</code></td>
|
||||
<td><code>‑‑exec‑after</code></td>
|
||||
<td><code>CMD</code></td>
|
||||
<td>Execute CMD after all files were downloaded successfully. <br />Example: --exec-after "cd {} && convert * ../doc.pdf"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-P</code></td>
|
||||
<td><code>--postprocessor</code></td>
|
||||
<td><code>‑P</code></td>
|
||||
<td><code>‑‑postprocessor</code></td>
|
||||
<td><code>NAME</code></td>
|
||||
<td>Activate the specified post processor</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -36,24 +36,25 @@ TABLE = """
|
||||
|
||||
ROW = """<tr>
|
||||
<td>{}</td>
|
||||
<td{}>{}</td>
|
||||
<td>{}</td>
|
||||
<td>{}</td>
|
||||
<td>{}</td>
|
||||
</tr>""".format
|
||||
|
||||
|
||||
sub = re.compile(r"'([^']+)'").sub
|
||||
tables = []
|
||||
sub = re.compile(r"'([^']+)'").sub
|
||||
nb_hyphen = "‑" # non-breaking hyphen
|
||||
|
||||
for group in option.build_parser()._action_groups[2:]:
|
||||
|
||||
tbody = []
|
||||
append = tbody.append
|
||||
width = ' width="28%"'
|
||||
|
||||
for action in group._group_actions:
|
||||
help = action.help
|
||||
if help == SUPPRESS:
|
||||
continue
|
||||
meta = action.metavar or ""
|
||||
|
||||
try:
|
||||
short, long = action.option_strings
|
||||
@ -65,15 +66,20 @@ for group in option.build_parser()._action_groups[2:]:
|
||||
short = ""
|
||||
|
||||
if short:
|
||||
short = "<code>" + short + "</code>"
|
||||
short = "<code>" + short.replace("-", nb_hyphen) + "</code>"
|
||||
if long:
|
||||
long = '<code>' + long + "</code>"
|
||||
long = "<code>" + long.replace("-", nb_hyphen) + "</code>"
|
||||
if meta:
|
||||
meta = "<code>" + meta.partition("[")[0] + "</code>"
|
||||
if help:
|
||||
help = help.replace("<", "<").replace(">", ">")
|
||||
help = sub("<code>\\1</code>", help)
|
||||
if "Example: " in help:
|
||||
help, sep, example = help.partition("Example: ")
|
||||
help = sub("<code>\\1</code>", help) + "<br />" + sep + example
|
||||
else:
|
||||
help = sub("<code>\\1</code>", help)
|
||||
|
||||
append(ROW(short, width, long, help))
|
||||
width = ""
|
||||
tbody.append(ROW(short, long, meta, help))
|
||||
|
||||
tables.append(TABLE(group.title, "\n".join(tbody)))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user