SeriesPlugin 1.3.1: Fixed typos
[enigma2-plugins.git] / seriesplugin / src / plugin.py
1
2 import os, sys, traceback
3
4 # Localization
5 from . import _
6
7 from time import time
8
9 # GUI (Screens)
10 from Screens.MessageBox import MessageBox
11
12 # Config
13 from Components.config import config, ConfigSubsection, ConfigEnableDisable, ConfigNumber, ConfigSelection, ConfigYesNo, ConfigText, ConfigSelectionNumber
14
15 # Plugin
16 from Components.PluginComponent import plugins
17 from Plugins.Plugin import PluginDescriptor
18
19 # Plugin internal
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
26
27
28 #######################################################
29 # Constants
30 NAME = "SeriesPlugin"
31 VERSION = "1.3.1"
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
45 try:
46         from Tools.HardwareInfo import HardwareInfo
47         DEVICE = HardwareInfo().get_device_name().strip()
48         
49         # Get Box Info
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()
56 except:
57         DEVICE = ''
58
59 WHERE_EPGMENU     = 'WHERE_EPGMENU'
60 WHERE_CHANNELMENU = 'WHERE_CHANNELMENU'
61
62
63 #######################################################
64 # Initialize Configuration
65 config.plugins.seriesplugin = ConfigSubsection()
66
67 config.plugins.seriesplugin.enabled                   = ConfigEnableDisable(default = False)
68
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)
75
76 #TODO config.plugins.seriesplugin.open MessageBox or TheTVDB  ConfigSelection if hasTheTVDB
77
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)
81
82 #config.plugins.seriesplugin.manager                   = ConfigSelection(choices = [("", "")], default = "")
83 #config.plugins.seriesplugin.guide                     = ConfigSelection(choices = [("", "")], default = "")
84
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)
89
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)
92
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)
97
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)
100
101 config.plugins.seriesplugin.skip_during_records       = ConfigYesNo(default=False)
102
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)
106
107 config.plugins.seriesplugin.check_timer_list          = ConfigYesNo(default = False)
108
109 config.plugins.seriesplugin.timer_popups              = ConfigYesNo(default = True)
110 config.plugins.seriesplugin.timer_popups_success      = ConfigYesNo(default = False)
111
112 config.plugins.seriesplugin.caching                   = ConfigYesNo(default = True)
113
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)
119
120 config.plugins.seriesplugin.ganalytics                = ConfigYesNo(default = True)
121
122 # Internal
123 config.plugins.seriesplugin.lookup_counter            = ConfigNumber(default = 0)
124 #config.plugins.seriesplugin.uid                       = ConfigText(default = str(time()), fixed_size = False)
125
126
127 #######################################################
128 # Start
129 def start(reason, **kwargs):
130         if config.plugins.seriesplugin.enabled.value:
131                 # Startup
132                 if reason == 0:
133                         # Start on demand if it is requested
134                         if config.plugins.seriesplugin.autotimer_independent.value:
135                                 startIndependent()
136                         
137                 # Shutdown
138                 elif reason == 1:
139                         from SeriesPlugin import resetInstance
140                         resetInstance()
141
142
143 #######################################################
144 # Plugin configuration
145 def setup(session, *args, **kwargs):
146         try:
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 )
152
153
154 #######################################################
155 # Event Info
156 def info(session, service=None, event=None, *args, **kwargs):
157         if config.plugins.seriesplugin.enabled.value:
158                 try:
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 )
164
165
166 #######################################################
167 # Extensions menu
168 def sp_extension(session, *args, **kwargs):
169         if config.plugins.seriesplugin.enabled.value:
170                 try:
171                         if session:
172                                 session.open(SeriesPluginInfoScreen)
173                 except Exception as e:
174                         splog(_("SeriesPlugin extension exception ") + str(e))
175
176
177 #######################################################
178 # Channel menu
179 def channel(session, service=None, *args, **kwargs):
180         if config.plugins.seriesplugin.enabled.value:
181                 try:
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))
188
189
190 #######################################################
191 # Timer
192 def checkTimers(session, *args, **kwargs):
193         runIndependent()
194
195
196 #######################################################
197 # Movielist menu rename
198 def movielist_rename(session, service, services=None, *args, **kwargs):
199         if config.plugins.seriesplugin.enabled.value:
200                 try:
201                         if services:
202                                 if not isinstance(services, list):
203                                         services = [services]   
204                         else:
205                                 services = [service]
206                         SeriesPluginRenamer(session, services)
207                 except Exception as e:
208                         splog(_("SeriesPlugin renamer exception ") + str(e))
209
210
211 #######################################################
212 # Movielist menu info
213 def movielist_info(session, service, *args, **kwargs):
214         if config.plugins.seriesplugin.enabled.value:
215                 try:
216                         session.open(SeriesPluginInfoScreen, service)
217                 except Exception as e:
218                         splog(_("SeriesPlugin extension exception ") + str(e))
219
220
221 #######################################################
222 # Timer renaming
223 def renameTimer(timer, name, begin, end, *args, **kwargs):
224         if config.plugins.seriesplugin.enabled.value:
225                 try:
226                         SeriesPluginTimer(timer, name, begin, end)
227                 except Exception as e:
228                         splog(_("SeriesPlugin label exception ") + str(e))
229
230
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!")
235                 try:
236                         SeriesPluginTimer(timer, name or timer.name, timer.begin, timer.end)
237                 except Exception as e:
238                         splog(_("SeriesPlugin label exception ") + str(e))
239
240
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!")
245                 try:
246                         SeriesPluginTimer(timer, timer.name, timer.begin, timer.end)
247                 except Exception as e:
248                         splog(_("SeriesPlugin label exception ") + str(e))
249
250
251 #######################################################
252 # Plugin main function
253 def Plugins(**kwargs):
254         descriptors = []
255         
256         #TODO icon
257         descriptors.append( PluginDescriptor(
258                                                                                         name = NAME + " " + _("Setup"),
259                                                                                         description = NAME + " " + _("Setup"),
260                                                                                         where = PluginDescriptor.WHERE_PLUGINMENU,
261                                                                                         fnc = setup,
262                                                                                         needsRestart = False) )
263         
264         if config.plugins.seriesplugin.enabled.value:
265                 
266                 overwriteAutoTimer()
267                 
268                 descriptors.append( PluginDescriptor(
269                                                                                                         #where = PluginDescriptor.WHERE_SESSIONSTART,
270                                                                                                         where = PluginDescriptor.WHERE_AUTOSTART,
271                                                                                                         needsRestart = False,
272                                                                                                         fnc = start) )
273
274                 if config.plugins.seriesplugin.menu_info.value:
275                         descriptors.append( PluginDescriptor(
276                                                                                                         name = SHOWINFO,
277                                                                                                         description = SHOWINFO,
278                                                                                                         where = PluginDescriptor.WHERE_EVENTINFO,
279                                                                                                         needsRestart = False,
280                                                                                                         fnc = info) )
281
282                 if config.plugins.seriesplugin.menu_extensions.value:
283                         descriptors.append(PluginDescriptor(
284                                                                                                         name = SHOWINFO,
285                                                                                                         description = SHOWINFO,
286                                                                                                         where = PluginDescriptor.WHERE_EXTENSIONSMENU,
287                                                                                                         fnc = sp_extension,
288                                                                                                         needsRestart = False) )
289                         
290                 if config.plugins.seriesplugin.menu_channel.value:
291                         descriptors.append( PluginDescriptor(
292                                                                                                         name = SHOWINFO,
293                                                                                                         description = SHOWINFO,
294                                                                                                         where = PluginDescriptor.WHERE_CHANNEL_CONTEXT_MENU,
295                                                                                                         fnc = channel,
296                                                                                                         needsRestart = False) )
297                 
298                 if config.plugins.seriesplugin.check_timer_list.value:
299                         descriptors.append(PluginDescriptor(
300                                                                                                         name = CHECKTIMERS,
301                                                                                                         description = CHECKTIMERS,
302                                                                                                         where = PluginDescriptor.WHERE_EXTENSIONSMENU,
303                                                                                                         fnc = checkTimers,
304                                                                                                         needsRestart = False) )
305                 
306                 if config.plugins.seriesplugin.menu_movie_info.value:
307                         descriptors.append( PluginDescriptor(
308                                                                                                         name = SHOWINFO,
309                                                                                                         description = SHOWINFO,
310                                                                                                         where = PluginDescriptor.WHERE_MOVIELIST,
311                                                                                                         fnc = movielist_info,
312                                                                                                         needsRestart = False) )
313                 
314                 if config.plugins.seriesplugin.menu_movie_rename.value:
315                         descriptors.append( PluginDescriptor(
316                                                                                                         name = RENAMESERIES,
317                                                                                                         description = RENAMESERIES,
318                                                                                                         where = PluginDescriptor.WHERE_MOVIELIST,
319                                                                                                         fnc = movielist_rename,
320                                                                                                         needsRestart = False) )
321                 
322                 if config.plugins.seriesplugin.menu_epg.value:
323                         addSeriesPlugin(WHERE_EPGMENU, SHOWINFO)
324
325         return descriptors
326
327
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
342
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
352
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) 
364                 return
365         EPGSelection_enterDateTime(self)
366
367 #def openOutdatedEPGSelection(self, reason=None):
368 #       if reason == 1:
369 #               EPGSelection_enterDateTime(self)
370
371 def closeafterfinish(self, retval=None):
372         self.close()
373
374
375 #######################################################
376 # Add / Remove menu functions
377 def addSeriesPlugin(menu, title, fnc=None):
378         # Add to menu
379         if( menu == WHERE_EPGMENU ):
380                 SPEPGSelectionInit()
381         else:
382                 from Components.PluginComponent import plugins
383                 if plugins:
384                         for p in plugins.getPlugins( where = menu ):
385                                 if p.name == title:
386                                         # Plugin is already in menu
387                                         break
388                         else:
389                                 # Plugin not in menu - add it
390                                 plugin = PluginDescriptor(
391                                                                                                                                 name = title,
392                                                                                                                                 description = title,
393                                                                                                                                 where = menu,
394                                                                                                                                 needsRestart = False,
395                                                                                                                                 fnc = fnc)
396                                 if menu in plugins.plugins:
397                                         plugins.plugins[ menu ].append(plugin)
398
399
400 def removeSeriesPlugin(menu, title):
401         # Remove from menu
402         if( menu == WHERE_EPGMENU ):
403                 SPEPGSelectionUndo()
404         else:
405                 from Components.PluginComponent import plugins
406                 if plugins:
407                         for p in plugins.getPlugins( where = menu ):
408                                 if p.name == title:
409                                         plugins.plugins[ menu ].remove(p)
410                                         break
411
412
413 #######################################################
414 # Overwrite AutoTimer support functions
415
416 try:
417         from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
418         #from Plugins.Extensions.AutoTimer.plugin import autotimer as AutoTimer
419 except:
420         AutoTimer = None
421
422 ATmodifyTimer = None
423 ATcheckSimilarity = None
424
425
426 def overwriteAutoTimer():
427         try:
428                 global ATmodifyTimer, ATcheckSimilarity
429                 if AutoTimer:
430                         if ATmodifyTimer is None:
431                                 # Backup original function
432                                 ATmodifyTimer = AutoTimer.modifyTimer
433                                 # Overwrite function
434                                 AutoTimer.modifyTimer = SPmodifyTimer
435                         if ATcheckSimilarity is None:
436                                 # Backup original function
437                                 ATcheckSimilarity = AutoTimer.checkSimilarity
438                                 # Overwrite function
439                                 AutoTimer.checkSimilarity = SPcheckSimilarity
440         except:
441                 splog("SeriesPlugin found old AutoTimer")
442
443
444 def recoverAutoTimer():
445         try:
446                 global ATmodifyTimer, ATcheckSimilarity
447                 if AutoTimer:
448                         if ATmodifyTimer:
449                                 AutoTimer.modifyTimer = ATmodifyTimer
450                                 ATmodifyTimer = None
451                         if ATcheckSimilarity:
452                                 AutoTimer.checkSimilarity = ATcheckSimilarity
453                                 ATcheckSimilarity = None
454         except:
455                 splog("SeriesPlugin found old AutoTimer")
456
457
458 #######################################################
459 # Customized support functions
460
461 from difflib import SequenceMatcher
462 from ServiceReference import ServiceReference
463
464 def SPmodifyTimer(self, timer, name, shortdesc, begin, end, serviceref, eit=None):
465         # Never overwrite existing names, You will lose Your series informations
466         #timer.name = name
467         # Only overwrite non existing descriptions
468         timer.description = timer.description or shortdesc
469         timer.begin = int(begin)
470         timer.end = int(end)
471         timer.service_ref = ServiceReference(serviceref)
472         if eit:
473                 timer.eit = eit
474
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
478         
479         if timer.searchForDuplicateDescription > 0 or force:
480                 foundShort = (shortdesc1 in shortdesc2 or shortdesc2 in shortdesc1) if (timer.searchForDuplicateDescription > 0 or force) else True
481                 
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 == ""):
488                         #       foundExt = True
489                         #else:
490                         foundExt = ( 0.8 < SequenceMatcher(lambda x: x == " ",extdesc1, extdesc2).ratio() )
491                 else:
492                         foundExt = True
493         else:
494                 foundShort = True
495                 foundExt = True
496         
497         return foundTitle and foundShort and foundExt