SeriesPlugin: 1.5.8 Fixed encoding, popups, channel list integration
[enigma2-plugins.git] / seriesplugin / src / plugin.py
1 # -*- coding: utf-8 -*-
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.5.8"
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.title_replace_chars       = ConfigYesNo(default = True)
91
92 config.plugins.seriesplugin.channel_file              = ConfigText(default = "/etc/enigma2/seriesplugin_channels.xml", fixed_size = False)
93 config.plugins.seriesplugin.channel_popups            = ConfigYesNo(default = False)
94
95 config.plugins.seriesplugin.rename_file               = ConfigYesNo(default = True)
96 config.plugins.seriesplugin.rename_tidy               = ConfigYesNo(default = False)
97 config.plugins.seriesplugin.rename_legacy             = ConfigYesNo(default = False)
98 config.plugins.seriesplugin.rename_existing_files     = ConfigYesNo(default = False)
99 config.plugins.seriesplugin.rename_popups             = ConfigYesNo(default = True)
100 config.plugins.seriesplugin.rename_popups_success     = ConfigYesNo(default = False)
101 config.plugins.seriesplugin.rename_popups_timeout     = ConfigSelectionNumber(-1, 20, 1, default = 3)
102
103 config.plugins.seriesplugin.max_time_drift            = ConfigSelectionNumber(0, 600, 1, default = 15)
104 config.plugins.seriesplugin.search_depths             = ConfigSelectionNumber(0, 10, 1, default = 0)
105
106 config.plugins.seriesplugin.skip_during_records       = ConfigYesNo(default=False)
107
108 config.plugins.seriesplugin.autotimer_independent     = ConfigYesNo(default = False)
109 config.plugins.seriesplugin.independent_cycle         = ConfigSelectionNumber(5, 24*60, 5, default = 60)
110 config.plugins.seriesplugin.independent_retry         = ConfigYesNo(default = False)
111
112 config.plugins.seriesplugin.check_timer_list          = ConfigYesNo(default = False)
113
114 config.plugins.seriesplugin.timer_popups              = ConfigYesNo(default = True)
115 config.plugins.seriesplugin.timer_popups_success      = ConfigYesNo(default = False)
116 config.plugins.seriesplugin.timer_popups_timeout     = ConfigSelectionNumber(-1, 20, 1, default = 3)
117
118 config.plugins.seriesplugin.caching                   = ConfigYesNo(default = True)
119
120 #config.plugins.seriesplugin.debug                     = ConfigYesNo(default = False)
121 config.plugins.seriesplugin.write_log                 = ConfigYesNo(default = False)
122 config.plugins.seriesplugin.log_file                  = ConfigText(default = "/tmp/seriesplugin.log", fixed_size = False)
123 config.plugins.seriesplugin.log_reply_user            = ConfigText(default = "Dreambox User", fixed_size = False)
124 config.plugins.seriesplugin.log_reply_mail            = ConfigText(default = "myemail@home.com", fixed_size = False)
125
126 config.plugins.seriesplugin.ganalytics                = ConfigYesNo(default = True)
127
128 # Internal
129 config.plugins.seriesplugin.lookup_counter            = ConfigNumber(default = 0)
130 #config.plugins.seriesplugin.uid                       = ConfigText(default = str(time()), fixed_size = False)
131
132
133 #######################################################
134 # Start
135 def start(reason, **kwargs):
136         if config.plugins.seriesplugin.enabled.value:
137                 # Startup
138                 if reason == 0:
139                         # Start on demand if it is requested
140                         if config.plugins.seriesplugin.autotimer_independent.value:
141                                 startIndependent()
142                         
143                 # Shutdown
144                 elif reason == 1:
145                         from SeriesPlugin import resetInstance
146                         resetInstance()
147
148
149 #######################################################
150 # Plugin configuration
151 def setup(session, *args, **kwargs):
152         try:
153                 session.open(SeriesPluginConfiguration)
154         except Exception as e:
155                 splog(_("SeriesPlugin setup exception ") + str(e))
156                 #exc_type, exc_value, exc_traceback = sys.exc_info()
157                 #splog( exc_type, exc_value, exc_traceback )
158
159
160 #######################################################
161 # Event Info
162 def info(session, service=None, event=None, *args, **kwargs):
163         if config.plugins.seriesplugin.enabled.value:
164                 try:
165                         session.open(SeriesPluginInfoScreen, service, event)
166                 except Exception as e:
167                         splog(_("SeriesPlugin info exception ") + str(e))
168                         #exc_type, exc_value, exc_traceback = sys.exc_info()
169                         #splog( exc_type, exc_value, exc_traceback )
170
171
172 #######################################################
173 # Extensions menu
174 def sp_extension(session, *args, **kwargs):
175         if config.plugins.seriesplugin.enabled.value:
176                 try:
177                         if session:
178                                 session.open(SeriesPluginInfoScreen)
179                 except Exception as e:
180                         splog(_("SeriesPlugin extension exception ") + str(e))
181
182
183 #######################################################
184 # Channel menu
185 def channel(session, service=None, *args, **kwargs):
186         if config.plugins.seriesplugin.enabled.value:
187                 try:
188                         from enigma import eServiceCenter
189                         info = eServiceCenter.getInstance().info(service)
190                         event = info.getEvent(service)
191                         session.open(SeriesPluginInfoScreen, service, event)
192                 except Exception as e:
193                         splog(_("SeriesPlugin extension exception ") + str(e))
194
195
196 #######################################################
197 # Timer
198 def checkTimers(session, *args, **kwargs):
199         runIndependent()
200
201
202 #######################################################
203 # Movielist menu rename
204 def movielist_rename(session, service, services=None, *args, **kwargs):
205         if config.plugins.seriesplugin.enabled.value:
206                 try:
207                         if services:
208                                 if not isinstance(services, list):
209                                         services = [services]   
210                         else:
211                                 services = [service]
212                         SeriesPluginRenamer(session, services)
213                 except Exception as e:
214                         splog(_("SeriesPlugin renamer exception ") + str(e))
215
216
217 #######################################################
218 # Movielist menu info
219 def movielist_info(session, service, *args, **kwargs):
220         if config.plugins.seriesplugin.enabled.value:
221                 try:
222                         session.open(SeriesPluginInfoScreen, service)
223                 except Exception as e:
224                         splog(_("SeriesPlugin extension exception ") + str(e))
225
226
227 #######################################################
228 # Timer renaming
229 def renameTimer(timer, name, begin, end, *args, **kwargs):
230         if config.plugins.seriesplugin.enabled.value:
231                 try:
232                         SeriesPluginTimer(timer, name, begin, end)
233                 except Exception as e:
234                         splog(_("SeriesPlugin label exception ") + str(e))
235
236
237 # For compatibility reasons
238 def modifyTimer(timer, name, *args, **kwargs):
239         if config.plugins.seriesplugin.enabled.value:
240                 splog("SeriesPlugin modifyTimer is deprecated - Update Your AutoTimer!")
241                 try:
242                         SeriesPluginTimer(timer, name or timer.name, timer.begin, timer.end)
243                 except Exception as e:
244                         splog(_("SeriesPlugin label exception ") + str(e))
245
246
247 # For compatibility reasons
248 def labelTimer(timer, begin=None, end=None, *args, **kwargs):
249         if config.plugins.seriesplugin.enabled.value:
250                 splog("SeriesPlugin labelTimer is deprecated - Update Your AutoTimer!")
251                 try:
252                         SeriesPluginTimer(timer, timer.name, timer.begin, timer.end)
253                 except Exception as e:
254                         splog(_("SeriesPlugin label exception ") + str(e))
255
256
257 #######################################################
258 # Plugin main function
259 def Plugins(**kwargs):
260         descriptors = []
261         
262         #TODO icon
263         descriptors.append( PluginDescriptor(
264                                                                                         name = NAME + " " + _("Setup"),
265                                                                                         description = NAME + " " + _("Setup"),
266                                                                                         where = PluginDescriptor.WHERE_PLUGINMENU,
267                                                                                         fnc = setup,
268                                                                                         needsRestart = False) )
269         
270         if config.plugins.seriesplugin.enabled.value:
271                 
272                 overwriteAutoTimer()
273                 
274                 descriptors.append( PluginDescriptor(
275                                                                                                         #where = PluginDescriptor.WHERE_SESSIONSTART,
276                                                                                                         where = PluginDescriptor.WHERE_AUTOSTART,
277                                                                                                         needsRestart = False,
278                                                                                                         fnc = start) )
279
280                 if config.plugins.seriesplugin.menu_info.value:
281                         descriptors.append( PluginDescriptor(
282                                                                                                         name = SHOWINFO,
283                                                                                                         description = SHOWINFO,
284                                                                                                         where = PluginDescriptor.WHERE_EVENTINFO,
285                                                                                                         needsRestart = False,
286                                                                                                         fnc = info) )
287
288                 if config.plugins.seriesplugin.menu_extensions.value:
289                         descriptors.append(PluginDescriptor(
290                                                                                                         name = SHOWINFO,
291                                                                                                         description = SHOWINFO,
292                                                                                                         where = PluginDescriptor.WHERE_EXTENSIONSMENU,
293                                                                                                         fnc = sp_extension,
294                                                                                                         needsRestart = False) )
295                 
296                 if config.plugins.seriesplugin.check_timer_list.value:
297                         descriptors.append(PluginDescriptor(
298                                                                                                         name = CHECKTIMERS,
299                                                                                                         description = CHECKTIMERS,
300                                                                                                         where = PluginDescriptor.WHERE_EXTENSIONSMENU,
301                                                                                                         fnc = checkTimers,
302                                                                                                         needsRestart = False) )
303                 
304                 if config.plugins.seriesplugin.menu_movie_info.value:
305                         descriptors.append( PluginDescriptor(
306                                                                                                         name = SHOWINFO,
307                                                                                                         description = SHOWINFO,
308                                                                                                         where = PluginDescriptor.WHERE_MOVIELIST,
309                                                                                                         fnc = movielist_info,
310                                                                                                         needsRestart = False) )
311                 
312                 if config.plugins.seriesplugin.menu_movie_rename.value:
313                         descriptors.append( PluginDescriptor(
314                                                                                                         name = RENAMESERIES,
315                                                                                                         description = RENAMESERIES,
316                                                                                                         where = PluginDescriptor.WHERE_MOVIELIST,
317                                                                                                         fnc = movielist_rename,
318                                                                                                         needsRestart = False) )
319                 
320                 if config.plugins.seriesplugin.menu_channel.value:
321                         try:
322                                 descriptors.append( PluginDescriptor(
323                                                                                                         name = SHOWINFO,
324                                                                                                         description = SHOWINFO,
325                                                                                                         where = PluginDescriptor.WHERE_CHANNEL_CONTEXT_MENU,
326                                                                                                         fnc = channel,
327                                                                                                         needsRestart = False) )
328                         except:
329                                 addSeriesPlugin(WHERE_CHANNELMENU, SHOWINFO)
330                 
331                 if config.plugins.seriesplugin.menu_epg.value:
332                         addSeriesPlugin(WHERE_EPGMENU, SHOWINFO)
333
334         return descriptors
335
336
337 #######################################################
338 # Override EPGSelection enterDateTime
339 EPGSelection_enterDateTime = None
340 #EPGSelection_openOutdatedEPGSelection = None
341 def SPEPGSelectionInit():
342         print "SeriesPlugin override EPGSelection"
343         global EPGSelection_enterDateTime #, EPGSelection_openOutdatedEPGSelection
344         if EPGSelection_enterDateTime is None: # and EPGSelection_openOutdatedEPGSelection is None:
345                 from Screens.EpgSelection import EPGSelection
346                 EPGSelection_enterDateTime = EPGSelection.enterDateTime
347                 EPGSelection.enterDateTime = enterDateTime
348                 #EPGSelection_openOutdatedEPGSelection = EPGSelection.openOutdatedEPGSelection
349                 #EPGSelection.openOutdatedEPGSelection = openOutdatedEPGSelection
350                 EPGSelection.SPcloseafterfinish = closeafterfinish
351
352 def SPEPGSelectionUndo():
353         print "SeriesPlugin undo override EPGSelection"
354         global EPGSelection_enterDateTime #, EPGSelection_openOutdatedEPGSelection
355         if EPGSelection_enterDateTime: # and EPGSelection_openOutdatedEPGSelection:
356                 from Screens.EpgSelection import EPGSelection
357                 EPGSelection.enterDateTime = EPGSelection_enterDateTime
358                 EPGSelection_enterDateTime = None
359                 #EPGSelection.openOutdatedEPGSelection = EPGSelection_openOutdatedEPGSelection
360                 #EPGSelection_openOutdatedEPGSelection = None
361
362 def enterDateTime(self):
363         from Screens.EpgSelection import EPG_TYPE_SINGLE,EPG_TYPE_MULTI,EPG_TYPE_SIMILAR
364         event = self["Event"].event
365         if self.type == EPG_TYPE_SINGLE:
366                 service = self.currentService
367         elif self.type == EPG_TYPE_MULTI:       
368                 service = self.services
369         elif self.type == EPG_TYPE_SIMILAR:
370                 service = self.currentService
371         if service and event:
372                 self.session.openWithCallback(self.SPcloseafterfinish, SeriesPluginInfoScreen, service, event) 
373                 return
374         EPGSelection_enterDateTime(self)
375
376 #def openOutdatedEPGSelection(self, reason=None):
377 #       if reason == 1:
378 #               EPGSelection_enterDateTime(self)
379
380
381 #######################################################
382 # Override ChannelContextMenu
383 ChannelContextMenu__init__ = None
384 def SPChannelContextMenuInit():
385         print "[SeriesPlugin] override ChannelContextMenu.__init__"
386         global ChannelContextMenu__init__
387         if ChannelContextMenu__init__ is None:
388                 from Screens.ChannelSelection import ChannelContextMenu
389                 ChannelContextMenu__init__ = ChannelContextMenu.__init__
390                 ChannelContextMenu.__init__ = SPChannelContextMenu__init__
391                 ChannelContextMenu.SPchannelShowSeriesInfo = channelShowSeriesInfo
392                 ChannelContextMenu.SPcloseafterfinish = closeafterfinish
393
394 def SPChannelContextMenuUndo():
395         print "[SeriesPlugin] override ChannelContextMenu.__init__"
396         global ChannelContextMenu__init__
397         if ChannelContextMenu__init__:
398                 from Screens.ChannelSelection import ChannelContextMenu
399                 ChannelContextMenu.__init__ = ChannelContextMenu__init__
400                 ChannelContextMenu__init__ = None
401
402 def SPChannelContextMenu__init__(self, session, csel):
403         from Components.ChoiceList import ChoiceEntryComponent
404         from Screens.ChannelSelection import MODE_TV
405         from Tools.BoundFunction import boundFunction
406         from enigma import eServiceReference
407         ChannelContextMenu__init__(self, session, csel)
408         current = csel.getCurrentSelection()
409         current_sel_path = current.getPath()
410         current_sel_flags = current.flags
411         if csel.mode == MODE_TV and not (current_sel_path or current_sel_flags & (eServiceReference.isDirectory|eServiceReference.isMarker)):
412                 self["menu"].list.insert(0, ChoiceEntryComponent(text=(SHOWINFO, boundFunction(self.SPchannelShowSeriesInfo))))
413
414 def channelShowSeriesInfo(self):
415         splog( "[SeriesPlugin] channelShowSeriesInfo ")
416         if config.plugins.seriesplugin.enabled.value:
417                 try:
418                         from enigma import eServiceCenter
419                         service = self.csel.servicelist.getCurrent()
420                         info = eServiceCenter.getInstance().info(service)
421                         event = info.getEvent(service)
422                         self.session.openWithCallback(self.SPcloseafterfinish, SeriesPluginInfoScreen, service, event)
423                 except Exception as e:
424                         splog(_("SeriesPlugin info exception ") + str(e))
425
426 def closeafterfinish(self, retval=None):
427         self.close()
428
429
430 #######################################################
431 # Add / Remove menu functions
432 def addSeriesPlugin(menu, title, fnc=None):
433         # Add to menu
434         if( menu == WHERE_EPGMENU ):
435                 SPEPGSelectionInit()
436         elif( menu == WHERE_CHANNELMENU ):
437                 try:
438                         SPChannelContextMenuInit()
439                 except:
440                         addSeriesPlugin(PluginDescriptor.WHERE_CHANNEL_CONTEXT_MENU, SHOWINFO, fnc)
441         else:
442                 from Components.PluginComponent import plugins
443                 if plugins:
444                         for p in plugins.getPlugins( where = menu ):
445                                 if p.name == title:
446                                         # Plugin is already in menu
447                                         break
448                         else:
449                                 # Plugin not in menu - add it
450                                 plugin = PluginDescriptor(
451                                                                                                                                 name = title,
452                                                                                                                                 description = title,
453                                                                                                                                 where = menu,
454                                                                                                                                 needsRestart = False,
455                                                                                                                                 fnc = fnc)
456                                 if menu in plugins.plugins:
457                                         plugins.plugins[ menu ].append(plugin)
458
459
460 def removeSeriesPlugin(menu, title):
461         # Remove from menu
462         if( menu == WHERE_EPGMENU ):
463                 SPEPGSelectionUndo()
464         elif( menu == WHERE_CHANNELMENU ):
465                 try:
466                         SPChannelContextMenuUndo()
467                 except:
468                         removeSeriesPlugin(PluginDescriptor.WHERE_CHANNEL_CONTEXT_MENU, SHOWINFO)
469         else:
470                 from Components.PluginComponent import plugins
471                 if plugins:
472                         for p in plugins.getPlugins( where = menu ):
473                                 if p.name == title:
474                                         plugins.plugins[ menu ].remove(p)
475                                         break
476
477
478 #######################################################
479 # Overwrite AutoTimer support functions
480
481 try:
482         from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
483         #from Plugins.Extensions.AutoTimer.plugin import autotimer as AutoTimer
484 except:
485         AutoTimer = None
486
487 ATmodifyTimer = None
488 ATcheckSimilarity = None
489
490
491 def overwriteAutoTimer():
492         try:
493                 global ATmodifyTimer, ATcheckSimilarity
494                 if AutoTimer:
495                         if ATmodifyTimer is None:
496                                 # Backup original function
497                                 ATmodifyTimer = AutoTimer.modifyTimer
498                                 # Overwrite function
499                                 AutoTimer.modifyTimer = SPmodifyTimer
500                         if ATcheckSimilarity is None:
501                                 # Backup original function
502                                 ATcheckSimilarity = AutoTimer.checkSimilarity
503                                 # Overwrite function
504                                 AutoTimer.checkSimilarity = SPcheckSimilarity
505         except:
506                 splog("SeriesPlugin found old AutoTimer")
507
508
509 def recoverAutoTimer():
510         try:
511                 global ATmodifyTimer, ATcheckSimilarity
512                 if AutoTimer:
513                         if ATmodifyTimer:
514                                 AutoTimer.modifyTimer = ATmodifyTimer
515                                 ATmodifyTimer = None
516                         if ATcheckSimilarity:
517                                 AutoTimer.checkSimilarity = ATcheckSimilarity
518                                 ATcheckSimilarity = None
519         except:
520                 splog("SeriesPlugin found old AutoTimer")
521
522
523 #######################################################
524 # Customized support functions
525
526 from difflib import SequenceMatcher
527 from ServiceReference import ServiceReference
528
529 def SPmodifyTimer(self, timer, name, shortdesc, begin, end, serviceref, eit=None):
530         # Never overwrite existing names, You will lose Your series informations
531         #timer.name = name
532         # Only overwrite non existing descriptions
533         timer.description = timer.description or shortdesc
534         timer.begin = int(begin)
535         timer.end = int(end)
536         timer.service_ref = ServiceReference(serviceref)
537         if eit:
538                 timer.eit = eit
539
540 def SPcheckSimilarity(self, timer, name1, name2, shortdesc1, shortdesc2, extdesc1, extdesc2, force=False):
541         # Check if the new title is part of the existing one
542         foundTitle = name1 in name2 or name2 in name1
543         
544         if timer.searchForDuplicateDescription > 0 or force:
545                 foundShort = (shortdesc1 in shortdesc2 or shortdesc2 in shortdesc1) if (timer.searchForDuplicateDescription > 0 or force) else True
546                 
547                 # NOTE: only check extended if short description already is a match because otherwise
548                 # it won't evaluate to True anyway
549                 if (timer.searchForDuplicateDescription > 0 or force) and foundShort and extdesc1 != extdesc2:
550                         # Some channels indicate replays in the extended descriptions
551                         # If the similarity percent is higher then 0.8 it is a very close match
552                         #if timer.series_labeling and (extdesc1 == "" or extdesc2 == ""):
553                         #       foundExt = True
554                         #else:
555                         foundExt = ( 0.8 < SequenceMatcher(lambda x: x == " ",extdesc1, extdesc2).ratio() )
556                 else:
557                         foundExt = True
558         else:
559                 foundShort = True
560                 foundExt = True
561         
562         return foundTitle and foundShort and foundExt