Added support for local manga.
[automanga.git] / manga / local.py
CommitLineData
1f51eb58
FT
1import os
2import lib
3pj = os.path.join
4
5def decode1(nm):
6 ret = []
7 p = 0
8 while p < len(nm):
9 if nm[p].isdigit():
10 s = p
11 p += 1
12 while p < len(nm) and nm[p].isdigit():
13 p += 1
14 ret += [nm[s:p]]
15 elif nm[p].isalpha():
16 s = p
17 p += 1
18 while p < len(nm) and nm[p].isalpha():
19 p += 1
20 ret += [nm[s:p]]
21 else:
22 ret += [nm[p]]
23 p += 1
24 return ret
25
26def genstr(s):
27 ret = []
28 for part in s:
29 if part.isdigit():
30 ret += [int]
31 else:
32 ret += [part]
33 return ret
34
35class imgstream(lib.imgstream):
36 def __init__(self, path):
37 self.bk = open(path, 'rb')
38 self.clen = os.fstat(self.bk.fileno()).st_size
39
40 def close(self):
41 self.bk.close()
42
43 def read(self, sz=None):
44 return self.bk.read(sz)
45
46class page(lib.page):
47 def __init__(self, manga, path, name, id, stack):
48 self.path = path
49 self.id = id
50 self.name = name
51 self.manga = manga
52 self.stack = stack
53
54 def open(self):
55 return imgstream(self.path)
56
57class interm(lib.pagelist):
58 def __init__(self, name, id, stack, direct):
59 self.name = name
60 self.id = id
61 self.stack = stack
62 self.direct = direct
63
64 def __len__(self):
65 return len(self.direct)
66
67 def __getitem__(self, n):
68 return self.direct[n]
69
70def maxstruct(flist):
71 mx = None
72 for dent in flist:
73 s = genstr(decode1(dent))
74 if mx is None:
75 mx = s
76 else:
77 nmx = []
78 for p, n in zip(mx, s):
79 if p == n:
80 nmx.append(p)
81 else:
82 break
83 mx = nmx
84 return mx
85
86class manga(lib.manga):
87 exts = ["jpg", "jpeg", "png", "gif"]
88
89 def __init__(self, path):
90 path = os.path.abspath(path)
91 if not os.path.isdir(path):
92 raise IOError("No such directory: " + path)
93 self.path = path
94 self.id = path
95 self.stack = []
96 if os.path.exists(pj(self.path, "name")):
97 with open(pj(self.path, "name")) as s:
98 self.name = s.readline().strip().decode("utf-8")
99 else:
100 self.name = os.path.basename(path).decode("utf-8")
101 self.direct = self.destruct()
102
103 def __len__(self):
104 return len(self.direct)
105
106 def __getitem__(self, idx):
107 return self.direct[idx]
108
109 def imglist(self):
110 if os.path.exists(pj(self.path, "order")):
111 with open(pj(self.path, "order")) as s:
112 return True, [line.strip() for line in s if os.path.exists(pj(self.path, line.strip()))]
113 else:
114 return False, [dent for dent in os.listdir(self.path) if '.' in dent and dent[dent.rindex('.') + 1:] in self.exts]
115
116 def bakenames(self, files):
117 ret = []
118 map = {}
119 for orig in files:
120 nm = orig
121 if '.' in nm:
122 nm = nm[:nm.rindex('.')]
123 ret.append(nm)
124 map[nm] = orig
125 return ret, map
126
127 def destruct(self):
128 ordered, files = self.imglist()
129 pages, orig = self.bakenames(files)
130 mx = maxstruct(pages)
131 var = [i for i, part in enumerate(mx) if part == int]
132 structs = [(nm, decode1(nm)) for nm in pages]
133 if not ordered:
134 structs.sort(key=lambda o: "".join(o[1][len(mx):]))
135 for i in reversed(var):
136 structs.sort(key=lambda o: int(o[1][i]))
137 def constree(p, structs, idx):
138 if idx == len(var):
139 pages = []
140 for nm, st in structs:
141 id = "".join(st[len(mx):])
142 pages.append(page(self, pj(self.path, orig[nm]), id, id, p.stack + [(p, len(pages))]))
143 return pages
144 else:
145 ids = set()
146 oids = []
147 for nm, st in structs:
148 cur = st[var[idx]]
149 if cur not in ids:
150 ids.add(cur)
151 oids.append(cur)
152 ret = []
153 for id in oids:
154 cur = interm(id, id, p.stack + [(p, len(ret))], [])
155 cur.direct = constree(cur, [(nm, st) for nm, st in structs if st[var[idx]] == id], idx + 1)
156 ret.append(cur)
157 return ret
158 return constree(self, structs, 0)
159
160class dumb(lib.library):
161 def byid(self, id):
162 if not os.path.isdir(id):
163 raise KeyError(id)
164 return manga(id)
165
166class directory(dumb):
167 def __init__(self, path):
168 if not os.path.isdir(path):
169 raise IOError("No such directory: " + path)
170 self.path = path
171
172 def byname(self, prefix):
173 ret = []
174 prefix = prefix.lower()
175 for dent in os.listdir(self.path):
176 if dent[:len(prefix)].lower() == prefix:
177 ret.append(manga(pj(self.path, dent)))
178 return ret
179
180 def __iter__(self):
181 for dent in os.listdir(self.path):
182 yield manga(pj(self.path, dent))
183
184library = dumb