--- /dev/null
+# -*- coding: utf-8 -*-
+# Copyright (C) 2012-2013 Parisson SARL
+
+# This software is a computer program whose purpose is to backup, analyse,
+# transcode and stream any audio content with its metadata over a web frontend.
+
+# This software is governed by the CeCILL license under French law and
+# abiding by the rules of distribution of free software. You can use,
+# modify and/ or redistribute the software under the terms of the CeCILL
+# license as circulated by CEA, CNRS and INRIA at the following URL
+# "http://www.cecill.info".
+
+# As a counterpart to the access to the source code and rights to copy,
+# modify and redistribute granted by the license, users are provided only
+# with a limited warranty and the software's author, the holder of the
+# economic rights, and the successive licensors have only limited
+# liability.
+
+# In this respect, the user's attention is drawn to the risks associated
+# with loading, using, modifying and/or developing or reproducing the
+# software by the user in light of its specific status of free software,
+# that may mean that it is complicated to manipulate, and that also
+# therefore means that it is reserved for developers and experienced
+# professionals having in-depth computer knowledge. Users are therefore
+# encouraged to load and test the software's suitability as regards their
+# requirements in conditions enabling the security of their systems and/or
+# data to be ensured and, more generally, to use and operate it in the
+# same conditions as regards security.
+
+# The fact that you are presently reading this means that you have had
+# knowledge of the CeCILL license and that you accept its terms.
+
+# Authors: Guillaume Pellerin <yomguy@parisson.com>
+
+
+from telemeta.util.xmltodict2 import *
+
+
+class KDEnLiveSession(object):
+
+ def __init__(self, path):
+ self.session = xmltodict(path)
+
+ def entries(self):
+ entries = []
+ for attr in self.session['children']:
+ if 'playlist' in attr['name'] and 'children' in attr:
+ for att in attr['children']:
+ if 'entry' in att['name'] and att['attributes']['producer'] != 'black':
+ entries.append(att['attributes'])
+ return entries
+
+ def entries_sorted(self):
+ return sorted(self.entries(), key=lambda k: int(k['in']), reverse=False)
+
+ def first_video_frame(self):
+ return int(self.entries_sorted()[0]['in'])
+
+ def profile(self):
+ for attr in self.session['children']:
+ if 'profile' in attr['name']:
+ return attr['attributes']
+
+ def markers_relative(self):
+ markers = []
+ fps = float(self.profile()['frame_rate_num'])
+ first_frame_seconds = self.first_video_frame()/fps
+ for attr in self.session['children']:
+ if 'kdenlivedoc' in attr['name']:
+ for att in attr['children']:
+ if 'markers' in att['name']:
+ for at in att['children']:
+ if 'marker' in at['name']:
+ time = float(at['attributes']['time'].replace(',','.')) - first_frame_seconds
+ at['attributes']['time'] = time
+ markers.append(at['attributes'])
+ return markers
+
+
+
+
+
--- /dev/null
+# -*- coding: utf-8 -*-
+""" xmltodict(): convert xml into tree of Python dicts.
+
+This was copied and modified from John Bair's recipe at aspn.activestate.com:
+ http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/149368
+"""
+import os
+import string
+import locale
+from xml.parsers import expat
+
+# If we're in Dabo, get the default encoding.
+#import dabo
+#import dabo.lib.DesignerUtils as desUtil
+#from dabo.dLocalize import _
+#from dabo.lib.utils import resolvePath
+#app = dabo.dAppRef
+#if app is not None:
+ #default_encoding = app.Encoding
+#else:
+ #enc = locale.getlocale()[1]
+ #if enc is None:
+ #enc = dabo.defaultEncoding
+ #default_encoding = enc
+
+# Python seems to need to compile code with \n linesep:
+code_linesep = "\n"
+eol = os.linesep
+default_encoding = 'utf-8'
+default_decoding = 'utf-8'
+
+class Xml2Obj:
+ """XML to Object"""
+ def __init__(self):
+ self.root = None
+ self.nodeStack = []
+ self.attsToSkip = []
+ self._inCode = False
+ self._mthdName = ""
+ self._mthdCode = ""
+ self._codeDict = None
+ self._inProp = False
+ self._propName = ""
+ self._propData = ""
+ self._propDict = None
+ self._currPropAtt = ""
+ self._currPropDict = None
+
+
+ def StartElement(self, name, attributes):
+ """SAX start element even handler"""
+ if name == "code":
+ # This is code for the parent element
+ self._inCode = True
+ parent = self.nodeStack[-1]
+ if not parent.has_key("code"):
+ parent["code"] = {}
+ self._codeDict = parent["code"]
+
+ elif name == "properties":
+ # These are the custom property definitions
+ self._inProp = True
+ self._propName = ""
+ self._propData = ""
+ parent = self.nodeStack[-1]
+ if not parent.has_key("properties"):
+ parent["properties"] = {}
+ self._propDict = parent["properties"]
+
+ else:
+ if self._inCode:
+ self._mthdName = name.encode()
+ elif self._inProp:
+ if self._propName:
+ # In the middle of a prop definition
+ self._currPropAtt = name.encode()
+ else:
+ self._propName = name.encode()
+ self._currPropDict = {}
+ self._currPropAtt = ""
+ else:
+ element = {"name": name.encode()}
+ if len(attributes) > 0:
+ for att in self.attsToSkip:
+ if attributes.has_key(att):
+ del attributes[att]
+ element["attributes"] = attributes
+
+ # Push element onto the stack and make it a child of parent
+ if len(self.nodeStack) > 0:
+ parent = self.nodeStack[-1]
+ if not parent.has_key("children"):
+ parent["children"] = []
+ parent["children"].append(element)
+ else:
+ self.root = element
+ self.nodeStack.append(element)
+
+
+ def EndElement(self, name):
+ """SAX end element event handler"""
+ if self._inCode:
+ if name == "code":
+ self._inCode = False
+ self._codeDict = None
+ else:
+ # End of an individual method
+ mth = self._mthdCode.strip()
+ if not mth.endswith("\n"):
+ mth += "\n"
+ self._codeDict[self._mthdName] = mth
+ self._mthdName = ""
+ self._mthdCode = ""
+ elif self._inProp:
+ if name == "properties":
+ self._inProp = False
+ self._propDict = None
+ elif name == self._propName:
+ # End of an individual prop definition
+ self._propDict[self._propName] = self._currPropDict
+ self._propName = ""
+ else:
+ # end of a property attribute
+ self._currPropDict[self._currPropAtt] = self._propData
+ self._propData = self._currPropAtt = ""
+ else:
+ self.nodeStack = self.nodeStack[:-1]
+
+
+ def CharacterData(self, data):
+ """SAX character data event handler"""
+ if self._inCode or data.strip():
+ data = data.replace("<", "<")
+ data = data.encode(default_encoding)
+ if self._inCode:
+ if self._mthdCode:
+ self._mthdCode += data
+ else:
+ self._mthdCode = data
+ elif self._inProp:
+ self._propData += data
+ else:
+ element = self.nodeStack[-1]
+ if not element.has_key("cdata"):
+ element["cdata"] = ""
+ element["cdata"] += data
+
+
+ def Parse(self, xml):
+ # Create a SAX parser
+ Parser = expat.ParserCreate(default_encoding)
+ # SAX event handlers
+ Parser.StartElementHandler = self.StartElement
+ Parser.EndElementHandler = self.EndElement
+ Parser.CharacterDataHandler = self.CharacterData
+ # Parse the XML File
+ ParserStatus = Parser.Parse(xml, 1)
+ return self.root
+
+
+ def ParseFromFile(self, filename):
+ return self.Parse(open(filename,"r").read())
+
+
+def xmltodict(xml, attsToSkip=[], addCodeFile=False):
+ """Given an xml string or file, return a Python dictionary."""
+ parser = Xml2Obj()
+ parser.attsToSkip = attsToSkip
+ isPath = os.path.exists(xml)
+ errmsg = ""
+ if eol not in xml and isPath:
+ # argument was a file
+ try:
+ ret = parser.ParseFromFile(xml)
+ except expat.ExpatError, e:
+ errmsg = _("The XML in '%s' is not well-formed and cannot be parsed: %s") % (xml, e)
+ else:
+ # argument must have been raw xml:
+ if not xml.strip().startswith("<?xml "):
+ # it's a bad file name
+ errmsg = _("The file '%s' could not be found") % xml
+ else:
+ try:
+ ret = parser.Parse(xml)
+ except expat.ExpatError:
+ errmsg = _("An invalid XML string was encountered")
+ if errmsg:
+ raise dabo.dException.XmlException, errmsg
+ if addCodeFile and isPath:
+ # Get the associated code file, if any
+ codePth = "%s-code.py" % os.path.splitext(xml)[0]
+ if os.path.exists(codePth):
+ try:
+ codeDict = desUtil.parseCodeFile(open(codePth).read())
+ desUtil.addCodeToClassDict(ret, codeDict)
+ except StandardError, e:
+ print "Failed to parse code file:", e
+ return ret
+
+
+def escQuote(val, noEscape=False, noQuote=False):
+ """Add surrounding quotes to the string, and escape
+ any illegal XML characters.
+ """
+ if not isinstance(val, basestring):
+ val = str(val)
+ if not isinstance(val, unicode):
+ val = unicode(val, default_encoding)
+ if noQuote:
+ qt = ''
+ else:
+ qt = '"'
+ slsh = "\\"
+# val = val.replace(slsh, slsh+slsh)
+ if not noEscape:
+ # First escape internal ampersands. We need to double them up due to a
+ # quirk in wxPython and the way it displays this character.
+ val = val.replace("&", "&&")
+ # Escape any internal quotes
+ val = val.replace('"', '"').replace("'", "'")
+ # Escape any high-order characters
+ chars = []
+ for pos, char in enumerate(list(val)):
+ if ord(char) > 127:
+ chars.append("&#%s;" % ord(char))
+ else:
+ chars.append(char)
+ val = "".join(chars)
+ val = val.replace("<", "<").replace(">", ">")
+ return "%s%s%s" % (qt, val, qt)
+
+
+def dicttoxml(dct, level=0, header=None, linesep=None):
+ """Given a Python dictionary, return an xml string.
+
+ The dictionary must be in the format returned by dicttoxml(), with keys
+ on "attributes", "code", "cdata", "name", and "children".
+
+ Send your own XML header, otherwise a default one will be used.
+
+ The linesep argument is a dictionary, with keys on levels, allowing the
+ developer to add extra whitespace depending on the level.
+ """
+ att = ""
+ ret = ""
+
+ if dct.has_key("attributes"):
+ for key, val in dct["attributes"].items():
+ # Some keys are already handled.
+ noEscape = key in ("sizerInfo",)
+ val = escQuote(val, noEscape)
+ att += " %s=%s" % (key, val)
+ ret += "%s<%s%s" % ("\t" * level, dct["name"], att)
+
+ if (not dct.has_key("cdata") and not dct.has_key("children")
+ and not dct.has_key("code") and not dct.has_key("properties")):
+ ret += " />%s" % eol
+ else:
+ ret += ">"
+ if dct.has_key("cdata"):
+ ret += "%s" % dct["cdata"].decode(default_encoding).replace("<", "<")
+
+ if dct.has_key("code"):
+ if len(dct["code"].keys()):
+ ret += "%s%s<code>%s" % (eol, "\t" * (level+1), eol)
+ methodTab = "\t" * (level+2)
+ for mthd, cd in dct["code"].items():
+ # Convert \n's in the code to eol:
+ cd = eol.join(cd.splitlines())
+
+ # Make sure that the code ends with a linefeed
+ if not cd.endswith(eol):
+ cd += eol
+
+ ret += "%s<%s><![CDATA[%s%s]]>%s%s</%s>%s" % (methodTab,
+ mthd, eol, cd, eol,
+ methodTab, mthd, eol)
+ ret += "%s</code>%s" % ("\t" * (level+1), eol)
+
+ if dct.has_key("properties"):
+ if len(dct["properties"].keys()):
+ ret += "%s%s<properties>%s" % (eol, "\t" * (level+1), eol)
+ currTab = "\t" * (level+2)
+ for prop, val in dct["properties"].items():
+ ret += "%s<%s>%s" % (currTab, prop, eol)
+ for propItm, itmVal in val.items():
+ itmTab = "\t" * (level+3)
+ ret += "%s<%s>%s</%s>%s" % (itmTab, propItm, itmVal,
+ propItm, eol)
+ ret += "%s</%s>%s" % (currTab, prop, eol)
+ ret += "%s</properties>%s" % ("\t" * (level+1), eol)
+
+ if dct.has_key("children") and len(dct["children"]) > 0:
+ ret += eol
+ for child in dct["children"]:
+ ret += dicttoxml(child, level+1, linesep=linesep)
+ indnt = ""
+ if ret.endswith(eol):
+ # Indent the closing tag
+ indnt = ("\t" * level)
+ ret += "%s</%s>%s" % (indnt, dct["name"], eol)
+
+ if linesep:
+ ret += linesep.get(level, "")
+
+ if level == 0:
+ if header is None:
+ header = '<?xml version="1.0" encoding="%s" standalone="no"?>%s' \
+ % (default_encoding, eol)
+ ret = header + ret
+
+ return ret
+
+
+def flattenClassDict(cd, retDict=None):
+ """Given a dict containing a series of nested objects such as would
+ be created by restoring from a cdxml file, returns a dict with all classIDs
+ as keys, and a dict as the corresponding value. The dict value will have
+ keys for the attributes and/or code, depending on what was in the original
+ dict. The end result is to take a nested dict structure and return a flattened
+ dict with all objects at the top level.
+ """
+ if retDict is None:
+ retDict = {}
+ atts = cd.get("attributes", {})
+ props = cd.get("properties", {})
+ kids = cd.get("children", [])
+ code = cd.get("code", {})
+ classID = atts.get("classID", "")
+ classFile = resolvePath(atts.get("designerClass", ""))
+ superclass = resolvePath(atts.get("superclass", ""))
+ superclassID = atts.get("superclassID", "")
+ if superclassID and os.path.exists(superclass):
+ # Get the superclass info
+ superCD = xmltodict(superclass, addCodeFile=True)
+ flattenClassDict(superCD, retDict)
+ if classID:
+ if os.path.exists(classFile):
+ # Get the class info
+ classCD = xmltodict(classFile, addCodeFile=True)
+ classAtts = classCD.get("attributes", {})
+ classProps = classCD.get("properties", {})
+ classCode = classCD.get("code", {})
+ classKids = classCD.get("children", [])
+ currDict = retDict.get(classID, {})
+ retDict[classID] = {"attributes": classAtts, "code": classCode,
+ "properties": classProps}
+ retDict[classID].update(currDict)
+ # Now update the child objects in the dict
+ for kid in classKids:
+ flattenClassDict(kid, retDict)
+ else:
+ # Not a file; most likely just a component in another class
+ currDict = retDict.get(classID, {})
+ retDict[classID] = {"attributes": atts, "code": code,
+ "properties": props}
+ retDict[classID].update(currDict)
+ if kids:
+ for kid in kids:
+ flattenClassDict(kid, retDict)
+ return retDict
+
+
+def addInheritedInfo(src, super, updateCode=False):
+ """Called recursively on the class container structure, modifying
+ the attributes to incorporate superclass information. When the
+ 'updateCode' parameter is True, superclass code is added to the
+ object's code
+ """
+ atts = src.get("attributes", {})
+ props = src.get("properties", {})
+ kids = src.get("children", [])
+ code = src.get("code", {})
+ classID = atts.get("classID", "")
+ if classID:
+ superInfo = super.get(classID, {"attributes": {}, "code": {}, "properties": {}})
+ src["attributes"] = superInfo["attributes"].copy()
+ src["attributes"].update(atts)
+ src["properties"] = superInfo.get("properties", {}).copy()
+ src["properties"].update(props)
+ if updateCode:
+ src["code"] = superInfo["code"].copy()
+ src["code"].update(code)
+ if kids:
+ for kid in kids:
+ addInheritedInfo(kid, super, updateCode)
+
+
+
+#if __name__ == "__main__":
+ #test_dict = {"name": "test", "attributes":{"path": "c:\\temp\\name",
+ #"problemChars": "Welcome to <Jos\xc3\xa9's \ Stuff!>\xc2\xae".decode("latin-1")}}
+ #print "test_dict:", test_dict
+ #xml = dicttoxml(test_dict)
+ #print "xml:", xml
+ #test_dict2 = xmltodict(xml)
+ #print "test_dict2:", test_dict2
+ #print "same?:", test_dict == test_dict2