Commit | Line | Data |
---|---|---|
375a030d FT |
1 | import os |
2 | pj = os.path.join | |
3 | ||
4 | home = os.getenv("HOME") | |
5 | if home is None or not os.path.isdir(home): | |
6 | raise Exception("Could not find home directory for profile keeping") | |
7 | basedir = pj(home, ".manga", "profiles") | |
8 | ||
9 | def openwdir(nm, mode="r"): | |
10 | if os.path.exists(nm): | |
11 | return open(nm, mode) | |
12 | if mode != "r": | |
13 | d = os.path.dirname(nm) | |
14 | if not os.path.isdir(d): | |
15 | os.makedirs(d) | |
16 | return open(nm, mode) | |
17 | ||
18 | def splitline(line): | |
19 | def bsq(c): | |
20 | if c == "\\": return "\\" | |
21 | elif c == '"': return '"' | |
22 | elif c == " ": return " " | |
23 | elif c == "n": return "\n" | |
24 | else: return "" | |
25 | ret = [] | |
26 | p = 0 | |
27 | buf = "" | |
28 | a = False | |
29 | while p < len(line): | |
30 | c = line[p] | |
31 | if c.isspace(): | |
32 | p += 1 | |
33 | else: | |
34 | while p < len(line): | |
35 | c = line[p] | |
36 | p += 1 | |
37 | if c == '"': | |
38 | a = True | |
39 | while p < len(line): | |
40 | c = line[p] | |
41 | p += 1 | |
42 | if c == '"': | |
43 | break | |
44 | elif c == "\\" and p < len(line): | |
45 | buf += bsq(line[p]) | |
46 | p += 1 | |
47 | else: | |
48 | buf += c | |
49 | elif c.isspace(): | |
50 | ret.append(buf) | |
51 | buf = "" | |
012c4cae | 52 | a = False |
375a030d FT |
53 | break |
54 | elif c == "\\" and p < len(line): | |
55 | buf += bsq(line[p]) | |
56 | p += 1 | |
57 | else: | |
58 | buf += c | |
59 | if a or buf != "": | |
60 | ret.append(buf) | |
61 | return ret | |
62 | ||
63 | def consline(*words): | |
64 | buf = "" | |
65 | for w in words: | |
66 | if any((c == "\\" or c == '"' or c == "\n" for c in w)): | |
67 | wb = "" | |
68 | for c in w: | |
69 | if c == "\\": wb += "\\\\" | |
70 | elif c == '"': wb += '\\"' | |
71 | elif c == "\n": wb += "\\n" | |
72 | else: wb += c | |
73 | w = wb | |
74 | if w == "" or any((c.isspace() for c in w)): | |
75 | w = '"' + w + '"' | |
76 | if buf != "": | |
77 | buf += " " | |
78 | buf += w | |
79 | return buf | |
80 | ||
81 | class manga(object): | |
43423668 | 82 | def __init__(self, profile, libnm, id): |
375a030d FT |
83 | self.profile = profile |
84 | self.libnm = libnm | |
85 | self.id = id | |
375a030d FT |
86 | self.props = self.loadprops() |
87 | ||
43423668 FT |
88 | def open(self): |
89 | import lib | |
90 | return lib.findlib(self.libnm).byid(self.id) | |
91 | ||
5997ac77 FT |
92 | def save(self): |
93 | pass | |
94 | ||
43423668 FT |
95 | class memmanga(manga): |
96 | def __init__(self, profile, libnm, id): | |
97 | super(memmanga, self).__init__(profile, libnm, id) | |
98 | ||
99 | def loadprops(self): | |
100 | return {} | |
101 | ||
102 | class filemanga(manga): | |
103 | def __init__(self, profile, libnm, id, path): | |
104 | self.path = path | |
105 | super(filemanga, self).__init__(profile, libnm, id) | |
106 | ||
375a030d FT |
107 | def loadprops(self): |
108 | ret = {} | |
109 | with openwdir(self.path) as f: | |
110 | for line in f: | |
111 | words = splitline(line) | |
112 | if len(words) < 1: continue | |
113 | if words[0] == "set" and len(words) > 2: | |
114 | ret[words[1]] = words[2] | |
115 | elif words[0] == "lset" and len(words) > 1: | |
116 | ret[words[1]] = words[2:] | |
117 | return ret | |
118 | ||
43423668 | 119 | def save(self): |
375a030d FT |
120 | with openwdir(self.path, "w") as f: |
121 | for key, val in self.props.iteritems(): | |
122 | if isinstance(val, str): | |
123 | f.write(consline("set", key, val) + "\n") | |
124 | else: | |
125 | f.write(consline("lset", key, *val) + "\n") | |
126 | ||
375a030d FT |
127 | class profile(object): |
128 | def __init__(self, dir): | |
129 | self.dir = dir | |
130 | self.name = None | |
131 | ||
132 | def getmapping(self): | |
133 | seq = 0 | |
134 | ret = {} | |
135 | if os.path.exists(pj(self.dir, "map")): | |
136 | with openwdir(pj(self.dir, "map")) as f: | |
137 | for ln in f: | |
138 | words = splitline(ln) | |
139 | if len(words) < 1: | |
140 | continue | |
141 | if words[0] == "seq" and len(words) > 1: | |
142 | try: | |
143 | seq = int(words[1]) | |
144 | except ValueError: | |
145 | pass | |
146 | elif words[0] == "manga" and len(words) > 3: | |
147 | try: | |
148 | ret[words[1], words[2]] = int(words[3]) | |
149 | except ValueError: | |
150 | pass | |
151 | return seq, ret | |
152 | ||
153 | def savemapping(self, seq, m): | |
154 | with openwdir(pj(self.dir, "map"), "w") as f: | |
155 | f.write(consline("seq", str(seq)) + "\n") | |
156 | for (libnm, id), num in m.iteritems(): | |
157 | f.write(consline("manga", libnm, id, str(num)) + "\n") | |
158 | ||
159 | def getmanga(self, libnm, id, creat=False): | |
160 | seq, m = self.getmapping() | |
161 | if (libnm, id) in m: | |
43423668 | 162 | return filemanga(self, libnm, id, pj(self.dir, "%i.manga" % m[(libnm, id)])) |
375a030d FT |
163 | if not creat: |
164 | raise KeyError("no such manga: (%s, %s)" % (libnm, id)) | |
165 | while True: | |
166 | try: | |
167 | fp = openwdir(pj(self.dir, "%i.manga" % seq), "wx") | |
168 | except IOError: | |
169 | seq += 1 | |
170 | else: | |
171 | break | |
172 | fp.close() | |
173 | m[(libnm, id)] = seq | |
174 | self.savemapping(seq, m) | |
43423668 | 175 | return filemanga(self, libnm, id, pj(self.dir, "%i.manga" % seq)) |
375a030d FT |
176 | |
177 | def setlast(self): | |
178 | if self.name is None: | |
179 | raise ValueError("profile at " + self.dir + " has no name") | |
180 | with openwdir(pj(basedir, "last"), "w") as f: | |
181 | f.write(self.name + "\n") | |
182 | ||
271d68da FT |
183 | def getaliases(self): |
184 | ret = {} | |
185 | if os.path.exists(pj(self.dir, "alias")): | |
186 | with openwdir(pj(self.dir, "alias")) as f: | |
187 | for ln in f: | |
188 | ln = splitline(ln) | |
189 | if len(ln) < 1: continue | |
190 | if ln[0] == "alias" and len(ln) > 3: | |
191 | ret[ln[1]] = ln[2], ln[3] | |
192 | return ret | |
193 | ||
194 | def savealiases(self, map): | |
195 | with openwdir(pj(self.dir, "alias"), "w") as f: | |
196 | for nm, (libnm, id) in map.iteritems(): | |
197 | f.write(consline("alias", nm, libnm, id) + "\n") | |
198 | ||
477d3ba0 FT |
199 | def file(self, name, mode="r"): |
200 | return openwdir(pj(self.dir, name), mode) | |
201 | ||
271d68da FT |
202 | def getalias(self, nm): |
203 | return self.getaliases()[nm] | |
204 | ||
205 | def setalias(self, nm, libnm, id): | |
206 | aliases = self.getaliases() | |
207 | aliases[nm] = libnm, id | |
208 | self.savealiases(aliases) | |
209 | ||
375a030d FT |
210 | @classmethod |
211 | def byname(cls, name): | |
212 | if not name or name == "last" or name[0] == '.': | |
213 | raise KeyError("invalid profile name: " + name) | |
214 | ret = cls(pj(basedir, name)) | |
215 | ret.name = name | |
216 | return ret | |
217 | ||
218 | @classmethod | |
219 | def last(cls): | |
220 | if not os.path.exists(pj(basedir, "last")): | |
221 | raise KeyError("there is no last used profile") | |
222 | with open(pj(basedir, "last")) as f: | |
223 | return cls.byname(f.readline().strip()) |