Commit | Line | Data |
---|---|---|
1f51eb58 | 1 | import os |
3cc7937c | 2 | from . import lib |
1f51eb58 FT |
3 | pj = os.path.join |
4 | ||
5 | def 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 | ||
26 | def 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 |
35 | def 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 | ||
43 | def 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 |
56 | class 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 | ||
67 | class 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 | ||
78 | class 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 | ||
91 | def 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 | ||
107 | class 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 | ||
191 | class dumb(lib.library): | |
192 | def byid(self, id): | |
193 | if not os.path.isdir(id): | |
194 | raise KeyError(id) | |
195 | return manga(id) | |
196 | ||
197 | class 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 | 220 | library = dumb |