The branch, dharma has been updated
       via  2753c8bd6f0f114518cc773cdd2813c5e2468b35 (commit)
      from  4873b555c6bce15d4f4b995d4542ebb23d7b36db (commit)

- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/scripts;a=commit;h=2753c8bd6f0f114518cc773cdd2813c5e2468b35

commit 2753c8bd6f0f114518cc773cdd2813c5e2468b35
Author: amet <[email protected]>
Date:   Tue Mar 13 22:32:11 2012 +0400

    [script.game.whatthemovie] -v0.9.3
    
    0.9.3
    - Fix white shot (website changes)
    
    0.9.2
    - Multithreading background scraping of shots
    - Now showing overall-score in addition to featurefilms-score
    - now going back and forward through already scraped shots with 'back' and 
'random'
    - Code cleanups and improvements
    - Removed the need for mechanize-lib

diff --git a/script.game.whatthemovie/addon.xml 
b/script.game.whatthemovie/addon.xml
index 872c413..72d78ca 100644
--- a/script.game.whatthemovie/addon.xml
+++ b/script.game.whatthemovie/addon.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <addon id="script.game.whatthemovie"
        name="WhatTheMovie"
-       version="0.9.1"
+       version="0.9.3"
        provider-name="sphere, tadi, skiller2k1">
     <requires>
         <import addon="xbmc.python" version="1.0"/>
diff --git a/script.game.whatthemovie/changelog.txt 
b/script.game.whatthemovie/changelog.txt
index e083085..16506ca 100644
--- a/script.game.whatthemovie/changelog.txt
+++ b/script.game.whatthemovie/changelog.txt
@@ -1,3 +1,13 @@
+0.9.3
+- Fix white shot (website changes)
+
+0.9.2
+- Multithreading background scraping of shots
+- Now showing overall-score in addition to featurefilms-score
+- now going back and forward through already scraped shots with 'back' and 
'random'
+- Code cleanups and improvements
+- Removed the need for mechanize-lib
+
 0.9.1 
 - Bugfix (error if player has exactly 1 point)
 
diff --git a/script.game.whatthemovie/resources/language/English/strings.xml 
b/script.game.whatthemovie/resources/language/English/strings.xml
index 323b24c..2721585 100644
--- a/script.game.whatthemovie/resources/language/English/strings.xml
+++ b/script.game.whatthemovie/resources/language/English/strings.xml
@@ -25,7 +25,7 @@ Misc     = 3300-3349
     <string id="3102">Wrong: [B]%s[/B]</string>
     <string id="3103">Not logged in</string>
     <string id="3104">Logged in as user: [B]%s[/B]</string>
-    <string id="3105">Your score: [B]%s[/B]</string>
+    <string id="3105">Your score: [B]%s[/B] ([B]%s[/B])</string>
     <string id="3106">Solved [B][COLOR=ff008B00]%s[/COLOR][/B] times, first by 
[B]%s[/B]</string>
     <string id="3107">Not solved yet</string>
     <string id="3108">Shot ID: [B]%s[/B]</string>
diff --git a/script.game.whatthemovie/resources/language/German/strings.xml 
b/script.game.whatthemovie/resources/language/German/strings.xml
index 1bfb497..7055e68 100644
--- a/script.game.whatthemovie/resources/language/German/strings.xml
+++ b/script.game.whatthemovie/resources/language/German/strings.xml
@@ -25,7 +25,7 @@ Misc     = 3300-3349
     <string id="3102">Falsch: [B]%s[/B]</string>
     <string id="3103">Nicht eingeloggt</string>
     <string id="3104">Eingeloggt als: [B]%s[/B]</string>
-    <string id="3105">Deine Punkte: [B]%s[/B]</string>
+    <string id="3105">Deine Punkte: [B]%s[/B] ([B]%s[/B])</string>
     <string id="3106">[B][COLOR=ff008B00]%s[/COLOR][/B] mal gelöst. Erster: 
[B]%s[/B]</string>
     <string id="3107">Bisher ungelöst</string>
     <string id="3108">Shot ID: [B]%s[/B]</string>
diff --git a/script.game.whatthemovie/resources/lib/gui.py 
b/script.game.whatthemovie/resources/lib/gui.py
index 0c9a300..3d658dd 100644
--- a/script.game.whatthemovie/resources/lib/gui.py
+++ b/script.game.whatthemovie/resources/lib/gui.py
@@ -59,6 +59,7 @@ class GUI(xbmcgui.WindowXMLDialog):
     CID_LIST_STARS = 1017
     CID_PROGR_OWN_RATING = 1018
     CID_GROUP_RATING = 1016
+    CID_LABEL_PRELOADS = 1020
 
     # STRING_IDs
     #  Messages
@@ -140,6 +141,7 @@ class GUI(xbmcgui.WindowXMLDialog):
         self.getString = self.Addon.getLocalizedString
         self.getSetting = self.Addon.getSetting
         self.setSetting = self.Addon.setSetting
+        self.createPaths()
 
         # get controls
         self.button_guess = self.getControl(self.CID_BUTTON_GUESS)
@@ -163,6 +165,7 @@ class GUI(xbmcgui.WindowXMLDialog):
         self.group_rating = self.getControl(self.CID_GROUP_RATING)
         self.progr_avg_rating = self.getControl(self.CID_PROGR_AVG_RATING)
         self.progr_own_rating = self.getControl(self.CID_PROGR_OWN_RATING)
+        self.label_preloads = self.getControl(self.CID_LABEL_PRELOADS)
 
         # set control visibility depending on xbmc-addon settings
         self.hideLabels()
@@ -179,9 +182,11 @@ class GUI(xbmcgui.WindowXMLDialog):
         user_agent = 'XBMC-ADDON - %s - V%s' % (self.ADDON_ID,
                                                 self.ADDON_VERSION)
         self.Quiz = whatthemovie.WhatTheMovie(user_agent)
+        self.Quiz.setImagePath(xbmc.translatePath(self.cache_path))
         # try to login and get first random shot. If it fails exit
         try:
             self.login()
+            self.Quiz.start(callback=self.updatePreload)
             self.getShot('random')
         except Exception, error:
             self.errorMessage(self.getString(self.SID_ERROR_LOGIN),
@@ -274,6 +279,7 @@ class GUI(xbmcgui.WindowXMLDialog):
 
     def closeDialog(self):
         self.setWTMProperty('main_image', '')
+        self.Quiz.stop()
         self.close()
 
     def getShot(self, shot_request):
@@ -282,19 +288,17 @@ class GUI(xbmcgui.WindowXMLDialog):
         self.setWTMProperty('busy', 'loading')
         # hide label_status
         self.setWTMProperty('solved_status', 'inactive')
-        # scrape shot and download picture
+        # scrape shot
         try:
             self.shot = self.Quiz.getShot(shot_request)
             shot = self.shot
-            image_path = self.downloadPic(shot['image_url'],
-                                          shot['shot_id'])
             self.log('Got a shot: %s' % self.shot)
         except Exception, error:
             self.errorMessage(self.getString(self.SID_ERROR_SHOT),
                               str(error))
             self.setWTMProperty('busy', '')
             return
-        self._showShotImage(image_path)
+        self._showShotImage(shot['image_url'])
         self._showShotType(shot['shot_type'])
         self._showShotPostedBy(shot['posted_by'])
         self._showShotSolvedStatus(shot['solved'])
@@ -479,8 +483,14 @@ class GUI(xbmcgui.WindowXMLDialog):
             self.setWTMProperty('sotd', '')
 
     def _showUserScore(self, score):
-        score_string = self.getString(self.SID_YOUR_SCORE) % str(score)
-        self.label_score.setLabel(score_string)
+        ff_score_label = (self.getString(self.SID_YOUR_SCORE) \
+                          % (score['ff_score'], score['all_score']))
+        self.label_score.setLabel(ff_score_label)
+
+    def updatePreload(self, num_preloads):
+        # fixme(anyone): This needs a better place ;-)
+        label = 'Preloads : %s' % num_preloads
+        self.label_preloads.setLabel(label)
 
     def rateShot(self, shot_id, own_rating):
         if self.logged_in:
@@ -544,7 +554,12 @@ class GUI(xbmcgui.WindowXMLDialog):
             # clear solved_status
             self.setWTMProperty('solved_status', 'inactive')
             guess = keyboard.getText().decode('utf8')
-            gives_point = (self.shot['gives_point'])  # call by value forced
+            # We need to avoid pythons call by reference with gives_point.
+            # If answer is right the api will turn the values from gives_point
+            # to false to avoid double scoring. Now we use var "gave_point"
+            # which wont be automatically updated.
+            gave_point = {'ff': (self.shot['gives_point']['ff']),
+                          'all': (self.shot['gives_point']['all'])}
             self.log('Try to check the title: %s' % guess)
             # enter checking status
             self.image_solution.setColorDiffuse('FFFFFF00')
@@ -562,7 +577,7 @@ class GUI(xbmcgui.WindowXMLDialog):
             # call answerRight or answerWrong
             if solution['is_right']:
                 self.answerRight(solution['title_year'],
-                                 gives_point)
+                                 gave_point)
             else:
                 self.answerWrong(guess)
 
@@ -572,12 +587,16 @@ class GUI(xbmcgui.WindowXMLDialog):
         self.setWTMProperty('solved_status', 'correct')
         self.image_solution.setColorDiffuse('FF00FF00')
         # if this shot gives points, do so
-        if gives_point:
-            self.score += 1
+        if gives_point['ff'] or gives_point['all']:
+            if gives_point['all']:
+                self.score['all_score'] += 1
+                message = self.getString(self.SID_ANSWER_RIGHT) % title_year
+            if gives_point['ff']:
+                self.score['ff_score'] += 1
+                message = self.getString(self.SID_ANSWER_RIGHT_POINT) % 
title_year
             self._showUserScore(self.score)
-            message = self.getString(self.SID_ANSWER_RIGHT_POINT) % title_year
         else:
-            message = self.getString(self.SID_ANSWER_RIGHT) % title_year
+            message = 'FIXME: Is this possible?'
         self.label_message.setLabel(message)
         # if user wants auto_jump, do so
         if self.getSetting('auto_jump_enabled') == 'true':
@@ -601,15 +620,15 @@ class GUI(xbmcgui.WindowXMLDialog):
         self.image_solution.setColorDiffuse('FFFF0000')
 
     def login(self):
-        self.score = 0
+        self.score = {'ff_score': 0,
+                      'all_score': 0}
         self.logged_in = False
         label = self.getString(self.SID_NOT_LOGGED_IN)
         # if login is enabeld start loop until
         # self.logged_in is true or user disables login
         if self.getSetting('login') == 'true':
-            cookie_dir = self.Addon.getAddonInfo('profile')
-            self.checkCreatePath(cookie_dir)
-            cookie_file = xbmc.translatePath('%s/cookie.txt' % cookie_dir)
+            cookie_file = xbmc.translatePath('%s/cookie.txt'
+                                             % self.profile_path)
             # try to login until self.logged_in becomes True
             while not self.logged_in:
                 if self.getSetting('login') == 'false':
@@ -631,7 +650,7 @@ class GUI(xbmcgui.WindowXMLDialog):
                     self.log('Login successfull via: %s' % self.logged_in)
                     # login successfully
                     label = self.getString(self.SID_LOGGED_IN_AS) % user
-                    self.score = int(self.Quiz.getScore(user)['ff_score'])
+                    self.score = self.Quiz.getScore(user)
                     self.setRandomOptions()
         self.label_loginstate.setLabel(label)
         self._showUserScore(self.score)
@@ -658,18 +677,11 @@ class GUI(xbmcgui.WindowXMLDialog):
             self.Quiz.setRandomOptions(options)
             self.setSetting('already_sent_options', current_options)
 
-    def downloadPic(self, image_url, shot_id):
-        subst_image_url = 'http://static.whatthemovie.com/images/substitute'
-        if not image_url.startswith(subst_image_url):
-            cache_dir = ('special://profile/addon_data/%s/cache'
-                         % self.ADDON_ID)
-            self.checkCreatePath(cache_dir)
-            image_path = xbmc.translatePath('%s/%s.jpg' % (cache_dir, shot_id))
-            if not os.path.isfile(image_path):
-                self.Quiz.downloadFile(image_url, image_path)
-        else:
-            image_path = image_url
-        return image_path
+    def createPaths(self):
+        self.profile_path = self.Addon.getAddonInfo('profile')
+        self.cache_path = self.profile_path + '/cache/'
+        self.checkCreatePath(self.profile_path)
+        self.checkCreatePath(self.cache_path)
 
     def checkCreatePath(self, path):
         result = False
diff --git a/script.game.whatthemovie/resources/lib/whatthemovie.py 
b/script.game.whatthemovie/resources/lib/whatthemovie.py
index fa8526d..3608c5d 100644
--- a/script.game.whatthemovie/resources/lib/whatthemovie.py
+++ b/script.game.whatthemovie/resources/lib/whatthemovie.py
@@ -19,9 +19,12 @@
 #
 #
 
-import mechanize
 import re
-from urllib import urlencode
+import urllib
+import urllib2
+import cookielib
+import threading
+import Queue
 from BeautifulSoup import BeautifulSoup
 
 
@@ -35,7 +38,8 @@ class WhatTheMovie(object):
                     'self_posted': False,
                     'bookmarked': False,
                     'favourite': False,
-                    'gives_point': True,
+                    'gives_point': {'ff': False,
+                                    'all': False},
                     'already_solved': False,
                     'tags': [u'tag1'],
                     'posted_by': u'Hagentinho',
@@ -67,13 +71,15 @@ class WhatTheMovie(object):
 
     def __init__(self, user_agent):
         # Get browser stuff
-        self.cookies = mechanize.LWPCookieJar()
-        self.browser = mechanize.Browser()
-        self.browser.set_cookiejar(self.cookies)
-        self.browser.addheaders = [('user-agent', user_agent)]
+        self.cookies = cookielib.LWPCookieJar()
+        processor = urllib2.HTTPCookieProcessor(self.cookies)
+        self.opener = urllib2.build_opener(processor)
+        self.opener.addheaders = [('user-agent', user_agent)]
         # Set empty returns
         self.shot = dict()
         self.last_shots = list()
+        self.image_download_path = None
+        self.running = False
 
     def login(self, user, password, cookie_path):
         logged_in = False
@@ -85,7 +91,7 @@ class WhatTheMovie(object):
         except IOError:
             cookie_found = False
         if cookie_found:
-            logged_in_user = self._getUsername(retrieve=True)
+            logged_in_user = self._getUsername()
             if logged_in_user == user:
                 logged_in = 'cookie'
         if not logged_in:
@@ -93,20 +99,41 @@ class WhatTheMovie(object):
             data_dict = dict()
             data_dict['name'] = user
             data_dict['upassword'] = password
-            data = urlencode(data_dict)
-            req = mechanize.Request(login_url, data)
-            self.browser.open(req)
+            data = urllib.urlencode(data_dict)
+            html = self.opener.open(login_url, data).read()
             logged_in_user = self._getUsername()
             if logged_in_user:
                 logged_in = 'auth'
                 self.cookies.save(cookie_path)
         return logged_in
 
-    def _getUsername(self, retrieve=False):
+    def setImagePath(self, image_download_path):
+        self.image_download_path = image_download_path
+
+    def start(self, num_workers=3, num_init_jobs=3, callback=None):
+        self.callback = callback
+        self.num_workers = num_workers
+        self.num_init_jobs = num_init_jobs
+        self.workers = [self.Scraper(self.opener, self.image_download_path,
+                        self.callback) for i in range(self.num_workers)]
+        for worker in self.workers:
+            worker.start()
+        for job in range(self.num_init_jobs):
+            self.Scraper.jobs.put('random')
+        self.running = True
+
+    def stop(self):
+        self.Scraper.exit_requested = True
+        for i in range(self.num_workers):
+            self.Scraper.jobs.put('exit')
+        for worker in self.workers:
+            worker.join()
+        self.running = False
+
+    def _getUsername(self, html=None):
         # only retrieve if there is no previous retrieve which we can use
-        if retrieve:
-            self.browser.open(self.MAIN_URL)
-        html = self.browser.response().read()
+        if not html:
+            html = self.opener.open(self.MAIN_URL).read()
         tree = BeautifulSoup(html)
         section = tree.find('li', attrs={'class': 'secondary_nav',
                                          'style': 'margin-left: 0'})
@@ -124,234 +151,76 @@ class WhatTheMovie(object):
 
     def _sendAjaxReq(self, url, data_dict=None):
         if data_dict:
-            post_data = urlencode(data_dict)
+            post_data = urllib.urlencode(data_dict)
         else:
             post_data = ' '
-        req = mechanize.Request(url, post_data)
+        req = urllib2.Request(url, post_data)
         req.add_header('Accept', 'text/javascript, */*')
         req.add_header('Content-Type',
                        'application/x-www-form-urlencoded; charset=UTF-8')
         req.add_header('X-Requested-With', 'XMLHttpRequest')
-        self.browser.open(req)
-        response = self.browser.response().read()
+        response = self.opener.open(req).read()
         response_c = response.replace('&amp;', '&').decode('unicode-escape')
         return response_c
 
     def getShot(self, shot_request):
+        if not self.running:
+            self.start()
         if self.OFFLINE_DEBUG:
             return self.OFFLINE_SHOT
         if shot_request == 'back':
             if self.last_shots:
+                self.Scraper.next_shots_lock.acquire()
+                self.Scraper.next_shots.insert(0, self.shot)
+                if self.callback:
+                    self.callback(len(self.Scraper.next_shots))
+                self.Scraper.next_shots_lock.release()
                 self.shot = self.last_shots.pop()
         else:
             if self.shot:  # if there is already a shot - put it in list
                 self.last_shots.append(self.shot)
             if shot_request.isdigit() or shot_request == 'random':
-                self.shot = self.scrapeShot(shot_request)
+                pass
             elif shot_request in self.shot['nav'].keys():
                 # fixme(sphere): replace with better logic
-                # if there is no shot_request in dict
+                # if there is no matching val in nav
                 if not self.shot['nav'][shot_request]:
                     # check if it is a unsolved request and try without
                     if (shot_request[-9:] == '_unsolved'
                         and self.shot['nav'][shot_request[:-9]]):
                         request = shot_request[:-9]
-                        resolved_shot_request = self.shot['nav'][request]
-                    else:
-                        # else fallback to random
-                        resolved_shot_request = 'random'
+                        shot_request = self.shot['nav'][request]
                 else:
-                    resolved_shot_request = self.shot['nav'][shot_request]
-                self.shot = self.scrapeShot(resolved_shot_request)
-        self.shot['requested_as'] = shot_request
-        return self.shot
-
-    def scrapeShot(self, shot_request):
-        self.shot = dict()
-        shot_url = '%s/shot/%s' % (self.MAIN_URL, shot_request)
-        self.browser.open(shot_url)
-        html = self.browser.response().read()
-        tree = BeautifulSoup(html)
-        # id
-        shot_id = tree.find('li', attrs={'class': 'number'}).string.strip()
-        # prev/next
-        nav = dict()
-        section = tree.find('ul', attrs={'id': 'nav_shots'}).findAll('li')
-        nav_types = ((0, 'first'), (1, 'prev'), (2, 'prev_unsolved'),
-                     (4, 'next_unsolved'), (5, 'next'), (6, 'last'))
-        for i, nav_type in nav_types:
-            if section[i].a:
-                nav[nav_type] = section[i].a['href'][6:]
-            else:
-                nav[nav_type] = None
-        # image url
-        image_url = tree.find('img', alt='guess this movie snapshot')['src']
-        # languages
-        lang_list = dict()
-        lang_list['main'] = list()
-        lang_list['hidden'] = list()
-        section = tree.find('ul', attrs={'class': 'language_flags'})
-        langs_main = section.findAll(lambda tag: len(tag.attrs) == 0)
-        for lang in langs_main:
-            if lang.img:
-                lang_list['main'].append(lang.img['src'][-6:-4])
-        langs_hidden = section.findAll('li',
-                                       attrs={'class': 'hidden_languages'})
-        for lang in langs_hidden:
-            if lang.img:
-                lang_list['hidden'].append(lang.img['src'][-6:-4])
-        lang_list['all'] = lang_list['main'] + lang_list['hidden']
-        # date
-        shot_date = None
-        section = tree.find('ul', attrs={'class': 'nav_date'})
-        if section:
-            r = ('<a href="/overview/(?P<year>[0-9]+)/'
-                 '(?P<month>[0-9]+)/(?P<day>[0-9]+)">')
-            date_match = re.search(r, unicode(section))
-            if date_match:
-                date_dict = date_match.groupdict()
-                if date_dict:
-                    shot_date = (int(date_dict['year']),
-                                 int(date_dict['month']),
-                                 int(date_dict['day']))
-        # posted by
-        sections = tree.find('ul',
-                             attrs={'class': 'nav_shotinfo'}).findAll('li')
-        if sections[0].a:
-            posted_by = sections[0].a.string
-        else:
-            posted_by = None
-        # solved
-        solved = dict()
-        try:
-            solved_string, solved_count = sections[1].string[8:].split()
-            if solved_string == 'solved':
-                solved['status'] = True
-                solved['count'] = int(solved_count.strip('()'))
-        except:
-            solved['status'] = False
-            solved['count'] = 0
-        try:
-            solved['first_by'] = sections[2].a.string
-        except:
-            solved['first_by'] = None
-        # already solved + own_shot
-        already_solved = False
-        self_posted = False
-        js_list = tree.findAll('script',
-                               attrs={'type': 'text/javascript'},
-                               text=re.compile('guess_problem'))
-        if js_list:
-            message = str(js_list)
-            if re.search('already solved', message):
-                already_solved = True
-            elif re.search('You posted this', message):
-                self_posted = True
-        # voting
-        voting = dict()
-        section = tree.find('script',
-                            attrs={'type': 'text/javascript'},
-                            text=re.compile('tt_shot_rating_stars'))
-        r = ('<strong>(?P<overall_rating>[0-9.]+|hidden)</strong> '
-             '\((?P<votes>[0-9]+) votes\)'
-             '(<br>Your rating: <strong>(?P<own_rating>[0-9.]+)</strong>)?')
-        if section:
-            voting = re.search(r, section).groupdict()
-        # tags
-        tags = list()
-        tags_list = tree.find('ul', attrs={'id':
-                                           'shot_tag_list'}).findAll('li')
-        for tag in tags_list:
-            if tag.a:
-                tags.append(tag.a.string)
-        # shot_type
-        section = tree.find('h2', attrs={'class':
-                                         'topbar_title'}).string.strip()
-        shot_type = 0  # Unknown
-        if section == 'New Submissions':
-            shot_type = 1
-        elif section == 'Feature Films':
-            shot_type = 2
-        elif section == 'The Archive':
-            shot_type = 3
-        elif section == 'Rejected Snapshots':
-            shot_type = 4
-        elif section == 'The Vault':
-            shot_type = 5
-        elif section == 'Deleted':
-            shot_type = 6
-        # gives_point
-        gives_point = False
-        if shot_type == 2 and not already_solved and not self_posted:
-            gives_point = True
-        # bookmarked
-        if tree.find('li', attrs={'id': 'watchbutton'}):
-            bookmark_link = tree.find('li', attrs={'id': 'watchbutton'}).a
-            try:
-                if bookmark_link['class'] == 'active':
-                    bookmarked = True
-            except KeyError:
-                bookmarked = False
-        else:
-            bookmarked = None  # Not logged in
-        # favourite
-        if tree.find('li', attrs={'class': 'love'}):
-            favourite_link = tree.find('li', attrs={'class': 'love'}).a
-            try:
-                if favourite_link['class'] == 'active':
-                    favourite = True
-            except KeyError:
-                favourite = False
-        else:
-            favourite = None  # Not logged in
-        # Snapshot of the Day
-        sotd = False
-        if tree.find('div', attrs={'class': 'sotd_banner'}):
-            sotd = True
-        # Solvable
-        solvable = False
-        section = tree.find('li', attrs={'id': 'solutionbutton'})
-        if section is not None:
-            try:
-                if section.a['class'] == 'inactive':
-                    solvable = False
-            except KeyError:
-                solvable = True
-        # redirected
-        redirected = False
-        section = tree.find('div', attrs={'class':
-                                          re.compile('flash_message')})
-        if section:
-            message = section.string
-            redirected = 1
-            if re.search('you are not allowed', message):
-                redirected = 2
-            if re.search('No such snapshot', message):
-                redirected = 3
-        # create return dict
-        self.shot['shot_id'] = shot_id
-        self.shot['image_url'] = image_url
-        self.shot['lang_list'] = lang_list
-        self.shot['posted_by'] = posted_by
-        self.shot['solved'] = solved
-        self.shot['date'] = shot_date
-        self.shot['already_solved'] = already_solved
-        self.shot['self_posted'] = self_posted
-        self.shot['voting'] = voting
-        self.shot['tags'] = tags
-        self.shot['shot_type'] = shot_type
-        self.shot['gives_point'] = gives_point
-        self.shot['nav'] = nav
-        self.shot['bookmarked'] = bookmarked
-        self.shot['favourite'] = favourite
-        self.shot['sotd'] = sotd
-        self.shot['solvable'] = solvable
-        self.shot['redirected'] = redirected
+                    shot_request = self.shot['nav'][shot_request]
+            if len(self.Scraper.next_shots) - 1 < self.num_init_jobs:
+                self.Scraper.jobs.put(shot_request)
+            # delete actual shot because we want a new one
+            self.shot = None
+            self.Scraper.new_shot_condition.acquire()
+            # as long as we dont have a shot which we want (ex. 'random')
+            while not self.shot:
+                # lock the list of preloaded shots
+                self.Scraper.next_shots_lock.acquire()
+                # search in already preloaded shots for one we want
+                for i, shot in enumerate(self.Scraper.next_shots):
+                    # if this is a shot we want
+                    if shot['requested_as'] == shot_request:
+                        # save the shot we want and delete from list
+                        self.shot = self.Scraper.next_shots.pop(i)
+                        if self.callback:
+                            self.callback(len(self.Scraper.next_shots))
+                        # stop searching in the list of preloaded shots
+                        break
+                # relase the lock - new shots can now be inserted from workers
+                self.Scraper.next_shots_lock.release()
+                # if our search was successfull leave the waiting state
+                if self.shot:
+                    break
+                # there was no shot we want - wait for a new
+                self.Scraper.new_shot_condition.wait()
+            self.Scraper.new_shot_condition.release()
         return self.shot
 
-    def downloadFile(self, url, local_path):
-        self.browser.retrieve(url, local_path, )
-
     def guessShot(self, shot_id, title_guess):
         if self.OFFLINE_DEBUG:
             if title_guess.lower() == self.OFFLINE_ANSWER['title'].lower():
@@ -370,8 +239,8 @@ class WhatTheMovie(object):
             if self.shot['shot_id'] == shot_id:
                 if not self.shot['already_solved']:
                     self.shot['already_solved'] = True
-                if self.shot['gives_point']:
-                    self.shot['gives_point'] = False
+                self.shot['gives_point'] = {'ff': False,
+                                            'all': False}
         return answer
 
     def rateShot(self, shot_id, user_rate, rerated='false'):
@@ -424,17 +293,254 @@ class WhatTheMovie(object):
         return solved_title
 
     def getScore(self, username):
+        score = {'ff_score': 0,
+                 'all_score': 0}
         if self.OFFLINE_DEBUG:
-            score = {'ff_score': 0,
-                     'all_score': 0}
             return score
-        score = 0
         profile_url = '%s/user/%s/' % (self.MAIN_URL, username)
-        self.browser.open(profile_url)
-        html = self.browser.response().read()
+        html = self.opener.open(profile_url).read()
         tree = BeautifulSoup(html)
         box = tree.find('div', attrs={'class': 'box_white'})
         r = ('>(?P<ff_score>[0-9]+) Feature Film.*'
              '>(?P<all_score>[0-9]+) Snapshot')
-        score = re.search(r, str(box.p)).groupdict()
+        if re.search(r, str(box.p)):
+            score_dict = re.search(r, str(box.p)).groupdict()
+            score = {'ff_score': int(score_dict['ff_score']),
+                     'all_score': int(score_dict['all_score'])}
         return score
+
+    class Scraper(threading.Thread):
+
+        jobs = Queue.Queue()
+        next_shots = list()
+        next_shots_lock = threading.Lock()
+        new_shot_condition = threading.Condition()
+        exit_requested = False
+
+        def __init__(self, opener, image_download_path, callback=None):
+            self.opener = opener
+            self.callback = callback
+            self.image_download_path = image_download_path
+            threading.Thread.__init__(self)
+
+        def run(self):
+            while not self.exit_requested:
+                job = WhatTheMovie.Scraper.jobs.get()
+                if job == 'exit':
+                    break
+                # scrape the shot - this will take some time
+                shot = self.scrapeShot(job)
+                # lock the list of shots
+                WhatTheMovie.Scraper.next_shots_lock.acquire()
+                # save the shot
+                WhatTheMovie.Scraper.next_shots.append(shot)
+                # tell that a new shot was inserted
+                WhatTheMovie.Scraper.new_shot_condition.acquire()
+                WhatTheMovie.Scraper.new_shot_condition.notify()
+                WhatTheMovie.Scraper.new_shot_condition.release()
+                if self.callback:
+                    self.callback(len(WhatTheMovie.Scraper.next_shots))
+                WhatTheMovie.Scraper.next_shots_lock.release()
+                try:  # python >= 2.5 needed for task_done
+                    WhatTheMovie.Scraper.jobs.task_done()
+                except AttributeError:
+                    pass
+
+        def scrapeShot(self, shot_request):
+            self.shot = dict()
+            shot_url = '%s/shot/%s' % (WhatTheMovie.MAIN_URL, shot_request)
+            html = self.opener.open(shot_url).read()
+            tree = BeautifulSoup(html)
+            # id
+            shot_id = tree.find('li', attrs={'class': 'number'}).string.strip()
+            # prev/next
+            nav = dict()
+            section = tree.find('ul', attrs={'id': 'nav_shots'}).findAll('li')
+            nav_types = ((0, 'first'), (1, 'prev'), (2, 'prev_unsolved'),
+                         (4, 'next_unsolved'), (5, 'next'), (6, 'last'))
+            for i, nav_type in nav_types:
+                if section[i].a:
+                    nav[nav_type] = section[i].a['href'][6:]
+                else:
+                    nav[nav_type] = None
+            # image url
+            section = tree.find('style', {'type': 'text/css'})
+            image_url = ''
+            if section:
+                r_img = re.compile('background-image:url\("(.+?)"\)')
+                m_img = re.search(r_img, section.string)
+                if m_img:
+                    image_url = WhatTheMovie.MAIN_URL + m_img.group(1)
+            subst_image_url = 'http://static.whatthemovie.com/images/subst'
+            if self.image_download_path:
+                if not image_url.startswith(subst_image_url):
+                    local_image_file = '%s%s.jpg' % (self.image_download_path,
+                                                     shot_id)
+                    urllib.urlretrieve(image_url, local_image_file, )
+                    image_url = local_image_file
+            # languages
+            lang_list = dict()
+            lang_list['main'] = list()
+            lang_list['hidden'] = list()
+            section = tree.find('ul', attrs={'class': 'language_flags'})
+            langs_main = section.findAll(lambda tag: len(tag.attrs) == 0)
+            for lang in langs_main:
+                if lang.img:
+                    lang_list['main'].append(lang.img['src'][-6:-4])
+            langs_hidden = section.findAll('li',
+                                           attrs={'class': 'hidden_languages'})
+            for lang in langs_hidden:
+                if lang.img:
+                    lang_list['hidden'].append(lang.img['src'][-6:-4])
+            lang_list['all'] = lang_list['main'] + lang_list['hidden']
+            # date
+            shot_date = None
+            section = tree.find('ul', attrs={'class': 'nav_date'})
+            if section:
+                r = ('<a href="/overview/(?P<year>[0-9]+)/'
+                     '(?P<month>[0-9]+)/(?P<day>[0-9]+)">')
+                date_match = re.search(r, unicode(section))
+                if date_match:
+                    date_dict = date_match.groupdict()
+                    if date_dict:
+                        shot_date = (int(date_dict['year']),
+                                     int(date_dict['month']),
+                                     int(date_dict['day']))
+            # posted by
+            sections = tree.find('ul',
+                                 attrs={'class': 'nav_shotinfo'}).findAll('li')
+            if sections[0].a:
+                posted_by = sections[0].a.string
+            else:
+                posted_by = None
+            # solved
+            solved = dict()
+            try:
+                solved_string, solved_count = sections[1].string[8:].split()
+                if solved_string == 'solved':
+                    solved['status'] = True
+                    solved['count'] = int(solved_count.strip('()'))
+            except:
+                solved['status'] = False
+                solved['count'] = 0
+            try:
+                solved['first_by'] = sections[2].a.string
+            except:
+                solved['first_by'] = None
+            # already solved + own_shot
+            already_solved = False
+            self_posted = False
+            js_list = tree.findAll('script',
+                                   attrs={'type': 'text/javascript'},
+                                   text=re.compile('guess_problem'))
+            if js_list:
+                message = str(js_list)
+                if re.search('already solved', message):
+                    already_solved = True
+                elif re.search('You posted this', message):
+                    self_posted = True
+            # voting
+            voting = dict()
+            section = tree.find('script',
+                                attrs={'type': 'text/javascript'},
+                                text=re.compile('tt_shot_rating_stars'))
+            r = ('<strong>(?P<overall_rating>[0-9.]+|hidden)</strong> '
+                 '\((?P<votes>[0-9]+) votes\)'
+                 '(<br>Your rating: <strong>(?P<own_rating>[0-9.]+)</strong)?')
+            if section:
+                voting = re.search(r, section).groupdict()
+            # tags
+            tags = list()
+            tags_list = tree.find('ul', attrs={'id':
+                                               'shot_tag_list'}).findAll('li')
+            for tag in tags_list:
+                if tag.a:
+                    tags.append(tag.a.string)
+            # shot_type
+            section = tree.find('h2', attrs={'class':
+                                             'topbar_title'}).string.strip()
+            shot_type = 0  # Unknown
+            if section == 'New Submissions':
+                shot_type = 1
+            elif section == 'Feature Films':
+                shot_type = 2
+            elif section == 'The Archive':
+                shot_type = 3
+            elif section == 'Rejected Snapshots':
+                shot_type = 4
+            elif section == 'The Vault':
+                shot_type = 5
+            elif section == 'Deleted':
+                shot_type = 6
+            # gives_point
+            gives_point = {'ff': False,
+                           'all': False}
+            if not already_solved and not self_posted:
+                gives_point['all'] = True
+                if shot_type == 2:
+                    gives_point['ff'] = True
+            # bookmarked
+            if tree.find('li', attrs={'id': 'watchbutton'}):
+                bookmark_link = tree.find('li', attrs={'id': 'watchbutton'}).a
+                try:
+                    if bookmark_link['class'] == 'active':
+                        bookmarked = True
+                except KeyError:
+                    bookmarked = False
+            else:
+                bookmarked = None  # Not logged in
+            # favourite
+            if tree.find('li', attrs={'class': 'love'}):
+                favourite_link = tree.find('li', attrs={'class': 'love'}).a
+                try:
+                    if favourite_link['class'] == 'active':
+                        favourite = True
+                except KeyError:
+                    favourite = False
+            else:
+                favourite = None  # Not logged in
+            # Snapshot of the Day
+            sotd = False
+            if tree.find('div', attrs={'class': 'sotd_banner'}):
+                sotd = True
+            # Solvable
+            solvable = False
+            section = tree.find('li', attrs={'id': 'solutionbutton'})
+            if section is not None:
+                try:
+                    if section.a['class'] == 'inactive':
+                        solvable = False
+                except KeyError:
+                    solvable = True
+            # redirected
+            redirected = False
+            section = tree.find('div', attrs={'class':
+                                              re.compile('flash_message')})
+            if section:
+                message = section.string
+                redirected = 1
+                if re.search('you are not allowed', message):
+                    redirected = 2
+                if re.search('No such snapshot', message):
+                    redirected = 3
+            # create return dict
+            self.shot['shot_id'] = shot_id
+            self.shot['image_url'] = image_url
+            self.shot['lang_list'] = lang_list
+            self.shot['posted_by'] = posted_by
+            self.shot['solved'] = solved
+            self.shot['date'] = shot_date
+            self.shot['already_solved'] = already_solved
+            self.shot['self_posted'] = self_posted
+            self.shot['voting'] = voting
+            self.shot['tags'] = tags
+            self.shot['shot_type'] = shot_type
+            self.shot['gives_point'] = gives_point
+            self.shot['nav'] = nav
+            self.shot['bookmarked'] = bookmarked
+            self.shot['favourite'] = favourite
+            self.shot['sotd'] = sotd
+            self.shot['solvable'] = solvable
+            self.shot['redirected'] = redirected
+            self.shot['requested_as'] = shot_request
+            return self.shot
diff --git 
a/script.game.whatthemovie/resources/skins/default/720p/script-WhatTheMovie-main.xml
 
b/script.game.whatthemovie/resources/skins/default/720p/script-WhatTheMovie-main.xml
index 75c55da..3db33b1 100644
--- 
a/script.game.whatthemovie/resources/skins/default/720p/script-WhatTheMovie-main.xml
+++ 
b/script.game.whatthemovie/resources/skins/default/720p/script-WhatTheMovie-main.xml
@@ -215,7 +215,7 @@
                     <ondown>3003</ondown>
                 </control>
             </control>
-            <control type="label" id="1001">
+                       <control type="label" id="1001">
                 <description>Login state label</description>
                 <posx>20</posx>
                 <posy>12</posy>
@@ -226,6 +226,17 @@
                 <shadowcolor>black</shadowcolor>
                 <visible>true</visible>
             </control>
+            <control type="label" id="1020">
+                <description>Preload label</description>
+                <posx>300</posx>
+                <posy>12</posy>
+                <width>450</width>
+                <align>left</align>
+                <font>font12</font>
+                <textcolor>white</textcolor>
+                <shadowcolor>black</shadowcolor>
+                <visible>true</visible>
+            </control>
             <control type="label" id="1004">
                 <description>Posted by label</description>
                 <posx>280</posx>

-----------------------------------------------------------------------

Summary of changes:
 script.game.whatthemovie/addon.xml                 |    2 +-
 script.game.whatthemovie/changelog.txt             |   10 +
 .../resources/language/English/strings.xml         |    2 +-
 .../resources/language/German/strings.xml          |    2 +-
 script.game.whatthemovie/resources/lib/gui.py      |   70 +-
 .../resources/lib/mechanize/__init__.py            |  211 --
 .../resources/lib/mechanize/_auth.py               |   68 -
 .../resources/lib/mechanize/_beautifulsoup.py      | 1077 -------
 .../resources/lib/mechanize/_clientcookie.py       | 1725 ----------
 .../resources/lib/mechanize/_debug.py              |   28 -
 .../resources/lib/mechanize/_firefox3cookiejar.py  |  248 --
 .../resources/lib/mechanize/_form.py               | 3280 --------------------
 .../resources/lib/mechanize/_gzip.py               |  105 -
 .../resources/lib/mechanize/_headersutil.py        |  241 --
 .../resources/lib/mechanize/_html.py               |  629 ----
 .../resources/lib/mechanize/_http.py               |  447 ---
 .../resources/lib/mechanize/_lwpcookiejar.py       |  185 --
 .../resources/lib/mechanize/_markupbase.py         |  393 ---
 .../resources/lib/mechanize/_mechanize.py          |  669 ----
 .../resources/lib/mechanize/_mozillacookiejar.py   |  161 -
 .../resources/lib/mechanize/_msiecookiejar.py      |  388 ---
 .../resources/lib/mechanize/_opener.py             |  442 ---
 .../resources/lib/mechanize/_pullparser.py         |  391 ---
 .../resources/lib/mechanize/_request.py            |   40 -
 .../resources/lib/mechanize/_response.py           |  525 ----
 .../resources/lib/mechanize/_rfc3986.py            |  245 --
 .../resources/lib/mechanize/_sgmllib_copy.py       |  559 ----
 .../resources/lib/mechanize/_sockettimeout.py      |    6 -
 .../resources/lib/mechanize/_testcase.py           |  162 -
 .../resources/lib/mechanize/_urllib2.py            |   50 -
 .../resources/lib/mechanize/_urllib2_fork.py       | 1414 ---------
 .../resources/lib/mechanize/_useragent.py          |  367 ---
 .../resources/lib/mechanize/_util.py               |  305 --
 .../resources/lib/mechanize/_version.py            |    2 -
 .../resources/lib/whatthemovie.py                  |  550 ++--
 .../default/720p/script-WhatTheMovie-main.xml      |   13 +-
 36 files changed, 394 insertions(+), 14618 deletions(-)
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/__init__.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_auth.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_beautifulsoup.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_clientcookie.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_debug.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_firefox3cookiejar.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_form.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_gzip.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_headersutil.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_html.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_http.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_lwpcookiejar.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_markupbase.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_mechanize.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_mozillacookiejar.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_msiecookiejar.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_opener.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_pullparser.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_request.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_response.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_rfc3986.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_sgmllib_copy.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_sockettimeout.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_testcase.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_urllib2.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_urllib2_fork.py
 delete mode 100644 
script.game.whatthemovie/resources/lib/mechanize/_useragent.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_util.py
 delete mode 100644 script.game.whatthemovie/resources/lib/mechanize/_version.py


hooks/post-receive
-- 
Scripts

------------------------------------------------------------------------------
Keep Your Developer Skills Current with LearnDevNow!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-d2d
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons

Reply via email to