added longely missed copyright notice
[pyvconv.git] / pyvconv.py
blob34b855ccbe33ee396c97b29ddcaa587124e5a809
1 # Pyvconv - A simple frontend for ffmpeg/mencoder
2 # Copyright (C) 2008, Kristian Rumberg (kristianrumberg@gmail.com)
4 # Permission to use, copy, modify, and/or distribute this software for any
5 # purpose with or without fee is hereby granted, provided that the above
6 # copyright notice and this permission notice appear in all copies.
8 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 import libxml2
17 import re
19 class Error(Exception):
20 def __init__(self, value):
21 Exception.__init__(self)
22 self.value = value
23 def __str__(self):
24 return repr(self.value)
26 class Variable:
27 def __init__(self, namestr, defaultstr, exprstr):
28 self.namestr = namestr
29 self.defaultstr = defaultstr
30 self.exprstr = exprstr
32 def __str__(self):
33 return self.namestr
35 def has_value(self):
36 return self.defaultstr != None
38 def evaluate(self):
39 if self.defaultstr == None:
40 raise Error("Error: Trying to eval variable " + self.namestr + " with no value")
41 return self.defaultstr
43 class OptionalSetting:
44 def __init__(self, namestr, exprstr):
45 self.namestr = namestr
46 self.exprstr = exprstr
48 def get_name(self):
49 return self.namestr
51 def evaluate(self, var_list):
52 instr = self.exprstr
53 for var in var_list:
54 if var_list[var].has_value():
55 p = re.compile( "\$\{" + var + "\}")
56 instr = p.sub( var_list[var].evaluate(), instr)
57 if instr.find("$") != -1:
58 instr = "" # if not all variables were found, return empty option
59 return instr
61 class RenderCommand:
62 def __init__(self, namestr, callstr, var_list, optset_list):
63 self.namestr = namestr
64 self.callstr = callstr
65 self.var_list = var_list
66 self.optset_list = optset_list
68 def get_name(self):
69 return self.namestr
71 def put_var(self, var):
72 self.var_list[str(var)] = var
74 def get_vars(self):
75 return self.var_list
77 def evaluate(self):
78 instr = self.callstr
80 p = re.compile("\$\[(\w+)\]")
81 for o in p.findall(instr):
82 if o not in self.optset_list:
83 raise Error("Error: Optional variable not defined")
84 instr = p.sub(self.optset_list[o].evaluate(self.var_list), instr)
86 p = re.compile("\$\{(\w+)\}")
87 for o in p.findall(instr):
88 if o not in self.var_list:
89 raise Error("Error: Variable \"" + o + "\" has not been assigned")
90 val = self.var_list[o].evaluate()
91 instr = instr.replace("${" + o + "}", val)
93 if instr.find("$") != -1:
94 raise Error("Error: all variables were not expanded")
95 return instr
97 def __str__(self):
98 return self.evaluate()
100 class RenderCommands:
101 def __init__(self):
102 self.cmdcall_dict = {}
103 self._read_config()
105 def _read_properties(self, propnode, mand_propnames, opt_propnames = []):
106 propdict = {}
108 for p in propnode:
109 if p.name in mand_propnames:
110 propdict[p.name] = str(p.content)
111 elif p.name != "text" and p.name not in opt_propnames:
112 raise Error("Error parsing XML: only name and call are accepted properties in the element command, found " + str(p.name))
114 if len(mand_propnames) != len(propdict.keys()):
115 raise Error("Error parsing XML: must supply both name and call in element command")
117 for p in propnode:
118 if p.name in opt_propnames:
119 propdict[p.name] = str(p.content)
120 elif p.name != "text" and p.name not in mand_propnames:
121 raise Error("Error parsing XML: only name and call are accepted properties in the element command, found " + str(p.name))
123 return propdict
125 def _read_config(self):
126 doc = libxml2.parseFile("rendercommands.xml")
127 cmd_xmllist = doc.xpathEval( '//command')
129 # read all commands from XML description
130 for cmdnode in cmd_xmllist:
131 if cmdnode.type == "element" and cmdnode.name == "command":
133 var_list = {}
134 optset_list = {}
136 if cmdnode.children:
137 for varsetnode in cmdnode.children:
138 if varsetnode.type == "element" and varsetnode.name == "variable":
139 props = self._read_properties(varsetnode.properties, ["name", "expr"], ["default"])
140 defprop = None
141 if "default" in props:
142 defprop = props["default"]
143 var_list[props["name"]] = Variable(props["name"], defprop, props["expr"])
145 elif varsetnode.type == "element" and varsetnode.name == "optionalsetting":
146 props = self._read_properties(varsetnode.properties, ["name", "expr"])
147 optset_list[props["name"]] = OptionalSetting(props["name"], props["expr"])
149 elif varsetnode.name != "text":
150 raise Error("Error parsing XML: only variable and optionalsetting elements allowed in command")
152 props = self._read_properties(cmdnode.properties, ["name", "call"])
153 self.cmdcall_dict[props["name"]] = RenderCommand(props["name"], props["call"], var_list, optset_list)
155 else:
156 raise Error("Error parsing XML: only command elements are supported")
158 def __iter__(self):
159 return self.cmdcall_dict.values().__iter__()
161 def main():
162 commands = RenderCommands()
163 for c in commands:
164 c.put_var(Variable("in", "src.avi", None))
165 c.put_var(Variable("out", "dest.avi", None))
166 print c
168 if __name__ == "__main__":
169 main()