local: Read and use prefix names.
[automanga.git] / manga / local.py
CommitLineData
1f51eb58 1import os
3cc7937c 2from . import lib
1f51eb58
FT
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
0d299ac7
FT
35def findname(names, files):
36 matches = list(names.keys())
37 for f in files:
38 matches = [pfx for pfx in matches if f.startswith(pfx)]
39 if len(matches) < 1: return None
40 matches.sort(key=len, reverse=True)
41 return names[matches[0]]
42
43def prefixes(path):
44 nmpath = pj(path, "names")
45 if not os.path.exists(nmpath):
46 return {}
47 ret = {}
48 with open(nmpath, "r") as fp:
49 for line in fp:
50 line = line.strip()
51 p = line.find(' ')
52 if p < 0: continue
53 ret[line[:p]] = line[p + 1:]
54 return ret
55
1f51eb58
FT
56class imgstream(lib.imgstream):
57 def __init__(self, path):
58 self.bk = open(path, 'rb')
59 self.clen = os.fstat(self.bk.fileno()).st_size
60
61 def close(self):
62 self.bk.close()
63
64 def read(self, sz=None):
65 return self.bk.read(sz)
66
67class page(lib.page):
68 def __init__(self, manga, path, name, id, stack):
69 self.path = path
70 self.id = id
71 self.name = name
72 self.manga = manga
73 self.stack = stack
74
75 def open(self):
76 return imgstream(self.path)
77
78class interm(lib.pagelist):
79 def __init__(self, name, id, stack, direct):
80 self.name = name
81 self.id = id
82 self.stack = stack
83 self.direct = direct
84
85 def __len__(self):
86 return len(self.direct)
87
88 def __getitem__(self, n):
89 return self.direct[n]
90
91def maxstruct(flist):
92 mx = None
93 for dent in flist:
94 s = genstr(decode1(dent))
95 if mx is None:
96 mx = s
97 else:
98 nmx = []
99 for p, n in zip(mx, s):
100 if p == n:
101 nmx.append(p)
102 else:
103 break
104 mx = nmx
105 return mx
106
107class manga(lib.manga):
108 exts = ["jpg", "jpeg", "png", "gif"]
109
110 def __init__(self, path):
111 path = os.path.abspath(path)
112 if not os.path.isdir(path):
113 raise IOError("No such directory: " + path)
114 self.path = path
115 self.id = path
116 self.stack = []
117 if os.path.exists(pj(self.path, "name")):
118 with open(pj(self.path, "name")) as s:
3cc7937c 119 self.name = s.readline().strip()
1f51eb58 120 else:
3cc7937c 121 self.name = os.path.basename(path)
1f51eb58
FT
122 self.direct = self.destruct()
123
124 def __len__(self):
125 return len(self.direct)
126
127 def __getitem__(self, idx):
128 return self.direct[idx]
129
130 def imglist(self):
131 if os.path.exists(pj(self.path, "order")):
132 with open(pj(self.path, "order")) as s:
133 return True, [line.strip() for line in s if os.path.exists(pj(self.path, line.strip()))]
134 else:
135 return False, [dent for dent in os.listdir(self.path) if '.' in dent and dent[dent.rindex('.') + 1:] in self.exts]
136
137 def bakenames(self, files):
138 ret = []
139 map = {}
140 for orig in files:
141 nm = orig
142 if '.' in nm:
143 nm = nm[:nm.rindex('.')]
144 ret.append(nm)
145 map[nm] = orig
146 return ret, map
147
148 def destruct(self):
149 ordered, files = self.imglist()
150 pages, orig = self.bakenames(files)
151 mx = maxstruct(pages)
fab05388
FT
152 if mx is None:
153 raise TypeError("could not figure out any structure")
1f51eb58
FT
154 var = [i for i, part in enumerate(mx) if part == int]
155 structs = [(nm, decode1(nm)) for nm in pages]
156 if not ordered:
157 structs.sort(key=lambda o: "".join(o[1][len(mx):]))
158 for i in reversed(var):
159 structs.sort(key=lambda o: int(o[1][i]))
0d299ac7 160 readnames = prefixes(self.path)
1f51eb58
FT
161 def constree(p, structs, idx):
162 if idx == len(var):
163 pages = []
164 for nm, st in structs:
165 id = "".join(st[len(mx):])
166 pages.append(page(self, pj(self.path, orig[nm]), id, id, p.stack + [(p, len(pages))]))
167 return pages
168 else:
169 ids = set()
170 oids = []
171 for nm, st in structs:
172 cur = st[var[idx]]
173 if cur not in ids:
174 ids.add(cur)
175 oids.append(cur)
176 ret = []
177 for id in oids:
afd66b91
FT
178 sub = [(nm, st) for nm, st in structs if st[var[idx]] == id]
179 if len(sub) == 1:
180 nm, st = sub[0]
181 id = "".join(st[var[idx]:])
182 ret.append(page(self, pj(self.path, orig[nm]), id, id, p.stack + [(p, len(ret))]))
183 else:
0d299ac7
FT
184 name = findname(readnames, [nm for (nm, st) in sub]) or id
185 cur = interm(name, id, p.stack + [(p, len(ret))], [])
afd66b91
FT
186 cur.direct = constree(cur, sub, idx + 1)
187 ret.append(cur)
1f51eb58
FT
188 return ret
189 return constree(self, structs, 0)
190
191class dumb(lib.library):
192 def byid(self, id):
193 if not os.path.isdir(id):
194 raise KeyError(id)
195 return manga(id)
196
197class directory(dumb):
198 def __init__(self, path):
199 if not os.path.isdir(path):
200 raise IOError("No such directory: " + path)
201 self.path = path
202
203 def byname(self, prefix):
204 ret = []
205 prefix = prefix.lower()
206 for dent in os.listdir(self.path):
207 if dent[:len(prefix)].lower() == prefix:
208 ret.append(manga(pj(self.path, dent)))
209 return ret
210
ffd12e71
FT
211 def search(self, expr):
212 expr = expr.lower()
213 return [manga(pj(self.path, dent)) for dent in os.listdir(self.path) if expr in dent.lower()]
214
1f51eb58
FT
215 def __iter__(self):
216 for dent in os.listdir(self.path):
217 yield manga(pj(self.path, dent))
218
ffd12e71 219
1f51eb58 220library = dumb