Permalink
Browse files

2.018 add download_range option #28

  • Loading branch information...
fffonion committed Oct 8, 2017
1 parent 6b04e55 commit d338984d5bc916d6f25d2cb99d71a42fdb4f7d29
Showing with 84 additions and 11 deletions.
  1. +4 −0 CHANGELOG.md
  2. +19 −3 README.MD
  3. +33 −5 xeHentai/cli.py
  4. +1 −0 xeHentai/const.py
  5. +2 −2 xeHentai/core.py
  6. +4 −0 xeHentai/i18n/en_us.py
  7. +4 −0 xeHentai/i18n/zh_hans.py
  8. +17 −1 xeHentai/task.py
View
@@ -1,5 +1,9 @@
# Changelog
## 2.018
- 增加`jpn_title`选项,选择是否使用日语标题
- 增加`download_range`选项,选择下载范围
## 2.017
- 修复匹配网址的正则表达式
- 修复表站自动转换里站逻辑
View
@@ -47,11 +47,15 @@ xeH
用法: xeH [-u USERNAME] [-k KEY] [-c COOKIE] [-i] [-o] [-t N] [-d DIR]
[--daemon] [-l /path/to/eh.log] [-p PROXY] [--proxy-image] [-v]
[--rpc-interface ADDR] [--rpc-port PORT] [--rpc-secret ...]
[-r BOOL] [-a BOOL] [-h] [--version]
[-r BOOL] [-a BOOL] [-j BOOL] [--download-range a-b,c-d,e] [-h]
[--version]
[url [url ...]]
绅♂士下载器
必选参数:
url 下载页的网址
可选参数:
-h, --help 显示帮助
-u USERNAME, --username USERNAME
@@ -77,11 +81,14 @@ xeH
将图片重命名为原始名称,如果关闭则使用序号 (默认: True)
-a BOOL, --archive BOOL
下载完成后生成zip压缩包并删除下载目录 (默认: False)
-j BOOL, --jpn-title BOOL
使用日语标题, 如果关闭则使用英文或罗马字标题 (默认: True)
--download-range a-b,c-d,e
设置需要下载的图片范围, 格式为 开始位置-结束位置, 或者单张图片的位置,
可以使用逗号来分隔多个范围, 例如 5-10,15,20-25
-h, --help 显示本帮助信息
--version 显示版本信息
如果参数未指定,则使用config.py中的默认值
```
如果参数未指定,则使用config.py中的默认值;否则将覆盖config.py设置的值。
@@ -132,6 +139,15 @@ Firefox用户需要安装[Greasemonkey](https://addons.mozilla.org/en-US/firefox
如果使用代理仅用于突破封锁的目的,则此项可以设置为`False`;如果需要保证隐私,请将此项设置为`True`。使用glype代理的用户建议将此项设为`False`
### 下载范围
下载范围仅可通过命令行模式或者交互模式设置。格式为使用`开始位置-结束位置`,例如`5-10`表示下载第5到第10张图片,包括第5和第10张;或者单个位置,例如`15`表示下载第15张图片。
可以通过逗号来分割多个范围,例如`5-10,15`表示下载第5到第10张图片以及第15张图片。
如果不输入下载范围,则默认下载所有图片。
## 其他说明
### 配额
View
@@ -93,6 +93,19 @@ def main(xeH, opt):
-f --force 即使超出配额也下载,默认为否
-j --no-jp-name 是否不使用日语命名,默认为否'''
def _parse_range(s):
rg = []
s = s.replace("", ",")
for r in s.split(','):
r = r.strip()
m = re.match(r'(\d+)(?:-(\d+))?$', r)
if not m:
raise argparse.ArgumentTypeError(logger.safestr(i18n.c(ERR_NOT_RANGE_FORMAT) % r))
start = int(m.group(1))
end = int(m.group(2) or start)
rg.append((start, end))
return sorted(rg)
def parse_opt():
_def = {k:v for k,v in default_config.__dict__.items() if not k.startswith("_")}
_def.update({k:v for k,v in config.__dict__.items() if not k.startswith("_")})
@@ -140,12 +153,15 @@ def parse_opt():
parser.add_argument('-a', '--archive', type = bool, metavar = "BOOL", default = _def['make_archive'],
dest = 'make_archive', help = i18n.XEH_OPT_a)
parser.add_argument('-j', '--jpn-title', type = bool, metavar = "BOOL", default = _def['jpn_title'],
dest = 'jpn_title', help = i18n.XEH_OPT_j)
dest = 'jpn_title', help = i18n.XEH_OPT_j)
parser.add_argument('--download-range', type = _parse_range, metavar = "a-b,c-d,e", default = None,
dest = 'download_range', help = i18n.XEH_OPT_download_range)
parser.add_argument('-h','--help', action = 'help', help = i18n.XEH_OPT_h)
parser.add_argument('--version', action = 'version', version = '%s v%.3f' % (SCRIPT_NAME, __version__),
parser.add_argument('--version', action = 'version',
version = '%s v%.3f%s' % (SCRIPT_NAME, __version__, '-dev' if DEVELOPMENT else ""),
help = i18n.XEH_OPT_version)
args = parser.parse_args()
return args
def interactive(xeH):
@@ -163,7 +179,7 @@ def _readline(x, default = ""):
while not pwd:
pwd = _readline(i18n.PS_PASSWD)
xeH.login_exhentai(uname, pwd)
url = proxy = ""
url = proxy = download_range = ""
while not url:
url = _readline(i18n.PS_URL)
url = url.split(",")
@@ -177,5 +193,17 @@ def _readline(x, default = ""):
rename_ori = _readline(i18n.PS_RENAME_ORI, 'y' if xeH.cfg['rename_ori'] else 'n') == 'y'
make_archive = _readline(i18n.PS_MAKE_ARCHIVE, 'y' if xeH.cfg['make_archive'] else 'n') == 'y'
jpn_title = _readline(i18n.PS_JPN_TITLE, 'y' if xeH.cfg['jpn_title'] else 'n') == 'y'
while not download_range:
_ = _readline(i18n.PS_DOWNLOAD_RANGE)
if not _:
download_range = []
break
try:
download_range = _parse_range(logger.safestr(_))
except argparse.ArgumentTypeError as ex:
print(ex)
else:
break
return {'urls': url, 'proxy': proxy, 'download_ori': download_ori, 'dir': _dir, 'rename_ori':rename_ori,
'make_archive': make_archive, 'jpn_title': jpn_title, 'save_tasks': False}
'make_archive': make_archive, 'jpn_title': jpn_title, 'save_tasks': False,
'download_range': download_range}
View
@@ -80,6 +80,7 @@
ERR_RPC_UNAUTHORIZED = 1200
ERR_CANNOT_CREATE_DIR = 1300
ERR_CANNOT_MAKE_ARCHIVE = 1301
ERR_NOT_RANGE_FORMAT = 1302
ERR_RPC_PARSE_ERROR = -32700
ERR_RPC_INVALID_REQUEST = -32600
ERR_RPC_METHOD_NOT_FOUND = -32601
View
@@ -97,7 +97,7 @@ def add_task(self, url, cfg_dict = {}):
url = url.strip()
cfg = {k:v for k, v in self.cfg.items() if k in (
"dir", "download_ori", "download_thread_cnt", "scan_thread_cnt",
"rename_ori", "make_archive", "jpn_title")}
"rename_ori", "make_archive", "jpn_title", "download_range")}
cfg.update(cfg_dict)
if cfg['download_ori'] and not self.has_login:
self.logger.warning(i18n.XEH_DOWNLOAD_ORI_NEED_LOGIN)
@@ -250,7 +250,7 @@ def _do_task(self, task_guid):
self.logger.info(i18n.TASK_TITLE % (
task_guid, task.meta['title']))
self.logger.info(i18n.TASK_WILL_DOWNLOAD_CNT % (
task_guid, task.meta['total'] - len(task._flist_done),
task_guid, task.meta['total'] - task.meta['finished'],
task.meta['total']))
# spawn thread to scan images
for i in range(task.config['scan_thread_cnt']):
View
@@ -18,6 +18,7 @@
ERR_TASK_CANNOT_RESUME: "this task can't be resumed",
ERR_CANNOT_CREATE_DIR: "can't create directory %s",
ERR_CANNOT_MAKE_ARCHIVE: "can't make archive %s",
ERR_NOT_RANGE_FORMAT: "'%s' is not a range format, expecting '1-2' or '3'",
# ERR_HATHDL_NOTFOUND: "hathdl not found",
ERR_RPC_PARSE_ERROR: "Parse error.",
ERR_RPC_INVALID_REQUEST: "Invalid request.",
@@ -54,6 +55,8 @@
XEH_OPT_rpc_secret = "jsonrpc secret string (current: %(default)s)"
XEH_OPT_a = "make an archive (.zip) after download and delete directory (current: %(default)s)"
XEH_OPT_j = "use Japanese title, use English/Romaji title if turned off (current: %(default)s)"
XEH_OPT_download_range = "specify ranges of images to be downloaded, in format start-end, or single index, " \
"use comma to concat multiple ranges, e.g.: 5-10,15,20-25, default to download all images"
XEH_OPT_h = "show this help message and exit"
XEH_OPT_version = "show program's version number and exit"
XEH_OPT_IGNORING_I = "ignoring -i option in daemon mode"
@@ -67,6 +70,7 @@
PS_RENAME_ORI = "Rename to original name (y/n, default:%s)? > "
PS_MAKE_ARCHIVE = "Make archive (y/n, default:%s)? > "
PS_JPN_TITLE = "Use Japanese title (y/n, default:%s)? > "
PS_DOWNLOAD_RANGE = "Download range, press enter to download all > "
PS_DOWNLOAD_DIR = "Download to (default: %s)\npress enter or enter new > "
PROXY_CANDIDATE_CNT = "proxy pool has %d candidates"
View
@@ -18,6 +18,7 @@
ERR_TASK_CANNOT_RESUME: "这个任务无法被恢复",
ERR_CANNOT_CREATE_DIR: "无法创建文件夹 %s",
ERR_CANNOT_MAKE_ARCHIVE: "无法制作压缩包 %s",
ERR_NOT_RANGE_FORMAT: "'%s'不符合范围的格式, 正确的格式为 1-3 或者 5",
# ERR_HATHDL_NOTFOUND: "hathdl文件未找到"
ERR_RPC_PARSE_ERROR: "Parse error.",
ERR_RPC_INVALID_REQUEST: "Invalid request.",
@@ -53,6 +54,8 @@
XEH_OPT_rpc_secret = "设置JSON-RPC密钥 (当前: %(default)s)"
XEH_OPT_a = "下载完成后生成zip压缩包并删除下载目录 (当前: %(default)s)"
XEH_OPT_j = "使用日语标题, 如果关闭则使用英文或罗马字标题 (当前: %(default)s)"
XEH_OPT_download_range = "设置下载的图片范围, 格式为 开始位置-结束位置, 或者单张图片的位置, " \
"使用逗号来分隔多个范围, 例如 5-10,15,20-25, 默认为下载所有"
XEH_OPT_h = "显示本帮助信息"
XEH_OPT_version = "显示版本信息"
XEH_OPT_IGNORING_I = "后台模式已忽略 -i 参数"
@@ -67,6 +70,7 @@
PS_RENAME_ORI = "是否自动重命名(默认%s) (y/n)? > "
PS_MAKE_ARCHIVE = "是否制作zip压缩包(默认%s) (y/n)? > "
PS_JPN_TITLE = "是否使用日语标题(默认%s) (y/n)? > "
PS_DOWNLOAD_RANGE = "下载范围, 使用逗号分割多个范围, 回车下载全部 > "
PS_DOWNLOAD_DIR = "下载目录 (当前: %s)\n回车确认或输入新路径 > "
PROXY_CANDIDATE_CNT = "代理池中有%d个代理"
View
@@ -139,8 +139,24 @@ def scan_downloaded(self, scaled = True):
donefile = False
if os.path.exists(os.path.join(fpath, ".xehdone")) or os.path.exists("%s.zip" % fpath):
donefile = True
# can only check un-renamed files
_range_idx = 0
for fid in range(1, self.meta['total'] + 1):
# check download range
if self.config['download_range']:
_found = False
# download_range is sorted asc
for start, end in self.config['download_range'][_range_idx:]:
if fid > end: # out of range right bound move to next range
_range_idx += 1
elif start <= fid <= end: # in range
_found = True
break
elif fid < start: # out of range left bound
break
if not _found:
self._flist_done.add(int(fid))
continue
# can only check un-renamed files
fname = os.path.join(fpath, self.get_fidpad(fid)) # id
if donefile or (os.path.exists(fname) and os.stat(fname).st_size > 0):
self._flist_done.add(int(fid))

0 comments on commit d338984

Please sign in to comment.