1# -*- coding: UTF-8 -*- 2 3__revision__ = '$Id$' 4 5# Copyright (c) 2006-2011 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 2 of the License, or 10# (at your option) any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU Library General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program; if not, write to the Free Software 19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 20 21# You may use and distribute this software under the terms of the 22# GNU General Public License, version 2 or later 23 24import gutils 25import movie 26import string 27import re 28 29plugin_name = "Kino.de" 30plugin_description = "KINO.DE" 31plugin_url = "www.kino.de" 32plugin_language = _("German") 33plugin_author = "Michael Jahn" 34plugin_author_email = "<mikej06@hotmail.com>" 35plugin_version = "1.16" 36 37class Plugin(movie.Movie): 38 url_to_use_base = 'http://www.kino.de/' 39 url_to_use = url_to_use_base + 'kinofilm/' 40 url_type = 'K' 41 42 def __init__(self, id): 43 self.encode='iso-8859-1' 44 elements = string.split(id, "_") 45 self.movie_id = elements[1] 46 if (elements[0] == "V"): 47 self.url_to_use_base = 'http://www.video.de/' 48 self.url_to_use = self.url_to_use_base + 'videofilm/' 49 self.url_type = 'V' 50 else: 51 self.url_to_use_base = 'http://www.kino.de/' 52 self.url_to_use = self.url_to_use_base + 'kinofilm/' 53 self.url_type = 'K' 54 self.url = self.url_to_use + str(self.movie_id) 55 56 def initialize(self): 57 if self.url_type == 'K': 58 url = self.url_to_use + string.replace(str(self.movie_id), '/', '/credits/') 59 self.creditspage = self.open_page(self.parent_window, url=url) 60 else: 61 self.creditspage = '' 62 videopageforkinourl = gutils.trim(self.page, 'class="videode"', 'Zum Film auf video.de') 63 if videopageforkinourl: 64 url = gutils.trim(videopageforkinourl, 'href="', '"') 65 self.videopage = self.open_page(self.parent_window, url=url) 66 else: 67 self.videopage = None 68 69 def get_image(self): 70 self.image_url = string.replace(string.replace(gutils.trim(self.page, '"picture":', ','), '"', ''), '\\', '') 71 if not self.image_url: 72 tmpdata = gutils.regextrim(self.page, '<div class="cover-area">', '</div>') 73 if tmpdata: 74 # video page 75 tmpdata = re.search('(http[:][/][/][^/]+[/]flbilder[/][^"\']+)', tmpdata) 76 if tmpdata: 77 self.image_url = tmpdata.group(1) 78 else: 79 # kino page 80 tmpdata = gutils.before(self.page, '<span style="line-height: 15px;">') 81 if tmpdata: 82 tmpparts = re.split('http://images.kino.de/s/', tmpdata) 83 if len(tmpparts) > 2: 84 self.image_url = 'http://images.kino.de/s/' + gutils.before(tmpparts[2], '"') 85 elif len(tmpparts) > 1: 86 self.image_url = 'http://images.kino.de/s/' + gutils.before(tmpparts[1], '"') 87 if not self.image_url and self.videopage: 88 tmpdata = gutils.regextrim(self.videopage, '<div class="cover-area">', '</div>') 89 if tmpdata: 90 # video page 91 tmpdata = re.search('(http[:][/][/][^/]+[/]flbilder[/][^"\']+)', tmpdata) 92 if tmpdata: 93 self.image_url = tmpdata.group(1) 94 95 96 def get_o_title(self): 97 self.o_title = gutils.regextrim(self.page, '(<p>Originaltitel[:] |Originaltitel<[^>]+>)', '(</tr>|</p>)') 98 if not self.o_title: 99 self.o_title = gutils.trim(self.page, '<h1(', ')') 100 if not self.o_title: 101 self.o_title = gutils.trim(self.page, '<div class="teaser">', '</') 102 if not self.o_title: 103 if self.videopage: 104 self.o_title = gutils.trim(self.videopage, '<p>Originaltitel: ', '</p>') 105 if not self.o_title: 106 self.o_title = gutils.regextrim(self.page, '<h1>', '(</h1>|</span>)') 107 108 def get_title(self): 109 self.title = gutils.trim(self.page, '<div class="teaser">', '</') 110 if not self.title: 111 self.title = gutils.regextrim(self.page, '<h1>', '(</h1>|</span>)') 112 113 def get_director(self): 114 self.director = gutils.trim(self.page, '<th>Regie:', '<th>') 115 if not self.director: 116 self.director = gutils.trim(self.creditspage, 'Regie:', '</li>') 117 118 def get_plot(self): 119 self.plot = gutils.trim(self.page, '<div class="yui-content">', '<div class="footer">') 120 if not self.plot: 121 # kino page 122 self.plot = gutils.after(gutils.trim(self.page, 'Filmhandlung & Hintergrund', '</div>'), '</h2>') 123 if not self.plot and self.videopage: 124 self.plot = gutils.trim(self.videopage, '<div class="yui-content">', '<div class="footer">') 125 if self.plot: 126 # video page 127 self.plot = re.sub('<script type="text/javascript">[^<]+</script>', '', self.plot) 128 self.plot = string.replace(self.plot, '>Großansicht</a>', '>') 129 self.plot = string.replace(self.plot, '>Schließen</a>', '>') 130 self.plot = string.replace(self.plot, '>zurück </a>', '>') 131 self.plot = string.replace(self.plot, '>1</a>', '>') 132 self.plot = string.replace(self.plot, '> weiter</a>', '>') 133 self.plot = string.replace(self.plot, '</h4>', '\n') 134 self.plot = gutils.clean(self.plot) 135 compiledmultiline = re.compile(r'^[^(]+[(]Foto[:][^)]+[)][ ]*$', re.MULTILINE) 136 self.plot = compiledmultiline.sub('', self.plot) 137 compiledmultiline = re.compile(r"(^\s+$|^\s*//\s*$)", re.MULTILINE) 138 self.plot = compiledmultiline.sub('', self.plot) 139 compiledmultiline = re.compile("^[\n]+$", re.MULTILINE) 140 self.plot = compiledmultiline.sub("\n", self.plot) 141 142 def get_year(self): 143 self.year = '' 144 tmp = gutils.trim(gutils.trim(self.page, '"releaseDate":', ','), ':"', '"') 145 if tmp: 146 self.year = tmp 147 else: 148 tmp = gutils.trim(self.page, '<div class="description">', '</div>') 149 if tmp: 150 searchyearandcountry = re.search('([0-9]{4})<br', tmp) 151 if searchyearandcountry: 152 self.year = searchyearandcountry.group(1) 153 if not self.year: 154 tmp = gutils.trim(self.page, '<span class="standardsmall"><strong>', '<br') 155 if tmp: 156 tmp = gutils.trim(tmp, '<strong>', '</strong>') 157 if tmp: 158 srchyear = re.search('([0-9]{4})', tmp) 159 if srchyear: 160 self.year = srchyear.group(1) 161 if not self.year and self.videopage: 162 tmp = gutils.trim(self.videopage, '<div class="description">', '</div>') 163 if tmp: 164 searchyearandcountry = re.search('([0-9]{4})<br', tmp) 165 if searchyearandcountry: 166 self.year = searchyearandcountry.group(1) 167 168 def get_runtime(self): 169 self.runtime = gutils.trim(self.page, '"runtime":', ',') 170 if not self.runtime: 171 srchresult = re.search('Laufzeit: ([0-9]+)[ \t]Min[.]<', self.page) 172 if srchresult != None: 173 self.runtime = srchresult.group(1) 174 if not self.runtime: 175 srchresult = re.search('>([0-9]+)[ \t]Min[.]<', self.page) 176 if srchresult != None: 177 self.runtime = srchresult.group(1) 178 if not self.runtime and self.videopage: 179 srchresult = re.search('Laufzeit: ([0-9]+)[ \t]Min[.]<', self.videopage) 180 if srchresult != None: 181 self.runtime = srchresult.group(1) 182 183 def get_genre(self): 184 self.genre = string.replace(gutils.trim(self.page, '"genre":', ','), '"', '') 185 if not self.genre: 186 self.genre = gutils.trim(self.page,'<p class="genre">', '</p>') 187 if not self.genre: 188 self.genre = gutils.trim(self.page, 'title="Zur Genreliste: Drama">', '<') 189 if not self.genre and self.videopage: 190 self.genre = gutils.trim(self.videopage,'<p class="genre">', '</p>') 191 192 def get_cast(self): 193 self.cast = '' 194 tmp = gutils.regextrim(self.page, '<th>Darsteller:', '(<th>[^&]|</table>)') 195 if tmp: 196 tmpparts = string.split(tmp, '<a href="/star/') 197 for tmppart in tmpparts[1:]: 198 name = gutils.trim(tmppart, '>', '<') 199 role = gutils.trim(tmppart, '>als ', '<') 200 if name: 201 if role: 202 self.cast = self.cast + name + _(' as ') + role + '\n' 203 else: 204 self.cast = self.cast + name + '\n' 205 if not self.cast: 206 elements = re.split('<h3>Darsteller</h3>', self.page) 207 for element in elements[1:]: 208 actor = gutils.trim(element, 'itemprop="name">', '<') 209 if actor: 210 self.cast = self.cast + actor 211 role = gutils.trim(element, 'itemprop="title">', '<') 212 if role and role != 'Darsteller': 213 self.cast = self.cast + _(' as ') + role 214 self.cast = self.cast + '\n' 215 216 def get_classification(self): 217 self.classification = string.replace(gutils.trim(self.page, '"fsk":', ','), '"', '') 218 if not self.classification: 219 self.classification = gutils.regextrim(self.page, 'FSK: ', '<') 220 if not self.classification and self.videopage: 221 self.classification = gutils.regextrim(self.videopage, 'FSK: ', '<') 222 223 def get_studio(self): 224 self.studio = '' 225 tmp = gutils.trim(self.page, '<div class="description">', '</div>') 226 if tmp: 227 tmp = gutils.trim(tmp, 'Regie:', '</p>') 228 if tmp: 229 self.studio = string.replace(gutils.after(tmp, '<br/>'), 'Verleih: ', '') 230 if not self.studio: 231 self.studio = gutils.trim(self.page, 'Verleih: ', '<') 232 if not self.studio: 233 self.studio = gutils.trim(self.page, 'Verleih:', '</li>') 234 if not self.studio and self.videopage: 235 tmp = gutils.trim(self.videopage, '<div class="description">', '</div>') 236 if tmp: 237 tmp = gutils.trim(tmp, 'Regie:', '</p>') 238 if tmp: 239 self.studio = string.replace(gutils.after(tmp, '<br/>'), 'Verleih: ', '') 240 241 def get_o_site(self): 242 self.o_site = "" 243 244 def get_site(self): 245 self.site = self.url_to_use + self.movie_id 246 247 def get_trailer(self): 248 self.trailer = '' 249 trailerparts = re.split('href="/trailer-und-bilder/film', self.page) 250 if len(trailerparts) > 1: 251 for trailerpart in trailerparts[1:]: 252 trailermatch = re.search('Trailer[ ]*</p>', trailerpart) 253 if trailermatch: 254 self.trailer = self.url_to_use_base + 'trailer-und-bilder/film' + gutils.before(trailerpart, '"') 255 break 256 if not self.trailer and self.url_type == 'K': 257 self.trailer = self.url_to_use + string.replace(str(self.movie_id), '/', '/trailer/') 258 259 def get_country(self): 260 self.country = '' 261 tmp = gutils.trim(self.page, '<div class="description">', '</div>') 262 if tmp: 263 searchyearandcountry = re.search('([^>0-9]+)[0-9]{4}<br', tmp) 264 if searchyearandcountry: 265 self.country = searchyearandcountry.group(1) 266 if not self.country: 267 tmp = gutils.trim(self.page, '<span class="standardsmall"><strong>', '<br') 268 if tmp: 269 tmp = gutils.trim(tmp, '<strong>', '</strong>') 270 if tmp: 271 self.country = gutils.before(tmp, ' ') 272 if not self.country: 273 self.country = gutils.trim(self.page, 'itemprop="contentLocation">', '<') 274 if not self.country and self.videopage: 275 tmp = gutils.trim(self.videopage, '<div class="description">', '</div>') 276 if tmp: 277 searchyearandcountry = re.search('([^>0-9]+)[0-9]{4}<br', tmp) 278 if searchyearandcountry: 279 self.country = searchyearandcountry.group(1) 280 281 def get_rating(self): 282 self.rating = 0 283 tmp = gutils.trim(self.page, '<h4>Filmbewertung</h4>', '</script>') 284 if tmp: 285 matched = re.search('ratingBar.setValue[(]([0-9]+)[)]', tmp) 286 if matched: 287 try: 288 self.rating = round(int(matched.group(1)) / 10.0, 0) 289 except: 290 pass 291 292 def get_notes(self): 293 self.notes = "" 294 tmp_notes = gutils.clean(gutils.trim(self.page, "<strong>Sprachen:</strong>", "</p>")) 295 if tmp_notes != "": 296 self.notes = self.notes + "Sprachen:\n" + tmp_notes + "\n\n" 297 tmp_notes = gutils.clean(gutils.trim(self.page, "<strong>Untertitel:</strong>", "</p>")) 298 if tmp_notes != "": 299 self.notes = self.notes + "Untertitel:\n" + tmp_notes + "\n\n" 300 tmp_notes = gutils.clean(gutils.trim(self.page, "<strong>Tonformat:</strong>", "</p>")) 301 if tmp_notes != "": 302 self.notes = self.notes + "Tonformat:\n" + tmp_notes + "\n\n" 303 tmp_notes = gutils.clean(gutils.trim(self.page, "<strong>Bildformat:</strong>", "</p>")) 304 if tmp_notes != "": 305 self.notes = self.notes + "Bildformat:\n" + tmp_notes + "\n\n" 306 tmp_notes = gutils.clean(gutils.trim(self.page, "<strong>EAN</strong>", "</p>")) 307 if tmp_notes != "": 308 self.notes = self.notes + "EAN:\n" + tmp_notes + "\n\n" 309 310 def get_screenplay(self): 311 self.screenplay = gutils.regextrim(self.page, '<th>Buch:', '<th>') 312 if not self.screenplay: 313 self.screenplay= gutils.trim(self.creditspage, 'Drehbuch: ', '</tr>') 314 if not self.screenplay: 315 elements = re.split('<h3>Drehbuch</h3>', self.page) 316 delimiter = '' 317 for element in elements[1:]: 318 self.screenplay = self.screenplay + delimiter + gutils.trim(element, 'itemprop="name">', '<') 319 delimiter = ', ' 320 321 def get_cameraman(self): 322 self.cameraman = gutils.regextrim(self.page, '<th>Kamera:', '(<th>|</table>)') 323 if not self.cameraman: 324 self.cameraman= gutils.trim(self.creditspage, 'Kamera ', '</tr>') 325 if not self.cameraman: 326 elements = re.split('"function-title">Kamera</span>', self.page) 327 delimiter = '' 328 for element in elements[1:]: 329 self.cameraman = self.cameraman + delimiter + gutils.trim(element, 'itemprop="name">', '<') 330 delimiter = ', ' 331 332class SearchPlugin(movie.SearchMovie): 333 334 def __init__(self): 335 self.original_url_search = 'http://www.kino.de/suche/film?hitsPerPage=50&searchString=' 336 self.translated_url_search = 'http://www.kino.de/suche/film?hitsPerPage=50&searchString=' 337 self.encode='iso-8859-1' 338 self.remove_accents = False 339 340 def search(self,parent_window): 341 self.open_search(parent_window) 342 pagemovie = self.page 343 # 344 # Look for DVD and VHS 345 # 346 self.url = "http://www.kino.de/suche/video?hitsPerPage=50&searchString=" 347 self.open_search(parent_window) 348 self.page = pagemovie + self.page 349 350 return self.page 351 352 def get_searches(self): 353 elements1 = re.split('href="/kinofilm/', self.page) 354 elements1[0] = None 355 for element in elements1: 356 if element != None: 357 title = gutils.clean(gutils.trim(element,'>','</a>')) + string.replace(' (' + 358 gutils.clean(gutils.trim(element, '<p>', "<br />")) + ')', '()', '') 359 if title != ' ': 360 self.ids.append("K_" + re.sub('[?].*', '', gutils.before(element,'"'))) 361 self.titles.append('Kino: ' + title) 362 363 elements2 = re.split('href="http://www.video.de/videofilm/', self.page) 364 elements2[0] = None 365 for element in elements2: 366 if element != None: 367 title = gutils.clean(gutils.trim(element,'>','</a>')) + string.replace(' (' + 368 gutils.clean(gutils.trim(gutils.before(element, '</li>'), '<p>', "<br />")) + ')', '()', '') 369 if title != ' ': 370 id = re.sub('[?].*', '', gutils.before(element,'"')) 371 self.ids.append("V_" + id) 372 type = '' 373 if 'blu-ray-disc-kauf' in id: 374 type = ' (Bluray-Kauf)' 375 if 'blu-ray-disc-leih' in id: 376 type = ' (Bluray-Verleih)' 377 if 'dvd-leih' in id: 378 type = ' (DVD-Verleih)' 379 if 'dvd-kauf' in id: 380 type = ' (DVD-Kauf)' 381 self.titles.append('Video: ' + title + type) 382 383# 384# Plugin Test 385# 386class SearchPluginTest(SearchPlugin): 387 # 388 # Configuration for automated tests: 389 # dict { movie_id -> [ expected result count for original url, expected result count for translated url ] } 390 # 391 test_configuration = { 392 'Rocky Balboa' : [ 10, 10 ], 393 'Arahan' : [ 10, 10 ], 394 'Ein glückliches Jahr' : [ 4, 4 ] 395 } 396 397class PluginTest: 398 # 399 # Configuration for automated tests: 400 # dict { movie_id -> dict { arribute -> value } } 401 # 402 # value: * True/False if attribute only should be tested for any value 403 # * or the expected value 404 # 405 test_configuration = { 406 'K_rocky-balboa/96132.html' : { 407 'title' : 'Rocky Balboa', 408 'o_title' : 'Rocky Balboa', 409 'director' : 'Sylvester Stallone', 410 'plot' : True, 411 'cast' : 'Sylvester Stallone' + _(' as ') + 'Rocky Balboa\n\ 412Antonio Traver' + _(' as ') + 'Mason "The Line" Dixon\n\ 413Burt Young' + _(' as ') + 'Paulie\n\ 414Geraldine Hughes' + _(' as ') + 'Marie\n\ 415Milo Ventimiglia' + _(' as ') + 'Rocky Jr.\n\ 416James Francis Kelly III' + _(' as ') + 'Steps\n\ 417Tony Burton' + _(' as ') + 'Duke\n\ 418A.J. Benza' + _(' as ') + 'L.C.', 419 'country' : 'USA', 420 'genre' : 'Drama', 421 'classification' : '12', 422 'studio' : 'Fox', 423 'o_site' : False, 424 'site' : 'http://www.kino.de/kinofilm/rocky-balboa/96132.html', 425 'trailer' : 'http://www.kino.de/kinofilm/rocky-balboa/trailer/96132.html', 426 'year' : 2007, 427 'notes' : False, 428 'runtime' : 102, 429 'image' : True, 430 'rating' : False, 431 'cameraman' : 'J. Clark Mathis', 432 'screenplay' : 'Sylvester Stallone' 433 }, 434 'K_ein-glueckliches-jahr/28675.html' : { 435 'title' : 'Ein glückliches Jahr', 436 'o_title' : 'La bonne année', 437 'director' : 'Claude Lelouch', 438 'plot' : True, 439 'cast' : 'Lino Ventura\n\ 440Françoise Fabian\n\ 441Charles Gérard\n\ 442André Falcon', 443 'country' : 'Frankreich/Italien', 444 'genre' : 'Drama', 445 'classification' : '12', 446 'studio' : 'Columbia TriStar', 447 'o_site' : False, 448 'site' : 'http://www.kino.de/kinofilm/ein-glueckliches-jahr/28675.html', 449 'trailer' : 'http://www.kino.de/kinofilm/ein-glueckliches-jahr/trailer/28675.html', 450 'year' : 1973, 451 'notes' : False, 452 'runtime' : 115, 453 'image' : True, 454 'rating' : False, 455 'cameraman' : 'Jean Collomb', 456 'screenplay' : 'Claude Lelouch' 457 }, 458 'V_ein-glueckliches-jahr-dvd/85546.html' : { 459 'title' : 'Ein glückliches Jahr', 460 'o_title' : 'La bonne année', 461 'director' : 'Claude Lelouch', 462 'plot' : True, 463 'cast' : 'Lino Ventura\n\ 464Françoise Fabian\n\ 465Charles Gérard\n\ 466André Falcon', 467 'country' : 'Frankreich/Italien', 468 'genre' : 'Drama', 469 'classification' : 'ab 12', 470 'studio' : 'Black Hill Pictures', 471 'o_site' : False, 472 'site' : 'http://www.video.de/videofilm/ein-glueckliches-jahr-dvd/85546.html', 473 'trailer' : False, 474 'year' : 1973, 475 'notes' : 'Sprachen:\n\ 476Deutsch DD 2.0, Französisch DD 2.0\n\ 477\n\ 478Tonformat:\n\ 479Dolby Digital 2.0\n\ 480\n\ 481Bildformat:\n\ 4821:1,33/4:3', 483 'runtime' : 110, 484 'image' : True, 485 'rating' : False, 486 'cameraman' : 'Jean Collomb', 487 'screenplay' : 'Claude Lelouch' 488 }, 489 'V_arahan-vanilla-dvd/90405.html' : { 490 'title' : 'Arahan', 491 'o_title' : 'Arahan jangpung dae jakjeon', 492 'director' : 'Ryoo Seung-wan', 493 'plot' : True, 494 'cast' : 'Ryu Seung-beom' + _(' as ') + 'Sang-hwan\n\ 495Yoon So-yi' + _(' as ') + 'Wi-jin\n\ 496Ahn Sung-kee' + _(' as ') + 'Ja-woon\n\ 497Jung Doo-hong' + _(' as ') + 'Heuk-woon\n\ 498Yun Ju-sang' + _(' as ') + 'Mu-woon', 499 'country' : 'Südkorea', 500 'genre' : 'Action/ Komödie', 501 'classification' : 'ab 16', 502 'studio' : 'Splendid Film', 503 'o_site' : False, 504 'site' : 'http://www.video.de/videofilm/arahan-vanilla-dvd/90405.html', 505 'trailer' : False, 506 'year' : 2004, 507 'notes' : 'Sprachen:\n\ 508Deutsch DD 5.1\n\ 509\n\ 510Tonformat:\n\ 511Dolby Digital 5.1\n\ 512\n\ 513Bildformat:\n\ 5141:1,78/16:9', 515 'runtime' : 108, 516 'image' : True, 517 'rating' : False, 518 'cameraman' : 'Lee Jun-gyu', 519 'screenplay' : 'Ryoo Seung-wan' 520 } 521 } 522