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