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