SeriesPlugin: 1.5.8 Fixed encoding, popups, channel list integration
[enigma2-plugins.git] / seriesplugin / src / Identifiers / Wunschliste.py
1 # -*- coding: utf-8 -*-
2 # by betonme @2012
3
4 # Imports
5 from Components.config import config
6
7 from Tools.BoundFunction import boundFunction
8
9 from urllib import urlencode
10
11 from HTMLParser import HTMLParser
12
13 from datetime import datetime
14
15 import re
16 from sys import maxint
17
18 # Internal
19 from Plugins.Extensions.SeriesPlugin.IdentifierBase import IdentifierBase
20 from Plugins.Extensions.SeriesPlugin.Channels import compareChannels
21 from Plugins.Extensions.SeriesPlugin.Logger import splog
22
23 from iso8601 import parse_date
24
25 import codecs
26 utf8_encoder = codecs.getencoder("utf-8")
27
28
29 # Constants
30 SERIESLISTURL     = "http://www.wunschliste.de/ajax/search_dropdown.pl?"
31 EPISODEIDURLPRINT = "http://www.wunschliste.de/epg_print.pl?"
32
33 # (Season.Episode) - EpisodeTitle
34 # (21.84) Folge 4985
35 # (105) Folge 105
36 # (4.11/4.11) Mama ist die Beste/Rund um die Uhr
37 # Galileo: Die schaerfste Chili der Welt
38 # Galileo: Jumbo auf Achse: Muelltonnenkoch
39 # Gute Zeiten, schlechte Zeiten: Folgen 4985 - 4988 (21.84) - Sa 05.05., 11.00:00 Uhr / RTL
40 #CompiledRegexpPrintTitle = re.compile( '(\(.*\) )?(.+)')
41
42 CompiledRegexpEpisode = re.compile( '((\d+)[\.x])?(\d+)')
43
44
45 def str_to_utf8(s):
46         # Convert a byte string with unicode escaped characters
47         splog("WL: str_to_utf8: s: ", repr(s))
48         unicode_str = s.decode('unicode-escape')
49         splog("WL: str_to_utf8: s: ", repr(unicode_str))
50         # Python 2.x can't convert the special chars nativly
51         utf8_str = utf8_encoder(unicode_str)[0]
52         splog("WL: str_to_utf8: s: ", repr(utf8_str))
53         return utf8_str
54
55
56 class WLPrintParser(HTMLParser):
57         def __init__(self):
58                 HTMLParser.__init__(self)
59                 self.tr= False
60                 self.td= False
61                 self.data = []
62                 self.list = []
63
64         def handle_starttag(self, tag, attributes):
65                 if tag == 'td':
66                         self.td= True
67                 elif tag == 'tr':
68                         self.tr= True
69
70         def handle_endtag(self, tag):
71                 if tag == 'td':
72                         self.td= False
73                 elif tag == 'tr':
74                         self.tr= False
75                         self.list.append(self.data)
76                         self.data= []
77
78         def handle_data(self, data):
79                 if self.tr and self.td:
80                         self.data.append(data)
81
82
83 class Wunschliste(IdentifierBase):
84         def __init__(self):
85                 IdentifierBase.__init__(self)
86
87         @classmethod
88         def knowsToday(cls):
89                 return True
90
91         @classmethod
92         def knowsFuture(cls):
93                 return True
94
95         def getEpisode(self, name, begin, end=None, service=None, channels=[]):
96                 # On Success: Return a single season, episode, title tuple
97                 # On Failure: Return a empty list or String or None
98                 
99                 self.begin = begin
100                 self.end = end
101                 self.service = service
102                 self.channels = channels
103                 
104                 self.knownids = []
105                 self.returnvalue = None
106                 
107                 # Check preconditions
108                 if not name:
109                         splog(_("Skip Wunschliste: No show name specified"))
110                         return _("Skip Wunschliste: No show name specified")
111                 if not begin:
112                         splog(_("Skip Wunschliste: No begin timestamp specified"))
113                         return _("Skip Wunschliste: No begin timestamp specified")
114                 
115                 splog("WunschlistePrint getEpisode")
116                 
117                 while name:     
118                         ids = self.getSeries(name)
119                         
120                         while ids:
121                                 idserie = ids.pop()
122                                 
123                                 if idserie and len(idserie) == 2:
124                                         id, idname = idserie
125                                         
126                                         # Handle encodings
127                                         self.series = str_to_utf8(idname)
128                                         
129                                         result = self.getNextPage( id )
130                                         if result:
131                                                 return result
132                                         
133                         else:
134                                 name = self.getAlternativeSeries(name)
135                 
136                 else:
137                         return ( self.returnvalue or _("No matching series found") )
138
139         def getSeries(self, name):
140                 #url = SERIESLISTURL + urlencode({ 'q' : re.sub("[^a-zA-Z0-9-*]", " ", name) })
141                 url = SERIESLISTURL + urlencode({ 'q' : name })
142                 data = self.getPage( url )
143                 
144                 if data and isinstance(data, basestring):
145                         data = self.parseSeries(data)
146                         self.doCache(url, data)
147                 
148                 if data and isinstance(data, list):
149                         splog("WunschlistePrint ids", data)
150                         return self.filterKnownIds(data)
151
152         def parseSeries(self, data):
153                 serieslist = []
154                 for line in data.splitlines():
155                         values = line.split("|")
156                         if len(values) == 4:
157                                 idname, countryyear, id, temp = values
158                                 splog(id, idname)
159                                 serieslist.append( (id, idname) )
160                         else:
161                                 splog("WunschlistePrint: ParseError: " + str(line))
162                 serieslist.reverse()
163                 return serieslist
164
165         def parseNextPage(self, data):
166                 # Handle malformed HTML issues
167                 #data = data.replace('"','&')
168                 data = data.replace('&','&')
169                 parser = WLPrintParser()
170                 parser.feed(data)
171                 #splog(parser.list)
172                 return parser.list
173
174         def getNextPage(self, id):
175                 splog("WunschlistePrint getNextPage")
176                 
177                 url = EPISODEIDURLPRINT + urlencode({ 's' : id })
178                 data = self.getPage( url )
179                 
180                 if data and isinstance(data, basestring):
181                         data = self.parseNextPage(data)
182                         self.doCache(url, data)
183                 
184                 if data and isinstance(data, list):
185                         trs = data
186                         
187                         yepisode = None
188                         ydelta = maxint
189                         year = str(datetime.today().year)
190                         
191                         for tds in trs:
192                                 if tds and len(tds) >= 5:
193                                         #print tds
194                                         xchannel, xday, xdate, xbegin, xend = tds[:5]
195                                         xtitle = "".join(tds[4:])
196                                         xbegin   = datetime.strptime( xdate+year+xbegin, "%d.%m.%Y%H.%M Uhr" )
197                                         #xend     = datetime.strptime( xdate+xend, "%d.%m.%Y%H.%M Uhr" )
198                                         #splog(xchannel, xdate, xbegin, xend, xtitle)
199                                         #splog(datebegin, xbegin, abs((datebegin - xbegin)))
200                                         
201                                         #Py2.6
202                                         delta = abs(self.begin - xbegin)
203                                         delta = delta.seconds + delta.days * 24 * 3600
204                                         #Py2.7 delta = abs(self.begin - xbegin).total_seconds()
205                                         splog(self.begin, xbegin, delta, int(config.plugins.seriesplugin.max_time_drift.value)*60)
206                                         
207                                         if delta <= int(config.plugins.seriesplugin.max_time_drift.value) * 60:
208                                                 
209                                                 if compareChannels(self.channels, xchannel, self.service):
210                                                 
211                                                         if delta < ydelta:
212                                                                 
213                                                                 print len(tds), tds
214                                                                 if len(tds) >= 7:
215                                                                         xepisode, xtitle = tds[5:7]
216                                                                 
217                                                                         if xepisode:
218                                                                                 result = CompiledRegexpEpisode.search(xepisode)
219                                                                                 
220                                                                                 if result and len(result.groups()) >= 3:
221                                                                                         xseason = result and result.group(2) or "1"
222                                                                                         xepisode = result and result.group(3) or "0"
223                                                                                 else:
224                                                                                         xseason = "1"
225                                                                                         xepisode = "0"
226                                                                         else:
227                                                                                 xseason = "1"
228                                                                                 xepisode = "0"
229                                                                 
230                                                                 elif len(tds) == 6:
231                                                                         xtitle = tds[5]
232                                                                         xseason = "0"
233                                                                         xepisode = "0"
234                                                                 
235                                                                 # Handle encodings
236                                                                 xtitle = str_to_utf8(xtitle)
237                                                                 
238                                                                 yepisode = (xseason, xepisode, xtitle, self.series)
239                                                                 ydelta = delta
240                                                         
241                                                         else: #if delta >= ydelta:
242                                                                 break
243                                                 
244                                                 else:
245                                                         self.returnvalue = _("Check the channel name")
246                                                 
247                                         elif yepisode:
248                                                 break
249                         
250                         if yepisode:
251                                 return ( yepisode )