140 lines
3.9 KiB
Python
140 lines
3.9 KiB
Python
|
#!/usr/bin/env python3
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
# CLI interface for the DeDRM plugin (useable without Calibre, too)
|
||
|
# Config implementation
|
||
|
|
||
|
from __future__ import absolute_import, print_function
|
||
|
|
||
|
# Taken from Calibre code - Copyright © 2008, Kovid Goyal kovid@kovidgoyal.net, GPLv3
|
||
|
|
||
|
#@@CALIBRE_COMPAT_CODE@@
|
||
|
|
||
|
import sys, os, codecs, json
|
||
|
|
||
|
config_dir = "/"
|
||
|
CONFIG_DIR_MODE = 0o700
|
||
|
iswindows = sys.platform.startswith('win')
|
||
|
|
||
|
|
||
|
filesystem_encoding = sys.getfilesystemencoding()
|
||
|
if filesystem_encoding is None:
|
||
|
filesystem_encoding = 'utf-8'
|
||
|
else:
|
||
|
try:
|
||
|
if codecs.lookup(filesystem_encoding).name == 'ascii':
|
||
|
filesystem_encoding = 'utf-8'
|
||
|
# On linux, unicode arguments to os file functions are coerced to an ascii
|
||
|
# bytestring if sys.getfilesystemencoding() == 'ascii', which is
|
||
|
# just plain dumb. This is fixed by the icu.py module which, when
|
||
|
# imported changes ascii to utf-8
|
||
|
except Exception:
|
||
|
filesystem_encoding = 'utf-8'
|
||
|
|
||
|
|
||
|
class JSONConfig(dict):
|
||
|
|
||
|
EXTENSION = '.json'
|
||
|
|
||
|
|
||
|
def __init__(self, rel_path_to_cf_file, base_path=config_dir):
|
||
|
dict.__init__(self)
|
||
|
self.no_commit = False
|
||
|
self.defaults = {}
|
||
|
self.file_path = os.path.join(base_path,
|
||
|
*(rel_path_to_cf_file.split('/')))
|
||
|
self.file_path = os.path.abspath(self.file_path)
|
||
|
if not self.file_path.endswith(self.EXTENSION):
|
||
|
self.file_path += self.EXTENSION
|
||
|
|
||
|
self.refresh()
|
||
|
|
||
|
def mtime(self):
|
||
|
try:
|
||
|
return os.path.getmtime(self.file_path)
|
||
|
except OSError:
|
||
|
return 0
|
||
|
|
||
|
def touch(self):
|
||
|
try:
|
||
|
os.utime(self.file_path, None)
|
||
|
except OSError:
|
||
|
pass
|
||
|
|
||
|
|
||
|
def decouple(self, prefix):
|
||
|
self.file_path = os.path.join(os.path.dirname(self.file_path), prefix + os.path.basename(self.file_path))
|
||
|
self.refresh()
|
||
|
|
||
|
def refresh(self, clear_current=True):
|
||
|
d = {}
|
||
|
if os.path.exists(self.file_path):
|
||
|
with open(self.file_path, "rb") as f:
|
||
|
raw = f.read()
|
||
|
try:
|
||
|
d = self.raw_to_object(raw) if raw.strip() else {}
|
||
|
except SystemError:
|
||
|
pass
|
||
|
except:
|
||
|
import traceback
|
||
|
traceback.print_exc()
|
||
|
d = {}
|
||
|
if clear_current:
|
||
|
self.clear()
|
||
|
self.update(d)
|
||
|
|
||
|
def has_key(self, key):
|
||
|
return dict.__contains__(self, key)
|
||
|
|
||
|
def set(self, key, val):
|
||
|
self.__setitem__(key, val)
|
||
|
|
||
|
def __delitem__(self, key):
|
||
|
try:
|
||
|
dict.__delitem__(self, key)
|
||
|
except KeyError:
|
||
|
pass # ignore missing keys
|
||
|
else:
|
||
|
self.commit()
|
||
|
|
||
|
def commit(self):
|
||
|
if self.no_commit:
|
||
|
return
|
||
|
if hasattr(self, 'file_path') and self.file_path:
|
||
|
dpath = os.path.dirname(self.file_path)
|
||
|
if not os.path.exists(dpath):
|
||
|
os.makedirs(dpath, mode=CONFIG_DIR_MODE)
|
||
|
with open(self.file_path, "w") as f:
|
||
|
raw = self.to_raw()
|
||
|
f.seek(0)
|
||
|
f.truncate()
|
||
|
f.write(raw)
|
||
|
|
||
|
def __enter__(self):
|
||
|
self.no_commit = True
|
||
|
|
||
|
def __exit__(self, *args):
|
||
|
self.no_commit = False
|
||
|
self.commit()
|
||
|
|
||
|
def raw_to_object(self, raw):
|
||
|
return json.loads(raw)
|
||
|
|
||
|
def to_raw(self):
|
||
|
return json.dumps(self, ensure_ascii=False)
|
||
|
|
||
|
def __getitem__(self, key):
|
||
|
try:
|
||
|
return dict.__getitem__(self, key)
|
||
|
except KeyError:
|
||
|
return self.defaults[key]
|
||
|
|
||
|
def get(self, key, default=None):
|
||
|
try:
|
||
|
return dict.__getitem__(self, key)
|
||
|
except KeyError:
|
||
|
return self.defaults.get(key, default)
|
||
|
|
||
|
def __setitem__(self, key, val):
|
||
|
dict.__setitem__(self, key, val)
|
||
|
self.commit()
|