mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-06-06 05:49:01 +08:00
add retry interval
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pixiv_downloader\n"
|
||||
"POT-Creation-Date: 2022-03-08 18:02+0800\n"
|
||||
"POT-Creation-Date: 2022-03-09 22:44+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <[email protected]>\n"
|
||||
@@ -69,15 +69,15 @@ msgstr ""
|
||||
msgid "Can not parse expired time:"
|
||||
msgstr ""
|
||||
|
||||
#: cookies.rs:366 data/json.rs:53 settings.rs:396 webclient.rs:275
|
||||
#: cookies.rs:366 data/json.rs:53 settings.rs:404 webclient.rs:288
|
||||
msgid "Failed to remove file:"
|
||||
msgstr ""
|
||||
|
||||
#: cookies.rs:372 data/json.rs:64 settings.rs:403 webclient.rs:281
|
||||
#: cookies.rs:372 data/json.rs:64 settings.rs:411 webclient.rs:294
|
||||
msgid "Failed to create file:"
|
||||
msgstr ""
|
||||
|
||||
#: cookies.rs:379 data/json.rs:70 settings.rs:409 webclient.rs:294
|
||||
#: cookies.rs:379 data/json.rs:70 settings.rs:417 webclient.rs:307
|
||||
msgid "Failed to write file:"
|
||||
msgstr ""
|
||||
|
||||
@@ -85,7 +85,7 @@ msgstr ""
|
||||
msgid "Failed to unescape string:"
|
||||
msgstr ""
|
||||
|
||||
#: download.rs:18 pixiv_web.rs:57
|
||||
#: download.rs:18 pixiv_web.rs:58
|
||||
msgid "Failed to initialize pixiv web api client."
|
||||
msgstr ""
|
||||
|
||||
@@ -114,7 +114,7 @@ msgid "Failed to get file name from url:"
|
||||
msgstr ""
|
||||
|
||||
#: download.rs:90 download.rs:96 download.rs:133 download.rs:139
|
||||
#: pixiv_web.rs:152
|
||||
#: pixiv_web.rs:153
|
||||
msgid "Failed to download image:"
|
||||
msgstr ""
|
||||
|
||||
@@ -126,82 +126,94 @@ msgstr ""
|
||||
msgid "Failed to add exif data to image:"
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:79
|
||||
#: dur.rs:73
|
||||
msgid "Failed to parse duration from string."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:85
|
||||
msgid "Warning: The specified config file not found."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:103
|
||||
#: opts.rs:109
|
||||
msgid "Usage:"
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:105
|
||||
#: opts.rs:111
|
||||
msgid "Download an artwork"
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:107
|
||||
#: opts.rs:113
|
||||
msgid "Fix the config file"
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:109
|
||||
#: opts.rs:115
|
||||
msgid "Print all available settings"
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:117
|
||||
#: opts.rs:123
|
||||
msgid "Print help message."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:121
|
||||
#: opts.rs:127
|
||||
msgid "The location of config file."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:127 settings_list.rs:8
|
||||
#: opts.rs:133 settings_list.rs:10
|
||||
msgid "The location of cookies file. Used for web API."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:133 settings_list.rs:9
|
||||
#: opts.rs:139 settings_list.rs:11
|
||||
msgid "The language of translated tags."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:136
|
||||
#: opts.rs:142
|
||||
msgid "Verbose logging."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:137
|
||||
#: opts.rs:143
|
||||
msgid "Overwrite existing file."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:138
|
||||
#: opts.rs:144
|
||||
msgid "Skip overwrite existing file."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:142 settings_list.rs:10
|
||||
#: opts.rs:148 settings_list.rs:12
|
||||
msgid "Max retry count if request failed."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:164
|
||||
#: opts.rs:154 settings_list.rs:13
|
||||
msgid "The interval (in seconds) between two retries."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:176
|
||||
msgid "Unknown command."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:174
|
||||
#: opts.rs:186
|
||||
msgid "Failed to parse ID:"
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:180
|
||||
#: opts.rs:192
|
||||
msgid "No URL or ID specified."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:188
|
||||
#: opts.rs:200
|
||||
msgid "No detailed command specified."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:201
|
||||
#: opts.rs:213
|
||||
msgid "Unknown config subcommand."
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:237
|
||||
#: opts.rs:249
|
||||
msgid "Retry count must be an non-negative integer:"
|
||||
msgstr ""
|
||||
|
||||
#: opts.rs:258
|
||||
msgid "Failed to parse retry interval:"
|
||||
msgstr ""
|
||||
|
||||
#: parser/description.rs:129 parser/metadata.rs:76
|
||||
msgid "Failed to parse HTML:"
|
||||
msgstr ""
|
||||
@@ -214,87 +226,99 @@ msgstr ""
|
||||
msgid "There are some nodes still in stack:"
|
||||
msgstr ""
|
||||
|
||||
#: parser/metadata.rs:54 pixiv_web.rs:111
|
||||
#: parser/metadata.rs:54 pixiv_web.rs:112
|
||||
msgid "Failed to parse JSON:"
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:72 pixiv_web.rs:77
|
||||
#: pixiv_web.rs:73 pixiv_web.rs:78
|
||||
msgid "Failed to get main page:"
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:83
|
||||
#: pixiv_web.rs:84
|
||||
msgid "Failed to parse main page."
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:87
|
||||
#: pixiv_web.rs:88
|
||||
msgid "Main page's data:"
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:102
|
||||
#: pixiv_web.rs:103
|
||||
msgid "Network error:"
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:121
|
||||
#: pixiv_web.rs:122
|
||||
msgid "Failed to detect error."
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:168 pixiv_web.rs:173
|
||||
#: pixiv_web.rs:169 pixiv_web.rs:174
|
||||
msgid "Failed to get artwork page:"
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:179
|
||||
#: pixiv_web.rs:180
|
||||
msgid "Failed to parse artwork page."
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:183
|
||||
#: pixiv_web.rs:184
|
||||
msgid "Artwork's data:"
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:197
|
||||
#: pixiv_web.rs:198
|
||||
msgid "Artwork's page data:"
|
||||
msgstr ""
|
||||
|
||||
#: pixiv_web.rs:221
|
||||
#: pixiv_web.rs:222
|
||||
msgid "Warning: Failed to save cookies file:"
|
||||
msgstr ""
|
||||
|
||||
#: retry_interval.rs:22
|
||||
msgid "Failed to get JSON object."
|
||||
msgstr ""
|
||||
|
||||
#: retry_interval.rs:37 retry_interval.rs:55
|
||||
msgid "Failed to parse JSON number."
|
||||
msgstr ""
|
||||
|
||||
#: retry_interval.rs:61 retry_interval.rs:65
|
||||
msgid "Unsupported JSON type."
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:29
|
||||
msgid "Multiple type"
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:264
|
||||
#: settings.rs:268
|
||||
msgid "Can not insert setting to JSON object."
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:331
|
||||
#: settings.rs:339
|
||||
msgid "Settings file is empty."
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:338
|
||||
#: settings.rs:346
|
||||
msgid "Can not read from settings file."
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:347
|
||||
#: settings.rs:355
|
||||
msgid "Can not parse settings file."
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:356
|
||||
#: settings.rs:364
|
||||
msgid "Unknown settings file."
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:367
|
||||
#: settings.rs:375
|
||||
msgid "\"<key>\" is invalid, you can use \"pixiv_downloader config fix\" to remove all invalid value."
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:386
|
||||
#: settings.rs:394
|
||||
msgid "Can not convert settings to JSON object."
|
||||
msgstr ""
|
||||
|
||||
#: settings.rs:414
|
||||
#: settings.rs:422
|
||||
msgid "Failed to flush file:"
|
||||
msgstr ""
|
||||
|
||||
#: settings_list.rs:7
|
||||
#: settings_list.rs:9
|
||||
msgid "Pixiv's refresh tokens. Used to login."
|
||||
msgstr ""
|
||||
|
||||
@@ -302,7 +326,7 @@ msgstr ""
|
||||
msgid "Do you want to delete file \"<file>\"?"
|
||||
msgstr ""
|
||||
|
||||
#: utils.rs:51 webclient.rs:146
|
||||
#: utils.rs:51 webclient.rs:152
|
||||
msgid "Can not parse URL:"
|
||||
msgstr ""
|
||||
|
||||
@@ -310,46 +334,50 @@ msgstr ""
|
||||
msgid "Failed to get file name from path:"
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:106
|
||||
#: webclient.rs:112
|
||||
msgid "Failed to parse Set-Cookie header."
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:111
|
||||
#: webclient.rs:117
|
||||
msgid "Failed to convert to string:"
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:153
|
||||
#: webclient.rs:159
|
||||
msgid "Parameters should be object or array:"
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:173
|
||||
#: webclient.rs:179
|
||||
msgid "Parameters should be array:"
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:177
|
||||
#: webclient.rs:183
|
||||
msgid "Parameters need at least a value:"
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:213
|
||||
#: webclient.rs:222
|
||||
msgid "Retry after <num> seconds."
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:226
|
||||
msgid "Retry <count> times now."
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:227
|
||||
#: webclient.rs:240
|
||||
msgid "Error when request:"
|
||||
msgstr ""
|
||||
|
||||
#: webclient.rs:288
|
||||
#: webclient.rs:301
|
||||
msgid "Error when downloading file:"
|
||||
msgstr ""
|
||||
|
||||
#: main.rs:65
|
||||
#: main.rs:68
|
||||
msgid "Failed to save config file:"
|
||||
msgstr ""
|
||||
|
||||
#: main.rs:76
|
||||
#: main.rs:79
|
||||
msgid "All available settings:"
|
||||
msgstr ""
|
||||
|
||||
#: main.rs:108
|
||||
#: main.rs:111
|
||||
msgid "Can not read config file:"
|
||||
msgstr ""
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pixiv_downloader\n"
|
||||
"POT-Creation-Date: 2022-03-08 18:02+0800\n"
|
||||
"PO-Revision-Date: 2022-03-08 18:02+0800\n"
|
||||
"POT-Creation-Date: 2022-03-09 22:44+0800\n"
|
||||
"PO-Revision-Date: 2022-03-09 22:45+0800\n"
|
||||
"Last-Translator: lifegpc <[email protected]>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: zh_CN\n"
|
||||
@@ -70,15 +70,15 @@ msgstr "无效的Cookie:"
|
||||
msgid "Can not parse expired time:"
|
||||
msgstr "无法解析过期时间:"
|
||||
|
||||
#: cookies.rs:366 data/json.rs:53 settings.rs:396 webclient.rs:275
|
||||
#: cookies.rs:366 data/json.rs:53 settings.rs:404 webclient.rs:288
|
||||
msgid "Failed to remove file:"
|
||||
msgstr "无法删除文件:"
|
||||
|
||||
#: cookies.rs:372 data/json.rs:64 settings.rs:403 webclient.rs:281
|
||||
#: cookies.rs:372 data/json.rs:64 settings.rs:411 webclient.rs:294
|
||||
msgid "Failed to create file:"
|
||||
msgstr "无法创建文件:"
|
||||
|
||||
#: cookies.rs:379 data/json.rs:70 settings.rs:409 webclient.rs:294
|
||||
#: cookies.rs:379 data/json.rs:70 settings.rs:417 webclient.rs:307
|
||||
msgid "Failed to write file:"
|
||||
msgstr "无法写入文件:"
|
||||
|
||||
@@ -86,7 +86,7 @@ msgstr "无法写入文件:"
|
||||
msgid "Failed to unescape string:"
|
||||
msgstr "无法反转义字符串:"
|
||||
|
||||
#: download.rs:18 pixiv_web.rs:57
|
||||
#: download.rs:18 pixiv_web.rs:58
|
||||
msgid "Failed to initialize pixiv web api client."
|
||||
msgstr "无法初始化 Pixiv 网页 API 客户端。"
|
||||
|
||||
@@ -115,7 +115,7 @@ msgid "Failed to get file name from url:"
|
||||
msgstr "无法从 URL 获取文件名:"
|
||||
|
||||
#: download.rs:90 download.rs:96 download.rs:133 download.rs:139
|
||||
#: pixiv_web.rs:152
|
||||
#: pixiv_web.rs:153
|
||||
msgid "Failed to download image:"
|
||||
msgstr "无法下载图片:"
|
||||
|
||||
@@ -127,82 +127,94 @@ msgstr "已下载图片:"
|
||||
msgid "Failed to add exif data to image:"
|
||||
msgstr "无法往图片增加 EXIF 数据:"
|
||||
|
||||
#: opts.rs:79
|
||||
#: dur.rs:73
|
||||
msgid "Failed to parse duration from string."
|
||||
msgstr "无法解析从字符串解析时长:"
|
||||
|
||||
#: opts.rs:85
|
||||
msgid "Warning: The specified config file not found."
|
||||
msgstr "警告:没有找到指定的设置文件。"
|
||||
|
||||
#: opts.rs:103
|
||||
#: opts.rs:109
|
||||
msgid "Usage:"
|
||||
msgstr "使用方法:"
|
||||
|
||||
#: opts.rs:105
|
||||
#: opts.rs:111
|
||||
msgid "Download an artwork"
|
||||
msgstr "下载一个作品"
|
||||
|
||||
#: opts.rs:107
|
||||
#: opts.rs:113
|
||||
msgid "Fix the config file"
|
||||
msgstr "修复设置文件"
|
||||
|
||||
#: opts.rs:109
|
||||
#: opts.rs:115
|
||||
msgid "Print all available settings"
|
||||
msgstr "打印所有可用的设置"
|
||||
|
||||
#: opts.rs:117
|
||||
#: opts.rs:123
|
||||
msgid "Print help message."
|
||||
msgstr "打印帮助信息。"
|
||||
|
||||
#: opts.rs:121
|
||||
#: opts.rs:127
|
||||
msgid "The location of config file."
|
||||
msgstr "设置文件的位置。"
|
||||
|
||||
#: opts.rs:127 settings_list.rs:8
|
||||
#: opts.rs:133 settings_list.rs:10
|
||||
msgid "The location of cookies file. Used for web API."
|
||||
msgstr "cookies 文件的位置。用于网页 API。"
|
||||
|
||||
#: opts.rs:133 settings_list.rs:9
|
||||
#: opts.rs:139 settings_list.rs:11
|
||||
msgid "The language of translated tags."
|
||||
msgstr "翻译后的标签语言。"
|
||||
|
||||
#: opts.rs:136
|
||||
#: opts.rs:142
|
||||
msgid "Verbose logging."
|
||||
msgstr "启用详细内容输出。"
|
||||
|
||||
#: opts.rs:137
|
||||
#: opts.rs:143
|
||||
msgid "Overwrite existing file."
|
||||
msgstr "覆盖已有文件。"
|
||||
|
||||
#: opts.rs:138
|
||||
#: opts.rs:144
|
||||
msgid "Skip overwrite existing file."
|
||||
msgstr "跳过覆盖已有文件。"
|
||||
|
||||
#: opts.rs:142 settings_list.rs:10
|
||||
#: opts.rs:148 settings_list.rs:12
|
||||
msgid "Max retry count if request failed."
|
||||
msgstr "请求失败时最大重试次数。"
|
||||
|
||||
#: opts.rs:164
|
||||
#: opts.rs:154 settings_list.rs:13
|
||||
msgid "The interval (in seconds) between two retries."
|
||||
msgstr "两次尝试的间隔时间(单位:秒)。"
|
||||
|
||||
#: opts.rs:176
|
||||
msgid "Unknown command."
|
||||
msgstr "未知指令。"
|
||||
|
||||
#: opts.rs:174
|
||||
#: opts.rs:186
|
||||
msgid "Failed to parse ID:"
|
||||
msgstr "无法解析 ID:"
|
||||
|
||||
#: opts.rs:180
|
||||
#: opts.rs:192
|
||||
msgid "No URL or ID specified."
|
||||
msgstr "没有指定网址或 ID。"
|
||||
|
||||
#: opts.rs:188
|
||||
#: opts.rs:200
|
||||
msgid "No detailed command specified."
|
||||
msgstr "没有指定更详细的指令。"
|
||||
|
||||
#: opts.rs:201
|
||||
#: opts.rs:213
|
||||
msgid "Unknown config subcommand."
|
||||
msgstr "未知的 config 子指令。"
|
||||
|
||||
#: opts.rs:237
|
||||
#: opts.rs:249
|
||||
msgid "Retry count must be an non-negative integer:"
|
||||
msgstr "重试次数不能是负数:"
|
||||
|
||||
#: opts.rs:258
|
||||
msgid "Failed to parse retry interval:"
|
||||
msgstr "无法解析间隔时间:"
|
||||
|
||||
#: parser/description.rs:129 parser/metadata.rs:76
|
||||
msgid "Failed to parse HTML:"
|
||||
msgstr "无法解析 HTML:"
|
||||
@@ -215,75 +227,87 @@ msgstr "在解析中发生了一些错误:"
|
||||
msgid "There are some nodes still in stack:"
|
||||
msgstr "堆栈中依旧有一些节点:"
|
||||
|
||||
#: parser/metadata.rs:54 pixiv_web.rs:111
|
||||
#: parser/metadata.rs:54 pixiv_web.rs:112
|
||||
msgid "Failed to parse JSON:"
|
||||
msgstr "无法解析 JSON:"
|
||||
|
||||
#: pixiv_web.rs:72 pixiv_web.rs:77
|
||||
#: pixiv_web.rs:73 pixiv_web.rs:78
|
||||
msgid "Failed to get main page:"
|
||||
msgstr "无法获取主页:"
|
||||
|
||||
#: pixiv_web.rs:83
|
||||
#: pixiv_web.rs:84
|
||||
msgid "Failed to parse main page."
|
||||
msgstr "无法解析主页。"
|
||||
|
||||
#: pixiv_web.rs:87
|
||||
#: pixiv_web.rs:88
|
||||
msgid "Main page's data:"
|
||||
msgstr "主页的数据:"
|
||||
|
||||
#: pixiv_web.rs:102
|
||||
#: pixiv_web.rs:103
|
||||
msgid "Network error:"
|
||||
msgstr "网络错误:"
|
||||
|
||||
#: pixiv_web.rs:121
|
||||
#: pixiv_web.rs:122
|
||||
msgid "Failed to detect error."
|
||||
msgstr "检测 error 字段失败。"
|
||||
|
||||
#: pixiv_web.rs:168 pixiv_web.rs:173
|
||||
#: pixiv_web.rs:169 pixiv_web.rs:174
|
||||
msgid "Failed to get artwork page:"
|
||||
msgstr "无法获取作品页:"
|
||||
|
||||
#: pixiv_web.rs:179
|
||||
#: pixiv_web.rs:180
|
||||
msgid "Failed to parse artwork page."
|
||||
msgstr "无法解析作品页。"
|
||||
|
||||
#: pixiv_web.rs:183
|
||||
#: pixiv_web.rs:184
|
||||
msgid "Artwork's data:"
|
||||
msgstr "作品数据:"
|
||||
|
||||
#: pixiv_web.rs:197
|
||||
#: pixiv_web.rs:198
|
||||
msgid "Artwork's page data:"
|
||||
msgstr "作品页面数据:"
|
||||
|
||||
#: pixiv_web.rs:221
|
||||
#: pixiv_web.rs:222
|
||||
msgid "Warning: Failed to save cookies file:"
|
||||
msgstr "警告:无法保存 cookies 文件:"
|
||||
|
||||
#: retry_interval.rs:22
|
||||
msgid "Failed to get JSON object."
|
||||
msgstr "无法获取 JSON 对象。"
|
||||
|
||||
#: retry_interval.rs:37 retry_interval.rs:55
|
||||
msgid "Failed to parse JSON number."
|
||||
msgstr "无法解析 JSON 数字:"
|
||||
|
||||
#: retry_interval.rs:61 retry_interval.rs:65
|
||||
msgid "Unsupported JSON type."
|
||||
msgstr "不支持的 JSON 类型。"
|
||||
|
||||
#: settings.rs:29
|
||||
msgid "Multiple type"
|
||||
msgstr "多种类型"
|
||||
|
||||
#: settings.rs:264
|
||||
#: settings.rs:268
|
||||
msgid "Can not insert setting to JSON object."
|
||||
msgstr "无法将设置插入 JSON 对象。"
|
||||
|
||||
#: settings.rs:331
|
||||
#: settings.rs:339
|
||||
msgid "Settings file is empty."
|
||||
msgstr "设置文件是空的。"
|
||||
|
||||
#: settings.rs:338
|
||||
#: settings.rs:346
|
||||
msgid "Can not read from settings file."
|
||||
msgstr "无法读取设置文件。"
|
||||
|
||||
#: settings.rs:347
|
||||
#: settings.rs:355
|
||||
msgid "Can not parse settings file."
|
||||
msgstr "无法解析设置文件。"
|
||||
|
||||
#: settings.rs:356
|
||||
#: settings.rs:364
|
||||
msgid "Unknown settings file."
|
||||
msgstr "未知的设置文件。"
|
||||
|
||||
#: settings.rs:367
|
||||
#: settings.rs:375
|
||||
msgid ""
|
||||
"\"<key>\" is invalid, you can use \"pixiv_downloader config fix\" to remove "
|
||||
"all invalid value."
|
||||
@@ -291,15 +315,15 @@ msgstr ""
|
||||
"\"<key>\" 不合法,您可以使用 \"pixiv_downloader config fix\" 来移除所有不合"
|
||||
"法的值。"
|
||||
|
||||
#: settings.rs:386
|
||||
#: settings.rs:394
|
||||
msgid "Can not convert settings to JSON object."
|
||||
msgstr "无法将设置转换为 JSON 对象。"
|
||||
|
||||
#: settings.rs:414
|
||||
#: settings.rs:422
|
||||
msgid "Failed to flush file:"
|
||||
msgstr "无法刷新文件缓冲区:"
|
||||
|
||||
#: settings_list.rs:7
|
||||
#: settings_list.rs:9
|
||||
msgid "Pixiv's refresh tokens. Used to login."
|
||||
msgstr "Pixiv 的 refresh tokens。用于登录。"
|
||||
|
||||
@@ -307,7 +331,7 @@ msgstr "Pixiv 的 refresh tokens。用于登录。"
|
||||
msgid "Do you want to delete file \"<file>\"?"
|
||||
msgstr "你想要删除文件 <file> 吗?"
|
||||
|
||||
#: utils.rs:51 webclient.rs:146
|
||||
#: utils.rs:51 webclient.rs:152
|
||||
msgid "Can not parse URL:"
|
||||
msgstr "无法解析 URL:"
|
||||
|
||||
@@ -315,46 +339,50 @@ msgstr "无法解析 URL:"
|
||||
msgid "Failed to get file name from path:"
|
||||
msgstr "无法从路径获取文件名:"
|
||||
|
||||
#: webclient.rs:106
|
||||
#: webclient.rs:112
|
||||
msgid "Failed to parse Set-Cookie header."
|
||||
msgstr "无法解析 Set-Cookie 头部。"
|
||||
|
||||
#: webclient.rs:111
|
||||
#: webclient.rs:117
|
||||
msgid "Failed to convert to string:"
|
||||
msgstr "无法转换为字符串:"
|
||||
|
||||
#: webclient.rs:153
|
||||
#: webclient.rs:159
|
||||
msgid "Parameters should be object or array:"
|
||||
msgstr "参数应该是对象或数组:"
|
||||
|
||||
#: webclient.rs:173
|
||||
#: webclient.rs:179
|
||||
msgid "Parameters should be array:"
|
||||
msgstr "参数应该是数组:"
|
||||
|
||||
#: webclient.rs:177
|
||||
#: webclient.rs:183
|
||||
msgid "Parameters need at least a value:"
|
||||
msgstr "参数需要至少含有一个值:"
|
||||
|
||||
#: webclient.rs:213
|
||||
#: webclient.rs:222
|
||||
msgid "Retry after <num> seconds."
|
||||
msgstr "<num> 秒后重试。"
|
||||
|
||||
#: webclient.rs:226
|
||||
msgid "Retry <count> times now."
|
||||
msgstr "正在进行第 <count> 次重试。"
|
||||
|
||||
#: webclient.rs:227
|
||||
#: webclient.rs:240
|
||||
msgid "Error when request:"
|
||||
msgstr "请求时发生错误:"
|
||||
|
||||
#: webclient.rs:288
|
||||
#: webclient.rs:301
|
||||
msgid "Error when downloading file:"
|
||||
msgstr "下载文件时发生错误:"
|
||||
|
||||
#: main.rs:65
|
||||
#: main.rs:68
|
||||
msgid "Failed to save config file:"
|
||||
msgstr "无法保存设置文件:"
|
||||
|
||||
#: main.rs:76
|
||||
#: main.rs:79
|
||||
msgid "All available settings:"
|
||||
msgstr "所有可用的设置:"
|
||||
|
||||
#: main.rs:108
|
||||
#: main.rs:111
|
||||
msgid "Can not read config file:"
|
||||
msgstr "无法读取设置文件:"
|
||||
|
||||
@@ -31,7 +31,7 @@ impl PixivData {
|
||||
}
|
||||
|
||||
/// Read data from JSON object.
|
||||
/// The object is from https://www.pixiv.net/artworks/<id>
|
||||
/// The object is from `https://www.pixiv.net/artworks/<id>`
|
||||
/// * `value` - The JSON object
|
||||
/// * `allow_overwrite` - Allow overwrite the data existing.
|
||||
pub fn from_web_page_data(&mut self, value: &JsonValue, allow_overwrite: bool) {
|
||||
|
||||
@@ -135,3 +135,15 @@ impl ToJson for String {
|
||||
Some(JsonValue::String(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for JsonValue {
|
||||
fn to_json(&self) -> Option<JsonValue> {
|
||||
Some(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for &JsonValue {
|
||||
fn to_json(&self) -> Option<JsonValue> {
|
||||
Some((*self).clone())
|
||||
}
|
||||
}
|
||||
|
||||
95
src/dur.rs
Normal file
95
src/dur.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use crate::gettext;
|
||||
use std::cmp::PartialEq;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum DurType {
|
||||
Second,
|
||||
MilliSecond,
|
||||
NanoSecond,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Dur {
|
||||
num: Option<u64>,
|
||||
f: Option<f64>,
|
||||
}
|
||||
|
||||
impl Dur {
|
||||
pub fn from_num(num: u64) -> Self {
|
||||
Self {
|
||||
num: Some(num),
|
||||
f: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_f(f: f64) -> Self {
|
||||
Self {
|
||||
num: None,
|
||||
f: Some(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_duration(&self, t: DurType) -> Duration {
|
||||
match t {
|
||||
DurType::Second => {
|
||||
if self.num.is_some() {
|
||||
Duration::from_secs(self.num.unwrap())
|
||||
} else {
|
||||
Duration::from_secs_f64(self.f.unwrap())
|
||||
}
|
||||
}
|
||||
DurType::MilliSecond => {
|
||||
if self.num.is_some() {
|
||||
Duration::from_millis(self.num.unwrap())
|
||||
} else {
|
||||
Duration::from_secs_f64(self.f.unwrap() / 1000f64)
|
||||
}
|
||||
}
|
||||
DurType::NanoSecond => {
|
||||
if self.num.is_some() {
|
||||
Duration::from_nanos(self.num.unwrap())
|
||||
} else {
|
||||
Duration::from_secs_f64(self.f.unwrap() / 1_000_000_000f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Dur {
|
||||
type Err = &'static str;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.trim();
|
||||
let num = s.parse::<u64>();
|
||||
if num.is_ok() {
|
||||
return Ok(Self::from_num(num.unwrap()));
|
||||
}
|
||||
let f = s.parse::<f64>();
|
||||
if num.is_ok() {
|
||||
return Ok(Self::from_f(f.unwrap()));
|
||||
}
|
||||
Err(gettext("Failed to parse duration from string."))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<u64> for Dur {
|
||||
fn eq(&self, other: &u64) -> bool {
|
||||
if self.num.is_some() {
|
||||
self.num.as_ref().unwrap() == other
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<f64> for Dur {
|
||||
fn eq(&self, other: &f64) -> bool {
|
||||
if self.f.is_some() {
|
||||
self.f.as_ref().unwrap() == other
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
172
src/list.rs
Normal file
172
src/list.rs
Normal file
@@ -0,0 +1,172 @@
|
||||
use std::clone::Clone;
|
||||
use std::cmp::PartialEq;
|
||||
use std::convert::AsMut;
|
||||
use std::convert::AsRef;
|
||||
use std::convert::From;
|
||||
use std::convert::Into;
|
||||
use std::default::Default;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::AddAssign;
|
||||
use std::ops::Index;
|
||||
use std::ops::IndexMut;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// A list which if index greater than count, which will return last one of the element.
|
||||
pub struct NonTailList<T> {
|
||||
/// The list
|
||||
data: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> AddAssign<T> for NonTailList<T> {
|
||||
fn add_assign(&mut self, rhs: T) {
|
||||
self.data.push(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> AddAssign<&T> for NonTailList<T> {
|
||||
fn add_assign(&mut self, rhs: &T) {
|
||||
self.data.push(rhs.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<NonTailList<T>> for NonTailList<T> {
|
||||
fn as_mut(&mut self) -> &mut NonTailList<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<NonTailList<T>> for NonTailList<T> {
|
||||
fn as_ref(&self) -> &NonTailList<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for NonTailList<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
data: self.data.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for NonTailList<T> where Vec<T>: Debug {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Vec::<T>::fmt(&self.data, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for NonTailList<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> From<&[T]> for NonTailList<T> {
|
||||
fn from(list: &[T]) -> Self {
|
||||
Self {
|
||||
data: Vec::from(list),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vec<T>> for NonTailList<T> {
|
||||
fn from(list: Vec<T>) -> Self {
|
||||
Self {
|
||||
data: list,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> From<&Vec<T>> for NonTailList<T> {
|
||||
fn from(list: &Vec<T>) -> Self {
|
||||
Self {
|
||||
data: list.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromStr> FromStr for NonTailList<T> {
|
||||
type Err = T::Err;
|
||||
/// Parse a list from string
|
||||
/// * `s` - a list of items separated by `,`
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// let l: NonTailList<i32> = NonTailList::from_str("1,2,3").unwrap();
|
||||
/// ```
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err>{
|
||||
let mut l: Vec<T> = Vec::new();
|
||||
let r = s.split(",");
|
||||
for i in r {
|
||||
let i = i.trim();
|
||||
let a = i.parse::<T>()?;
|
||||
l.push(a);
|
||||
}
|
||||
Ok(Self {
|
||||
data: l,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Into<Vec<T>> for NonTailList<T> {
|
||||
fn into(self) -> Vec<T> {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Into<Vec<T>> for &NonTailList<T> {
|
||||
fn into(self) -> Vec<T> {
|
||||
self.data.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Index<usize> for NonTailList<T> {
|
||||
type Output = T;
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
let count = self.data.len();
|
||||
if index < count {
|
||||
&self.data[index]
|
||||
} else {
|
||||
&self.data[count - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IndexMut<usize> for NonTailList<T> {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
let count = self.data.len();
|
||||
if index < count {
|
||||
self.data.index_mut(index)
|
||||
} else {
|
||||
self.data.index_mut(count - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, V> PartialEq<Vec<V>> for NonTailList<T> where T: PartialEq<V> {
|
||||
fn eq(&self, other: &Vec<V>) -> bool {
|
||||
&self.data == other
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_non_tail_list() {
|
||||
let mut l = NonTailList::from(vec![1, 2, 3]);
|
||||
assert_eq!(1, l[0]);
|
||||
assert_eq!(2, l[1]);
|
||||
assert_eq!(3, l[2]);
|
||||
assert_eq!(3, l[3]);
|
||||
l[0] = 0;
|
||||
assert_eq!(0, l[0]);
|
||||
let l2: Vec<i32> = l.as_ref().into();
|
||||
assert_eq!(l2, vec![0, 2, 3]);
|
||||
assert_eq!(l[4], 3);
|
||||
l += 4;
|
||||
assert_eq!(l[3], 4);
|
||||
let l = NonTailList::<i32>::from_str("1, 2, 3").unwrap();
|
||||
assert!(l == vec![1, 2, 3]);
|
||||
assert_eq!(l, vec![1, 2, 3]);
|
||||
let l2: Vec<i32> = l.as_ref().into();
|
||||
assert_eq!(l2, vec![1, 2, 3]);
|
||||
}
|
||||
@@ -24,14 +24,17 @@ mod _exif;
|
||||
mod cookies;
|
||||
mod data;
|
||||
mod download;
|
||||
mod dur;
|
||||
#[cfg(feature = "exif")]
|
||||
mod exif;
|
||||
mod i18n;
|
||||
mod list;
|
||||
mod opthelper;
|
||||
mod opts;
|
||||
mod parser;
|
||||
mod pixiv_link;
|
||||
mod pixiv_web;
|
||||
mod retry_interval;
|
||||
mod settings;
|
||||
mod settings_list;
|
||||
mod utils;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::opts::CommandOpts;
|
||||
use crate::list::NonTailList;
|
||||
use crate::retry_interval::parse_retry_interval_from_json;
|
||||
use crate::settings::SettingStore;
|
||||
use std::time::Duration;
|
||||
|
||||
/// An sturct to access all available settings/command line switches
|
||||
#[derive(Clone)]
|
||||
@@ -8,6 +11,7 @@ pub struct OptHelper<'a> {
|
||||
opt: &'a CommandOpts,
|
||||
/// Settings
|
||||
settings: &'a SettingStore,
|
||||
default_retry_interval: NonTailList<Duration>,
|
||||
}
|
||||
|
||||
impl<'a> OptHelper<'a> {
|
||||
@@ -34,7 +38,13 @@ impl<'a> OptHelper<'a> {
|
||||
}
|
||||
|
||||
pub fn new(opt: &'a CommandOpts, settings: &'a SettingStore) -> Self {
|
||||
Self { opt, settings }
|
||||
let mut l = NonTailList::default();
|
||||
l += Duration::new(3, 0);
|
||||
Self {
|
||||
opt,
|
||||
settings,
|
||||
default_retry_interval: l,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overwrite(&self) -> Option<bool> {
|
||||
@@ -56,4 +66,16 @@ impl<'a> OptHelper<'a> {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Return retry interval
|
||||
pub fn retry_interval(&self) -> NonTailList<Duration> {
|
||||
if self.opt.retry_interval.is_some() {
|
||||
return self.opt.retry_interval.as_ref().unwrap().clone();
|
||||
}
|
||||
if self.settings.have("retry-interval") {
|
||||
let v = self.settings.get("retry-interval").unwrap();
|
||||
return parse_retry_interval_from_json(v).unwrap();
|
||||
}
|
||||
self.default_retry_interval.clone()
|
||||
}
|
||||
}
|
||||
|
||||
21
src/opts.rs
21
src/opts.rs
@@ -1,11 +1,14 @@
|
||||
extern crate getopts;
|
||||
|
||||
use crate::gettext;
|
||||
use crate::list::NonTailList;
|
||||
use crate::pixiv_link::PixivID;
|
||||
use crate::retry_interval::parse_retry_interval_from_str;
|
||||
use crate::utils::check_file_exists;
|
||||
use crate::utils::get_exe_path_else_current;
|
||||
use getopts::Options;
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Command Line command
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
@@ -52,6 +55,8 @@ pub struct CommandOpts {
|
||||
pub overwrite: Option<bool>,
|
||||
/// Max retry count.
|
||||
pub retry: Option<u64>,
|
||||
/// Retry interval
|
||||
pub retry_interval: Option<NonTailList<Duration>>,
|
||||
}
|
||||
|
||||
impl CommandOpts {
|
||||
@@ -66,6 +71,7 @@ impl CommandOpts {
|
||||
verbose: false,
|
||||
overwrite: None,
|
||||
retry: None,
|
||||
retry_interval: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +148,12 @@ pub fn parse_cmd() -> Option<CommandOpts> {
|
||||
gettext("Max retry count if request failed."),
|
||||
"COUNT",
|
||||
);
|
||||
opts.optopt(
|
||||
"",
|
||||
"retry-interval",
|
||||
gettext("The interval (in seconds) between two retries."),
|
||||
"LIST",
|
||||
);
|
||||
let result = match opts.parse(&argv[1..]) {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
@@ -239,5 +251,14 @@ pub fn parse_cmd() -> Option<CommandOpts> {
|
||||
}
|
||||
re.as_mut().unwrap().retry = Some(c.unwrap());
|
||||
}
|
||||
if result.opt_present("retry-interval") {
|
||||
let s = result.opt_str("retry-interval").unwrap();
|
||||
let r = parse_retry_interval_from_str(s.as_str());
|
||||
if r.is_err() {
|
||||
println!("{} {}", gettext("Failed to parse retry interval:"), r.unwrap_err());
|
||||
return None;
|
||||
}
|
||||
re.as_mut().unwrap().retry_interval = Some(r.unwrap());
|
||||
}
|
||||
re
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ impl<'a> PixivWebClient<'a> {
|
||||
if retry.is_some() {
|
||||
self.client.retry = retry.unwrap();
|
||||
}
|
||||
self.client.retry_interval = Some(self.helper.retry_interval());
|
||||
self.inited = true;
|
||||
true
|
||||
}
|
||||
|
||||
84
src/retry_interval.rs
Normal file
84
src/retry_interval.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use crate::data::json::ToJson;
|
||||
use crate::dur::Dur;
|
||||
use crate::dur::DurType;
|
||||
use crate::gettext;
|
||||
use crate::list::NonTailList;
|
||||
use json::JsonValue;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
pub fn parse_retry_interval_from_str(s: &str) -> Result<NonTailList<Duration>, &'static str> {
|
||||
let l: Vec<Dur> = NonTailList::<Dur>::from_str(s)?.into();
|
||||
let mut r = Vec::new();
|
||||
for i in l {
|
||||
r.push(i.to_duration(DurType::Second));
|
||||
}
|
||||
Ok(NonTailList::from(r))
|
||||
}
|
||||
|
||||
pub fn parse_retry_interval_from_json<T: ToJson>(s: T) -> Result<NonTailList<Duration>, &'static str> {
|
||||
let obj = s.to_json();
|
||||
if obj.is_none() {
|
||||
return Err(gettext("Failed to get JSON object."));
|
||||
}
|
||||
let obj = obj.unwrap();
|
||||
let mut r = NonTailList::<Duration>::default();
|
||||
if obj.is_number() {
|
||||
match obj.as_u64() {
|
||||
Some(num) => {
|
||||
r += Duration::new(num, 0);
|
||||
}
|
||||
None => {
|
||||
match obj.as_f64() {
|
||||
Some(num) => {
|
||||
r += Duration::from_secs_f64(num);
|
||||
}
|
||||
None => {
|
||||
return Err(gettext("Failed to parse JSON number."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if obj.is_array() {
|
||||
for v in obj.members() {
|
||||
if v.is_number() {
|
||||
match v.as_u64() {
|
||||
Some(num) => {
|
||||
r += Duration::new(num, 0);
|
||||
}
|
||||
None => {
|
||||
match v.as_f64() {
|
||||
Some(num) => {
|
||||
r += Duration::from_secs_f64(num);
|
||||
}
|
||||
None => {
|
||||
return Err(gettext("Failed to parse JSON number."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(gettext("Unsupported JSON type."));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(gettext("Unsupported JSON type."));
|
||||
}
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn check_retry_interval(s: &JsonValue) -> bool {
|
||||
parse_retry_interval_from_json(s).is_ok()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_retry_interval() {
|
||||
let l = parse_retry_interval_from_str("2, 3, 4").unwrap();
|
||||
assert_eq!(l, vec![Duration::new(2, 0), Duration::new(3, 0), Duration::new(4, 0)]);
|
||||
let l = parse_retry_interval_from_json(json::parse("123").unwrap()).unwrap();
|
||||
assert_eq!(l, vec![Duration::new(123, 0)]);
|
||||
let l = parse_retry_interval_from_json(json::parse("123.7").unwrap()).unwrap();
|
||||
assert_eq!(l, vec![Duration::new(123, 700_000_000)]);
|
||||
let l = parse_retry_interval_from_json(json::array![123, 123.7, 230]).unwrap();
|
||||
assert_eq!(l, vec![Duration::new(123, 0), Duration::new(123, 700_000_000), Duration::new(230, 0)]);
|
||||
}
|
||||
@@ -255,6 +255,10 @@ impl SettingJar {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn have(&self, key: &str) -> bool {
|
||||
self.settings.contains_key(key)
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> Option<JsonValue> {
|
||||
let mut v = JsonValue::new_object();
|
||||
for (_, val) in self.settings.iter() {
|
||||
@@ -301,6 +305,10 @@ impl SettingStore {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn have(&self, key: &str) -> bool {
|
||||
self.data.have(key)
|
||||
}
|
||||
|
||||
pub fn have_str(&self, key: &str) -> bool {
|
||||
let obj = self.data.get(key);
|
||||
if obj.is_none() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::gettext;
|
||||
use crate::retry_interval::check_retry_interval;
|
||||
use crate::settings::SettingDes;
|
||||
use crate::settings::JsonValueType;
|
||||
use json::JsonValue;
|
||||
@@ -9,6 +10,7 @@ pub fn get_settings_list() -> Vec<SettingDes> {
|
||||
SettingDes::new("cookies", gettext("The location of cookies file. Used for web API."), JsonValueType::Str, None).unwrap(),
|
||||
SettingDes::new("language", gettext("The language of translated tags."), JsonValueType::Str, None).unwrap(),
|
||||
SettingDes::new("retry", gettext("Max retry count if request failed."), JsonValueType::Number, Some(check_u64)).unwrap(),
|
||||
SettingDes::new("retry-interval", gettext("The interval (in seconds) between two retries."), JsonValueType::Multiple, Some(check_retry_interval)).unwrap(),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -3,17 +3,20 @@ extern crate spin_on;
|
||||
use crate::cookies::Cookie;
|
||||
use crate::cookies::CookieJar;
|
||||
use crate::gettext;
|
||||
use crate::list::NonTailList;
|
||||
use crate::utils::ask_need_overwrite;
|
||||
use futures_util::StreamExt;
|
||||
use json::JsonValue;
|
||||
use reqwest::{Client, IntoUrl, RequestBuilder, Response};
|
||||
use spin_on::spin_on;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::fs::remove_file;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
pub trait ToHeaders {
|
||||
fn to_headers(&self) -> Option<HashMap<String, String>>;
|
||||
@@ -76,6 +79,8 @@ pub struct WebClient {
|
||||
pub verbose: bool,
|
||||
/// Retry times, 0 means disable
|
||||
pub retry: u64,
|
||||
/// Retry interval
|
||||
pub retry_interval: Option<NonTailList<Duration>>,
|
||||
}
|
||||
|
||||
impl WebClient {
|
||||
@@ -86,6 +91,7 @@ impl WebClient {
|
||||
cookies: CookieJar::new(),
|
||||
verbose: false,
|
||||
retry: 3,
|
||||
retry_interval: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,6 +216,13 @@ impl WebClient {
|
||||
}
|
||||
count += 1;
|
||||
if count <= self.retry {
|
||||
if self.retry_interval.is_some() {
|
||||
let t = self.retry_interval.as_ref().unwrap()[(count - 1).try_into().unwrap()];
|
||||
if !t.is_zero() {
|
||||
println!("{}", gettext("Retry after <num> seconds.").replace("<num>", format!("{}", t.as_secs_f64()).as_str()).as_str());
|
||||
spin_on(tokio::time::sleep(t));
|
||||
}
|
||||
}
|
||||
println!("{}", gettext("Retry <count> times now.").replace("<count>", format!("{}", count).as_str()).as_str());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user