1 from Plugins.Plugin import PluginDescriptor
2 from MyTubeService import GoogleSuggestions, validate_cert, get_rnd
3 from MyTubeSearch import ConfigTextWithGoogleSuggestions
4 from Tools.BoundFunction import boundFunction
5 from Screens.MessageBox import MessageBox
6 from Screens.Screen import Screen
7 from Screens.ChoiceBox import ChoiceBox
8 from Screens.InfoBar import MoviePlayer
9 from Screens.VirtualKeyBoard import VirtualKeyBoard
10 from Components.ActionMap import ActionMap, NumberActionMap
11 from Components.Label import Label
12 from Components.ScrollLabel import ScrollLabel
13 from Components.ProgressBar import ProgressBar
14 from Components.Pixmap import Pixmap
15 from Components.Button import Button
16 from Components.Sources.List import List
17 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
18 from Components.AVSwitch import AVSwitch
19 from Components.ActionMap import HelpableActionMap
20 from Components.config import config, Config, ConfigSelection, ConfigSubsection, ConfigText, getConfigListEntry, ConfigYesNo, ConfigIP, ConfigNumber,ConfigLocations
21 from Components.config import KEY_DELETE, KEY_BACKSPACE, KEY_LEFT, KEY_RIGHT, KEY_HOME, KEY_END, KEY_TOGGLEOW, KEY_ASCII, KEY_TIMEOUT
22 from Components.ConfigList import ConfigListScreen
23 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
24 from Components.Console import Console
25 from Components.Sources.Source import Source
26 from Components.Task import Task, Job, job_manager
28 from threading import Thread
29 from threading import Condition
31 from Tools.Directories import pathExists, fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE, SCOPE_HDD
32 from Tools.LoadPixmap import LoadPixmap
33 from Tools.Downloader import HTTPProgressDownloader, downloadWithProgress
34 from enigma import eTimer, quitMainloop,eListbox,ePoint, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_VALIGN_CENTER, eListboxPythonMultiContent, eListbox, gFont, getDesktop, ePicLoad, eServiceCenter, iServiceInformation, eServiceReference,iSeekableService,iServiceInformation, iPlayableService, iPlayableServicePtr
35 from os import path as os_path, system as os_system, unlink, stat, mkdir, popen, makedirs, listdir, access, rename, remove, W_OK, R_OK, F_OK
36 from twisted.web import client
37 from twisted.internet import reactor
40 from Screens.InfoBarGenerics import InfoBarShowHide, InfoBarSeek, InfoBarNotifications, InfoBarServiceNotifications
41 from enigma import eTPM
42 from __init__ import bin2long, long2bin, rsa_pub1024, decrypt_block
44 rootkey = ['\x9f', '|', '\xe4', 'G', '\xc9', '\xb4', '\xf4', '#', '&', '\xce', '\xb3', '\xfe', '\xda', '\xc9', 'U', '`', '\xd8', '\x8c', 's', 'o', '\x90', '\x9b', '\\', 'b', '\xc0', '\x89', '\xd1', '\x8c', '\x9e', 'J', 'T', '\xc5', 'X', '\xa1', '\xb8', '\x13', '5', 'E', '\x02', '\xc9', '\xb2', '\xe6', 't', '\x89', '\xde', '\xcd', '\x9d', '\x11', '\xdd', '\xc7', '\xf4', '\xe4', '\xe4', '\xbc', '\xdb', '\x9c', '\xea', '}', '\xad', '\xda', 't', 'r', '\x9b', '\xdc', '\xbc', '\x18', '3', '\xe7', '\xaf', '|', '\xae', '\x0c', '\xe3', '\xb5', '\x84', '\x8d', '\r', '\x8d', '\x9d', '2', '\xd0', '\xce', '\xd5', 'q', '\t', '\x84', 'c', '\xa8', ')', '\x99', '\xdc', '<', '"', 'x', '\xe8', '\x87', '\x8f', '\x02', ';', 'S', 'm', '\xd5', '\xf0', '\xa3', '_', '\xb7', 'T', '\t', '\xde', '\xa7', '\xf1', '\xc9', '\xae', '\x8a', '\xd7', '\xd2', '\xcf', '\xb2', '.', '\x13', '\xfb', '\xac', 'j', '\xdf', '\xb1', '\x1d', ':', '?']
46 config.plugins.mytube = ConfigSubsection()
47 config.plugins.mytube.search = ConfigSubsection()
49 config.plugins.mytube.search.searchTerm = ConfigTextWithGoogleSuggestions("", False, threaded = True)
50 config.plugins.mytube.search.orderBy = ConfigSelection(
52 ("relevance", _("Relevance")),
53 ("viewCount", _("View Count")),
54 ("published", _("Published")),
55 ("rating", _("Rating"))
57 config.plugins.mytube.search.time = ConfigSelection(
59 ("all_time", _("All Time")),
60 ("this_month", _("This Month")),
61 ("this_week", _("This Week")),
64 config.plugins.mytube.search.racy = ConfigSelection(
66 ("include", _("Yes")),
69 config.plugins.mytube.search.categories = ConfigSelection(
72 ("Film", _("Film & Animation")),
73 ("Autos", _("Autos & Vehicles")),
74 ("Music", _("Music")),
75 ("Animals", _("Pets & Animals")),
76 ("Sports", _("Sports")),
77 ("Travel", _("Travel & Events")),
78 ("Shortmov", _("Short Movies")),
79 ("Games", _("Gaming")),
80 ("Comedy", _("Comedy")),
81 ("People", _("People & Blogs")),
82 ("News", _("News & Politics")),
83 ("Entertainment", _("Entertainment")),
84 ("Education", _("Education")),
85 ("Howto", _("Howto & Style")),
86 ("Nonprofit", _("Nonprofits & Activism")),
87 ("Tech", _("Science & Technology"))
89 config.plugins.mytube.search.lr = ConfigSelection(
92 ("au", _("Australia")),
95 ("cz", _("Czech Republic")),
98 ("gb", _("Great Britain")),
99 ("au", _("Australia")),
100 ("nl", _("Holland")),
101 ("hk", _("Hong Kong")),
103 ("ie", _("Ireland")),
108 ("nz", _("New Zealand")),
111 ("kr", _("South Korea")),
115 ("us", _("United States"))
117 config.plugins.mytube.search.sortOrder = ConfigSelection(
119 ("ascending", _("Ascending")),
120 ("descending", _("Descending"))
123 config.plugins.mytube.general = ConfigSubsection()
124 config.plugins.mytube.general.showHelpOnOpen = ConfigYesNo(default = True)
125 config.plugins.mytube.general.loadFeedOnOpen = ConfigYesNo(default = True)
126 config.plugins.mytube.general.startFeed = ConfigSelection(
128 ("hd", _("HD videos")),
129 ("most_viewed", _("Most viewed")),
130 ("top_rated", _("Top rated")),
131 ("recently_featured", _("Recently featured")),
132 ("most_discussed", _("Most discussed")),
133 ("top_favorites", _("Top favorites")),
134 ("most_linked", _("Most linked")),
135 ("most_responded", _("Most responded")),
136 ("most_recent", _("Most recent"))
138 config.plugins.mytube.general.on_movie_stop = ConfigSelection(default = "ask", choices = [
139 ("ask", _("Ask user")), ("quit", _("Return to movie list")), ("playnext", _("Play next video")), ("playagain", _("Play video again")) ])
141 config.plugins.mytube.general.on_exit = ConfigSelection(default = "ask", choices = [
142 ("ask", _("Ask user")), ("quit", _("Return to movie list"))])
144 default = resolveFilename(SCOPE_HDD)
145 tmp = config.movielist.videodirs.value
146 if default not in tmp:
148 config.plugins.mytube.general.videodir = ConfigSelection(default = default, choices = tmp)
149 config.plugins.mytube.general.history = ConfigText(default="")
150 config.plugins.mytube.general.clearHistoryOnClose = ConfigYesNo(default = False)
151 #config.plugins.mytube.general.useHTTPProxy = ConfigYesNo(default = False)
152 #config.plugins.mytube.general.ProxyIP = ConfigIP(default=[0,0,0,0])
153 #config.plugins.mytube.general.ProxyPort = ConfigNumber(default=8080)
155 class downloadJob(Job):
156 def __init__(self, url, file, title):
157 Job.__init__(self, title)
158 downloadTask(self, url, file)
160 class downloadTask(Task):
161 def __init__(self, job, url, file):
162 Task.__init__(self, job, ("download task"))
170 def run(self, callback):
171 self.callback = callback
172 self.download = downloadWithProgress(self.url,self.local)
173 self.download.addProgress(self.http_progress)
174 self.download.start().addCallback(self.http_finished).addErrback(self.http_failed)
176 def http_progress(self, recvbytes, totalbytes):
177 #print "[http_progress] recvbytes=%d, totalbytes=%d" % (recvbytes, totalbytes)
178 self.progress = int(self.end*recvbytes/float(totalbytes))
180 def http_finished(self, string=""):
181 print "[http_finished]" + str(string)
182 Task.processFinished(self, 0)
184 def http_failed(self, failure_instance=None, error_message=""):
185 if error_message == "" and failure_instance is not None:
186 error_message = failure_instance.getErrorMessage()
187 print "[http_failed] " + error_message
188 Task.processFinished(self, 1)
192 from MyTubeService import myTubeService
193 from MyTubeSearch import MyTubeSettingsScreen,MyTubeTasksScreen,MyTubeHistoryScreen
196 class MyTubePlayerMainScreen(Screen, ConfigListScreen):
197 BASE_STD_FEEDURL = "http://gdata.youtube.com/feeds/api/standardfeeds/"
199 #(entry, Title, Description, TubeID, thumbnail, PublishedDate,Views,duration,ratings )
201 <screen name="MyTubePlayerMainScreen" flags="wfNoBorder" position="0,0" size="720,576" title="MyTubePlayerMainScreen..." >
202 <ePixmap position="0,0" zPosition="-1" size="720,576" pixmap="~/mytubemain_bg.png" alphatest="on" transparent="1" backgroundColor="transparent"/>
203 <widget name="config" zPosition="2" position="60,60" size="600,50" scrollbarMode="showNever" transparent="1" />
204 <widget source="feedlist" render="Listbox" position="49,110" size="628,385" zPosition="1" scrollbarMode="showOnDemand" transparent="1" backgroundPixmap="~/list_bg.png" selectionPixmap="~/list_sel.png" >
205 <convert type="TemplatedMultiContent">
208 MultiContentEntryPixmapAlphaTest(pos = (0, 0), size = (100, 75), png = 4), # index 4 is the thumbnail
209 MultiContentEntryText(pos = (100, 1), size = (500, 22), font=0, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 1), # index 1 is the Title
210 MultiContentEntryText(pos = (100, 24), size = (300, 18), font=1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 5), # index 5 is the Published Date
211 MultiContentEntryText(pos = (100, 43), size = (300, 18), font=1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 6), # index 6 is the Views Count
212 MultiContentEntryText(pos = (400, 24), size = (200, 18), font=1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 7), # index 7 is the duration
213 MultiContentEntryText(pos = (400, 43), size = (200, 18), font=1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 8), # index 8 is the ratingcount
216 MultiContentEntryText(pos = (10, 1), size = (560, 28), font=2, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 0), # index 0 is the name
217 MultiContentEntryText(pos = (10, 22), size = (560, 46), font=3, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 1), # index 2 is the description
220 "fonts": [gFont("Regular", 22),gFont("Regular", 18),gFont("Regular", 26),gFont("Regular", 20)],
226 <ePixmap pixmap="skin_default/buttons/key_info.png" position="50,500" zPosition="4" size="35,25" alphatest="on" transparent="1" />
227 <ePixmap pixmap="skin_default/buttons/key_menu.png" position="50,520" zPosition="4" size="35,25" alphatest="on" transparent="1" />
228 <ePixmap position="90,500" size="100,40" zPosition="4" pixmap="~/plugin.png" alphatest="on" transparent="1" />
229 <ePixmap position="190,500" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
230 <ePixmap position="330,500" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
231 <ePixmap position="470,500" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
232 <widget name="key_red" position="190,500" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
233 <widget name="key_green" position="330,500" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
234 <widget name="key_yellow" position="470,500" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
235 <widget name="ButtonBlue" pixmap="skin_default/buttons/button_blue.png" position="610,510" zPosition="10" size="15,16" transparent="1" alphatest="on" />
236 <widget name="VKeyIcon" pixmap="skin_default/vkey_icon.png" position="620,495" zPosition="10" size="60,48" transparent="1" alphatest="on" />
237 <widget name="thumbnail" position="0,0" size="100,75" alphatest="on"/> # fake entry for dynamic thumbnail resizing, currently there is no other way doing this.
238 <widget name="HelpWindow" position="160,255" zPosition="1" size="1,1" transparent="1" alphatest="on" />
241 def __init__(self, session, l2key):
242 Screen.__init__(self, session)
243 self.session = session
246 self.skin_path = plugin_path
249 self.currentFeedName = None
252 self.video_playlist = []
254 self.mytubeentries = None
260 self.screenshotList = []
261 self.pixmaps_to_load = []
264 self.oldfeedentrycount = 0
265 self.appendEntries = False
266 self.lastservice = session.nav.getCurrentlyPlayingServiceReference()
267 self.propagateUpDownNormally = True
269 self.HistoryWindow = None
271 self.searchtext = _("Welcome to the MyTube Youtube Player.\n\nWhile entering your search term(s) you will get suggestions displayed matching your search term.\n\nTo select a suggestion press DOWN on your remote, select the desired result and press OK on your remote to start the search.\n\nPress exit to get back to the input field.")
272 self.feedtext = _("Welcome to the MyTube Youtube Player.\n\nUse the Bouqet+ button to navigate to the search field and the Bouqet- to navigate to the video entries.\n\nTo play a movie just press OK on your remote control.\n\nPress info to see the movie description.\n\nPress the Menu button for additional options.\n\nThe Help button shows this help again.")
273 self.currList = "configlist"
276 self["feedlist"] = List(self.videolist)
277 self["thumbnail"] = Pixmap()
278 self["thumbnail"].hide()
279 self["HelpWindow"] = Pixmap()
280 self["HelpWindow"].hide()
281 self["key_red"] = Button(_("Close"))
282 self["key_green"] = Button(_("Std. Feeds"))
283 self["key_yellow"] = Button(_("History"))
284 self["ButtonBlue"] = Pixmap()
285 self["VKeyIcon"] = Pixmap()
286 self["ButtonBlue"].hide()
287 self["VKeyIcon"].hide()
289 self["searchactions"] = ActionMap(["ShortcutActions", "WizardActions", "HelpActions", "MediaPlayerActions"],
292 "back": self.leavePlayer,
293 "red": self.leavePlayer,
294 "blue": self.openKeyboard,
295 "yellow": self.handleHistory,
297 "down": self.handleSuggestions,
298 "left": self.keyLeft,
299 "right": self.keyRight,
300 "prevBouquet": self.switchToFeedList,
301 "nextBouquet": self.switchToConfigList,
302 "displayHelp": self.handleHelpWindow,
303 "menu" : self.handleMenu,
306 self["suggestionactions"] = ActionMap(["ShortcutActions", "WizardActions", "MediaPlayerActions", "HelpActions"],
309 "back": self.switchToConfigList,
310 "red": self.switchToConfigList,
311 "nextBouquet": self.switchToConfigList,
312 "prevBouquet": self.switchToFeedList,
314 "down": self.keyDown,
315 "left": self.keyLeft,
316 "right": self.keyRight,
320 self["videoactions"] = ActionMap(["ShortcutActions", "WizardActions", "MediaPlayerActions", "MovieSelectionActions", "HelpActions"],
323 "back": self.leavePlayer,
324 "red": self.leavePlayer,
325 "yellow": self.handleHistory,
327 "down": self.keyDown,
328 "nextBouquet": self.switchToConfigList,
329 "green": self.keyStdFeed,
330 "showEventInfo": self.showVideoInfo,
331 "displayHelp": self.handleHelpWindow,
332 "menu" : self.handleMenu,
335 self["statusactions"] = ActionMap(["ShortcutActions", "WizardActions", "HelpActions", "MediaPlayerActions"],
337 "back": self.leavePlayer,
338 "red": self.leavePlayer,
339 "nextBouquet": self.switchToConfigList,
340 "green": self.keyStdFeed,
341 "yellow": self.handleHistory,
344 self["historyactions"] = ActionMap(["ShortcutActions", "WizardActions", "MediaPlayerActions", "MovieSelectionActions", "HelpActions"],
347 "back": self.closeHistory,
348 "red": self.closeHistory,
349 "yellow": self.handleHistory,
351 "down": self.keyDown,
352 "left": self.keyLeft,
353 "right": self.keyRight,
356 self["videoactions"].setEnabled(False)
357 self["statusactions"].setEnabled(False)
358 self["historyactions"].setEnabled(False)
360 self.timer_startDownload = eTimer()
361 self.timer_startDownload.timeout.callback.append(self.downloadThumbnails)
362 self.timer_thumbnails = eTimer()
363 self.timer_thumbnails.timeout.callback.append(self.updateFeedThumbnails)
365 self.SearchConfigEntry = None
366 self.searchContextEntries = []
367 config.plugins.mytube.search.searchTerm.value = ""
368 ConfigListScreen.__init__(self, self.searchContextEntries, session)
370 self.onLayoutFinish.append(self.layoutFinished)
371 self.onShown.append(self.setWindowTitle)
372 self.onClose.append(self.__onClose)
373 self.Timer = eTimer()
374 self.Timer.callback.append(self.TimerFire)
378 del self.timer_startDownload
379 del self.timer_thumbnails
381 self.session.nav.playService(self.lastservice)
383 def layoutFinished(self):
384 self.currList = "status"
385 current = self["config"].getCurrent()
386 if current[1].help_window.instance is not None:
387 current[1].help_window.instance.hide()
389 l3cert = etpm.getCert(eTPM.TPMD_DT_LEVEL3_CERT)
390 if l3cert is None or l3cert is "":
391 self["videoactions"].setEnabled(False)
392 self["searchactions"].setEnabled(False)
393 self["config_actions"].setEnabled(False)
394 self["historyactions"].setEnabled(False)
395 self["statusactions"].setEnabled(True)
396 self.hideSuggestions()
398 self.statuslist.append(( _("Genuine Dreambox validation failed!"), _("Verify your Dreambox authenticity by running the genuine dreambox plugin!" ) ))
399 self["feedlist"].style = "state"
400 self['feedlist'].setList(self.statuslist)
403 self.l3key = validate_cert(l3cert, self.l2key)
404 if self.l3key is None:
405 print "l3cert invalid"
412 val = etpm.challenge(rnd)
413 result = decrypt_block(val, self.l3key)
416 if result[80:88] == rnd:
417 self.statuslist.append(( _("Fetching feed entries"), _("Trying to download the Youtube feed entries. Please wait..." ) ))
418 self["feedlist"].style = "state"
419 self['feedlist'].setList(self.statuslist)
420 self.Timer.start(200)
422 self.statuslist.append(( _("Genuine Dreambox validation failed!"), _("Verify your Dreambox authenticity by running the genuine dreambox plugin!" ) ))
423 self["feedlist"].style = "state"
424 self['feedlist'].setList(self.statuslist)
428 if config.plugins.mytube.general.loadFeedOnOpen.value:
429 self.setState('getFeed')
431 self.setState('byPass')
433 def setWindowTitle(self):
434 self.setTitle(_("MyTubePlayer"))
436 def createSetup(self):
437 self.searchContextEntries = []
438 self.SearchConfigEntry = getConfigListEntry(_("Search Term(s)"), config.plugins.mytube.search.searchTerm)
439 self.searchContextEntries.append(self.SearchConfigEntry)
440 self["config"].list = self.searchContextEntries
441 self["config"].l.setList(self.searchContextEntries)
443 def setState(self,status = None):
445 self.currList = "status"
446 self["videoactions"].setEnabled(False)
447 self["searchactions"].setEnabled(False)
448 self["config_actions"].setEnabled(False)
449 self["historyactions"].setEnabled(False)
450 self["statusactions"].setEnabled(True)
451 self["ButtonBlue"].hide()
452 self["VKeyIcon"].hide()
454 self.hideSuggestions()
456 if self.l3key is not None:
460 val = etpm.challenge(rnd)
461 result = decrypt_block(val, self.l3key)
462 if not result or result[80:88] != rnd:
463 self["key_green"].show()
464 self.statuslist.append(( _("Genuine Dreambox validation failed!"), _("Verify your Dreambox authenticity by running the genuine dreambox plugin!" ) ))
465 self["feedlist"].style = "state"
466 self['feedlist'].setList(self.statuslist)
468 print "Genuine Dreambox validation passed"
469 if self.FirstRun == True:
470 self.appendEntries = False
471 myTubeService.startService()
472 if self.HistoryWindow is not None:
473 self.HistoryWindow.deactivate()
474 self.HistoryWindow.instance.hide()
475 if status == 'getFeed':
476 self.statuslist.append(( _("Fetching feed entries"), _("Trying to download the Youtube feed entries. Please wait..." ) ))
477 elif status == 'getSearchFeed':
478 self.statuslist.append(( _("Fetching search entries"), _("Trying to download the Youtube search results. Please wait..." ) ))
479 elif status == 'Error':
480 self.statuslist.append(( _("An error occured."), _("There was an error getting the feed entries. Please try again." ) ))
481 elif status == 'noVideos':
482 self["key_green"].show()
483 self.statuslist.append(( _("No videos to display"), _("Please select a standard feed or try searching for videos." ) ))
484 elif status == 'byPass':
485 self.statuslist.append(( _("Not fetching feed entries"), _("Please enter your search term." ) ))
486 self["feedlist"].style = "state"
487 self['feedlist'].setList(self.statuslist)
488 self.switchToConfigList()
489 self["feedlist"].style = "state"
490 self['feedlist'].setList(self.statuslist)
491 if self.FirstRun == True:
492 if config.plugins.mytube.general.loadFeedOnOpen.value:
493 if config.plugins.mytube.general.startFeed.value == 'hd':
494 self.FeedURL = "http://gdata.youtube.com/feeds/api/videos/-/HD"
496 self.FeedURL = self.BASE_STD_FEEDURL + str(config.plugins.mytube.general.startFeed.value)
497 self.getFeed(self.FeedURL, str(config.plugins.mytube.general.startFeed.value))
500 def handleHelpWindow(self):
501 print "[handleHelpWindow]"
502 if self.currList == "configlist":
503 self.hideSuggestions()
504 self.session.openWithCallback(self.ScreenClosed, MyTubeVideoHelpScreen, self.skin_path, wantedinfo = self.searchtext, wantedtitle = _("MyTubePlayer Help") )
505 elif self.currList == "feedlist":
506 self.session.openWithCallback(self.ScreenClosed, MyTubeVideoHelpScreen, self.skin_path, wantedinfo = self.feedtext, wantedtitle = _("MyTubePlayer Help") )
508 def handleFirstHelpWindow(self):
509 print "[handleFirstHelpWindow]"
510 if config.plugins.mytube.general.showHelpOnOpen.value is True:
511 if self.currList == "configlist":
512 self.hideSuggestions()
513 self.session.openWithCallback(self.firstRunHelpClosed, MyTubeVideoHelpScreen, self.skin_path,wantedinfo = self.feedtext, wantedtitle = _("MyTubePlayer Help") )
515 self.FirstRun = False
517 def firstRunHelpClosed(self):
518 if self.FirstRun == True:
519 self.FirstRun = False
520 self.switchToConfigList()
522 def handleMenu(self):
523 if self.currList == "configlist":
525 (_("MyTube Settings"), "settings"),
527 self.hideSuggestions()
528 self.session.openWithCallback(self.openMenu, ChoiceBox, title=_("Select your choice."), list = menulist)
530 elif self.currList == "feedlist":
531 menulist = [(_("MyTube Settings"), "settings")]
533 (_("View related videos"), "related"),
534 (_("View response videos"), "response")
536 if config.usage.setup_level.index >= 2: # expert+
538 (_("Download Video"), "download"),
539 (_("View active downloads"), "downview")
542 self.hideSuggestions()
543 self.session.openWithCallback(self.openMenu, ChoiceBox, title=_("Select your choice."), list = menulist)
545 def openMenu(self, answer):
546 answer = answer and answer[1]
547 if answer == "settings":
548 print "settings selected"
549 self.session.openWithCallback(self.ScreenClosed,MyTubeSettingsScreen, self.skin_path )
550 elif answer == "related":
551 current = self["feedlist"].getCurrent()[0]
552 self.setState('getFeed')
553 self.getRelatedVideos(current)
554 elif answer == "response":
555 current = self["feedlist"].getCurrent()[0]
556 self.setState('getFeed')
557 self.getResponseVideos(current)
558 elif answer == "download":
559 if self.currList == "feedlist":
560 current = self[self.currList].getCurrent()
564 myurl = myentry.getVideoUrl()
565 filename = str(config.plugins.mytube.general.videodir.value)+ str(myentry.getTitle()) + '.mp4'
566 job_manager.AddJob(downloadJob(myurl,filename, str(myentry.getTitle())[:30]))
567 elif answer == "downview":
569 for job in job_manager.getPendingJobs():
570 self.tasklist.append((job,job.name,job.getStatustext(),int(100*job.progress/float(job.end)) ,str(100*job.progress/float(job.end)) + "%" ))
571 self.session.open(MyTubeTasksScreen, self.skin_path , self.tasklist)
575 def openKeyboard(self):
576 self.hideSuggestions()
577 self.session.openWithCallback(self.SearchEntryCallback, VirtualKeyBoard, title = (_("Enter your search term(s)")), text = config.plugins.mytube.search.searchTerm.value)
579 def ScreenClosed(self):
580 print "ScreenCLosed, restoring old window state"
581 if self.currList == "historylist":
582 if self.HistoryWindow.status() is False:
583 self.HistoryWindow.activate()
584 self.HistoryWindow.instance.show()
585 elif self.currList == "configlist":
586 self.switchToConfigList()
587 ConfigListScreen.keyOK(self)
588 elif self.currList == "feedlist":
589 self.switchToFeedList()
591 def SearchEntryCallback(self, callback = None):
592 if callback is not None and len(callback):
593 config.plugins.mytube.search.searchTerm.value = callback
594 ConfigListScreen.keyOK(self)
595 self["config"].getCurrent()[1].getSuggestions()
596 current = self["config"].getCurrent()
597 if current[1].help_window.instance is not None:
598 current[1].help_window.instance.show()
599 if current[1].suggestionsWindow.instance is not None:
600 current[1].suggestionsWindow.instance.show()
601 self.propagateUpDownNormally = True
603 def openStandardFeedClosed(self, answer):
604 answer = answer and answer[1]
605 if answer is not None:
607 self.FeedURL = "http://gdata.youtube.com/feeds/api/videos/-/HD"
609 self.FeedURL = self.BASE_STD_FEEDURL + str(answer)
610 self.setState('getFeed')
611 self.appendEntries = False
612 self.getFeed(self.FeedURL, str(answer))
614 def handleLeave(self, how):
615 self.is_closing = True
617 if self.currList == "configlist":
620 (_("No"), "continue"),
621 (_("No, but switch to video entries."), "switch2feed")
626 (_("No"), "continue"),
627 (_("No, but switch to video search."), "switch2search")
629 self.session.openWithCallback(self.leavePlayerConfirmed, ChoiceBox, title=_("Really quit MyTube Player?"), list = list)
631 self.leavePlayerConfirmed([True, how])
633 def leavePlayer(self):
635 if self.HistoryWindow is not None:
636 self.HistoryWindow.deactivate()
637 self.HistoryWindow.instance.hide()
638 if self.currList == "configlist":
639 current = self["config"].getCurrent()
640 if current[1].suggestionsWindow.activeState is True:
641 self.propagateUpDownNormally = True
642 current[1].deactivateSuggestionList()
643 self["config"].invalidateCurrent()
645 self.hideSuggestions()
646 self.handleLeave(config.plugins.mytube.general.on_exit.value)
648 self.hideSuggestions()
649 self.handleLeave(config.plugins.mytube.general.on_exit.value)
651 def leavePlayerConfirmed(self, answer):
652 answer = answer and answer[1]
655 elif answer == "continue":
656 if self.currList == "historylist":
657 if self.HistoryWindow.status() is False:
658 self.HistoryWindow.activate()
659 self.HistoryWindow.instance.show()
660 elif self.currList == "configlist":
661 self.switchToConfigList()
662 elif self.currList == "feedlist":
663 self.switchToFeedList()
664 elif answer == "switch2feed":
665 self.switchToFeedList()
666 elif answer == "switch2search":
667 self.switchToConfigList()
669 if self.currList == "historylist":
670 if self.HistoryWindow.status() is False:
671 self.HistoryWindow.activate()
672 self.HistoryWindow.instance.show()
673 elif self.currList == "configlist":
674 self.switchToConfigList()
675 elif self.currList == "feedlist":
676 self.switchToFeedList()
679 if self["config"].getCurrent()[1].suggestionsWindow is not None:
680 self.session.deleteDialog(self["config"].getCurrent()[1].suggestionsWindow)
681 if self.HistoryWindow is not None:
682 self.session.deleteDialog(self.HistoryWindow)
683 if config.plugins.mytube.general.showHelpOnOpen.value is True:
684 config.plugins.mytube.general.showHelpOnOpen.value = False
685 config.plugins.mytube.general.showHelpOnOpen.save()
686 if not config.plugins.mytube.general.clearHistoryOnClose.value:
687 if self.History and len(self.History):
688 config.plugins.mytube.general.history.value = ",".join(self.History)
690 config.plugins.mytube.general.history.value = ""
691 config.plugins.mytube.general.history.save()
692 config.plugins.mytube.general.save()
693 config.plugins.mytube.save()
697 print "self.currList im KeyOK",self.currList
698 if self.currList == "configlist" or self.currList == "suggestionslist":
699 self["config"].invalidateCurrent()
700 if config.plugins.mytube.search.searchTerm.value != "":
702 searchContext = config.plugins.mytube.search.searchTerm.value
703 print "Search searchcontext",searchContext
704 if isinstance(self["config"].getCurrent()[1], ConfigTextWithGoogleSuggestions) and not self.propagateUpDownNormally:
705 self.propagateUpDownNormally = True
706 self["config"].getCurrent()[1].deactivateSuggestionList()
707 self.setState('getSearchFeed')
708 self.runSearch(searchContext)
709 elif self.currList == "feedlist":
710 current = self[self.currList].getCurrent()
714 if myentry is not None:
715 myurl = myentry.getVideoUrl()
716 print "Playing URL",myurl
717 if myurl is not None:
718 myreference = eServiceReference(4097,0,myurl)
719 myreference.setName(myentry.getTitle())
720 self.session.open(MyTubePlayer, myreference, self.lastservice, infoCallback = self.showVideoInfo, nextCallback = self.getNextEntry, prevCallback = self.getPrevEntry )
722 self.session.open(MessageBox, _("Sorry, video is not available!"), MessageBox.TYPE_INFO)
723 elif self.currList == "historylist":
724 if self.HistoryWindow is not None:
725 config.plugins.mytube.search.searchTerm.value = self.HistoryWindow.getSelection()
726 self["config"].invalidateCurrent()
727 if config.plugins.mytube.search.searchTerm.value != "":
728 searchContext = config.plugins.mytube.search.searchTerm.value
729 print "Search searchcontext",searchContext
730 self.setState('getSearchFeed')
731 self.runSearch(searchContext)
734 print "self.currList im KeyUp",self.currList
735 if self.currList == "suggestionslist":
736 if config.plugins.mytube.search.searchTerm.value != "":
737 if not self.propagateUpDownNormally:
738 self["config"].getCurrent()[1].suggestionListUp()
739 self["config"].invalidateCurrent()
740 elif self.currList == "feedlist":
741 self[self.currList].selectPrevious()
742 elif self.currList == "historylist":
743 if self.HistoryWindow is not None and self.HistoryWindow.shown:
744 self.HistoryWindow.up()
747 print "self.currList im KeyDown",self.currList
748 if self.currList == "suggestionslist":
749 if config.plugins.mytube.search.searchTerm.value != "":
750 if not self.propagateUpDownNormally:
751 self["config"].getCurrent()[1].suggestionListDown()
752 self["config"].invalidateCurrent()
753 elif self.currList == "feedlist":
754 print self[self.currList].count()
755 print self[self.currList].index
756 if self[self.currList].index == self[self.currList].count()-1 and myTubeService.getNextFeedEntriesURL() is not None:
757 self.session.openWithCallback(self.getNextEntries, MessageBox, _("Do you want to see more entries?"))
759 self[self.currList].selectNext()
760 elif self.currList == "historylist":
761 if self.HistoryWindow is not None and self.HistoryWindow.shown:
762 self.HistoryWindow.down()
764 print "self.currList im KeyRight",self.currList
765 if self.propagateUpDownNormally:
766 ConfigListScreen.keyRight(self)
768 if self.currList == "suggestionslist":
769 if config.plugins.mytube.search.searchTerm.value != "":
770 self["config"].getCurrent()[1].suggestionListPageDown()
771 self["config"].invalidateCurrent()
772 elif self.currList == "historylist":
773 if self.HistoryWindow is not None and self.HistoryWindow.shown:
774 self.HistoryWindow.pageDown()
777 print "self.currList im kEyLeft",self.currList
778 if self.propagateUpDownNormally:
779 ConfigListScreen.keyLeft(self)
781 if self.currList == "suggestionslist":
782 if config.plugins.mytube.search.searchTerm.value != "":
783 self["config"].getCurrent()[1].suggestionListPageUp()
784 self["config"].invalidateCurrent()
785 elif self.currList == "historylist":
786 if self.HistoryWindow is not None and self.HistoryWindow.shown:
787 self.HistoryWindow.pageDown()
788 def keyStdFeed(self):
789 self.hideSuggestions()
790 menulist = [(_("HD videos"), "hd")]
792 (_("Top rated"), "top_rated"),
793 (_("Top favorites"), "top_favorites"),
794 (_("Most viewed"), "most_viewed"),
795 (_("Most popular"), "most_popular"),
796 (_("Most recent"), "most_recent"),
797 (_("Most discussed"), "most_discussed"),
798 (_("Most linked"), "most_linked"),
799 (_("Recently featured"), "recently_featured"),
800 (_("Most responded"), "most_responded")
802 self.session.openWithCallback(self.openStandardFeedClosed, ChoiceBox, title=_("Select new feed to view."), list = menulist)
804 def handleSuggestions(self):
805 print "handleSuggestions"
806 print "self.currList",self.currList
807 if self.currList == "configlist":
808 self.switchToSuggestionsList()
809 elif self.currList == "historylist":
810 if self.HistoryWindow is not None and self.HistoryWindow.shown:
811 self.HistoryWindow.down()
813 def switchToSuggestionsList(self):
814 print "switchToSuggestionsList"
815 self.currList = "suggestionslist"
816 self["ButtonBlue"].hide()
817 self["VKeyIcon"].hide()
818 self["statusactions"].setEnabled(False)
819 self["config_actions"].setEnabled(False)
820 self["videoactions"].setEnabled(False)
821 self["searchactions"].setEnabled(False)
822 self["suggestionactions"].setEnabled(True)
823 self["historyactions"].setEnabled(False)
824 self["key_green"].hide()
825 self.propagateUpDownNormally = False
826 self["config"].invalidateCurrent()
827 if self.HistoryWindow is not None and self.HistoryWindow.shown:
828 self.HistoryWindow.deactivate()
829 self.HistoryWindow.instance.hide()
831 def switchToConfigList(self):
832 print "switchToConfigList"
833 self.currList = "configlist"
834 self["config_actions"].setEnabled(True)
835 self["historyactions"].setEnabled(False)
836 self["statusactions"].setEnabled(False)
837 self["videoactions"].setEnabled(False)
838 self["suggestionactions"].setEnabled(False)
839 self["searchactions"].setEnabled(True)
840 self["key_green"].hide()
841 self["ButtonBlue"].show()
842 self["VKeyIcon"].show()
843 self["config"].invalidateCurrent()
844 helpwindowpos = self["HelpWindow"].getPosition()
845 current = self["config"].getCurrent()
846 if current[1].help_window.instance is not None:
847 current[1].help_window.instance.move(ePoint(helpwindowpos[0],helpwindowpos[1]))
848 current[1].help_window.instance.show()
849 if current[1].suggestionsWindow.instance is not None:
850 current[1].suggestionsWindow.instance.show()
851 self["config"].getCurrent()[1].getSuggestions()
852 self.propagateUpDownNormally = True
853 if self.HistoryWindow is not None and self.HistoryWindow.shown:
854 self.HistoryWindow.deactivate()
855 self.HistoryWindow.instance.hide()
856 if self.FirstRun == True:
857 self.handleFirstHelpWindow()
859 def switchToFeedList(self, append = False):
860 print "switchToFeedList"
861 print "switching to feedlist from:",self.currList
862 print "len(self.videolist):",len(self.videolist)
863 if self.HistoryWindow is not None and self.HistoryWindow.shown:
864 self.HistoryWindow.deactivate()
865 self.HistoryWindow.instance.hide()
866 self.hideSuggestions()
867 if len(self.videolist):
868 self.currList = "feedlist"
869 self["ButtonBlue"].hide()
870 self["VKeyIcon"].hide()
871 self["videoactions"].setEnabled(True)
872 self["suggestionactions"].setEnabled(False)
873 self["searchactions"].setEnabled(False)
874 self["statusactions"].setEnabled(False)
875 self["historyactions"].setEnabled(False)
876 self["key_green"].show()
877 self["config_actions"].setEnabled(False)
879 self[self.currList].setIndex(0)
880 self["feedlist"].updateList(self.videolist)
882 self.setState('noVideos')
885 def switchToHistory(self):
886 print "switchToHistory"
887 self.oldlist = self.currList
888 self.currList = "historylist"
889 print "switchToHistory currentlist",self.currList
890 print "switchToHistory oldlist",self.oldlist
891 self.hideSuggestions()
892 self["ButtonBlue"].hide()
893 self["VKeyIcon"].hide()
894 self["key_green"].hide()
895 self["videoactions"].setEnabled(False)
896 self["suggestionactions"].setEnabled(False)
897 self["searchactions"].setEnabled(False)
898 self["statusactions"].setEnabled(False)
899 self["config_actions"].setEnabled(False)
900 self["historyactions"].setEnabled(True)
901 self.HistoryWindow.activate()
902 self.HistoryWindow.instance.show()
904 def handleHistory(self):
905 if self.HistoryWindow is None:
906 self.HistoryWindow = self.session.instantiateDialog(MyTubeHistoryScreen)
907 if self.currList in ("configlist","feedlist"):
908 if self.HistoryWindow.status() is False:
909 print "status is FALSE,switchToHistory"
910 self.switchToHistory()
911 elif self.currList == "historylist":
914 def closeHistory(self):
915 print "closeHistory currentlist",self.currList
916 print "closeHistory oldlist",self.oldlist
917 if self.currList == "historylist":
918 if self.HistoryWindow.status() is True:
919 print "status is TRUE, closing historyscreen"
920 self.HistoryWindow.deactivate()
921 self.HistoryWindow.instance.hide()
922 if self.oldlist == "configlist":
923 self.switchToConfigList()
924 elif self.oldlist == "feedlist":
925 self.switchToFeedList()
927 def add2History(self):
928 if self.History is None:
929 self.History = config.plugins.mytube.general.history.value.split(',')
930 if self.History[0] == '':
932 print "self.History im add",self.History
933 if config.plugins.mytube.search.searchTerm.value in self.History:
934 self.History.remove((config.plugins.mytube.search.searchTerm.value))
935 self.History.insert(0,(config.plugins.mytube.search.searchTerm.value))
936 if len(self.History) == 30:
938 config.plugins.mytube.general.history.value = ",".join(self.History)
939 config.plugins.mytube.general.history.save()
940 print "configvalue",config.plugins.mytube.general.history.value
942 def hideSuggestions(self):
943 current = self["config"].getCurrent()
944 if current[1].help_window.instance is not None:
945 current[1].help_window.instance.hide()
946 if current[1].suggestionsWindow.instance is not None:
947 current[1].suggestionsWindow.instance.hide()
948 self.propagateUpDownNormally = True
950 def getFeed(self, feedUrl, feedName):
952 feed = myTubeService.getFeed(feedUrl)
955 print "Error querying feed :",feedName
957 self.setState('Error')
960 self.buildEntryList()
962 def getNextEntries(self, result):
965 nextUrl = myTubeService.getNextFeedEntriesURL()
966 if nextUrl is not None:
967 self.appendEntries = True
968 self.getFeed(nextUrl, _("More video entries."))
970 def getRelatedVideos(self, myentry):
972 myurl = myentry.getRelatedVideos()
973 print "RELATEDURL--->",myurl
974 if myurl is not None:
975 self.appendEntries = False
976 self.getFeed(myurl, _("Related video entries."))
978 def getResponseVideos(self, myentry):
980 myurl = myentry.getResponseVideos()
981 print "RESPONSEURL--->",myurl
982 if myurl is not None:
983 self.appendEntries = False
984 self.getFeed(myurl, _("Response video entries."))
986 def runSearch(self, searchContext = None):
987 print "[MyTubePlayer] runSearch"
988 if searchContext is not None:
989 print "[MyTubePlayer] searchDialogClosed: ", searchContext
990 self.searchFeed(searchContext)
992 def searchFeed(self, searchContext):
993 print "[MyTubePlayer] searchFeed"
994 self.appendEntries = False
996 feed = myTubeService.search(searchContext,
997 orderby = config.plugins.mytube.search.orderBy.value,
998 racy = config.plugins.mytube.search.racy.value,
999 lr = config.plugins.mytube.search.lr.value,
1000 categories = [ config.plugins.mytube.search.categories.value ],
1001 sortOrder = config.plugins.mytube.search.sortOrder.value)
1002 except Exception, e:
1004 print "Error querying search for :",config.plugins.mytube.search.searchTerm.value
1006 self.setState('Error')
1007 if feed is not None:
1009 if self.FirstRun == True:
1010 self.FirstRun = False
1011 self.buildEntryList()
1013 def buildEntryList(self):
1014 self.mytubeentries = None
1015 self.screenshotList = []
1017 self.mytubeentries = myTubeService.getEntries()
1018 self.maxentries = len(self.mytubeentries)-1
1019 if self.mytubeentries and len(self.mytubeentries):
1020 if self.appendEntries == False:
1022 for entry in self.mytubeentries:
1023 TubeID = entry.getTubeId()
1025 thumbnailUrl = entry.getThumbnailUrl(0)
1026 if thumbnailUrl is not None:
1027 self.screenshotList.append((TubeID,thumbnailUrl))
1028 if not self.Details.has_key(TubeID):
1029 self.Details[TubeID] = { 'thumbnail': None}
1030 self.videolist.append(self.buildEntryComponent(entry, TubeID))
1031 if len(self.videolist):
1032 self["feedlist"].style = "default"
1033 self["feedlist"].disable_callbacks = True
1034 self["feedlist"].list = self.videolist
1035 self["feedlist"].disable_callbacks = False
1036 self["feedlist"].setIndex(0)
1037 self["feedlist"].setList(self.videolist)
1038 self["feedlist"].updateList(self.videolist)
1039 if self.FirstRun == True:
1040 self.switchToConfigList()
1042 self.switchToFeedList()
1044 self.oldfeedentrycount = self["feedlist"].count()
1045 for entry in self.mytubeentries:
1046 TubeID = entry.getTubeId()
1048 thumbnailUrl = entry.getThumbnailUrl(0)
1049 if thumbnailUrl is not None:
1050 self.screenshotList.append((TubeID,thumbnailUrl))
1051 if not self.Details.has_key(TubeID):
1052 self.Details[TubeID] = { 'thumbnail': None}
1053 self.videolist.append(self.buildEntryComponent(entry, TubeID))
1054 if len(self.videolist):
1055 self["feedlist"].style = "default"
1056 old_index = self["feedlist"].index
1057 self["feedlist"].disable_callbacks = True
1058 self["feedlist"].list = self.videolist
1059 self["feedlist"].disable_callbacks = False
1060 self["feedlist"].setList(self.videolist)
1061 self["feedlist"].setIndex(old_index)
1062 self["feedlist"].updateList(self.videolist)
1063 self["feedlist"].selectNext()
1064 self.switchToFeedList(True)
1065 if not self.timer_startDownload.isActive():
1066 print "STARRTDOWNLOADTIMER IM BUILDENTRYLIST"
1067 self.timer_startDownload.start(5)
1069 self.setState('Error')
1072 def buildEntryComponent(self, entry,TubeID):
1073 Title = entry.getTitle()
1074 print "Titel-->",Title
1075 Description = entry.getDescription()
1077 PublishedDate = entry.getPublishedDate()
1078 if PublishedDate is not "unknown":
1079 published = PublishedDate.split("T")[0]
1081 published = "unknown"
1082 Views = entry.getViews()
1083 if Views is not "not available":
1086 views = "not available"
1087 Duration = entry.getDuration()
1088 if Duration is not 0:
1089 durationInSecs = int(Duration)
1090 mins = int(durationInSecs / 60)
1091 secs = durationInSecs - mins * 60
1092 duration = "%d:%02d" % (mins, secs)
1094 duration = "not available"
1095 Ratings = entry.getNumRaters()
1096 if Ratings is not "":
1101 if self.Details[myTubeID]["thumbnail"]:
1102 thumbnail = self.Details[myTubeID]["thumbnail"]
1103 return((entry, Title, Description, myTubeID, thumbnail, _("Added: ") + str(published), _("Views: ") + str(views), _("Duration: ") + str(duration), _("Ratings: ") + str(ratings) ))
1105 def getNextEntry(self):
1106 i = self["feedlist"].getIndex() + 1
1107 if i < len(self.videolist):
1108 self["feedlist"].selectNext()
1109 current = self["feedlist"].getCurrent()
1111 myentry = current[0]
1113 myurl = myentry.getVideoUrl()
1114 if myurl is not None:
1115 print "Got a URL to stream"
1116 myreference = eServiceReference(4097,0,myurl)
1117 myreference.setName(myentry.getTitle())
1118 return myreference,False
1120 print "NoURL im getNextEntry"
1123 print "no more entries to play"
1126 def getPrevEntry(self):
1127 i = self["feedlist"].getIndex() - 1
1129 self["feedlist"].selectPrevious()
1130 current = self["feedlist"].getCurrent()
1132 myentry = current[0]
1134 myurl = myentry.getVideoUrl()
1135 if myurl is not None:
1136 print "Got a URL to stream"
1137 myreference = eServiceReference(4097,0,myurl)
1138 myreference.setName(myentry.getTitle())
1139 return myreference,False
1144 def showVideoInfo(self):
1145 if self.currList == "feedlist":
1146 self.openInfoScreen()
1148 def openInfoScreen(self):
1149 if self.currList == "feedlist":
1150 current = self[self.currList].getCurrent()
1152 myentry = current[0]
1154 print "Title im showVideoInfo",myentry.getTitle()
1155 videoinfos = myentry.PrintEntryDetails()
1156 self.session.open(MyTubeVideoInfoScreen, self.skin_path, videoinfo = videoinfos )
1158 def downloadThumbnails(self):
1159 self.timer_startDownload.stop()
1160 for entry in self.screenshotList:
1161 thumbnailUrl = entry[1]
1163 thumbnailFile = "/tmp/"+str(tubeid)+".jpg"
1164 if self.Details.has_key(tubeid):
1165 if self.Details[tubeid]["thumbnail"] is None:
1166 if thumbnailUrl is not None:
1167 if tubeid not in self.pixmaps_to_load:
1168 self.pixmaps_to_load.append(tubeid)
1169 if (os_path.exists(thumbnailFile) == True):
1170 self.fetchFinished(False,tubeid)
1172 client.downloadPage(thumbnailUrl,thumbnailFile).addCallback(self.fetchFinished,str(tubeid)).addErrback(self.fetchFailed,str(tubeid))
1174 if tubeid not in self.pixmaps_to_load:
1175 self.pixmaps_to_load.append(tubeid)
1176 self.fetchFinished(False,tubeid, failed = True)
1178 def fetchFailed(self,string,tubeid):
1179 print "thumbnail-fetchFailed for: ",tubeid,string.getErrorMessage()
1180 self.fetchFinished(False,tubeid, failed = True)
1182 def fetchFinished(self,x,tubeid, failed = False):
1183 print "thumbnail-fetchFinished for:",tubeid
1184 self.pixmaps_to_load.remove(tubeid)
1186 thumbnailFile = resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/MyTube/plugin.png")
1188 thumbnailFile = "/tmp/"+str(tubeid)+".jpg"
1189 sc = AVSwitch().getFramebufferScale()
1190 if (os_path.exists(thumbnailFile) == True):
1191 self.picloads[tubeid] = ePicLoad()
1192 self.picloads[tubeid].PictureData.get().append(boundFunction(self.finish_decode, tubeid))
1193 self.picloads[tubeid].setPara((self["thumbnail"].instance.size().width(), self["thumbnail"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
1194 self.picloads[tubeid].startDecode(thumbnailFile)
1196 self.pixmaps_to_load.append(tubeid)
1197 self.fetchFinished(False,tubeid, failed = True)
1199 def finish_decode(self,tubeid,info):
1200 print "thumbnail finish_decode:", tubeid,info
1201 ptr = self.picloads[tubeid].getData()
1202 thumbnailFile = "/tmp/"+str(tubeid)+".jpg"
1204 if self.Details.has_key(tubeid):
1205 self.Details[tubeid]["thumbnail"] = ptr
1206 if (os_path.exists(thumbnailFile) == True):
1207 remove(thumbnailFile)
1208 del self.picloads[tubeid]
1210 del self.picloads[tubeid]
1211 if self.Details.has_key(tubeid):
1212 self.Details[tubeid]["thumbnail"] = None
1213 self.timer_thumbnails.start(1)
1215 def updateFeedThumbnails(self):
1216 self.timer_thumbnails.stop()
1217 if len(self.picloads) != 0:
1218 self.timer_thumbnails.start(1)
1221 for entry in self.videolist:
1223 if self.Details.has_key(tubeid):
1224 if self.Details[tubeid]["thumbnail"] is not None:
1225 thumbnail = entry[4]
1226 if thumbnail == None:
1228 self.videolist[idx] = self.buildEntryComponent(myentry, tubeid )
1230 if self.currList == "feedlist":
1231 self["feedlist"].updateList(self.videolist)
1234 class MyTubeVideoInfoScreen(Screen):
1236 <screen name="MyTubeVideoInfoScreen" flags="wfNoBorder" position="0,0" size="720,576" title="MyTubePlayerMainScreen..." >
1237 <ePixmap position="0,0" zPosition="-1" size="720,576" pixmap="~/mytubemain_bg.png" alphatest="on" transparent="1" backgroundColor="transparent"/>
1238 <widget name="title" position="60,50" size="600,50" zPosition="5" valign="center" halign="left" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1239 <widget name="starsbg" pixmap="~/starsbar_empty.png" position="560,220" zPosition="5" size="100,20" transparent="1" alphatest="on" />
1240 <widget name="stars" pixmap="~/starsbar_filled.png" position="560,220" zPosition="6" size="100,20" transparent="1" />
1241 <widget source="infolist" render="Listbox" position="50,110" size="620,110" zPosition="6" scrollbarMode="showNever" selectionDisabled="1" transparent="1">
1242 <convert type="TemplatedMultiContent">
1245 MultiContentEntryPixmapAlphaTest(pos = (0, 4), size = (130, 98), png = 0), # index 0 is the thumbnail
1246 MultiContentEntryPixmapAlphaTest(pos = (130, 4), size = (130, 98), png = 1), # index 0 is the thumbnail
1247 MultiContentEntryPixmapAlphaTest(pos = (260, 4), size = (130, 98), png = 2), # index 0 is the thumbnail
1248 MultiContentEntryPixmapAlphaTest(pos = (390, 4), size = (130, 98), png = 3), # index 0 is the thumbnail
1251 MultiContentEntryText(pos = (10, 40), size = (550, 38), font=2, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 0), # index 0 is the name
1254 "fonts": [gFont("Regular", 20),gFont("Regular", 14),gFont("Regular", 28)],
1259 <widget name="author" position="60,220" size="300,20" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top" />
1260 <widget name="duration" position="370,220" size="200,20" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top" />
1261 <widget name="published" position="60,245" size="300,20" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top" />
1262 <widget name="views" position="370,245" size="200,20" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top" />
1263 <widget name="tags" position="60,270" size="600,20" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top" />
1264 <widget name="detailtext" position="60,300" size="610,200" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top"/>
1265 <ePixmap position="100,500" size="100,40" zPosition="0" pixmap="~/plugin.png" alphatest="on" transparent="1" />
1266 <ePixmap position="220,500" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1267 <widget name="key_red" position="220,500" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1268 <widget name="thumbnail" position="0,0" size="130,98" alphatest="on"/> # fake entry for dynamic thumbnail resizing, currently there is no other way doing this.
1271 def __init__(self, session, plugin_path, videoinfo = None):
1272 Screen.__init__(self, session)
1273 self.session = session
1274 self.skin_path = plugin_path
1275 self.videoinfo = videoinfo
1277 self.thumbnails = []
1279 self["title"] = Label()
1280 self["key_red"] = Button(_("Close"))
1281 self["thumbnail"] = Pixmap()
1282 self["thumbnail"].hide()
1283 self["detailtext"] = ScrollLabel()
1284 self["starsbg"] = Pixmap()
1285 self["stars"] = ProgressBar()
1286 self["duration"] = Label()
1287 self["author"] = Label()
1288 self["published"] = Label()
1289 self["views"] = Label()
1290 self["tags"] = Label()
1291 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions", "MovieSelectionActions"],
1296 "down": self.pageDown,
1297 "left": self.pageUp,
1298 "right": self.pageDown,
1301 self["infolist"] = List(self.infolist)
1302 self.timer = eTimer()
1303 self.timer.callback.append(self.picloadTimeout)
1304 self.onLayoutFinish.append(self.layoutFinished)
1305 self.onShown.append(self.setWindowTitle)
1307 def layoutFinished(self):
1308 self.statuslist = []
1309 self.statuslist.append(( _("Downloading screenshots. Please wait..." ),_("Downloading screenshots. Please wait..." ) ))
1310 self["infolist"].style = "state"
1311 self['infolist'].setList(self.statuslist)
1312 self.loadPreviewpics()
1313 if self.videoinfo["Title"] is not None:
1314 self["title"].setText(self.videoinfo["Title"])
1316 if self.videoinfo["Description"] is not None:
1317 Description = self.videoinfo["Description"]
1320 if Description is not None:
1321 self["detailtext"].setText(Description.strip())
1323 if self.videoinfo["RatingAverage"] is not 0:
1324 ratingStars = int(round(20 * float(self.videoinfo["RatingAverage"]), 0))
1325 self["stars"].setValue(ratingStars)
1327 self["stars"].hide()
1328 self["starsbg"].hide()
1330 if self.videoinfo["Duration"] is not 0:
1331 durationInSecs = int(self.videoinfo["Duration"])
1332 mins = int(durationInSecs / 60)
1333 secs = durationInSecs - mins * 60
1334 duration = "%d:%02d" % (mins, secs)
1335 self["duration"].setText(_("Duration: ") + str(duration))
1337 if self.videoinfo["Author"] is not None or '':
1338 self["author"].setText(_("Author: ") + self.videoinfo["Author"])
1340 if self.videoinfo["Published"] is not "unknown":
1341 self["published"].setText(_("Added: ") + self.videoinfo["Published"].split("T")[0])
1343 if self.videoinfo["Views"] is not "not available":
1344 self["views"].setText(_("Views: ") + str(self.videoinfo["Views"]))
1346 if self.videoinfo["Tags"] is not "not available":
1347 self["tags"].setText(_("Tags: ") + str(self.videoinfo["Tags"]))
1349 def setWindowTitle(self):
1350 self.setTitle(_("MyTubeVideoInfoScreen"))
1353 self["detailtext"].pageUp()
1356 self["detailtext"].pageDown()
1358 def loadPreviewpics(self):
1359 self.thumbnails = []
1360 self.mythumbubeentries = None
1364 self.mythumbubeentries = self.videoinfo["Thumbnails"]
1365 self.maxentries = len(self.mythumbubeentries)-1
1366 if self.mythumbubeentries and len(self.mythumbubeentries):
1368 for entry in self.mythumbubeentries:
1369 TubeID = self.videoinfo["TubeID"]
1370 ThumbID = TubeID + str(currindex)
1371 thumbnailFile = "/tmp/" + ThumbID + ".jpg"
1372 currPic = [currindex,ThumbID,thumbnailFile,None]
1373 self.thumbnails.append(currPic)
1375 thumbnailUrl = entry
1376 if thumbnailUrl is not None:
1377 client.downloadPage(thumbnailUrl,thumbnailFile).addCallback(self.fetchFinished,currindex,ThumbID).addErrback(self.fetchFailed,currindex,ThumbID)
1382 def fetchFailed(self, string, index, id):
1383 print "[fetchFailed] for index:" + str(index) + "for ThumbID:" + id + string.getErrorMessage()
1385 def fetchFinished(self, string, index, id):
1386 print "[fetchFinished] for index:" + str(index) + " for ThumbID:" + id
1387 self.decodePic(index)
1389 def decodePic(self, index):
1390 sc = AVSwitch().getFramebufferScale()
1391 self.picloads[index] = ePicLoad()
1392 self.picloads[index].PictureData.get().append(boundFunction(self.finish_decode, index))
1393 for entry in self.thumbnails:
1394 if entry[0] == index:
1396 thumbnailFile = entry[2]
1397 if (os_path.exists(thumbnailFile) == True):
1398 print "[decodePic] DECODING THUMBNAIL for INDEX:"+ str(self.index) + "and file: " + thumbnailFile
1399 self.picloads[index].setPara((self["thumbnail"].instance.size().width(), self["thumbnail"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
1400 self.picloads[index].startDecode(thumbnailFile)
1402 print "[decodePic] Thumbnail file NOT FOUND !!!-->:",thumbnailFile
1404 def finish_decode(self, picindex = None, picInfo=None):
1405 print "finish_decode - of INDEX", picindex
1406 ptr = self.picloads[picindex].getData()
1408 self.thumbnails[picindex][3] = ptr
1409 if (os_path.exists(self.thumbnails[picindex][2]) == True):
1410 print "removing", self.thumbnails[picindex][2]
1411 remove(self.thumbnails[picindex][2])
1412 del self.picloads[picindex]
1413 if len(self.picloads) == 0:
1414 self.timer.startLongTimer(3)
1416 def picloadTimeout(self):
1418 if len(self.picloads) == 0:
1419 self.buildInfoList()
1421 self.timer.startLongTimer(2)
1423 def buildInfoList(self):
1429 if self.thumbnails[0][3] is not None:
1430 Thumbail0 = self.thumbnails[0][3]
1431 if self.thumbnails[1][3] is not None:
1432 Thumbail1 = self.thumbnails[1][3]
1433 if self.thumbnails[2][3] is not None:
1434 Thumbail2 = self.thumbnails[2][3]
1435 if self.thumbnails[3][3] is not None:
1436 Thumbail3 = self.thumbnails[3][3]
1437 self.infolist.append(( Thumbail0, Thumbail1, Thumbail2, Thumbail3))
1438 if len(self.infolist):
1439 self["infolist"].style = "default"
1440 self["infolist"].disable_callbacks = True
1441 self["infolist"].list = self.infolist
1442 self["infolist"].disable_callbacks = False
1443 self["infolist"].setIndex(0)
1444 self["infolist"].setList(self.infolist)
1445 self["infolist"].updateList(self.infolist)
1448 class MyTubeVideoHelpScreen(Screen):
1450 <screen name="MyTubeVideoHelpScreen" flags="wfNoBorder" position="0,0" size="720,576" title="MyTubePlayerMainScreen..." >
1451 <ePixmap position="0,0" zPosition="-1" size="720,576" pixmap="~/mytubemain_bg.png" alphatest="on" transparent="1" backgroundColor="transparent"/>
1452 <widget name="title" position="60,50" size="600,50" zPosition="5" valign="center" halign="left" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1453 <widget name="detailtext" position="60,120" size="610,370" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top"/>
1454 <ePixmap position="100,500" size="100,40" zPosition="0" pixmap="~/plugin.png" alphatest="on" transparent="1" />
1455 <ePixmap position="220,500" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1456 <widget name="key_red" position="220,500" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1459 def __init__(self, session, plugin_path, wantedinfo = None, wantedtitle = None):
1460 Screen.__init__(self, session)
1461 self.session = session
1462 self.skin_path = plugin_path
1463 self.wantedinfo = wantedinfo
1464 self.wantedtitle = wantedtitle
1465 self["title"] = Label()
1466 self["key_red"] = Button(_("Close"))
1467 self["detailtext"] = ScrollLabel()
1469 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
1474 "down": self.pageDown,
1475 "left": self.pageUp,
1476 "right": self.pageDown,
1479 self.onLayoutFinish.append(self.layoutFinished)
1480 self.onShown.append(self.setWindowTitle)
1482 def layoutFinished(self):
1483 if self.wantedtitle is None:
1484 self["title"].setText(_("Help"))
1486 self["title"].setText(self.wantedtitle)
1487 if self.wantedinfo is None:
1488 self["detailtext"].setText(_("This is the help screen. Feed me with something to display."))
1490 self["detailtext"].setText(self.wantedinfo)
1492 def setWindowTitle(self):
1493 self.setTitle(_("MyTubeVideohelpScreen"))
1496 self["detailtext"].pageUp()
1499 self["detailtext"].pageDown()
1502 class MyTubePlayer(Screen, InfoBarNotifications):
1506 ENABLE_RESUME_SUPPORT = True
1507 ALLOW_SUSPEND = True
1509 skin = """<screen name="MyTubePlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent">
1510 <ePixmap position="0,0" pixmap="skin_default/info-bg_mp.png" zPosition="-1" size="720,160" />
1511 <ePixmap position="29,40" pixmap="skin_default/screws_mp.png" size="665,104" alphatest="on" />
1512 <ePixmap position="48,70" pixmap="skin_default/icons/mp_buttons.png" size="108,13" alphatest="on" />
1513 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" size="15,10" alphatest="on" />
1514 <widget source="session.CurrentService" render="Label" position="230,73" size="360,40" font="Regular;20" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1">
1515 <convert type="ServiceName">Name</convert>
1517 <widget source="session.CurrentService" render="Label" position="580,73" size="90,24" font="Regular;20" halign="right" backgroundColor="#4e5a74" transparent="1">
1518 <convert type="ServicePosition">Length</convert>
1520 <widget source="session.CurrentService" render="Label" position="205,129" size="100,20" font="Regular;18" halign="center" valign="center" backgroundColor="#06224f" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1">
1521 <convert type="ServicePosition">Position</convert>
1523 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" foregroundColor="#20224f">
1524 <convert type="ServicePosition">Gauge</convert>
1526 <widget source="session.CurrentService" render="Label" position="576,129" size="100,20" font="Regular;18" halign="center" valign="center" backgroundColor="#06224f" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1">
1527 <convert type="ServicePosition">Remaining</convert>
1531 def __init__(self, session, service, lastservice, infoCallback = None, nextCallback = None, prevCallback = None):
1532 Screen.__init__(self, session)
1533 InfoBarNotifications.__init__(self)
1534 self.session = session
1535 self.service = service
1536 self.infoCallback = infoCallback
1537 self.nextCallback = nextCallback
1538 self.prevCallback = prevCallback
1539 self.screen_timeout = 5000
1540 self.nextservice = None
1542 print "evEOF=%d" % iPlayableService.evEOF
1543 self.__event_tracker = ServiceEventTracker(screen = self, eventmap =
1545 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
1546 iPlayableService.evStart: self.__serviceStarted,
1547 iPlayableService.evEOF: self.__evEOF,
1550 self["actions"] = ActionMap(["OkCancelActions", "InfobarSeekActions", "MediaPlayerActions", "MovieSelectionActions"],
1553 "cancel": self.leavePlayer,
1554 "stop": self.leavePlayer,
1555 "playpauseService": self.playpauseService,
1556 "seekFwd": self.playNextFile,
1557 "seekBack": self.playPrevFile,
1558 "showEventInfo": self.showVideoInfo,
1562 self.lastservice = lastservice
1564 self.hidetimer = eTimer()
1565 self.hidetimer.timeout.get().append(self.ok)
1566 self.returning = False
1568 self.state = self.STATE_PLAYING
1569 self.lastseekstate = self.STATE_PLAYING
1571 self.onPlayStateChanged = [ ]
1572 self.__seekableStatusChanged()
1575 self.onClose.append(self.__onClose)
1577 def __onClose(self):
1578 self.session.nav.stopService()
1581 print "evEOF=%d" % iPlayableService.evEOF
1583 self.handleLeave(config.plugins.mytube.general.on_movie_stop.value)
1585 def __setHideTimer(self):
1586 self.hidetimer.start(self.screen_timeout)
1588 def showInfobar(self):
1590 if self.state == self.STATE_PLAYING:
1591 self.__setHideTimer()
1595 def hideInfobar(self):
1597 self.hidetimer.stop()
1605 def showVideoInfo(self):
1608 if self.infoCallback is not None:
1612 def playNextFile(self):
1613 print "playNextFile"
1614 nextservice,error = self.nextCallback()
1615 print "nextservice--->",nextservice
1616 if nextservice is None:
1617 self.handleLeave(config.plugins.mytube.general.on_movie_stop.value, error)
1619 self.playService(nextservice)
1622 def playPrevFile(self):
1623 print "playPrevFile"
1624 prevservice,error = self.prevCallback()
1625 if prevservice is None:
1626 self.handleLeave(config.plugins.mytube.general.on_movie_stop.value, error)
1628 self.playService(prevservice)
1631 def playagain(self):
1633 if self.state != self.STATE_IDLE:
1637 def playService(self, newservice):
1638 if self.state != self.STATE_IDLE:
1640 self.service = newservice
1644 if self.state == self.STATE_PAUSED:
1646 self.__setHideTimer()
1647 self.state = self.STATE_PLAYING
1648 self.session.nav.playService(self.service)
1650 self.__setHideTimer()
1652 def stopCurrent(self):
1654 self.session.nav.stopService()
1655 self.state = self.STATE_IDLE
1657 def playpauseService(self):
1658 print "playpauseService"
1659 if self.state == self.STATE_PLAYING:
1661 elif self.state == self.STATE_PAUSED:
1662 self.unPauseService()
1664 def pauseService(self):
1665 print "pauseService"
1666 if self.state == self.STATE_PLAYING:
1667 self.setSeekState(self.STATE_PAUSED)
1669 def unPauseService(self):
1670 print "unPauseService"
1671 if self.state == self.STATE_PAUSED:
1672 self.setSeekState(self.STATE_PLAYING)
1676 service = self.session.nav.getCurrentService()
1680 seek = service.seek()
1682 if seek is None or not seek.isCurrentlySeekable():
1687 def isSeekable(self):
1688 if self.getSeek() is None:
1692 def __seekableStatusChanged(self):
1693 print "seekable status changed!"
1694 if not self.isSeekable():
1695 self.setSeekState(self.STATE_PLAYING)
1699 def __serviceStarted(self):
1700 self.state = self.STATE_PLAYING
1701 self.__seekableStatusChanged()
1703 def setSeekState(self, wantstate):
1704 print "setSeekState"
1705 if wantstate == self.STATE_PAUSED:
1706 print "trying to switch to Pause- state:",self.STATE_PAUSED
1707 elif wantstate == self.STATE_PLAYING:
1708 print "trying to switch to playing- state:",self.STATE_PLAYING
1709 service = self.session.nav.getCurrentService()
1711 print "No Service found"
1713 pauseable = service.pause()
1714 if pauseable is None:
1715 print "not pauseable."
1716 self.state = self.STATE_PLAYING
1718 if pauseable is not None:
1719 print "service is pausable"
1720 if wantstate == self.STATE_PAUSED:
1721 print "WANT TO PAUSE"
1723 self.state = self.STATE_PAUSED
1725 self.hidetimer.stop()
1727 elif wantstate == self.STATE_PLAYING:
1728 print "WANT TO PLAY"
1730 self.state = self.STATE_PLAYING
1732 self.__setHideTimer()
1734 for c in self.onPlayStateChanged:
1739 def handleLeave(self, how, error = False):
1740 self.is_closing = True
1744 (_("No, but play video again"), "playagain"),
1745 (_("Yes, but play next video"), "playnext"),
1746 (_("Yes, but play previous video"), "playprev"),
1749 self.session.openWithCallback(self.leavePlayerConfirmed, ChoiceBox, title=_("Stop playing this movie?"), list = list)
1751 self.session.openWithCallback(self.leavePlayerConfirmed, ChoiceBox, title=_("No playable video found! Stop playing this movie?"), list = list)
1753 self.leavePlayerConfirmed([True, how])
1755 def leavePlayer(self):
1756 self.handleLeave(config.plugins.mytube.general.on_movie_stop.value)
1758 def leavePlayerConfirmed(self, answer):
1759 answer = answer and answer[1]
1760 if answer == "quit":
1762 elif answer == "playnext":
1764 elif answer == "playprev":
1766 elif answer == "playagain":
1769 def doEofInternal(self, playing):
1770 if not self.execing:
1774 self.handleLeave(config.usage.on_movie_eof.value)
1777 def MyTubeMain(session, **kwargs):
1779 l2cert = etpm.getCert(eTPM.TPMD_DT_LEVEL2_CERT)
1781 print "l2cert not found"
1784 l2key = validate_cert(l2cert, rootkey)
1786 print "l2cert invalid"
1790 session.open(MyTubePlayerMainScreen,l2key)
1793 def Plugins(path, **kwargs):
1796 return PluginDescriptor(
1797 name=_("My TubePlayer"),
1798 description=_("Play YouTube movies"),
1799 where = [ PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU ],
1800 icon = "plugin.png", fnc = MyTubeMain)