mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-07-30 19:40:03 -07:00
add subliminal for subtitle download. #253
This commit is contained in:
parent
47289c903a
commit
c3889c01b1
149 changed files with 34173 additions and 33 deletions
418
libs/xdg/IniFile.py
Normal file
418
libs/xdg/IniFile.py
Normal file
|
@ -0,0 +1,418 @@
|
|||
"""
|
||||
Base Class for DesktopEntry, IconTheme and IconData
|
||||
"""
|
||||
|
||||
import re, os, stat, io
|
||||
from xdg.Exceptions import (ParsingError, DuplicateGroupError, NoGroupError,
|
||||
NoKeyError, DuplicateKeyError, ValidationError,
|
||||
debug)
|
||||
import xdg.Locale
|
||||
from xdg.util import u
|
||||
|
||||
def is_ascii(s):
|
||||
"""Return True if a string consists entirely of ASCII characters."""
|
||||
try:
|
||||
s.encode('ascii', 'strict')
|
||||
return True
|
||||
except UnicodeError:
|
||||
return False
|
||||
|
||||
class IniFile:
|
||||
defaultGroup = ''
|
||||
fileExtension = ''
|
||||
|
||||
filename = ''
|
||||
|
||||
tainted = False
|
||||
|
||||
def __init__(self, filename=None):
|
||||
self.content = dict()
|
||||
if filename:
|
||||
self.parse(filename)
|
||||
|
||||
def __cmp__(self, other):
|
||||
return cmp(self.content, other.content)
|
||||
|
||||
def parse(self, filename, headers=None):
|
||||
'''Parse an INI file.
|
||||
|
||||
headers -- list of headers the parser will try to select as a default header
|
||||
'''
|
||||
# for performance reasons
|
||||
content = self.content
|
||||
|
||||
if not os.path.isfile(filename):
|
||||
raise ParsingError("File not found", filename)
|
||||
|
||||
try:
|
||||
# The content should be UTF-8, but legacy files can have other
|
||||
# encodings, including mixed encodings in one file. We don't attempt
|
||||
# to decode them, but we silence the errors.
|
||||
fd = io.open(filename, 'r', encoding='utf-8', errors='replace')
|
||||
except IOError as e:
|
||||
if debug:
|
||||
raise e
|
||||
else:
|
||||
return
|
||||
|
||||
# parse file
|
||||
for line in fd:
|
||||
line = line.strip()
|
||||
# empty line
|
||||
if not line:
|
||||
continue
|
||||
# comment
|
||||
elif line[0] == '#':
|
||||
continue
|
||||
# new group
|
||||
elif line[0] == '[':
|
||||
currentGroup = line.lstrip("[").rstrip("]")
|
||||
if debug and self.hasGroup(currentGroup):
|
||||
raise DuplicateGroupError(currentGroup, filename)
|
||||
else:
|
||||
content[currentGroup] = {}
|
||||
# key
|
||||
else:
|
||||
try:
|
||||
key, value = line.split("=", 1)
|
||||
except ValueError:
|
||||
raise ParsingError("Invalid line: " + line, filename)
|
||||
|
||||
key = key.strip() # Spaces before/after '=' should be ignored
|
||||
try:
|
||||
if debug and self.hasKey(key, currentGroup):
|
||||
raise DuplicateKeyError(key, currentGroup, filename)
|
||||
else:
|
||||
content[currentGroup][key] = value.strip()
|
||||
except (IndexError, UnboundLocalError):
|
||||
raise ParsingError("Parsing error on key, group missing", filename)
|
||||
|
||||
fd.close()
|
||||
|
||||
self.filename = filename
|
||||
self.tainted = False
|
||||
|
||||
# check header
|
||||
if headers:
|
||||
for header in headers:
|
||||
if header in content:
|
||||
self.defaultGroup = header
|
||||
break
|
||||
else:
|
||||
raise ParsingError("[%s]-Header missing" % headers[0], filename)
|
||||
|
||||
# start stuff to access the keys
|
||||
def get(self, key, group=None, locale=False, type="string", list=False):
|
||||
# set default group
|
||||
if not group:
|
||||
group = self.defaultGroup
|
||||
|
||||
# return key (with locale)
|
||||
if (group in self.content) and (key in self.content[group]):
|
||||
if locale:
|
||||
value = self.content[group][self.__addLocale(key, group)]
|
||||
else:
|
||||
value = self.content[group][key]
|
||||
else:
|
||||
if debug:
|
||||
if group not in self.content:
|
||||
raise NoGroupError(group, self.filename)
|
||||
elif key not in self.content[group]:
|
||||
raise NoKeyError(key, group, self.filename)
|
||||
else:
|
||||
value = ""
|
||||
|
||||
if list == True:
|
||||
values = self.getList(value)
|
||||
result = []
|
||||
else:
|
||||
values = [value]
|
||||
|
||||
for value in values:
|
||||
if type == "boolean":
|
||||
value = self.__getBoolean(value)
|
||||
elif type == "integer":
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
value = 0
|
||||
elif type == "numeric":
|
||||
try:
|
||||
value = float(value)
|
||||
except ValueError:
|
||||
value = 0.0
|
||||
elif type == "regex":
|
||||
value = re.compile(value)
|
||||
elif type == "point":
|
||||
x, y = value.split(",")
|
||||
value = int(x), int(y)
|
||||
|
||||
if list == True:
|
||||
result.append(value)
|
||||
else:
|
||||
result = value
|
||||
|
||||
return result
|
||||
# end stuff to access the keys
|
||||
|
||||
# start subget
|
||||
def getList(self, string):
|
||||
if re.search(r"(?<!\\)\;", string):
|
||||
list = re.split(r"(?<!\\);", string)
|
||||
elif re.search(r"(?<!\\)\|", string):
|
||||
list = re.split(r"(?<!\\)\|", string)
|
||||
elif re.search(r"(?<!\\),", string):
|
||||
list = re.split(r"(?<!\\),", string)
|
||||
else:
|
||||
list = [string]
|
||||
if list[-1] == "":
|
||||
list.pop()
|
||||
return list
|
||||
|
||||
def __getBoolean(self, boolean):
|
||||
if boolean == 1 or boolean == "true" or boolean == "True":
|
||||
return True
|
||||
elif boolean == 0 or boolean == "false" or boolean == "False":
|
||||
return False
|
||||
return False
|
||||
# end subget
|
||||
|
||||
def __addLocale(self, key, group=None):
|
||||
"add locale to key according the current lc_messages"
|
||||
# set default group
|
||||
if not group:
|
||||
group = self.defaultGroup
|
||||
|
||||
for lang in xdg.Locale.langs:
|
||||
langkey = "%s[%s]" % (key, lang)
|
||||
if langkey in self.content[group]:
|
||||
return langkey
|
||||
|
||||
return key
|
||||
|
||||
# start validation stuff
|
||||
def validate(self, report="All"):
|
||||
"""Validate the contents, raising ``ValidationError`` if there
|
||||
is anything amiss.
|
||||
|
||||
report can be 'All' / 'Warnings' / 'Errors'
|
||||
"""
|
||||
|
||||
self.warnings = []
|
||||
self.errors = []
|
||||
|
||||
# get file extension
|
||||
self.fileExtension = os.path.splitext(self.filename)[1]
|
||||
|
||||
# overwrite this for own checkings
|
||||
self.checkExtras()
|
||||
|
||||
# check all keys
|
||||
for group in self.content:
|
||||
self.checkGroup(group)
|
||||
for key in self.content[group]:
|
||||
self.checkKey(key, self.content[group][key], group)
|
||||
# check if value is empty
|
||||
if self.content[group][key] == "":
|
||||
self.warnings.append("Value of Key '%s' is empty" % key)
|
||||
|
||||
# raise Warnings / Errors
|
||||
msg = ""
|
||||
|
||||
if report == "All" or report == "Warnings":
|
||||
for line in self.warnings:
|
||||
msg += "\n- " + line
|
||||
|
||||
if report == "All" or report == "Errors":
|
||||
for line in self.errors:
|
||||
msg += "\n- " + line
|
||||
|
||||
if msg:
|
||||
raise ValidationError(msg, self.filename)
|
||||
|
||||
# check if group header is valid
|
||||
def checkGroup(self, group):
|
||||
pass
|
||||
|
||||
# check if key is valid
|
||||
def checkKey(self, key, value, group):
|
||||
pass
|
||||
|
||||
# check random stuff
|
||||
def checkValue(self, key, value, type="string", list=False):
|
||||
if list == True:
|
||||
values = self.getList(value)
|
||||
else:
|
||||
values = [value]
|
||||
|
||||
for value in values:
|
||||
if type == "string":
|
||||
code = self.checkString(value)
|
||||
if type == "localestring":
|
||||
continue
|
||||
elif type == "boolean":
|
||||
code = self.checkBoolean(value)
|
||||
elif type == "numeric":
|
||||
code = self.checkNumber(value)
|
||||
elif type == "integer":
|
||||
code = self.checkInteger(value)
|
||||
elif type == "regex":
|
||||
code = self.checkRegex(value)
|
||||
elif type == "point":
|
||||
code = self.checkPoint(value)
|
||||
if code == 1:
|
||||
self.errors.append("'%s' is not a valid %s" % (value, type))
|
||||
elif code == 2:
|
||||
self.warnings.append("Value of key '%s' is deprecated" % key)
|
||||
|
||||
def checkExtras(self):
|
||||
pass
|
||||
|
||||
def checkBoolean(self, value):
|
||||
# 1 or 0 : deprecated
|
||||
if (value == "1" or value == "0"):
|
||||
return 2
|
||||
# true or false: ok
|
||||
elif not (value == "true" or value == "false"):
|
||||
return 1
|
||||
|
||||
def checkNumber(self, value):
|
||||
# float() ValueError
|
||||
try:
|
||||
float(value)
|
||||
except:
|
||||
return 1
|
||||
|
||||
def checkInteger(self, value):
|
||||
# int() ValueError
|
||||
try:
|
||||
int(value)
|
||||
except:
|
||||
return 1
|
||||
|
||||
def checkPoint(self, value):
|
||||
if not re.match("^[0-9]+,[0-9]+$", value):
|
||||
return 1
|
||||
|
||||
def checkString(self, value):
|
||||
return 0 if is_ascii(value) else 1
|
||||
|
||||
def checkRegex(self, value):
|
||||
try:
|
||||
re.compile(value)
|
||||
except:
|
||||
return 1
|
||||
|
||||
# write support
|
||||
def write(self, filename=None, trusted=False):
|
||||
if not filename and not self.filename:
|
||||
raise ParsingError("File not found", "")
|
||||
|
||||
if filename:
|
||||
self.filename = filename
|
||||
else:
|
||||
filename = self.filename
|
||||
|
||||
if os.path.dirname(filename) and not os.path.isdir(os.path.dirname(filename)):
|
||||
os.makedirs(os.path.dirname(filename))
|
||||
|
||||
with io.open(filename, 'w', encoding='utf-8') as fp:
|
||||
|
||||
# An executable bit signifies that the desktop file is
|
||||
# trusted, but then the file can be executed. Add hashbang to
|
||||
# make sure that the file is opened by something that
|
||||
# understands desktop files.
|
||||
if trusted:
|
||||
fp.write(u("#!/usr/bin/env xdg-open\n"))
|
||||
|
||||
if self.defaultGroup:
|
||||
fp.write(u("[%s]\n") % self.defaultGroup)
|
||||
for (key, value) in self.content[self.defaultGroup].items():
|
||||
fp.write(u("%s=%s\n") % (key, value))
|
||||
fp.write(u("\n"))
|
||||
for (name, group) in self.content.items():
|
||||
if name != self.defaultGroup:
|
||||
fp.write(u("[%s]\n") % name)
|
||||
for (key, value) in group.items():
|
||||
fp.write(u("%s=%s\n") % (key, value))
|
||||
fp.write(u("\n"))
|
||||
|
||||
# Add executable bits to the file to show that it's trusted.
|
||||
if trusted:
|
||||
oldmode = os.stat(filename).st_mode
|
||||
mode = oldmode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
||||
os.chmod(filename, mode)
|
||||
|
||||
self.tainted = False
|
||||
|
||||
def set(self, key, value, group=None, locale=False):
|
||||
# set default group
|
||||
if not group:
|
||||
group = self.defaultGroup
|
||||
|
||||
if locale == True and len(xdg.Locale.langs) > 0:
|
||||
key = key + "[" + xdg.Locale.langs[0] + "]"
|
||||
|
||||
try:
|
||||
self.content[group][key] = value
|
||||
except KeyError:
|
||||
raise NoGroupError(group, self.filename)
|
||||
|
||||
self.tainted = (value == self.get(key, group))
|
||||
|
||||
def addGroup(self, group):
|
||||
if self.hasGroup(group):
|
||||
if debug:
|
||||
raise DuplicateGroupError(group, self.filename)
|
||||
else:
|
||||
self.content[group] = {}
|
||||
self.tainted = True
|
||||
|
||||
def removeGroup(self, group):
|
||||
existed = group in self.content
|
||||
if existed:
|
||||
del self.content[group]
|
||||
self.tainted = True
|
||||
else:
|
||||
if debug:
|
||||
raise NoGroupError(group, self.filename)
|
||||
return existed
|
||||
|
||||
def removeKey(self, key, group=None, locales=True):
|
||||
# set default group
|
||||
if not group:
|
||||
group = self.defaultGroup
|
||||
|
||||
try:
|
||||
if locales:
|
||||
for name in list(self.content[group]):
|
||||
if re.match("^" + key + xdg.Locale.regex + "$", name) and name != key:
|
||||
del self.content[group][name]
|
||||
value = self.content[group].pop(key)
|
||||
self.tainted = True
|
||||
return value
|
||||
except KeyError as e:
|
||||
if debug:
|
||||
if e == group:
|
||||
raise NoGroupError(group, self.filename)
|
||||
else:
|
||||
raise NoKeyError(key, group, self.filename)
|
||||
else:
|
||||
return ""
|
||||
|
||||
# misc
|
||||
def groups(self):
|
||||
return self.content.keys()
|
||||
|
||||
def hasGroup(self, group):
|
||||
return group in self.content
|
||||
|
||||
def hasKey(self, key, group=None):
|
||||
# set default group
|
||||
if not group:
|
||||
group = self.defaultGroup
|
||||
|
||||
return key in self.content[group]
|
||||
|
||||
def getFileName(self):
|
||||
return self.filename
|
Loading…
Add table
Add a link
Reference in a new issue