-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path2chdownloader.py
107 lines (94 loc) · 3.79 KB
/
2chdownloader.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/env python3
"""
Данная утилита предназначена для скачивания файлов с имиджборды 2ch.hk.
Created by https://github.com/kiriharu
Re-writed by https://github.com/undefinedvalue0103
"""
import requests
import re
SITE = "https://2ch.hk"
def download_file(fileobject: dict):
"""
Download file. Parameters given in file object
@param fileobject: dict{path,fullname,md5}
"""
url = SITE + fileobject["path"]
fallback = fileobject["name"]
name = fileobject["md5"] + " " + fileobject.get("fullname", fallback)
try:
with open(name, "wb") as fd:
with requests.get(url, stream=True) as rq:
expected_size = int(rq.headers.get("Content-Length", 1))
downloaded = 0
for chunk in rq.iter_content(chunk_size=8192):
downloaded += len(chunk)
progress = downloaded / expected_size
width = int(progress * 10)
line = "[I] %35s: [%s%s] %7.3f%%" % (fileobject["path"],
"=" * width,
" " * (10 - width),
progress * 100)
print(line, end="\r", flush=True)
fd.write(chunk)
fd.flush()
except IOError as e:
print("[E] Filed to open file %r: %r" % (name, e))
except Exception as e:
print("[E] Exception occurred: %r" % e)
else:
print("")
def iter_files(board: str, thread: int = None, status: str = None):
"""
Yields files from thread
@param board: str, board letters (example, 'b')
@param thread: int/None, thread ID. If ommited, all threads given.
@param status: str/None, status string. used for progress
@returns generator(fileobject:dict)
"""
if thread is not None:
thread_url = f"{SITE}/{board}/res/{thread}.json"
print("[I] Getting", thread_url, status or "")
data = requests.get(thread_url).json()
for thread in data["threads"]:
for post in thread["posts"]:
for fileobj in post["files"]:
if fileobj["type"] != 100:
yield fileobj
else:
for index in range(1, 10):
index = "index" if index == 1 else index
page_url = f"{SITE}/{board}/{index}.json"
print("[I] Getting", page_url)
data = requests.get(page_url).json()
threads = len(data["threads"])
for i, thread in enumerate(data["threads"], 1):
thread_num = thread["thread_num"]
for fileobj in iter_files(board, thread_num, "%3d/%3d" % (i, threads)):
yield fileobj
def main():
print("Welcome to 2chdownloader!")
print("Type board name as 'name' for downloading entire board")
print("Type thread as 'board/thread' for downloading one thread")
print("Type 'exit' for exit")
while True:
try:
line = input("> ")
if line == "exit":
return
elif re.match(r"^(\w+)$", line):
for fileobj in iter_files(line):
download_file(fileobj)
print("[I] Done")
elif re.match(r"^(\w+)\/(\d+)$", line):
board, thread = line.split("/")
for fileobj in iter_files(board, int(thread)):
download_file(fileobj)
print("[I] Done")
else:
print("Something went wrong")
except KeyboardInterrupt:
print("[I] Type 'exit' for exit")
except Exception as e:
print("[E]", e)
if __name__ == '__main__':
main()