Merge branch 'master' of git.dolda2000.com:/srv/git/r/automanga
[automanga.git] / getmanga
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