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