import hashlib import re from pathlib import Path import logging logger = logging.getLogger() def get_fname(url): m = hashlib.md5() m.update(url.encode('utf8')) return m.hexdigest() class Store: def __init__(self, basedir: Path = None): if basedir is None: basedir = Path('~/.local/share/marxbook/bookmarks/').expanduser() self.basedir = basedir self.serializer = Serializer() def add(self, url: str, title=None, tag=[], description=''): dest = self.basedir dest.mkdir(parents=True, exist_ok=True) fname = get_fname(url) fpath = dest / fname content = self.serializer.encode(dict( url=url, title=title, tags=tag, description=description)) with fpath.open('w') as buf: buf.write(content) def get(self, path: str): fpath = self.basedir / path with fpath.open() as buf: return self.serializer.decode(buf.read()) def __iter__(self): for urlfile in self.basedir.glob('**/*'): if not urlfile.is_file(): continue data = self.get(urlfile) ret = { 'Path': str(urlfile.relative_to(self.basedir)) } ret.update(data) yield ret def folder(self, folder: str): return Store(self.basedir / folder) HEADER_LINE = re.compile(r'^([^:]+): (.*)$') class Serializer: def __init__(self): pass def encode(self, data: dict) -> str: m = '' tags = data.pop('tags', []) # those are special! for key in data: m += '%s: %s\n' % (key.title(), str(data[key]).replace('\n', ' ')) for tag in tags: m += '%s: %s\n' % ('Tag', tag) return m def decode(self, content: str) -> dict: d: dict = {'Tag': []} for num, line in enumerate(content.split('\n'), 1): if not line.strip(): continue m = HEADER_LINE.match(line) if m is None: logger.error("Invalid line %d" % num) continue key, value = m.groups() key = key.title() if key == 'Tag': d[key].append(value) else: d[key] = value return d if __name__ == '__main__': import sys s = Store() # print(s.get(sys.argv[1])) for line in s.list(sys.argv[1]): print(line)