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
7 from Components.config import config, ConfigText, ConfigSelection, ConfigNothing, getConfigListEntry
8 from Components.ActionMap import ActionMap
9 from Components.ConfigList import ConfigList, ConfigListScreen
10 from Components.Sources.StaticText import StaticText
11 from enigma import eTimer, eServiceCenter, iServiceInformation, eConsoleAppContainer
12 from os import access, chmod, X_OK
14 mcut_path = "/usr/lib/enigma2/python/Plugins/Extensions/MovieCut/bin/mcut"
16 def main(session, service, **kwargs):
17 # Hack to make sure it is executable
18 if not access(mcut_path, X_OK):
20 session.open(MovieCut, service, **kwargs)
22 def Plugins(**kwargs):
23 return PluginDescriptor(name="MovieCut", description=_("Execute cuts..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)
26 class MovieCut(ChoiceBox):
27 def __init__(self, session, service):
28 self.service = service
29 serviceHandler = eServiceCenter.getInstance()
30 path = self.service.getPath()
31 info = serviceHandler.info(self.service)
35 self.name = info.getName(self.service)
37 (_("Don't cut"), "CALLFUNC", self.confirmed0),
38 (_("Replace the original movie with the cut movie"), "CALLFUNC", self.confirmed1),
39 (_("Place the cut movie in a new file ending with \" cut\""), "CALLFUNC", self.confirmed2),
40 (_("Advanced cut specification..."), "CALLFUNC", self.confirmed3),
42 ChoiceBox.__init__(self, session, _("How would you like to cut \"%s\"?") % (self.name), list = tlist, selection = 0)
43 self.skinName = "ChoiceBox"
45 def confirmed0(self, arg):
48 def confirmed1(self, arg):
49 MovieCutSpawn(self.session, self, [mcut_path, "-r", self.service.getPath()], self.name)
51 def confirmed2(self, arg):
52 MovieCutSpawn(self.session, self, [mcut_path, self.service.getPath()], self.name)
54 def confirmed3(self, arg):
55 serviceHandler = eServiceCenter.getInstance()
56 info = serviceHandler.info(self.service)
57 path = self.service.getPath()
58 self.name = info.getName(self.service)
59 descr = info.getInfoString(self.service, iServiceInformation.sDescription)
60 self.session.openWithCallback(self.advcutConfirmed, AdvancedCutInput, self.name, path, descr)
62 def advcutConfirmed(self, ret):
63 if len(ret) <= 1 or not ret[0]:
69 clist.append(self.service.getPath())
71 clist += ["-o", ret[2]]
73 clist += ["-n", ret[3]]
75 clist += ["-d", ret[4]]
79 MovieCutSpawn(self.session, self, clist, self.name)
81 class AdvancedCutInput(Screen, ConfigListScreen):
82 def __init__(self, session, name, path, descr):
83 Screen.__init__(self, session)
84 self.skinName = [ "AdvancedCutInput", "Setup" ]
86 self["key_green"] = StaticText(_("OK"))
87 self["key_red"] = StaticText(_("Cancel"))
89 if self.baseName(path) == self.baseName(name):
93 dir = self.dirName(path)
94 file = self.baseName(path) + " cut"
95 self.input_replace = ConfigSelection(choices = [("no", _("No")), ("yes", _("Yes"))], default = "no")
96 self.input_file = ConfigText(default = file, fixed_size = False, visible_width = 45)
97 self.input_title = ConfigText(default = title, fixed_size = False, visible_width = 45)
98 self.input_descr = ConfigText(default = descr, fixed_size = False, visible_width = 45)
99 tmp = config.movielist.videodirs.value
102 self.input_dir = ConfigSelection(choices = tmp, default = dir)
103 self.input_manual = ConfigSelection(choices = [("no", _("Cutlist")), ("yes", _("Manual specification"))], default = "no")
104 self.input_space = ConfigNothing()
105 self.input_manualcuts = ConfigText(default = "", fixed_size = False)
106 self.input_manualcuts.setUseableChars(" 0123456789:.")
108 self["actions"] = ActionMap(["SetupActions"],
110 "ok": self.keySelectOrGo,
112 "cancel": self.keyCancel,
116 ConfigListScreen.__init__(self, self.list)
117 self.entry_replace = getConfigListEntry(_("Replace original:"), self.input_replace)
118 self.entry_file = getConfigListEntry(_("New filename:"), self.input_file)
119 self.entry_title = getConfigListEntry(_("New title:"), self.input_title)
120 self.entry_descr = getConfigListEntry(_("New description:"), self.input_descr)
121 self.entry_dir = getConfigListEntry(_("New location:"), self.input_dir)
122 self.entry_manual = getConfigListEntry(_("Cut source:"), self.input_manual)
123 self.entry_space = getConfigListEntry(_("Cuts (an IN OUT IN OUT ... sequence of hour:min:sec)"), self.input_space)
124 self.entry_manualcuts = getConfigListEntry(":", self.input_manualcuts)
125 self.createSetup(self["config"])
127 self.onLayoutFinish.append(self.layoutFinished)
129 def layoutFinished(self):
130 self.setTitle(_("Cut Parameter Input"))
132 def createSetup(self, configlist):
136 if self.input_replace.value == "no":
146 if self.input_manual.value == "yes":
149 self.entry_manualcuts,
152 configlist.list = list
153 configlist.l.setList(list)
156 ConfigListScreen.keyLeft(self)
157 cc = self["config"].getCurrent()
158 if cc is self.entry_replace or cc is self.entry_manual:
159 self.createSetup(self["config"])
162 ConfigListScreen.keyRight(self)
163 cc = self["config"].getCurrent()
164 if cc is self.entry_replace or cc is self.entry_manual:
165 self.createSetup(self["config"])
167 def pathSelected(self, res):
169 if config.movielist.videodirs.value != self.input_dir.choices:
170 self.input_dir.setChoices(config.movielist.videodirs.value, default=res)
171 self.input_dir.value = res
173 def keySelectOrGo(self):
174 if self["config"].getCurrent() == self.entry_dir:
175 self.session.openWithCallback(
178 _("Choose target folder"),
179 self.input_dir.value,
185 if self.input_replace.value == "yes":
188 path = self.rejoinName(self.input_dir.value, self.input_file.value)
189 if self.input_manual.value == "no":
192 cuts = self.input_manualcuts.value.split(' ')
195 self.close((True, self.input_replace.value, path, self.input_title.value, self.input_descr.value, cuts))
200 def baseName(self, str):
201 name = str.split('/')[-1]
202 if name.endswith(".ts") is True:
207 def dirName(self, str):
208 return '/'.join(str.split('/')[:-1]) + '/'
210 def rejoinName(self, dir, name):
212 if name.endswith(".ts") is True:
213 return dir + name[:-3]
219 self.container = eConsoleAppContainer()
220 self.container.appClosed.append(self.runDone)
224 def enqueue(self, cb, cmd):
225 self.queue.append((cb, cmd))
237 self.container.execute(*self.queue[0][1])
239 def runDone(self, retval):
240 cb = self.queue[0][0]
241 self.queue = self.queue[1:]
245 global_mcut_errors = [_("The movie \"%s\" is successfully cut"),
246 _("Cutting failed for movie \"%s\"")+":\n"+_("Bad arguments"),
247 _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .ts file"),
248 _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .cuts file"),
249 _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .ap file"),
250 _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .ts file"),
251 _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .cuts file"),
252 _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .ap file"),
253 _("Cutting failed for movie \"%s\"")+":\n"+_("Empty .ap file"),
254 _("Cutting failed for movie \"%s\"")+":\n"+_("No cuts specified"),
255 _("Cutting failed for movie \"%s\"")+":\n"+_("Read/write error (disk full?)"),
256 _("Cutting was aborted for movie \"%s\"")]
258 global_mcut_queue = MovieCutQueue()
260 global_mcut_block = False
263 def __init__(self, session, parent, clist, name):
264 global global_mcut_queue
265 global global_mcut_block
266 self.session = session
269 self.clist = [clist[0]] + clist
272 self.waitTimer = eTimer()
273 self.waitTimer.callback.append(self.doWaitAck)
274 if global_mcut_queue.enqueue(self.doAck, self.clist):
275 mess = _("The movie \"%s\" is cut in the background.") % (self.name)
277 mess = _("Another movie is currently cut.\nThe movie \"%s\" will be cut in the background after it.") % (self.name)
278 global_mcut_block = True
279 self.dialog = self.session.openWithCallback(self.endc, MessageBox, mess, MessageBox.TYPE_INFO)
281 def doAck(self, retval):
282 global global_mcut_errors
283 # if WIFEXITED(retval):
284 # self.mess = global_mcut_errors[WEXITSTATUS(retval)] % (self.name)
286 # self.mess = global_mcut_errors[-1] % (self.name)
287 self.mess = global_mcut_errors[retval] % (self.name)
291 global global_mcut_block
292 if Screens.Standby.inStandby or not self.session.in_exec or (global_mcut_block and not self.dialog):
293 self.waitTimer.start(2000, True)
295 global_mcut_block = True
296 self.session.openWithCallback(self.endw, MessageBox, self.mess, MessageBox.TYPE_INFO)
298 def endw(self, arg = 0):
299 global global_mcut_block
300 global_mcut_block = False
301 if self.session.current_dialog == self.dialog:
302 self.session.current_dialog.close(True)
305 def endc(self, arg = 0):
306 global global_mcut_block
307 global_mcut_block = False
310 # self.session.current_dialog.close()