The branch, eden has been updated
       via  b930921d4d8c303740616ae9385e0c5db9c53fb6 (commit)
       via  5a31ca4317ec7eef67030bc732566a91cdcc21af (commit)
      from  309de40e60c623ee50ecd0fd3beecfb7778cee4e (commit)

- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=b930921d4d8c303740616ae9385e0c5db9c53fb6

commit b930921d4d8c303740616ae9385e0c5db9c53fb6
Author: spiff <[email protected]>
Date:   Fri Oct 19 15:30:13 2012 +0200

    [plugin.video.twitch] updated to version 0.2.2

diff --git a/plugin.video.twitch/addon.xml b/plugin.video.twitch/addon.xml
index 0ee85b6..17f304a 100644
--- a/plugin.video.twitch/addon.xml
+++ b/plugin.video.twitch/addon.xml
@@ -1,5 +1,5 @@
 <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
-<addon id='plugin.video.twitch' version='0.2.1' name='TwitchTV' 
provider-name='StateOfTheArt'>
+<addon id='plugin.video.twitch' version='0.2.2' name='TwitchTV' 
provider-name='StateOfTheArt'>
   <requires>
     <import addon='xbmc.python' version='2.0'/>
     <import addon='script.module.simplejson' version='2.0.10'/>
diff --git a/plugin.video.twitch/changelog.txt 
b/plugin.video.twitch/changelog.txt
index ca1a498..e383461 100644
--- a/plugin.video.twitch/changelog.txt
+++ b/plugin.video.twitch/changelog.txt
@@ -21,4 +21,6 @@
 - added selection of prefered video settings
 - added fallback-function, if selected video does not support video settings
 0.2.1
-- added featured streams section
\ No newline at end of file
+- added featured streams section
+0.2.2
+- added teams section - thx to kokarn
\ No newline at end of file
diff --git a/plugin.video.twitch/default.py b/plugin.video.twitch/default.py
index b9080d3..d726d05 100644
--- a/plugin.video.twitch/default.py
+++ b/plugin.video.twitch/default.py
@@ -1,280 +1,355 @@
-import xbmcplugin
-import xbmcgui
-import sys
-import urllib2,urllib,re
-import xbmcaddon
-import os
-import xbmcvfs
-try:
-    import json
-except:
-    import simplejson as json
-
-thisPlugin = int(sys.argv[1])
-settings = xbmcaddon.Addon(id='plugin.video.twitch')
-httpHeaderUserAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) 
Gecko/20100101 Firefox/6.0'
-translation = settings.getLocalizedString
-ITEMS_PER_SITE=20
-
-def downloadWebData(url):
-    try:
-        req = urllib2.Request(url)
-        req.add_header('User-Agent', httpHeaderUserAgent)
-        response = urllib2.urlopen(req)
-        data=response.read()
-        response.close()
-        return data
-    except urllib2.URLError, e:
-        xbmc.executebuiltin("XBMC.Notification("+translation(31000)+"," + 
translation(32001) +")")
-       
-def createMainListing():
-    addDir(translation(30005),'','featured','')
-    addDir(translation(30001),'','games','')
-    addDir(translation(30002),'','following','')
-    addDir(translation(30003),'','search','')
-    addDir(translation(30004),'','settings','')
-    xbmcplugin.endOfDirectory(thisPlugin)
-
-def createFollowingList():
-    username = settings.getSetting('username').lower()
-    if not username:
-        settings.openSettings()
-        username = settings.getSetting('username').lower()
-    jsonString = 
downloadWebData(url='http://api.justin.tv/api/user/favorites/'+username+'.json?limit=40&offset=0')
-    xmlDataOnlineStreams = 
downloadWebData(url='http://api.justin.tv/api/stream/list.xml')
-    if jsonString is None or xmlDataOnlineStreams is None:
-        return
-    jsonData=json.loads(jsonString)
-    for x in jsonData:
-        name = x['status']
-        image = x['image_url_huge']
-        loginname = x['login']
-        if len(name) <= 0:
-            name = loginname
-        if xmlDataOnlineStreams.count('<login>'+loginname+'</login>') > 0:
-            addLink(name,loginname,'play',image,loginname)
-    xbmcplugin.endOfDirectory(thisPlugin)
-       
-def createListOfFeaturedStreams():
-    
jsonString=downloadWebData(url='https://api.twitch.tv/kraken/streams/featured')
-    jsonData=json.loads(jsonString)
-    for x in jsonData['featured']:
-        try:
-            image = x['stream']['channel']['logo']
-            image = image.replace("http://","",1)
-            image = urllib.quote(image)
-            image = 'http://' + image
-        except:
-            image = ""
-        name = x['stream']['channel']['status']
-        if name == '':
-            name = x['stream']['channel']['display_name']
-        channelname = x['stream']['channel']['name']
-        addLink(name,'...','play',image,channelname)
-    xbmcplugin.endOfDirectory(thisPlugin)
- 
-def createListOfGames(index=0):
-    
jsonString=downloadWebData(url='https://api.twitch.tv/kraken/games/top?limit='+str(ITEMS_PER_SITE)+'&offset='+str(index*ITEMS_PER_SITE))
-    jsonData=json.loads(jsonString)
-    for x in jsonData['top']:
-        try:
-            name = str(x['game']['name'])
-            game = urllib.quote(name)
-            image = ''
-        except:
-            continue
-        try:
-            image = x['game']['images']['super']
-            image = image.replace("http://","",1)
-            image = urllib.quote(image)
-            image = 'http://' + image
-        except:
-            image = ''
-        addDir(name,game,'channel',image)
-    if len(jsonData['top']) >= ITEMS_PER_SITE:
-        addDir(translation(31001),'','games','',index+1)
-    xbmcplugin.endOfDirectory(thisPlugin)
-
-def search():
-    keyboard = xbmc.Keyboard('', translation(30101))
-    keyboard.doModal()
-    if keyboard.isConfirmed() and keyboard.getText():
-        search_string = urllib.quote_plus(keyboard.getText())
-        sdata = 
downloadWebData('http://api.swiftype.com/api/v1/public/engines/search.json?callback=jQuery1337&q='+search_string+'&engine_key=9NXQEpmQPwBEz43TM592&page=1&per_page='+str(ITEMS_PER_SITE))
-        sdata = sdata.replace('jQuery1337','');
-        sdata = sdata[1:len(sdata)-1]
-        jdata = json.loads(sdata)
-        records = jdata['records']['broadcasts']
-        for x in records:
-            addLink(x['title'],x['user'],'play',x['thumbnail'],x['user'])
-        xbmcplugin.endOfDirectory(thisPlugin)
-       
-def createListForGame(gameName, index=0):
-    
jsonString=downloadWebData(url='https://api.twitch.tv/kraken/streams?game='+gameName+'&limit='+str(ITEMS_PER_SITE)+'&offset='+str(index*ITEMS_PER_SITE))
-    jsonData=json.loads(jsonString)
-    for x in jsonData['streams']:
-        try:
-            image = x['channel']['logo']
-            image = image.replace("http://","",1)
-            image = urllib.quote(image)
-            image = 'http://' + image
-        except:
-            image = ""
-        name = x['channel']['status']
-        if name == '':
-            name = x['channel']['display_name']
-        channelname = x['channel']['name']
-        addLink(name,'...','play',image,channelname)
-    if len(jsonData['streams']) >= ITEMS_PER_SITE:
-        addDir(translation(31001),url,'channel','',index+1)
-    xbmcplugin.endOfDirectory(thisPlugin)
-       
-def addLink(name,url,mode,iconimage,channelname):
-        
u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&channelname="+channelname
-        ok=True
-        liz=xbmcgui.ListItem(name, iconImage="DefaultVideo.png", 
thumbnailImage=iconimage)
-        liz.setInfo( type="Video", infoLabels={ "Title": name } )
-        liz.setProperty('IsPlayable', 'true')
-        
ok=xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz)
-        return ok
-               
-def addDir(name,url,mode,iconimage,index=0):
-        
u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&siteIndex="+str(index)
-        ok=True
-        liz=xbmcgui.ListItem(name, iconImage="DefaultFolder.png", 
thumbnailImage=iconimage)
-        liz.setInfo( type="Video", infoLabels={ "Title": name } )
-        
ok=xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
-        return ok
-               
-def get_request(url, headers=None):
-        try:
-            if headers is None:
-                headers = {'User-agent' : httpHeaderUserAgent,
-                           'Referer' : 'http://www.justin.tv/'}
-            req = urllib2.Request(url,None,headers)
-            response = urllib2.urlopen(req)
-            link=response.read()
-            response.close()
-            return link
-        except urllib2.URLError, e:
-            errorStr = str(e.read())
-            if hasattr(e, 'code'):
-                if str(e.code) == '403':
-                    if 'archive' in url:
-                        
xbmc.executebuiltin("XBMC.Notification("+translation(31000)+"," 
+translation(32003)+ " " +name+")")
-                
xbmc.executebuiltin("XBMC.Notification("+translation(31000)+"," + 
translation(32001) +")")
-
-       
-def parameters_string_to_dict(parameters):
-        ''' Convert parameters encoded in a URL to a dict. '''
-        paramDict = {}
-        if parameters:
-            paramPairs = parameters[1:].split("&")
-            for paramsPair in paramPairs:
-                paramSplits = paramsPair.split('=')
-                if (len(paramSplits)) == 2:
-                    paramDict[paramSplits[0]] = paramSplits[1]
-        return paramDict
-               
-def getSwfUrl(channel_name):
-        ''' Helper method to grab the swf url, resolving HTTP 301/302 along 
the way'''
-        base_url = 
'http://www.justin.tv/widgets/live_embed_player.swf?channel=%s' % channel_name
-        headers = {'User-agent' : httpHeaderUserAgent,
-                   'Referer' : 'http://www.justin.tv/'+channel_name}
-        req = urllib2.Request(base_url, None, headers)
-        response = urllib2.urlopen(req)
-        return response.geturl()
-               
-def getBestJtvTokenPossible(name):
-        '''Helper method to find another jtv token'''
-        swf_url = getSwfUrl(name)
-        headers = {'User-agent' : httpHeaderUserAgent,
-                   'Referer' : swf_url}
-        url = 'http://usher.justin.tv/find/'+name+'.json?type=any&group='
-        data = json.loads(get_request(url,headers))
-        bestVideoHeight = -1
-        bestIndex = -1
-        index = 0
-        for x in data:
-            value = x.get('token', '')
-            videoHeight = int(x['video_height'])
-            if (value != '') and (videoHeight > bestVideoHeight):
-                bestVideoHeight = x['video_height']
-                bestIndex = index  
-            index = index + 1
-        return data[bestIndex]
-
-def playLive(name, play=False, password=None):
-        swf_url = getSwfUrl(name)
-        headers = {'User-agent' : httpHeaderUserAgent,
-                   'Referer' : swf_url}
-        chosenQuality = settings.getSetting('video')
-        videoTypeName = 'any'
-        if chosenQuality == '0':
-            videoTypeName = 'any'
-        elif chosenQuality == '1':
-            videoTypeName = '720p'
-        elif chosenQuality == '2':
-            videoTypeName = '480p'
-        elif chosenQuality == '3':
-            videoTypeName = '360p'
-        url = 
'http://usher.justin.tv/find/'+name+'.json?type='+videoTypeName+'&private_code=null&group='
-        data = json.loads(get_request(url,headers))
-        tokenIndex = 0
-        if data == []:
-            
xbmc.executebuiltin("XBMC.Notification("+translation(31000)+","+translation(32002)+")")
-            return
-        try:
-            '''trying to get a token in desired quality'''
-            token = ' 
jtv='+data[tokenIndex]['token'].replace('\\','\\5c').replace(' 
','\\20').replace('"','\\22')
-            rtmp = data[tokenIndex]['connect']+'/'+data[tokenIndex]['play']
-        except:
-            
xbmc.executebuiltin("XBMC.Notification("+translation(32005)+","+translation(32006)+")")
-            jtvtoken = getBestJtvTokenPossible(name)
-            if jtvtoken == '':
-                
xbmc.executebuiltin("XBMC.Notification("+translation(31000)+","+translation(32004)+")")
-                return
-            token = ' jtv='+jtvtoken['token'].replace('\\','\\5c').replace(' 
','\\20').replace('"','\\22')
-            rtmp = jtvtoken['connect']+'/'+jtvtoken['play']
-        
-        swf = ' swfUrl=%s swfVfy=1 live=1' % swf_url
-        Pageurl = ' Pageurl=http://www.justin.tv/'+name
-        url = rtmp+token+swf+Pageurl
-        if play == True:
-            info = xbmcgui.ListItem(name)
-            playlist = xbmc.PlayList(1)
-            playlist.clear()
-            playlist.add(url, info)
-            xbmc.executebuiltin('playlist.playoffset(video,0)')
-        else:
-            item = xbmcgui.ListItem(path=url)
-            xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, item)
-
-params=parameters_string_to_dict(sys.argv[2])
-mode=params.get('mode')
-url=params.get('url')
-sIndex=params.get('siteIndex')
-try:
-    index = int(sIndex)
-except Exception:
-    index = 0
-channelname=params.get('channelname')
-if type(url)==type(str()):
-       url=urllib.unquote_plus(url)
-if mode == 'games':
-       createListOfGames(index)  
-elif mode == 'featured':
-       createListOfFeaturedStreams()
-elif mode == 'channel':
-       createListForGame(url, index)
-elif mode == 'play':
-       playLive(channelname)
-elif mode == 'following':
-       createFollowingList()
-elif mode == 'settings':
-       settings.openSettings()
-elif mode == 'search':
-       search()
-else:
-       createMainListing()
-
+import xbmcplugin

+import xbmcgui

+import sys

+import urllib2,urllib,re

+import xbmcaddon

+import os

+import xbmcvfs

+import socket

+try:

+    import json

+except:

+    import simplejson as json

+

+thisPlugin = int(sys.argv[1])

+settings = xbmcaddon.Addon(id='plugin.video.twitch')

+httpHeaderUserAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) 
Gecko/20100101 Firefox/6.0'

+translation = settings.getLocalizedString

+ITEMS_PER_SITE=20

+

+def downloadWebData(url):

+    try:

+        req = urllib2.Request(url)

+        req.add_header('User-Agent', httpHeaderUserAgent)

+        response = urllib2.urlopen(req)

+        data=response.read()

+        response.close()

+        return data

+    except urllib2.HTTPError, e:

+        # HTTP errors usualy contain error information in JSON Format

+        return e.fp.read()

+    except urllib2.URLError, e:

+        xbmc.executebuiltin("XBMC.Notification("+translation(32001)+"," + 
translation(32010) +")")

+

+def getJsonFromTwitchApi(url):

+    jsonString=downloadWebData(url)

+    if jsonString is None:

+        return None

+    try:

+        jsonData=json.loads(jsonString)

+    except:

+        
xbmc.executebuiltin('XBMC.Notification("'+translation(32008)+'","'+translation(32008)+'")')

+        return None

+    if type(jsonData) is dict and 'error' in jsonData.keys():

+        
xbmc.executebuiltin('XBMC.Notification("'+translation(32007)+'","'+jsonData['error']+'")')

+        return None

+    return jsonData

+       

+def createMainListing():

+    addDir(translation(30005),'','featured','')

+    addDir(translation(30001),'','games','')

+    addDir(translation(30002),'','following','')

+    addDir(translation(30006),'','teams','')

+    addDir(translation(30003),'','search','')

+    addDir(translation(30004),'','settings','')

+    xbmcplugin.endOfDirectory(thisPlugin)

+

+def createFollowingList():

+    username = settings.getSetting('username').lower()

+    if not username:

+        settings.openSettings()

+        username = settings.getSetting('username').lower()

+    #Using xml in this case, because it's alot faster than parsing throw the 
big json result

+    xmlDataOnlineStreams = 
downloadWebData(url='http://api.justin.tv/api/stream/list.xml')

+    jsonData = 
getJsonFromTwitchApi(url='http://api.justin.tv/api/user/favorites/'+username+'.json')

+    if jsonData is None:

+        return

+    for x in jsonData:

+        name = x['status']

+        image = x['image_url_huge']

+        loginname = x['login']

+        if len(name) <= 0:

+            name = loginname

+        if xmlDataOnlineStreams.count('<login>'+loginname+'</login>') > 0:

+            addLink(name,loginname,'play',image,loginname)

+    xbmcplugin.endOfDirectory(thisPlugin)

+       

+def createListOfFeaturedStreams():

+    jsonData = 
getJsonFromTwitchApi(url='https://api.twitch.tv/kraken/streams/featured')

+    if jsonData is None:

+        return

+    for x in jsonData['featured']:

+        try:

+            image = x['stream']['channel']['logo']

+            image = image.replace("http://","",1)

+            image = urllib.quote(image)

+            image = 'http://' + image

+        except:

+            image = ""

+        name = x['stream']['channel']['status']

+        if name == '':

+            name = x['stream']['channel']['display_name']

+        channelname = x['stream']['channel']['name']

+        addLink(name,'...','play',image,channelname)

+    xbmcplugin.endOfDirectory(thisPlugin)

+

+def createListOfTeams():

+    #Temporary solution until twitch api method is available

+    
jsonString=downloadWebData(url='https://spreadsheets.google.com/feeds/list/0ArmMFLQnLIp8dFJ5bW9aOW03VHY5aUhsUFNXSUl1SXc/od6/public/basic?alt=json')

+    if jsonString is None:

+        return

+    try:

+        jsonData=json.loads(jsonString)

+    except:

+        
xbmc.executebuiltin('XBMC.Notification("'+translation(32008)+'","'+translation(32008)+'")')

+        return

+    for x in jsonData['feed']['entry']:

+        teamData = x['content']['$t'].split(',')

+        try:

+            image = teamData[1][7:]

+            image = image.replace("http://","",1)

+            image = urllib.quote(image)

+            image = 'http://' + image

+        except:

+            image = ""

+        name = x['title']['$t']

+        channelname = teamData[0][7:]

+        addDir(name,channelname,'team',image,)

+    xbmcplugin.endOfDirectory(thisPlugin)

+

+def createListOfTeamStreams(team=''):

+    jsonData = 
getJsonFromTwitchApi(url='http://api.twitch.tv/api/team/'+team+'/live_channels.json')

+    if jsonData is None:

+        return

+    for x in jsonData['channels']:

+        try:

+            image = x['channel']['image']['size600']

+            image = image.replace("http://","",1)

+            image = urllib.quote(image)

+            image = 'http://' + image

+        except:

+            image = ""

+        if x['channel']['title'] is None:

+            name = x['channel']['display_name']

+        else:

+            name = x['channel']['display_name']+' - '+x['channel']['title']

+        channelname = x['channel']['name']

+        addLink(name,'...','play',image,channelname)

+    xbmcplugin.endOfDirectory(thisPlugin)

+ 

+def createListOfGames(index=0):

+    jsonData = 
getJsonFromTwitchApi(url='https://api.twitch.tv/kraken/games/top?limit='+str(ITEMS_PER_SITE)+'&offset='+str(index*ITEMS_PER_SITE))

+    if jsonData is None:

+        return

+    for x in jsonData['top']:

+        try:

+            name = str(x['game']['name'])

+            game = urllib.quote(name)

+            image = ''

+        except:

+            continue

+        try:

+            image = x['game']['images']['super']

+            image = image.replace("http://","",1)

+            image = urllib.quote(image)

+            image = 'http://' + image

+        except:

+            image = ''

+        addDir(name,game,'channel',image)

+    if len(jsonData['top']) >= ITEMS_PER_SITE:

+        addDir(translation(31001),'','games','',index+1)

+    xbmcplugin.endOfDirectory(thisPlugin)

+

+def search():

+    keyboard = xbmc.Keyboard('', translation(30101))

+    keyboard.doModal()

+    if keyboard.isConfirmed() and keyboard.getText():

+        search_string = urllib.quote_plus(keyboard.getText())

+        sdata = 
downloadWebData('http://api.swiftype.com/api/v1/public/engines/search.json?callback=jQuery1337&q='+search_string+'&engine_key=9NXQEpmQPwBEz43TM592&page=1&per_page='+str(ITEMS_PER_SITE))

+        sdata = sdata.replace('jQuery1337','');

+        sdata = sdata[1:len(sdata)-1]

+        jdata = json.loads(sdata)

+        records = jdata['records']['broadcasts']

+        for x in records:

+            addLink(x['title'],x['user'],'play',x['thumbnail'],x['user'])

+        xbmcplugin.endOfDirectory(thisPlugin)

+

+       

+def createListForGame(gameName, index=0):

+    
jsonString=downloadWebData(url='https://api.twitch.tv/kraken/streams?game='+gameName+'&limit='+str(ITEMS_PER_SITE)+'&offset='+str(index*ITEMS_PER_SITE))

+    if jsonString is None:

+        return

+    jsonData=json.loads(jsonString)

+    try:

+        jsonData=json.loads(jsonString)

+    except:

+        
xbmc.executebuiltin('XBMC.Notification("'+translation(32008)+'","'+translation(32008)+'")')

+        return

+    for x in jsonData['streams']:

+        try:

+            image = x['channel']['logo']

+            image = image.replace("http://","",1)

+            image = urllib.quote(image)

+            image = 'http://' + image

+        except:

+            image = ""

+        name = x['channel']['status']

+        if name == '':

+            name = x['channel']['display_name']

+        channelname = x['channel']['name']

+        addLink(name,'...','play',image,channelname)

+    if len(jsonData['streams']) >= ITEMS_PER_SITE:

+        addDir(translation(31001),url,'channel','',index+1)

+    xbmcplugin.endOfDirectory(thisPlugin)

+       

+def addLink(name,url,mode,iconimage,channelname):

+        
u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&channelname="+channelname

+        ok=True

+        liz=xbmcgui.ListItem(name, iconImage="DefaultVideo.png", 
thumbnailImage=iconimage)

+        liz.setInfo( type="Video", infoLabels={ "Title": name } )

+        liz.setProperty('IsPlayable', 'true')

+        
ok=xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz)

+        return ok

+               

+def addDir(name,url,mode,iconimage,index=0):

+        
u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&siteIndex="+str(index)

+        ok=True

+        liz=xbmcgui.ListItem(name, iconImage="DefaultFolder.png", 
thumbnailImage=iconimage)

+        liz.setInfo( type="Video", infoLabels={ "Title": name } )

+        
ok=xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)

+        return ok

+               

+def get_request(url, headers=None):

+        try:

+            if headers is None:

+                headers = {'User-agent' : httpHeaderUserAgent,

+                           'Referer' : 'http://www.twitch.tv/'}

+            req = urllib2.Request(url,None,headers)

+            response = urllib2.urlopen(req)

+            link=response.read()

+            response.close()

+            return link

+        except urllib2.URLError, e:

+            errorStr = str(e.read())

+            if hasattr(e, 'code'):

+                if str(e.code) == '403':

+                    if 'archive' in url:

+                        
xbmc.executebuiltin("XBMC.Notification("+translation(31000)+"," 
+translation(32003)+ " " +name+")")

+                
xbmc.executebuiltin("XBMC.Notification("+translation(31000)+"," + 
translation(32001) +")")

+

+       

+def parameters_string_to_dict(parameters):

+        # Convert parameters encoded in a URL to a dict.

+        paramDict = {}

+        if parameters:

+            paramPairs = parameters[1:].split("&")

+            for paramsPair in paramPairs:

+                paramSplits = paramsPair.split('=')

+                if (len(paramSplits)) == 2:

+                    paramDict[paramSplits[0]] = paramSplits[1]

+        return paramDict

+               

+def getSwfUrl(channel_name):

+        # Helper method to grab the swf url, resolving HTTP 301/302 along the 
way

+        base_url = 
'http://www.justin.tv/widgets/live_embed_player.swf?channel=%s' % channel_name

+        headers = {'User-agent' : httpHeaderUserAgent,

+                   'Referer' : 'http://www.justin.tv/'+channel_name}

+        req = urllib2.Request(base_url, None, headers)

+        response = urllib2.urlopen(req)

+        return response.geturl()

+               

+def getBestJtvTokenPossible(name):

+        # Helper method to find another jtv token

+        swf_url = getSwfUrl(name)

+        headers = {'User-agent' : httpHeaderUserAgent,

+                   'Referer' : swf_url}

+        url = 'http://usher.justin.tv/find/'+name+'.json?type=any&group='

+        data = json.loads(get_request(url,headers))

+        bestVideoHeight = -1

+        bestIndex = 0

+        index = 0

+        for x in data:

+            value = x.get('token', '')

+            videoHeight = int(x['video_height'])

+            if (value != '') and (videoHeight > bestVideoHeight):

+                bestVideoHeight = x['video_height']

+                bestIndex = index  

+            index = index + 1

+        return data[bestIndex]

+

+def playLive(name, play=False, password=None):

+        swf_url = getSwfUrl(name)

+        headers = {'User-agent' : httpHeaderUserAgent,

+                   'Referer' : swf_url}

+        chosenQuality = settings.getSetting('video')

+        videoTypeName = 'any'

+        if chosenQuality == '0':

+            videoTypeName = 'any'

+        elif chosenQuality == '1':

+            videoTypeName = '720p'

+        elif chosenQuality == '2':

+            videoTypeName = '480p'

+        elif chosenQuality == '3':

+            videoTypeName = '360p'

+        url = 
'http://usher.justin.tv/find/'+name+'.json?type='+videoTypeName+'&private_code=null&group='

+        data = json.loads(get_request(url,headers))

+        tokenIndex = 0

+

+        try:

+            # trying to get a token in desired quality

+            token = ' 
jtv='+data[tokenIndex]['token'].replace('\\','\\5c').replace(' 
','\\20').replace('"','\\22')

+            rtmp = data[tokenIndex]['connect']+'/'+data[tokenIndex]['play']

+        except:

+            
xbmc.executebuiltin("XBMC.Notification("+translation(32005)+","+translation(32006)+")")

+            jtvtoken = getBestJtvTokenPossible(name)

+            if jtvtoken == '':

+                
xbmc.executebuiltin("XBMC.Notification("+translation(31000)+","+translation(32004)+")")

+                return

+            token = ' jtv='+jtvtoken['token'].replace('\\','\\5c').replace(' 
','\\20').replace('"','\\22')

+            rtmp = jtvtoken['connect']+'/'+jtvtoken['play']

+        

+        swf = ' swfUrl=%s swfVfy=1 live=1' % swf_url

+        Pageurl = ' Pageurl=http://www.justin.tv/'+name

+        url = rtmp+token+swf+Pageurl

+        if play == True:

+            info = xbmcgui.ListItem(name)

+            playlist = xbmc.PlayList(1)

+            playlist.clear()

+            playlist.add(url, info)

+            xbmc.executebuiltin('playlist.playoffset(video,0)')

+        else:

+            item = xbmcgui.ListItem(path=url)

+            xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, item)

+

+params=parameters_string_to_dict(sys.argv[2])

+mode=params.get('mode')

+url=params.get('url')

+sIndex=params.get('siteIndex')

+try:

+    index = int(sIndex)

+except:

+    index = 0

+channelname=params.get('channelname')

+if type(url)==type(str()):

+       url=urllib.unquote_plus(url)

+if mode == 'games':

+       createListOfGames(index)  

+elif mode == 'featured':

+       createListOfFeaturedStreams()

+elif mode == 'channel':

+       createListForGame(url, index)

+elif mode == 'play':

+       playLive(channelname)

+elif mode == 'following':

+       createFollowingList()

+elif mode == 'teams':

+        createListOfTeams()

+elif mode == 'team':

+        createListOfTeamStreams(url)

+elif mode == 'settings':

+       settings.openSettings()

+elif mode == 'search':

+       search()

+else:

+       createMainListing()

+

diff --git a/plugin.video.twitch/resources/language/English/strings.xml 
b/plugin.video.twitch/resources/language/English/strings.xml
index 63a3a97..67751ba 100644
--- a/plugin.video.twitch/resources/language/English/strings.xml
+++ b/plugin.video.twitch/resources/language/English/strings.xml
@@ -1,32 +1,37 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<strings>
-  <!-- main menu -->
-  <string id="30001">Games</string>
-  <string id="30002">Following</string>
-  <string id="30003">Search</string>
-  <string id="30004">Settings</string>
-  <string id="30005">Featured Streams</string>
-  
-  <!--search -->
-  <string id="30101">Search for channels</string>
-  
-  <!--general --> 
-  <string id="31000">TwitchTV</string>
-  <string id="31001">next page...</string>
-
-   <!--notifications --> 
-  <string id="32001">Http error</string>
-  <string id="32002">No Live Data Found</string>
-  <string id="32003">No archives found for</string>
-  <string id="32004">User Token Error</string>
-  <string id="32005">Changed video settings</string>
-  <string id="32006">Selected video settings are not available</string>
-  
-  <!--settings -->
-  <string id="33000">Video Quality</string>
-  <string id="33001">Best possible</string>
-  <string id="33002">720p</string>
-  <string id="33003">480p</string>
-  <string id="33004">360p</string>
-  
-</strings>
\ No newline at end of file
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>

+<strings>

+  <!-- main menu -->

+  <string id="30001">Games</string>

+  <string id="30002">Following</string>

+  <string id="30003">Search</string>

+  <string id="30004">Settings</string>

+  <string id="30005">Featured Streams</string>

+  <string id="30006">Teams</string>

+  

+  <!--search -->

+  <string id="30101">Search for channels</string>

+  

+  <!--general --> 

+  <string id="31000">TwitchTV</string>

+  <string id="31001">next page...</string>

+

+   <!--notifications --> 

+  <string id="32001">Http error</string>

+  <string id="32002">No Live Data Found</string>

+  <string id="32003">No archives found for</string>

+  <string id="32004">User Token Error</string>

+  <string id="32005">Changed video settings</string>

+  <string id="32006">Selected video settings are not available</string>

+  <string id="32007">TwitchApi error</string>

+  <string id="32008">JSON error</string>

+  <string id="32009">Failed to parse the result set</string>

+  <string id="32010">Please check your internet connection</string>

+  

+  <!--settings -->

+  <string id="33000">Video Quality</string>

+  <string id="33001">Best possible</string>

+  <string id="33002">720p</string>

+  <string id="33003">480p</string>

+  <string id="33004">360p</string>

+  

+</strings>

diff --git a/plugin.video.twitch/resources/language/German/strings.xml 
b/plugin.video.twitch/resources/language/German/strings.xml
index d51c540..d3e8315 100644
--- a/plugin.video.twitch/resources/language/German/strings.xml
+++ b/plugin.video.twitch/resources/language/German/strings.xml
@@ -1,31 +1,36 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<strings>
-  <!-- main menu -->
-  <string id="30001">Games</string>
-  <string id="30002">Folgend</string>
-  <string id="30003">Suche</string>
-  <string id="30004">Einstellungen</string>
-  <string id="30005">Featured Streams</string>
-  
-  <!-- search -->
-  <string id="30101">Suche nach Kanälen</string>
-  
-   <!--general --> 
-  <string id="31000">TwitchTV</string>
-  <string id="31001">nächste Seite...</string>
-
-   <!--notifications --> 
-  <string id="32001">Http Fehler</string>
-  <string id="32002">Keine Live-Daten gefunden</string>
-  <string id="32003">Keine Archive gefunden für</string>
-  <string id="32004">User Token Fehler</string>
-  <string id="32005">Geaenderte Video Einstellung</string>
-  <string id="32006">Gewaehlte Qualitaet nicht verfuegbar...Eventuell Premium 
Content?</string>
-  
-    <!--settings -->
-  <string id="33000">Video Qualität</string>
-  <string id="33001">Beste</string>
-  <string id="33002">720p</string>
-  <string id="33003">480p</string>
-  <string id="33004">360p</string>
-</strings>
\ No newline at end of file
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>

+<strings>

+  <!-- main menu -->

+  <string id="30001">Games</string>

+  <string id="30002">Folgend</string>

+  <string id="30003">Suche</string>

+  <string id="30004">Einstellungen</string>

+  <string id="30005">Featured Streams</string>

+  <string id="30006">Teams</string>

+  

+  <!-- search -->

+  <string id="30101">Suche nach Kanälen</string>

+  

+   <!--general --> 

+  <string id="31000">TwitchTV</string>

+  <string id="31001">nächste Seite...</string>

+

+   <!--notifications --> 

+  <string id="32001">Http Fehler</string>

+  <string id="32002">Keine Live-Daten gefunden</string>

+  <string id="32003">Keine Archive gefunden für</string>

+  <string id="32004">User Token Fehler</string>

+  <string id="32005">Geaenderte Video Einstellung</string>

+  <string id="32006">Gewaehlte Qualitaet nicht verfuegbar...Eventuell Premium 
Content?</string>

+  <string id="32007">TwitchApi Fehler</string>

+  <string id="32008">JSON Fehler</string>

+  <string id="32009">Fehlerhaftes Datenformat</string>

+  <string id="32010">Bitte Internet-Verbindung pruefen</string>

+  

+    <!--settings -->

+  <string id="33000">Video Qualität</string>

+  <string id="33001">Beste</string>

+  <string id="33002">720p</string>

+  <string id="33003">480p</string>

+  <string id="33004">360p</string>

+</strings>


http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=5a31ca4317ec7eef67030bc732566a91cdcc21af

commit 5a31ca4317ec7eef67030bc732566a91cdcc21af
Author: spiff <[email protected]>
Date:   Fri Oct 19 15:29:15 2012 +0200

    [plugin.image.iphoto] updated to version 1.9.2

diff --git a/plugin.image.iphoto/addon.py b/plugin.image.iphoto/addon.py
index 89370ea..0b5c471 100644
--- a/plugin.image.iphoto/addon.py
+++ b/plugin.image.iphoto/addon.py
@@ -194,8 +194,6 @@ def list_albums(params):
 
     albums = db.GetAlbums()
     if (not albums):
-       dialog = gui.Dialog()
-       dialog.ok(addon.getLocalizedString(30240), 
addon.getLocalizedString(30241))
        return
 
     commands = []
@@ -248,8 +246,6 @@ def list_events(params):
 
     rolls = db.GetRolls()
     if (not rolls):
-       dialog = gui.Dialog()
-       dialog.ok(addon.getLocalizedString(30240), 
addon.getLocalizedString(30241))
        return
 
     commands = []
@@ -310,8 +306,6 @@ def list_faces(params):
 
     faces = db.GetFaces()
     if (not faces):
-       dialog = gui.Dialog()
-       dialog.ok(addon.getLocalizedString(30240), 
addon.getLocalizedString(30241))
        return
 
     commands = []
@@ -378,8 +372,6 @@ def list_places(params):
 
     places = db.GetPlaces()
     if (not places):
-       dialog = gui.Dialog()
-       dialog.ok(addon.getLocalizedString(30240), 
addon.getLocalizedString(30241))
        return
 
     commands = []
@@ -441,8 +433,6 @@ def list_keywords(params):
 
     keywords = db.GetKeywords()
     if (not keywords):
-       dialog = gui.Dialog()
-       dialog.ok(addon.getLocalizedString(30240), 
addon.getLocalizedString(30241))
        return
 
     hidden_keywords = addon.getSetting('hidden_keywords')
@@ -542,12 +532,13 @@ def import_library(xmlpath, xmlfile, masterspath, 
masters_realpath, enable_place
     else:
        gui.Window(10000).setProperty("iphoto_scanning", "True")
 
-    # always ignore Books and currently selected album
+    # always ignore Books and all Event type albums
     album_ign = []
     album_ign.append("Book")
     album_ign.append("Selected Event Album")
+    album_ign.append("Event")
 
-    # ignore albums published to MobileMe if configured to do so
+    # ignore albums published to MobileMe/iCloud if configured to do so
     album_ign_publ = addon.getSetting('album_ignore_published')
     if (album_ign_publ == ""):
        album_ign_publ = "true"
@@ -590,7 +581,7 @@ def import_library(xmlpath, xmlfile, masterspath, 
masters_realpath, enable_place
     except:
        print traceback.print_exc()
     else:
-       iparser = IPhotoParser(xmlpath, xmlfile, masterspath, masters_realpath, 
album_ign, enable_places, map_aspect, db.AddAlbumNew, db.AddRollNew, 
db.AddFaceNew, db.AddKeywordNew, db.AddMediaNew, import_progress_callback, 
progress_dialog)
+       iparser = IPhotoParser(xmlpath, xmlfile, masterspath, masters_realpath, 
album_ign, enable_places, map_aspect, db.SetConfig, db.AddAlbumNew, 
db.AddRollNew, db.AddFaceNew, db.AddKeywordNew, db.AddMediaNew, 
import_progress_callback, progress_dialog)
 
        try:
            progress_dialog.update(0, addon.getLocalizedString(30219))
@@ -608,11 +599,6 @@ def import_library(xmlpath, xmlfile, masterspath, 
masters_realpath, enable_place
            print "iPhoto: Library imported successfully."
            progress_dialog.close()
            gui.Window(10000).setProperty("iphoto_scanning", "False")
-           try:
-               # this is non-critical
-               db.UpdateLastImport()
-           except:
-               pass
 
 def reset_db(params):
     try:
diff --git a/plugin.image.iphoto/addon.xml b/plugin.image.iphoto/addon.xml
index dde6093..edabc96 100644
--- a/plugin.image.iphoto/addon.xml
+++ b/plugin.image.iphoto/addon.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="plugin.image.iphoto" name="iPhoto" version="1.9.1" 
provider-name="jingai">
+<addon id="plugin.image.iphoto" name="iPhoto" version="1.9.2" 
provider-name="jingai">
     <requires>
        <import addon="xbmc.python" version="2.0"/>
        <import addon="script.module.simplejson" version="2.0.10"/>
diff --git a/plugin.image.iphoto/changelog.txt 
b/plugin.image.iphoto/changelog.txt
index d5ba4d8..8c30d50 100644
--- a/plugin.image.iphoto/changelog.txt
+++ b/plugin.image.iphoto/changelog.txt
@@ -1,3 +1,7 @@
+1.9.2 - 20121017
+- Fixes for iPhoto 9.4.
+- Ignore Albums of type "Event".
+
 1.9.1 - 20120803
 - Support for Metropolis skin.
 
diff --git a/plugin.image.iphoto/resources/lib/iphoto_parser.py 
b/plugin.image.iphoto/resources/lib/iphoto_parser.py
index 75f842b..a98f226 100644
--- a/plugin.image.iphoto/resources/lib/iphoto_parser.py
+++ b/plugin.image.iphoto/resources/lib/iphoto_parser.py
@@ -16,6 +16,7 @@ except:
 
 import sys
 import os
+import time
 import locale
 
 try:
@@ -172,7 +173,7 @@ class IPhotoDB:
               id integer primary key,
               name varchar,
               thumbpath varchar,
-              keyphotoid integer,
+              keyphotoid varchar,
               keyphotoidx integer,
               photocount integer,
               faceorder integer
@@ -273,16 +274,13 @@ class IPhotoDB:
 
        self.Commit()
 
-    def UpdateLastImport(self):
-       try:
-           self.SetConfig('lastimport', 'dummy')
-           self.dbconn.execute("""UPDATE config
-                                  SET value = datetime('now')
-                                  WHERE key = ?""",
-                               ('lastimport',))
-           self.Commit()
-       except Exception, e:
-           print "iphoto.db: UpdateLastImport: " + to_str(e)
+    def GetIphotoVersion(self):
+       verstr = self.GetConfig('version')
+       if (verstr == None):
+           ver = 0.0
+       else:
+           ver = float('.'.join(verstr.split('.')[:2]))
+       return ver
 
     def GetTableId(self, table, value, column='name', autoadd=False, 
autoclean=True):
        try:
@@ -383,11 +381,19 @@ class IPhotoDB:
        faces = []
        try:
            cur = self.dbconn.cursor()
+
+           if (self.GetIphotoVersion() < 9.4):
+               idtype = "M.id"
+           else:
+               idtype = "M.guid"
+
            cur.execute("""SELECT F.id, F.name, F.thumbpath, F.photocount
-                        FROM faces F LEFT JOIN media M ON F.keyphotoid = M.id
-                        ORDER BY F.faceorder""")
+                        FROM faces F LEFT JOIN media M ON F.keyphotoid = %s
+                        ORDER BY F.faceorder""" % (idtype))
+
            for tuple in cur:
                faces.append(tuple)
+
            cur.close()
        except Exception, e:
            print "iphoto.db: GetFaces: " + to_str(e)
@@ -633,6 +639,11 @@ class IPhotoDB:
        try:
            cur = self.dbconn.cursor()
 
+           if (self.GetIphotoVersion() < 9.4):
+               cmpkey = 'MediaID'
+           else:
+               cmpkey = 'GUID'
+
            faces = []
            cur.execute("""SELECT id, keyphotoid, keyphotoidx FROM faces""")
            for tuple in cur:
@@ -644,7 +655,7 @@ class IPhotoDB:
                VALUES (?, ?)""", (faceid, mediaid))
 
                for fid, fkey, fkeyidx in faces:
-                   if int(fkey) == int(mediaid):
+                   if (fkey == media[cmpkey]):
                        fthumb = os.path.splitext(thumbpath)[0] + "_face%s.jpg" 
% (fkeyidx)
                        self.dbconn.execute("""
                        UPDATE faces SET thumbpath = ?
@@ -791,6 +802,8 @@ class IPhotoParserState:
        self.nphotos = 0
        self.nphotostotal = 0
        self.level = 0
+       self.appversion = False
+       self.inappversion = 0
        self.archivepath = False
        self.inarchivepath = 0
        self.albums = False
@@ -812,6 +825,7 @@ class IPhotoParserState:
 class IPhotoParser:
     def __init__(self, library_path="", xmlfile="", masters_path="", 
masters_real_path="",
                 album_ign=[], enable_places=False, map_aspect=0.0,
+                config_callback=None,
                 album_callback=None, roll_callback=None, face_callback=None, 
keyword_callback=None, photo_callback=None,
                 progress_callback=None, progress_dialog=None):
        self.libraryPath = library_path
@@ -820,10 +834,11 @@ class IPhotoParser:
        self.mastersRealPath = masters_real_path
        if (self.mastersPath and self.mastersRealPath):
            try:
-               print "Rewriting referenced masters path '%s'" % 
(to_str(self.mastersPath))
-               print "as '%s'" % (to_str(self.mastersRealPath))
+               print "iphoto.db: Rewriting referenced masters path '%s'" % 
(to_str(self.mastersPath))
+               print "iphoto.db: as '%s'" % (to_str(self.mastersRealPath))
            except:
                pass
+       self.iphotoVersion = "0.0.0"
        self.imagePath = ""
        self.parser = xml.parsers.expat.ParserCreate()
        self.parser.StartElementHandler = self.StartElement
@@ -844,6 +859,7 @@ class IPhotoParser:
        self.albumIgn = album_ign
        self.enablePlaces = enable_places
        self.mapAspect = map_aspect
+       self.ConfigCallback = config_callback
        self.AlbumCallback = album_callback
        self.RollCallback = roll_callback
        self.FaceCallback = face_callback
@@ -938,6 +954,15 @@ class IPhotoParser:
                    self.PhotoCallback(a, self.imagePath, self.libraryPath, 
self.mastersPath, self.mastersRealPath, self.enablePlaces, self.mapAspect, 
self.updateProgress)
                    state.nphotos += 1
                    self.updateProgress()
+
+           if (self.ConfigCallback):
+               print "iphoto.db: Writing configuration"
+               if (self.iphotoVersion != "0.0.0"):
+                   self.ConfigCallback('version', self.iphotoVersion)
+               try:
+                   self.ConfigCallback('lastimport', to_str(time.time()))
+               except:
+                   pass
        except ParseCanceled:
            raise
        except Exception, e:
@@ -967,7 +992,10 @@ class IPhotoParser:
     def StartElement(self, name, attrs):
        state = self.state
        self.lastdata = False
-       if (state.archivepath):
+       if (state.appversion):
+           state.inappversion += 1
+           state.key = name
+       elif (state.archivepath):
            state.inarchivepath += 1
            state.key = name
        elif (state.albums):
@@ -1004,14 +1032,23 @@ class IPhotoParser:
        self.lastdata = False
        state = self.state
 
-       if (state.archivepath):
+       # Application Version
+       if (state.appversion):
+           if (not state.key):
+               self.iphotoVersion = state.value
+               print "iphoto.db: Detected iPhoto Version %s" % 
self.iphotoVersion
+               state.appversion = False
+           state.inappversion -= 1
+
+       # Archive Path
+       elif (state.archivepath):
            if (not state.key):
                self.imagePath = state.value
                state.archivepath = False
                if (self.imagePath != self.libraryPath):
                    try:
-                       print "Rewriting iPhoto archive path '%s'" % 
(to_str(self.imagePath))
-                       print "as '%s'" % (to_str(self.libraryPath))
+                       print "iPhoto.db: Rewriting iPhoto archive path '%s'" % 
(to_str(self.imagePath))
+                       print "iPhoto.db: as '%s'" % (to_str(self.libraryPath))
                    except:
                        pass
            state.inarchivepath -= 1
@@ -1098,7 +1135,14 @@ class IPhotoParser:
 
        # determine which section we are in
        if (state.key and state.level == 3):
-           if (data == "Archive Path"):
+           if (data == "Application Version"):
+               state.appversion = True
+               state.albums = False
+               state.rolls = False
+               state.faces = False
+               state.keywords = False
+               state.master = False
+           elif (data == "Archive Path"):
                state.archivepath = True
                state.albums = False
                state.rolls = False
@@ -1106,6 +1150,7 @@ class IPhotoParser:
                state.keywords = False
                state.master = False
            elif (data == "List of Albums"):
+               state.appversion = False
                state.archivepath = False
                state.albums = True
                state.rolls = False
@@ -1113,6 +1158,7 @@ class IPhotoParser:
                state.keywords = False
                state.master = False
            elif (data == "List of Rolls"):
+               state.appversion = False
                state.archivepath = False
                state.albums = False
                state.rolls = True
@@ -1120,6 +1166,7 @@ class IPhotoParser:
                state.keywords = False
                state.master = False
            elif (data == "List of Faces"):
+               state.appversion = False
                state.archivepath = False
                state.albums = False
                state.rolls = False
@@ -1127,6 +1174,7 @@ class IPhotoParser:
                state.keywords = False
                state.master = False
            elif (data == "List of Keywords"):
+               state.appversion = False
                state.archivepath = False
                state.albums = False
                state.rolls = False
@@ -1134,6 +1182,7 @@ class IPhotoParser:
                state.keywords = True
                state.master = False
            elif (data == "Master Image List"):
+               state.appversion = False
                state.archivepath = False
                state.albums = False
                state.rolls = False

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

Summary of changes:
 plugin.image.iphoto/addon.py                       |   22 +-
 plugin.image.iphoto/addon.xml                      |    2 +-
 plugin.image.iphoto/changelog.txt                  |    4 +
 plugin.image.iphoto/resources/lib/iphoto_parser.py |   91 +++-
 plugin.video.twitch/addon.xml                      |    2 +-
 plugin.video.twitch/changelog.txt                  |    4 +-
 plugin.video.twitch/default.py                     |  635 +++++++++++---------
 .../resources/language/English/strings.xml         |   69 ++-
 .../resources/language/German/strings.xml          |   67 ++-
 9 files changed, 511 insertions(+), 385 deletions(-)


hooks/post-receive
-- 
Plugins

------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_sfd2d_oct
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons

Reply via email to