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