Commit | Line | Data |
---|---|---|
64eb9fa5 FT |
1 | #!/usr/bin/python3 |
2 | ||
3 | import sys, os, getopt, time, random | |
4 | import manga.lib, manga.profile | |
5 | from PIL import Image | |
6 | ||
7 | verbose = 0 | |
8 | wait = 10 | |
9 | ||
10 | def msg(vl, msg, *args): | |
11 | if verbose >= vl: | |
12 | sys.stderr.write("getmanga: " + (msg % args) + "\n") | |
13 | ||
14 | def getprop(nm, default=None): | |
15 | if "dl-" + nm in mprof.props: | |
16 | return mprof.props["dl-" + nm] | |
17 | if nm in props: | |
18 | return props[nm] | |
19 | return default | |
20 | ||
21 | def digits(num): | |
22 | n, i = 10, 1 | |
23 | while True: | |
24 | if num < n: | |
25 | return i | |
26 | n, i = n * 10, i + 1 | |
27 | ||
28 | def autoname(page): | |
29 | ret = "" | |
30 | for t, i in page.stack: | |
31 | if ret: | |
32 | ret += "-" | |
33 | ret += "%0*i" % (digits(len(t) + 1), i + 1) | |
34 | return ret | |
35 | ||
36 | def expand(pattern, page): | |
37 | ret = "" | |
38 | si = 0 | |
39 | fp = 0 | |
40 | while True: | |
41 | p = pattern.find('%', fp) | |
42 | if p < 0: | |
43 | if si < len(page.stack): | |
44 | sys.stderr.write("getmanga: pattern %s did not match page %s\n" % | |
45 | (pattern, "/".join(t.name for t, i in page.stack))) | |
46 | sys.exit(1) | |
47 | return ret + pattern[fp:] | |
48 | ret += pattern[fp:p] | |
49 | m = pattern[p:p + 1] | |
50 | if m == "%": | |
51 | ret += "%" | |
52 | else: | |
53 | if si >= len(page.stack): | |
54 | sys.stderr.write("getmanga: pattern %s did not match page %s\n" % | |
55 | (pattern, "/".join(t.name for t, i in page.stack))) | |
56 | sys.exit(1) | |
57 | t, ti = page.stack[si] | |
58 | si += 1 | |
59 | if m == "i": | |
60 | ret += "%0*i" % (digits(len(t) + 1), ti + 1) | |
61 | elif m == "n": | |
62 | ret += t.name | |
63 | elif m == "d": | |
64 | ret += t.id | |
65 | else: | |
66 | sys.stderr.write("getmanga: %s: unknown specified `%s'\n" % (m)) | |
67 | sys.exit(1) | |
68 | ||
69 | def download(mng, tdir, pattern): | |
70 | exts = ["", ".jpg", ".jpeg", ".png", ".gif"] | |
71 | fmts = {"PNG": "png", "JPEG": "jpeg", "GIF": "gif"} | |
72 | for page in manga.lib.cursor(mng): | |
73 | if pattern is None: | |
74 | nm = autoname(page) | |
75 | else: | |
76 | nm = expand(pattern, page) | |
77 | path = os.path.join(tdir, nm) | |
78 | if any(os.path.exists(path + ext) for ext in exts): | |
79 | msg(2, "%s exists, skipping", nm) | |
80 | continue | |
81 | msg(1, "getting %s...", nm) | |
82 | with page.open() as fp: | |
83 | with open(path, "wb") as out: | |
84 | while True: | |
85 | data = fp.read(65536) | |
86 | if data == b"": | |
87 | break | |
88 | out.write(data) | |
89 | try: | |
90 | img = Image.open(path) | |
91 | except OSError: | |
92 | fmt = None | |
93 | else: | |
94 | fmt = img.format | |
95 | if fmt not in fmts: | |
96 | sys.stderr.write("getmanga: warning: could not determine file format of %s, leaving as is\n" % nm) | |
97 | else: | |
98 | os.rename(path, path + "." + fmts[fmt]) | |
99 | msg(3, "%s -> %s", nm, nm + "." + fmts[fmt]) | |
100 | cwait = abs(random.gauss(0, 1) * wait) | |
101 | msg(2, "waiting %.1f s...", cwait) | |
102 | time.sleep(cwait) | |
103 | ||
104 | def usage(out): | |
105 | out.write("usage: getmanga [-hv] [-w WAIT] [-p PROFILE] DIRECTORY [LIBRARY ID]\n") | |
106 | ||
107 | def main(): | |
108 | global verbose, wait, mprof, props | |
109 | ||
110 | opts, args = getopt.getopt(sys.argv[1:], "hvp:w:") | |
111 | profnm = "" | |
112 | for o, a in opts: | |
113 | if o == "-h": | |
114 | usage(sys.stdout) | |
115 | sys.exit(0) | |
116 | elif o == "-p": | |
117 | profnm = a | |
118 | elif o == "-v": | |
119 | verbose += 1 | |
120 | elif o == "-w": | |
121 | wait = int(a) | |
122 | if len(args) < 1: | |
123 | usage(sys.stderr) | |
124 | sys.exit(1) | |
125 | tdir = args[0] | |
126 | ||
127 | if not os.path.isdir(tdir): | |
128 | sys.stderr.write("getmanga: %s: not a directory\n" % (tdir)) | |
129 | sys.exit(1) | |
130 | ||
131 | pfile = os.path.join(tdir, ".props") | |
132 | props = {} | |
133 | if os.path.exists(pfile): | |
134 | with open(pfile, "r") as fp: | |
135 | for words in splitlines(f): | |
136 | if words[0] == "set" and len(words) > 2: | |
137 | props[words[1]] = words[2] | |
138 | elif words[0] == "lset" and len(words) > 1: | |
139 | props[words[1]] = words[2:] | |
140 | ||
141 | if profnm == "": | |
142 | profile = manga.profile.profile.last() | |
143 | else: | |
144 | profile = manga.profile.profile.byname(profnm) | |
145 | ||
146 | if len(args) == 2: | |
147 | usage(sys.stderr) | |
148 | sys.exit(1) | |
149 | elif len(args) > 2: | |
150 | libnm, mid = args[1:3] | |
151 | elif isinstance(props.get("manga"), list): | |
152 | libnm, mid = props["manga"] | |
153 | else: | |
154 | sys.stderr.write("getmanga: %s: id is neither saved nor given\n" % (tdir)) | |
155 | sys.exit(1) | |
156 | try: | |
157 | lib = manga.lib.findlib(libnm) | |
158 | except ImportError: | |
159 | sys.stderr.write("getmanga: no such library: %s\n" % (libnm)) | |
160 | sys.exit(1) | |
161 | try: | |
162 | mng = lib.byid(mid) | |
163 | except KeyError: | |
164 | sys.stderr.write("getmanga: no such manga: %s\n" % (mid)) | |
165 | sys.exit(1) | |
166 | mprof = profile.getmanga(libnm, mng.id) | |
167 | ||
168 | download(mprof.open(), tdir, getprop("pattern")) | |
169 | ||
170 | if __name__ == "__main__": | |
171 | try: | |
172 | main() | |
173 | except KeyboardInterrupt: | |
174 | pass |