Temporary fix to broken eConsoleAppContainer interface
[vuplus_dvbapp-plugin] / moviecut / src_py / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2 from Screens.Screen import Screen
3 from Screens.MessageBox import MessageBox
4 from Screens.ChoiceBox import ChoiceBox
5 from Screens.LocationBox import MovieLocationBox
6 import Screens.Standby
7 from Components.config import *
8 from Components.ActionMap import ActionMap, NumberActionMap
9 from Components.ConfigList import ConfigList, ConfigListScreen
10 from Components.Button import Button
11 from Components.Label import Label
12 from Components.Pixmap import Pixmap
13 from enigma import eTimer, eServiceReference, eServiceCenter, iServiceInformation, eConsoleAppContainer
14 from os import access, chmod, X_OK
15
16 mcut_path = "/usr/lib/enigma2/python/Plugins/Extensions/MovieCut/bin/mcut"
17 # Hack to make sure it is executable
18 if not access(mcut_path, X_OK):
19         chmod(mcut_path, 493)
20
21 def main(session, service, **kwargs):
22         session.open(MovieCut, service, **kwargs)
23
24 def Plugins(**kwargs):
25         return PluginDescriptor(name="MovieCut", description=_("Execute cuts..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)
26
27
28 class MovieCut(ChoiceBox):
29         def __init__(self, session, service):
30                 self.service = service
31                 serviceHandler = eServiceCenter.getInstance()
32                 path = self.service.getPath()
33                 info = serviceHandler.info(self.service)
34                 if not info:
35                         self.name = path
36                 else:
37                         self.name = info.getName(self.service)
38                 tlist = []
39                 tlist.append((_("Don't cut"), "CALLFUNC", self.confirmed0))
40                 tlist.append((_("Replace the original movie with the cut movie"), "CALLFUNC", self.confirmed1))
41                 tlist.append((_("Place the cut movie in a new file ending with \" cut\""), "CALLFUNC", self.confirmed2))
42                 tlist.append((_("Advanced cut specification..."), "CALLFUNC", self.confirmed3))
43                 ChoiceBox.__init__(self, session, _("How would you like to cut \"%s\"?") % (self.name), list = tlist, selection = 0)
44                 self.skinName = "ChoiceBox"
45
46         def confirmed0(self, arg):
47                 self.close()
48
49         def confirmed1(self, arg):
50                 MovieCutSpawn(self.session, self, [mcut_path, "-r", self.service.getPath()], self.name)
51
52         def confirmed2(self, arg):
53                 MovieCutSpawn(self.session, self, [mcut_path, self.service.getPath()], self.name)
54
55         def confirmed3(self, arg):
56                 serviceHandler = eServiceCenter.getInstance()
57                 info = serviceHandler.info(self.service)
58                 self.path = self.service.getPath()
59                 self.name = info.getName(self.service)
60                 self.descr = info.getInfoString(self.service, iServiceInformation.sDescription)
61                 self.session.openWithCallback(self.advcutConfirmed, AdvancedCutInput, self.name, self.path, self.descr)
62
63         def advcutConfirmed(self, ret):
64                 if len(ret) <= 1 or not ret[0]:
65                         self.close()
66                         return
67                 clist = [mcut_path]
68                 if ret[1] == True:
69                         clist.append("-r")
70                 clist.append(self.service.getPath())
71                 if ret[2] != False:
72                         clist += ["-o", ret[2]]
73                 if ret[3] != False:
74                         clist += ["-n", ret[3]]
75                 if ret[4] != False:
76                         clist += ["-d", ret[4]]
77                 if ret[5] != False:
78                         clist.append("-c")
79                         clist += ret[5]
80                 MovieCutSpawn(self.session, self, clist, self.name)
81                 
82 class AdvancedCutInput(Screen, ConfigListScreen):
83         skin = """
84         <screen name="AdvancedCutInput" position="80,100" size="550,320" title="Cut Parameter Input">
85                 <widget name="config" position="5,10" size="530,250" />
86                 <widget name="ok" position="90,265" size="140,40" pixmap="skin_default/buttons/green.png" alphatest="on" />
87                 <widget name="oktext" position="90,265" size="140,40" valign="center" halign="center" zPosition="2" font="Regular;20" transparent="1" />
88                 <widget name="cancel" position="320,265" size="140,40" pixmap="skin_default/buttons/red.png" alphatest="on" />
89                 <widget name="canceltext" position="320,265" size="140,40" valign="center" halign="center" zPosition="2" font="Regular;20" transparent="1" />
90         </screen>"""
91
92         def __init__(self, session, name, path, descr):
93                 self.skin = AdvancedCutInput.skin
94                 Screen.__init__(self, session)
95
96                 self["oktext"] = Label(_("OK"))
97                 self["canceltext"] = Label(_("Cancel"))
98                 self["ok"] = Pixmap()
99                 self["cancel"] = Pixmap()
100
101                 if self.baseName(path) == self.baseName(name):
102                         self.title = ""
103                 else:
104                         self.title = name
105                 self.dir = self.dirName(path)
106                 self.file = self.baseName(path) + " cut"
107                 self.descr = descr
108                 self.input_replace = ConfigSelection(choices = [("no", _("No")), ("yes", _("Yes"))], default = "no")
109                 self.input_file = ConfigText(default = self.file, fixed_size = False, visible_width = 45)
110                 self.input_title = ConfigText(default = self.title, fixed_size = False, visible_width = 45)
111                 self.input_descr = ConfigText(default = self.descr, fixed_size = False, visible_width = 45)
112                 tmp = config.movielist.videodirs.value
113                 if not self.dir in tmp:
114                         tmp.append(self.dir)
115                 self.input_dir = ConfigSelection(choices = tmp, default = self.dir)
116                 self.input_manual = ConfigSelection(choices = [("no", _("Cutlist")), ("yes", _("Manual specification"))], default = "no")
117                 self.input_space = ConfigNothing()
118                 self.input_manualcuts = ConfigText(default = "", fixed_size = False)
119                 self.input_manualcuts.setUseableChars(" 0123456789:.")
120                 self["actions"] = NumberActionMap(["SetupActions"],
121                 {
122                         "ok": self.keySelectOrGo,
123                         "save": self.keyGo,
124                         "cancel": self.keyCancel,
125                 }, -2)
126
127                 self.list = []
128                 ConfigListScreen.__init__(self, self.list)
129                 self.entry_replace = getConfigListEntry(_("Replace original:"), self.input_replace)
130                 self.entry_file = getConfigListEntry(_("New filename:"), self.input_file)
131                 self.entry_title = getConfigListEntry(_("New title:"), self.input_title)
132                 self.entry_descr = getConfigListEntry(_("New description:"), self.input_descr)
133                 self.entry_dir = getConfigListEntry(_("New location:"), self.input_dir)
134                 self.entry_manual = getConfigListEntry(_("Cut source:"), self.input_manual)
135                 self.entry_space = getConfigListEntry(_("Cuts (an IN OUT IN OUT ... sequence of hour:min:sec)"), self.input_space)
136                 self.entry_manualcuts = getConfigListEntry(":", self.input_manualcuts)
137                 self.createSetup(self["config"])
138
139         def createSetup(self, configlist):
140                 self.list = []
141                 self.list.append(self.entry_replace)
142                 if self.input_replace.value == "no":
143                         self.list.append(self.entry_file)
144                         self.list.append(self.entry_dir)
145                 self.list.append(self.entry_title)
146                 self.list.append(self.entry_descr)
147                 self.list.append(self.entry_manual)
148                 if self.input_manual.value == "yes":
149                         self.list.append(self.entry_space)
150                         self.list.append(self.entry_manualcuts)
151                 configlist.list = self.list
152                 configlist.l.setList(self.list)
153
154         def keyLeft(self):
155                 ConfigListScreen.keyLeft(self)
156                 cc = self["config"].getCurrent()
157                 if cc is self.entry_replace or cc is self.entry_manual:
158                         self.createSetup(self["config"])
159
160         def keyRight(self):
161                 ConfigListScreen.keyRight(self)
162                 cc = self["config"].getCurrent()
163                 if cc is self.entry_replace or cc is self.entry_manual:
164                         self.createSetup(self["config"])
165
166         def pathSelected(self, res):
167                 if res is not None:
168                         if config.movielist.videodirs.value != self.input_dir.choices:
169                                 self.input_dir.setChoices(config.movielist.videodirs.value, default=res)
170                         self.input_dir.value = res
171
172         def keySelectOrGo(self):
173                 if self["config"].getCurrent() == self.entry_dir:
174                         self.session.openWithCallback(
175                                 self.pathSelected,
176                                 MovieLocationBox,
177                                 _("Choose target folder"),
178                                 self.input_dir.value,
179                         )
180                 else:
181                         self.keyGo()
182
183         def keyGo(self):
184                 if self.input_replace.value == "yes":
185                         path = False
186                 else:
187                         path = self.rejoinName(self.input_dir.value, self.input_file.value)
188                 if self.input_manual.value == "no":
189                         cuts = False
190                 else:
191                         cuts = self.input_manualcuts.value.split(' ')
192                         while "" in cuts:
193                                 cuts.remove("")
194                 self.close((True, self.input_replace.value, path, self.input_title.value, self.input_descr.value, cuts))
195
196         def keyCancel(self):
197                 self.close((False,))
198
199         def baseName(self, str):
200                 name = str.split('/')[-1]
201                 if name.endswith(".ts") is True:
202                         return name[:-3]
203                 else:
204                         return name
205
206         def dirName(self, str):
207                 return '/'.join(str.split('/')[:-1]) + '/'
208
209         def rejoinName(self, dir, name):
210                 name = name.strip()
211                 if name.endswith(".ts") is True:
212                         return dir + name[:-3]
213                 else:
214                         return dir + name
215
216 class MovieCutQueue:
217         def __init__(self):
218                 self.container = eConsoleAppContainer()
219                 self.container.appClosed.append(self.runDone)
220                 self.queue = []
221                 self.running = False
222
223         def enqueue(self, cb, cmd):
224                 self.queue.append((cb, cmd))
225                 if not self.running:
226                         self.running = True
227                         self.runNext()
228                         return True
229                 else:
230                         return False
231
232         def runNext(self):
233                 if not self.queue:
234                         self.running = False
235                 else:
236                         self.container.execute(*self.queue[0][1])
237
238         def runDone(self, retval):
239                 cb = self.queue[0][0]
240                 self.queue = self.queue[1:]
241                 cb(retval)
242                 self.runNext()
243
244 global_mcut_errors = [_("The movie \"%s\" is successfully cut"),
245                       _("Cutting failed for movie \"%s\"")+":\n"+_("Bad arguments"),
246                       _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .ts file"),
247                       _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .cuts file"),
248                       _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .ap file"),
249                       _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .ts file"),
250                       _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .cuts file"),
251                       _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .ap file"),
252                       _("Cutting failed for movie \"%s\"")+":\n"+_("Empty .ap file"),
253                       _("Cutting failed for movie \"%s\"")+":\n"+_("No cuts specified"),
254                       _("Cutting failed for movie \"%s\"")+":\n"+_("Read/write error (disk full?)"),
255                       _("Cutting was aborted for movie \"%s\"")]
256
257 global_mcut_queue = MovieCutQueue()
258
259 global_mcut_block = False
260
261 class MovieCutSpawn:
262         def __init__(self, session, parent, clist, name):
263                 global global_mcut_queue
264                 global global_mcut_block
265                 self.session = session
266                 self.parent = parent
267                 self.name = name
268                 self.clist = [clist[0]] + clist
269                 self.mess = ""
270                 self.dialog = False
271                 self.waitTimer = eTimer()
272                 self.waitTimer.callback.append(self.doWaitAck)
273                 if global_mcut_queue.enqueue(self.doAck, self.clist):
274                         mess = _("The movie \"%s\" is cut in the background.") % (self.name)
275                 else:
276                         mess = _("Another movie is currently cut.\nThe movie \"%s\" will be cut in the background after it.") % (self.name)
277                 global_mcut_block = True
278                 self.dialog = self.session.openWithCallback(self.endc, MessageBox, mess, MessageBox.TYPE_INFO)
279
280         def doAck(self, retval):
281                 global global_mcut_errors
282 #               if WIFEXITED(retval):
283 #                       self.mess = global_mcut_errors[WEXITSTATUS(retval)] % (self.name)
284 #               else:
285 #                       self.mess = global_mcut_errors[-1] % (self.name)
286                 self.mess = global_mcut_errors[retval] % (self.name)
287                 self.doWaitAck()
288
289         def doWaitAck(self):
290                 global global_mcut_block
291                 if Screens.Standby.inStandby or not self.session.in_exec or (global_mcut_block and not self.dialog):
292                         self.waitTimer.start(2000, True)
293                 else:
294                         global_mcut_block = True
295                         self.session.openWithCallback(self.endw, MessageBox, self.mess, MessageBox.TYPE_INFO)
296
297         def endw(self, arg = 0):
298                 global global_mcut_block
299                 global_mcut_block = False
300                 if self.session.current_dialog == self.dialog:
301                         self.session.current_dialog.close(True)
302                         self.endc(arg)
303
304         def endc(self, arg = 0):
305                 global global_mcut_block
306                 global_mcut_block = False
307                 self.dialog = False
308                 self.parent.close()
309 #               self.session.current_dialog.close()