raise Exception("Could not find home directory for profile keeping")
basedir = pj(home, ".manga", "profiles")
+class txfile(object):
+ def __init__(self, name, mode):
+ self.realname = name
+ self.tempname = name + ".new"
+ self.bk = open(self.tempname, mode)
+
+ def close(self, abort=False):
+ self.bk.close()
+ if abort:
+ os.unlink(self.tempname)
+ else:
+ os.rename(self.tempname, self.realname)
+
+ def read(self, sz=-1):
+ return self.bk.read(sz)
+
+ def write(self, data):
+ return self.bk.write(data)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *exc_info):
+ if exc_info[0] is not None:
+ self.close(True)
+ else:
+ self.close(False)
+
def openwdir(nm, mode="r"):
+ ft = open
+ if mode == "W":
+ mode = "w"
+ ft = txfile
if os.path.exists(nm):
- return open(nm, mode)
+ return ft(nm, mode)
if mode != "r":
d = os.path.dirname(nm)
if not os.path.isdir(d):
os.makedirs(d)
- return open(nm, mode)
+ return ft(nm, mode)
def splitline(line):
def bsq(c):
ret.append(buf)
return ret
+def splitlines(fp):
+ for line in fp:
+ cur = splitline(line)
+ if len(cur) < 1:
+ continue
+ yield cur
+
def consline(*words):
buf = ""
for w in words:
return buf
class manga(object):
- def __init__(self, profile, libnm, id, path):
+ def __init__(self, profile, libnm, id):
self.profile = profile
self.libnm = libnm
self.id = id
- self.path = path
self.props = self.loadprops()
+ def open(self):
+ from . import lib
+ return lib.findlib(self.libnm).byid(self.id)
+
+ def save(self):
+ pass
+
+class memmanga(manga):
+ def __init__(self, profile, libnm, id):
+ super(memmanga, self).__init__(profile, libnm, id)
+
+ def loadprops(self):
+ return {}
+
+class tagview(object):
+ def __init__(self, manga):
+ self.manga = manga
+ self.profile = manga.profile
+
+ def add(self, *tags):
+ mt = self.getall(self.profile)
+ ctags = mt.setdefault((self.manga.libnm, self.manga.id), set())
+ ctags |= set(tags)
+ self.save(self.profile, mt)
+
+ def remove(self, *tags):
+ mt = self.getall(self.profile)
+ ctags = mt.get((self.manga.libnm, self.manga.id), set())
+ ctags -= set(tags)
+ if len(ctags) < 1:
+ try:
+ del mt[self.manga.libnm, self.manga.id]
+ except KeyError:
+ pass
+ self.save(self.profile, mt)
+
+ def __iter__(self):
+ return iter(self.getall(self.profile).get((self.manga.libnm, self.manga.id), set()))
+
+ @staticmethod
+ def getall(profile):
+ ret = {}
+ try:
+ with profile.file("tags") as fp:
+ for words in splitlines(fp):
+ libnm, id = words[0:2]
+ tags = set(words[2:])
+ ret[libnm, id] = tags
+ except IOError:
+ pass
+ return ret
+
+ @staticmethod
+ def save(profile, m):
+ with profile.file("tags", "W") as fp:
+ for (libnm, id), tags in m.items():
+ fp.write(consline(libnm, id, *tags) + "\n")
+
+ @staticmethod
+ def bytag(profile, tag):
+ try:
+ with profile.file("tags") as fp:
+ for words in splitlines(fp):
+ libnm, id = words[0:2]
+ tags = words[2:]
+ if tag in tags:
+ yield profile.getmanga(libnm, id)
+ except IOError:
+ pass
+
+class filemanga(manga):
+ def __init__(self, profile, libnm, id, path):
+ self.path = path
+ super(filemanga, self).__init__(profile, libnm, id)
+ self.tags = tagview(self)
+
def loadprops(self):
ret = {}
with openwdir(self.path) as f:
- for line in f:
- words = splitline(line)
- if len(words) < 1: continue
+ for words in splitlines(f):
if words[0] == "set" and len(words) > 2:
ret[words[1]] = words[2]
elif words[0] == "lset" and len(words) > 1:
ret[words[1]] = words[2:]
return ret
- def prop(self, key, default=KeyError):
- if key not in self.props:
- if default is KeyError:
- raise KeyError(key)
- return default
- return self.props[key]
-
- def __getitem__(self, key):
- return self.props[key]
-
- def __contains__(self, key):
- return key in self.props
-
- def setprop(self, key, val):
- self.props[key] = val
-
- def saveprops(self):
- with openwdir(self.path, "w") as f:
- for key, val in self.props.iteritems():
+ def save(self):
+ with openwdir(self.path, "W") as f:
+ for key, val in self.props.items():
if isinstance(val, str):
f.write(consline("set", key, val) + "\n")
else:
f.write(consline("lset", key, *val) + "\n")
- def open(self):
- import lib
- return lib.findlib(self.libnm).byid(self.id)
-
class profile(object):
def __init__(self, dir):
self.dir = dir
ret = {}
if os.path.exists(pj(self.dir, "map")):
with openwdir(pj(self.dir, "map")) as f:
- for ln in f:
- words = splitline(ln)
- if len(words) < 1:
- continue
+ for words in splitlines(f):
if words[0] == "seq" and len(words) > 1:
try:
seq = int(words[1])
return seq, ret
def savemapping(self, seq, m):
- with openwdir(pj(self.dir, "map"), "w") as f:
+ with openwdir(pj(self.dir, "map"), "W") as f:
f.write(consline("seq", str(seq)) + "\n")
- for (libnm, id), num in m.iteritems():
+ for (libnm, id), num in m.items():
f.write(consline("manga", libnm, id, str(num)) + "\n")
def getmanga(self, libnm, id, creat=False):
seq, m = self.getmapping()
if (libnm, id) in m:
- return manga(self, libnm, id, pj(self.dir, "%i.manga" % m[(libnm, id)]))
+ return filemanga(self, libnm, id, pj(self.dir, "%i.manga" % m[(libnm, id)]))
if not creat:
raise KeyError("no such manga: (%s, %s)" % (libnm, id))
while True:
fp.close()
m[(libnm, id)] = seq
self.savemapping(seq, m)
- return manga(self, libnm, id, pj(self.dir, "%i.manga" % seq))
+ return filemanga(self, libnm, id, pj(self.dir, "%i.manga" % seq))
def setlast(self):
if self.name is None:
raise ValueError("profile at " + self.dir + " has no name")
- with openwdir(pj(basedir, "last"), "w") as f:
+ with openwdir(pj(basedir, "last"), "W") as f:
f.write(self.name + "\n")
+ def getaliases(self):
+ ret = {}
+ if os.path.exists(pj(self.dir, "alias")):
+ with openwdir(pj(self.dir, "alias")) as f:
+ for ln in f:
+ ln = splitline(ln)
+ if len(ln) < 1: continue
+ if ln[0] == "alias" and len(ln) > 3:
+ ret[ln[1]] = ln[2], ln[3]
+ return ret
+
+ def savealiases(self, map):
+ with openwdir(pj(self.dir, "alias"), "W") as f:
+ for nm, (libnm, id) in map.items():
+ f.write(consline("alias", nm, libnm, id) + "\n")
+
+ def file(self, name, mode="r"):
+ return openwdir(pj(self.dir, name), mode)
+
+ def getalias(self, nm):
+ return self.getaliases()[nm]
+
+ def setalias(self, nm, libnm, id):
+ aliases = self.getaliases()
+ aliases[nm] = libnm, id
+ self.savealiases(aliases)
+
+ def bytag(self, tag):
+ return tagview.bytag(self, tag)
+
@classmethod
def byname(cls, name):
if not name or name == "last" or name[0] == '.':