Added simplistic keyword searching to mrnet and local libraries.
[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)
fab05388
FT
131 if mx is None:
132 raise TypeError("could not figure out any structure")
1f51eb58
FT
133 var = [i for i, part in enumerate(mx) if part == int]
134 structs = [(nm, decode1(nm)) for nm in pages]
135 if not ordered:
136 structs.sort(key=lambda o: "".join(o[1][len(mx):]))
137 for i in reversed(var):
138 structs.sort(key=lambda o: int(o[1][i]))
139 def constree(p, structs, idx):
140 if idx == len(var):
141 pages = []
142 for nm, st in structs:
143 id = "".join(st[len(mx):])
144 pages.append(page(self, pj(self.path, orig[nm]), id, id, p.stack + [(p, len(pages))]))
145 return pages
146 else:
147 ids = set()
148 oids = []
149 for nm, st in structs:
150 cur = st[var[idx]]
151 if cur not in ids:
152 ids.add(cur)
153 oids.append(cur)
154 ret = []
155 for id in oids:
afd66b91
FT
156 sub = [(nm, st) for nm, st in structs if st[var[idx]] == id]
157 if len(sub) == 1:
158 nm, st = sub[0]
159 id = "".join(st[var[idx]:])
160 ret.append(page(self, pj(self.path, orig[nm]), id, id, p.stack + [(p, len(ret))]))
161 else:
162 cur = interm(id, id, p.stack + [(p, len(ret))], [])
163 cur.direct = constree(cur, sub, idx + 1)
164 ret.append(cur)
1f51eb58
FT
165 return ret
166 return constree(self, structs, 0)
167
168class dumb(lib.library):
169 def byid(self, id):
170 if not os.path.isdir(id):
171 raise KeyError(id)
172 return manga(id)
173
174class directory(dumb):
175 def __init__(self, path):
176 if not os.path.isdir(path):
177 raise IOError("No such directory: " + path)
178 self.path = path
179
180 def byname(self, prefix):
181 ret = []
182 prefix = prefix.lower()
183 for dent in os.listdir(self.path):
184 if dent[:len(prefix)].lower() == prefix:
185 ret.append(manga(pj(self.path, dent)))
186 return ret
187
ffd12e71
FT
188 def search(self, expr):
189 expr = expr.lower()
190 return [manga(pj(self.path, dent)) for dent in os.listdir(self.path) if expr in dent.lower()]
191
1f51eb58
FT
192 def __iter__(self):
193 for dent in os.listdir(self.path):
194 yield manga(pj(self.path, dent))
195
ffd12e71 196
1f51eb58 197library = dumb