2 import os, sys, traceback
10 from Screens.MessageBox import MessageBox
13 from Components.config import config, ConfigSubsection, ConfigEnableDisable, ConfigNumber, ConfigSelection, ConfigYesNo, ConfigText, ConfigSelectionNumber
16 from Components.PluginComponent import plugins
17 from Plugins.Plugin import PluginDescriptor
20 from SeriesPluginTimer import SeriesPluginTimer
21 from SeriesPluginInfoScreen import SeriesPluginInfoScreen
22 from SeriesPluginRenamer import SeriesPluginRenamer
23 from SeriesPluginIndependent import startIndependent, runIndependent
24 from SeriesPluginConfiguration import SeriesPluginConfiguration
25 from Logger import splog
28 #######################################################
32 DESCRIPTION = _("SeriesPlugin")
33 SHOWINFO = _("Show series info (SP)")
34 RENAMESERIES = _("Rename serie(s) (SP)")
35 CHECKTIMERS = _("Check timer list for series (SP)")
36 SUPPORT = "http://bit.ly/seriespluginihad"
37 DONATE = "http://bit.ly/seriespluginpaypal"
38 ABOUT = "\n " + NAME + " " + VERSION + "\n\n" \
39 + _(" (C) 2012 by betonme @ IHAD \n\n") \
40 + _(" {lookups:d} successful lookups.\n") \
41 + _(" How much time have You saved?\n\n") \
42 + _(" Support: ") + SUPPORT + "\n" \
43 + _(" Feel free to donate. \n") \
44 + _(" PayPal: ") + DONATE
46 from Tools.HardwareInfo import HardwareInfo
47 DEVICE = HardwareInfo().get_device_name().strip()
50 #from Components.Network import iNetwork
51 #self.BoxID = iNetwork.getAdapterAttribute("eth0", "mac")
52 #self.DeviceName = HardwareInfo().get_device_name()
53 #from Components.About import about
54 #self.EnigmaVersion = about.getEnigmaVersionString()
55 #self.ImageVersion = about.getVersionString()
59 WHERE_EPGMENU = 'WHERE_EPGMENU'
60 WHERE_CHANNELMENU = 'WHERE_CHANNELMENU'
63 #######################################################
64 # Initialize Configuration
65 config.plugins.seriesplugin = ConfigSubsection()
67 config.plugins.seriesplugin.enabled = ConfigEnableDisable(default = False)
69 config.plugins.seriesplugin.menu_info = ConfigYesNo(default = True)
70 config.plugins.seriesplugin.menu_extensions = ConfigYesNo(default = False)
71 config.plugins.seriesplugin.menu_epg = ConfigYesNo(default = False)
72 config.plugins.seriesplugin.menu_channel = ConfigYesNo(default = True)
73 config.plugins.seriesplugin.menu_movie_info = ConfigYesNo(default = True)
74 config.plugins.seriesplugin.menu_movie_rename = ConfigYesNo(default = True)
76 #TODO config.plugins.seriesplugin.open MessageBox or TheTVDB ConfigSelection if hasTheTVDB
78 config.plugins.seriesplugin.identifier_elapsed = ConfigText(default = "", fixed_size = False)
79 config.plugins.seriesplugin.identifier_today = ConfigText(default = "", fixed_size = False)
80 config.plugins.seriesplugin.identifier_future = ConfigText(default = "", fixed_size = False)
82 #config.plugins.seriesplugin.manager = ConfigSelection(choices = [("", "")], default = "")
83 #config.plugins.seriesplugin.guide = ConfigSelection(choices = [("", "")], default = "")
85 config.plugins.seriesplugin.pattern_file = ConfigText(default = "/etc/enigma2/seriesplugin_patterns.json", fixed_size = False)
86 config.plugins.seriesplugin.pattern_title = ConfigText(default = "{org:s} S{season:02d}E{episode:02d} {title:s}", fixed_size = False)
87 config.plugins.seriesplugin.pattern_description = ConfigText(default = "S{season:02d}E{episode:02d} {title:s} {org:s}", fixed_size = False)
88 #config.plugins.seriesplugin.pattern_record = ConfigText(default = "{org:s} S{season:02d}E{episode:02d} {title:s}", fixed_size = False)
90 config.plugins.seriesplugin.channel_file = ConfigText(default = "/etc/enigma2/seriesplugin_channels.xml", fixed_size = False)
91 config.plugins.seriesplugin.channel_popups = ConfigYesNo(default = False)
93 config.plugins.seriesplugin.tidy_rename = ConfigYesNo(default = False)
94 config.plugins.seriesplugin.rename_file = ConfigYesNo(default = True)
95 config.plugins.seriesplugin.rename_popups = ConfigYesNo(default = True)
96 config.plugins.seriesplugin.rename_popups_success = ConfigYesNo(default = False)
98 config.plugins.seriesplugin.max_time_drift = ConfigSelectionNumber(0, 600, 1, default = 15)
99 config.plugins.seriesplugin.search_depths = ConfigSelectionNumber(0, 10, 1, default = 0)
101 config.plugins.seriesplugin.skip_during_records = ConfigYesNo(default=False)
103 config.plugins.seriesplugin.autotimer_independent = ConfigYesNo(default = False)
104 config.plugins.seriesplugin.independent_cycle = ConfigSelectionNumber(5, 24*60, 5, default = 60)
105 config.plugins.seriesplugin.independent_retry = ConfigYesNo(default = False)
107 config.plugins.seriesplugin.check_timer_list = ConfigYesNo(default = False)
109 config.plugins.seriesplugin.timer_popups = ConfigYesNo(default = True)
110 config.plugins.seriesplugin.timer_popups_success = ConfigYesNo(default = False)
112 config.plugins.seriesplugin.caching = ConfigYesNo(default = True)
114 #config.plugins.seriesplugin.debug = ConfigYesNo(default = False)
115 config.plugins.seriesplugin.write_log = ConfigYesNo(default = False)
116 config.plugins.seriesplugin.log_file = ConfigText(default = "/tmp/seriesplugin.log", fixed_size = False)
117 config.plugins.seriesplugin.log_reply_user = ConfigText(default = "Dreambox User", fixed_size = False)
118 config.plugins.seriesplugin.log_reply_mail = ConfigText(default = "myemail@home.com", fixed_size = False)
120 config.plugins.seriesplugin.ganalytics = ConfigYesNo(default = True)
123 config.plugins.seriesplugin.lookup_counter = ConfigNumber(default = 0)
124 #config.plugins.seriesplugin.uid = ConfigText(default = str(time()), fixed_size = False)
127 #######################################################
129 def start(reason, **kwargs):
130 if config.plugins.seriesplugin.enabled.value:
133 # Start on demand if it is requested
134 if config.plugins.seriesplugin.autotimer_independent.value:
139 from SeriesPlugin import resetInstance
143 #######################################################
144 # Plugin configuration
145 def setup(session, *args, **kwargs):
147 session.open(SeriesPluginConfiguration)
148 except Exception as e:
149 splog(_("SeriesPlugin setup exception ") + str(e))
150 #exc_type, exc_value, exc_traceback = sys.exc_info()
151 #splog( exc_type, exc_value, exc_traceback )
154 #######################################################
156 def info(session, service=None, event=None, *args, **kwargs):
157 if config.plugins.seriesplugin.enabled.value:
159 session.open(SeriesPluginInfoScreen, service, event)
160 except Exception as e:
161 splog(_("SeriesPlugin info exception ") + str(e))
162 #exc_type, exc_value, exc_traceback = sys.exc_info()
163 #splog( exc_type, exc_value, exc_traceback )
166 #######################################################
168 def sp_extension(session, *args, **kwargs):
169 if config.plugins.seriesplugin.enabled.value:
172 session.open(SeriesPluginInfoScreen)
173 except Exception as e:
174 splog(_("SeriesPlugin extension exception ") + str(e))
177 #######################################################
179 def channel(session, service=None, *args, **kwargs):
180 if config.plugins.seriesplugin.enabled.value:
182 from enigma import eServiceCenter
183 info = eServiceCenter.getInstance().info(service)
184 event = info.getEvent(service)
185 session.open(SeriesPluginInfoScreen, service, event)
186 except Exception as e:
187 splog(_("SeriesPlugin extension exception ") + str(e))
190 #######################################################
192 def checkTimers(session, *args, **kwargs):
196 #######################################################
197 # Movielist menu rename
198 def movielist_rename(session, service, services=None, *args, **kwargs):
199 if config.plugins.seriesplugin.enabled.value:
202 if not isinstance(services, list):
203 services = [services]
206 SeriesPluginRenamer(session, services)
207 except Exception as e:
208 splog(_("SeriesPlugin renamer exception ") + str(e))
211 #######################################################
212 # Movielist menu info
213 def movielist_info(session, service, *args, **kwargs):
214 if config.plugins.seriesplugin.enabled.value:
216 session.open(SeriesPluginInfoScreen, service)
217 except Exception as e:
218 splog(_("SeriesPlugin extension exception ") + str(e))
221 #######################################################
223 def renameTimer(timer, name, begin, end, *args, **kwargs):
224 if config.plugins.seriesplugin.enabled.value:
226 SeriesPluginTimer(timer, name, begin, end)
227 except Exception as e:
228 splog(_("SeriesPlugin label exception ") + str(e))
231 # For compatibility reasons
232 def modifyTimer(timer, name, *args, **kwargs):
233 if config.plugins.seriesplugin.enabled.value:
234 splog("SeriesPlugin modifyTimer is deprecated - Update Your AutoTimer!")
236 SeriesPluginTimer(timer, name or timer.name, timer.begin, timer.end)
237 except Exception as e:
238 splog(_("SeriesPlugin label exception ") + str(e))
241 # For compatibility reasons
242 def labelTimer(timer, begin=None, end=None, *args, **kwargs):
243 if config.plugins.seriesplugin.enabled.value:
244 splog("SeriesPlugin labelTimer is deprecated - Update Your AutoTimer!")
246 SeriesPluginTimer(timer, timer.name, timer.begin, timer.end)
247 except Exception as e:
248 splog(_("SeriesPlugin label exception ") + str(e))
251 #######################################################
252 # Plugin main function
253 def Plugins(**kwargs):
257 descriptors.append( PluginDescriptor(
258 name = NAME + " " + _("Setup"),
259 description = NAME + " " + _("Setup"),
260 where = PluginDescriptor.WHERE_PLUGINMENU,
262 needsRestart = False) )
264 if config.plugins.seriesplugin.enabled.value:
268 descriptors.append( PluginDescriptor(
269 #where = PluginDescriptor.WHERE_SESSIONSTART,
270 where = PluginDescriptor.WHERE_AUTOSTART,
271 needsRestart = False,
274 if config.plugins.seriesplugin.menu_info.value:
275 descriptors.append( PluginDescriptor(
277 description = SHOWINFO,
278 where = PluginDescriptor.WHERE_EVENTINFO,
279 needsRestart = False,
282 if config.plugins.seriesplugin.menu_extensions.value:
283 descriptors.append(PluginDescriptor(
285 description = SHOWINFO,
286 where = PluginDescriptor.WHERE_EXTENSIONSMENU,
288 needsRestart = False) )
290 if config.plugins.seriesplugin.menu_channel.value:
291 descriptors.append( PluginDescriptor(
293 description = SHOWINFO,
294 where = PluginDescriptor.WHERE_CHANNEL_CONTEXT_MENU,
296 needsRestart = False) )
298 if config.plugins.seriesplugin.check_timer_list.value:
299 descriptors.append(PluginDescriptor(
301 description = CHECKTIMERS,
302 where = PluginDescriptor.WHERE_EXTENSIONSMENU,
304 needsRestart = False) )
306 if config.plugins.seriesplugin.menu_movie_info.value:
307 descriptors.append( PluginDescriptor(
309 description = SHOWINFO,
310 where = PluginDescriptor.WHERE_MOVIELIST,
311 fnc = movielist_info,
312 needsRestart = False) )
314 if config.plugins.seriesplugin.menu_movie_rename.value:
315 descriptors.append( PluginDescriptor(
317 description = RENAMESERIES,
318 where = PluginDescriptor.WHERE_MOVIELIST,
319 fnc = movielist_rename,
320 needsRestart = False) )
322 if config.plugins.seriesplugin.menu_epg.value:
323 addSeriesPlugin(WHERE_EPGMENU, SHOWINFO)
328 #######################################################
329 # Override EPGSelection enterDateTime
330 EPGSelection_enterDateTime = None
331 #EPGSelection_openOutdatedEPGSelection = None
332 def SPEPGSelectionInit():
333 print "SeriesPlugin override EPGSelection"
334 global EPGSelection_enterDateTime, EPGSelection_openOutdatedEPGSelection
335 if EPGSelection_enterDateTime is None: # and EPGSelection_openOutdatedEPGSelection is None:
336 from Screens.EpgSelection import EPGSelection
337 EPGSelection_enterDateTime = EPGSelection.enterDateTime
338 EPGSelection.enterDateTime = enterDateTime
339 #EPGSelection_openOutdatedEPGSelection = EPGSelection.openOutdatedEPGSelection
340 #EPGSelection.openOutdatedEPGSelection = openOutdatedEPGSelection
341 EPGSelection.SPcloseafterfinish = closeafterfinish
343 def SPEPGSelectionUndo():
344 print "SeriesPlugin undo override EPGSelection"
345 global EPGSelection_enterDateTime, EPGSelection_openOutdatedEPGSelection
346 if EPGSelection_enterDateTime and EPGSelection_openOutdatedEPGSelection:
347 from Screens.EpgSelection import EPGSelection
348 EPGSelection.enterDateTime = EPGSelection_enterDateTime
349 EPGSelection_enterDateTime = None
350 #EPGSelection.openOutdatedEPGSelection = EPGSelection_openOutdatedEPGSelection
351 #EPGSelection_openOutdatedEPGSelection = None
353 def enterDateTime(self):
354 from Screens.EpgSelection import EPG_TYPE_SINGLE,EPG_TYPE_MULTI,EPG_TYPE_SIMILAR
355 event = self["Event"].event
356 if self.type == EPG_TYPE_SINGLE:
357 service = self.currentService
358 elif self.type == EPG_TYPE_MULTI:
359 service = self.services
360 elif self.type == EPG_TYPE_SIMILAR:
361 service = self.currentService
362 if service and event:
363 self.session.openWithCallback(self.SPcloseafterfinish, SeriesPluginInfoScreen, service, event)
365 EPGSelection_enterDateTime(self)
367 #def openOutdatedEPGSelection(self, reason=None):
369 # EPGSelection_enterDateTime(self)
371 def closeafterfinish(self, retval=None):
375 #######################################################
376 # Add / Remove menu functions
377 def addSeriesPlugin(menu, title, fnc=None):
379 if( menu == WHERE_EPGMENU ):
382 from Components.PluginComponent import plugins
384 for p in plugins.getPlugins( where = menu ):
386 # Plugin is already in menu
389 # Plugin not in menu - add it
390 plugin = PluginDescriptor(
394 needsRestart = False,
396 if menu in plugins.plugins:
397 plugins.plugins[ menu ].append(plugin)
400 def removeSeriesPlugin(menu, title):
402 if( menu == WHERE_EPGMENU ):
405 from Components.PluginComponent import plugins
407 for p in plugins.getPlugins( where = menu ):
409 plugins.plugins[ menu ].remove(p)
413 #######################################################
414 # Overwrite AutoTimer support functions
417 from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
418 #from Plugins.Extensions.AutoTimer.plugin import autotimer as AutoTimer
423 ATcheckSimilarity = None
426 def overwriteAutoTimer():
428 global ATmodifyTimer, ATcheckSimilarity
430 if ATmodifyTimer is None:
431 # Backup original function
432 ATmodifyTimer = AutoTimer.modifyTimer
434 AutoTimer.modifyTimer = SPmodifyTimer
435 if ATcheckSimilarity is None:
436 # Backup original function
437 ATcheckSimilarity = AutoTimer.checkSimilarity
439 AutoTimer.checkSimilarity = SPcheckSimilarity
441 splog("SeriesPlugin found old AutoTimer")
444 def recoverAutoTimer():
446 global ATmodifyTimer, ATcheckSimilarity
449 AutoTimer.modifyTimer = ATmodifyTimer
451 if ATcheckSimilarity:
452 AutoTimer.checkSimilarity = ATcheckSimilarity
453 ATcheckSimilarity = None
455 splog("SeriesPlugin found old AutoTimer")
458 #######################################################
459 # Customized support functions
461 from difflib import SequenceMatcher
462 from ServiceReference import ServiceReference
464 def SPmodifyTimer(self, timer, name, shortdesc, begin, end, serviceref, eit=None):
465 # Never overwrite existing names, You will lose Your series informations
467 # Only overwrite non existing descriptions
468 timer.description = timer.description or shortdesc
469 timer.begin = int(begin)
471 timer.service_ref = ServiceReference(serviceref)
475 def SPcheckSimilarity(self, timer, name1, name2, shortdesc1, shortdesc2, extdesc1, extdesc2, force=False):
476 # Check if the new title is part of the existing one
477 foundTitle = name1 in name2 or name2 in name1
479 if timer.searchForDuplicateDescription > 0 or force:
480 foundShort = (shortdesc1 in shortdesc2 or shortdesc2 in shortdesc1) if (timer.searchForDuplicateDescription > 0 or force) else True
482 # NOTE: only check extended if short description already is a match because otherwise
483 # it won't evaluate to True anyway
484 if (timer.searchForDuplicateDescription > 0 or force) and foundShort and extdesc1 != extdesc2:
485 # Some channels indicate replays in the extended descriptions
486 # If the similarity percent is higher then 0.8 it is a very close match
487 #if timer.series_labeling and (extdesc1 == "" or extdesc2 == ""):
490 foundExt = ( 0.8 < SequenceMatcher(lambda x: x == " ",extdesc1, extdesc2).ratio() )
497 return foundTitle and foundShort and foundExt