The branch, frodo has been updated
via 0859b6c751a634f06524114b21eae9c9ec7f6a15 (commit)
via 923ff507934be2129acce2eca9947e63046cb235 (commit)
from c24502345a96fe14c0df04bc7bc69501bf3fe32e (commit)
- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=0859b6c751a634f06524114b21eae9c9ec7f6a15
commit 0859b6c751a634f06524114b21eae9c9ec7f6a15
Author: beenje <[email protected]>
Date: Wed Apr 3 22:02:04 2013 +0200
[plugin.video.twitch] updated to version 0.2.6
diff --git a/plugin.video.twitch/addon.xml b/plugin.video.twitch/addon.xml
index 17f304a..cf018bb 100644
--- a/plugin.video.twitch/addon.xml
+++ b/plugin.video.twitch/addon.xml
@@ -1,8 +1,9 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
-<addon id='plugin.video.twitch' version='0.2.2' name='TwitchTV'
provider-name='StateOfTheArt'>
+<addon id='plugin.video.twitch' version='0.2.6' name='TwitchTV'
provider-name='StateOfTheArt'>
<requires>
- <import addon='xbmc.python' version='2.0'/>
+ <import addon='xbmc.python' version='2.1.0'/>
<import addon='script.module.simplejson' version='2.0.10'/>
+ <import addon="script.module.xbmcswift2" version="1.2.0"/>
</requires>
<extension point='xbmc.python.pluginsource' library='default.py'>
<provides>video</provides>
@@ -10,9 +11,13 @@
<extension point='xbmc.addon.metadata'>
<platform>all</platform>
<language>en</language>
+ <source>https://github.com/StateOfTheArt89/Twitch.tv-on-XBMC</source>
+ <license>GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007</license>
<summary lang='de'>TwitchTV video plugin</summary>
<description lang='de'>Schaue die besten Gaming-Streams auf
XBMC!</description>
<summary lang='en'>TwitchTV video plugin</summary>
<description lang='en'>Watch your favorite gaming streams on
XBMC!</description>
+ <summary lang='pl'>TwitchTV video plugin</summary>
+ <description lang='pl'>OglÄ
daj ulubione programy TwitchTV na
XBMC!</description>
</extension>
</addon>
diff --git a/plugin.video.twitch/changelog.txt
b/plugin.video.twitch/changelog.txt
index e383461..315b815 100644
--- a/plugin.video.twitch/changelog.txt
+++ b/plugin.video.twitch/changelog.txt
@@ -23,4 +23,18 @@
0.2.1
- added featured streams section
0.2.2
-- added teams section - thx to kokarn
\ No newline at end of file
+- added teams section - thx to kokarn
+0.2.3
+- code refactor
+- integration of xbmcswift2
+0.2.4
+- fixed bug in following section
+- fixed bug in function getBestJtvTokenPossible
+0.2.5
+- serveral fixes and new features thx to grocal
+- fixed 'status' in favorite json data might be null
+- new translation: Polish
+- changed getting live favorite channels from on single .json query
(user/favorite with live=true variable set)
+- channel listing in format "[channel_name] channel_status_text"
+0.2.6
+- bug fix: crashes or wrong error messages, when opening streams
\ No newline at end of file
diff --git a/plugin.video.twitch/default.py b/plugin.video.twitch/default.py
index d726d05..506021f 100644
--- a/plugin.video.twitch/default.py
+++ b/plugin.video.twitch/default.py
@@ -1,355 +1,324 @@
-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()
-
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+import xbmcplugin
+import xbmcgui
+import sys
+import urllib2
+import urllib
+import re
+import xbmcaddon
+import os
+import socket
+try:
+ import json
+except:
+ import simplejson as json
+from xbmcswift2 import Plugin
+
+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
+plugin = Plugin()
+
+
+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:
+ showNotification(translation(32001), translation(32010))
+
+def showNotification(caption, text):
+ xbmc.executebuiltin("XBMC.Notification(" + caption + "," + text + ")")
+
+
+def getJsonFromTwitchApi(url):
+ jsonString = downloadWebData(url)
+ if jsonString is None:
+ return None
+ try:
+ jsonData = json.loads(jsonString)
+ except:
+ showNotification(translation(32008), translation(32008))
+ return None
+ if type(jsonData) is dict and 'error' in jsonData.keys():
+ showNotification(translation(32007),jsonData['error'])
+ return None
+ return jsonData
+
+def getTitle(streamer, title, viewers):
+ titleDisplay = settings.getSetting('titledisplay')
+ if streamer is None:
+ streamer = '-'
+ if title is None:
+ title = 'no title'
+ if viewers is None:
+ viewers = '0'
+
+ streamTitle = streamer + ' - ' + title
+ if titleDisplay == '0':
+ #Streamer - Stream Title
+ streamTitle = streamer + ' - ' + title
+ elif titleDisplay == '1':
+ #Viewers - Streamer - Stream Title
+ streamTitle = str(viewers) + ' - ' + streamer + ' - ' + title
+ elif titleDisplay == '2':
+ #Stream Title
+ streamTitle = title
+ elif titleDisplay == '3':
+ #Streamer
+ streamTitle = streamer
+ return streamTitle
+
+
[email protected]('/')
+def createMainListing():
+ items = [
+ {'label': translation(30005), 'path': plugin.url_for(
+ endpoint='createListOfFeaturedStreams'
+ )},
+ {'label': translation(30001), 'path': plugin.url_for(
+ endpoint='createListOfGames', sindex='0'
+ )},
+ {'label': translation(30002), 'path': plugin.url_for(
+ endpoint='createFollowingList'
+ )},
+ {'label': translation(30006), 'path': plugin.url_for(
+ endpoint='createListOfTeams', sindex='0'
+ )},
+ {'label': translation(30003), 'path': plugin.url_for(
+ endpoint='search'
+ )},
+ {'label': translation(30004), 'path': plugin.url_for(
+ endpoint='showSettings'
+ )}
+ ]
+ return items
+
[email protected]('/createListOfFeaturedStreams/')
+def createListOfFeaturedStreams():
+ items = []
+ jsonData = getJsonFromTwitchApi(
+ url='https://api.twitch.tv/kraken/streams/featured')
+ if jsonData is None:
+ return
+ for x in jsonData['featured']:
+ try:
+ streamData = x['stream']
+ channelData = x['stream']['channel']
+ loginname = channelData['name']
+ title = getTitle(streamer=channelData.get('name'),
title=channelData.get('status'), viewers=streamData.get('viewers'))
+ items.append({'label': title, 'path':
plugin.url_for(endpoint='playLive', name=loginname),
+ 'is_playable': True, 'icon' : channelData['logo']})
+ except:
+ pass
+ return items
+
+
[email protected]('/createListOfGames/<sindex>/')
+def createListOfGames(sindex):
+ index = int(sindex)
+ items = []
+ 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'])
+ except:
+ continue
+ try:
+ image = x['game']['images']['super']
+ except:
+ image = ''
+ items.append({'label': name, 'path': plugin.url_for(
+ 'createListForGame', gameName=name, sindex='0'), 'icon' : image})
+ if len(jsonData['top']) >= ITEMS_PER_SITE:
+ items.append({'label': translation(31001), 'path':
plugin.url_for('createListOfGames', sindex=str(index + 1))})
+ return items
+
+
[email protected]('/createListForGame/<gameName>/<sindex>/')
+def createListForGame(gameName, sindex):
+ index = int(sindex)
+ items = []
+ jsonData =
getJsonFromTwitchApi(url='https://api.twitch.tv/kraken/streams?game=' +
urllib.quote_plus(gameName) + '&limit=' + str(ITEMS_PER_SITE) + '&offset=' +
str(index * ITEMS_PER_SITE))
+ if jsonData is None:
+ return
+ for x in jsonData['streams']:
+ channelData = x['channel']
+ try:
+ image = channelData['logo']
+ except:
+ image = ""
+ title = getTitle(streamer=channelData.get('name'),
title=channelData.get('status'), viewers=x.get('viewers'))
+ items.append({'label': title, 'path':
plugin.url_for(endpoint='playLive', name=channelData['name']),
+ 'is_playable' : True, 'icon' : image})
+ if len(jsonData['streams']) >= ITEMS_PER_SITE:
+ items.append({'label': translation(31001), 'path': plugin.url_for(
+ 'createListForGame', gameName=gameName, sindex=str(index + 1))})
+ return items
+
+
[email protected]('/createFollowingList/')
+def createFollowingList():
+ items = []
+ username = settings.getSetting('username').lower()
+ if not username:
+ settings.openSettings()
+ username = settings.getSetting('username').lower()
+ jsonData = getJsonFromTwitchApi('http://api.justin.tv/api/user/favorites/'
+ username + '.json?limit=100&offset=0&live=true')
+ if jsonData is None:
+ return
+ for x in jsonData:
+ loginname = x['login']
+ image = x['image_url_huge']
+ title = getTitle(streamer=x.get('login'), title=x.get('status'),
viewers=x.get('views_count'))
+ items.append({'label': title , 'path':
plugin.url_for(endpoint='playLive', name=loginname), 'icon' : image,
'is_playable' : True})
+ return items
+
[email protected]('/createListOfTeams/')
+def createListOfTeams():
+ items = []
+ jsonData = getJsonFromTwitchApi('https://api.twitch.tv/kraken/teams/')
+ if jsonData is None:
+ return
+ for x in jsonData['teams']:
+ try:
+ image = x['logo']
+ except:
+ image = ""
+ name = x['name']
+ items.append({'label': name, 'path':
plugin.url_for(endpoint='createListOfTeamStreams', team=name), 'icon' : image})
+ return items
+
+
[email protected]('/createListOfTeamStreams/<team>/')
+def createListOfTeamStreams(team):
+ items = []
+ jsonData = getJsonFromTwitchApi(url='http://api.twitch.tv/api/team/' +
urllib.quote_plus(team) + '/live_channels.json')
+ if jsonData is None:
+ return
+ for x in jsonData['channels']:
+ try:
+ image = x['channel']['image']['size600']
+ except:
+ image = ""
+ try:
+ channelData = x['channel']
+ title = getTitle(streamer=channelData.get('display_name'),
title=channelData.get('title'), viewers=channelData.get('current_viewers'))
+ channelname = x['channel']['name']
+ items.append({'label': title, 'path':
plugin.url_for(endpoint='playLive', name=channelname), 'is_playable' : True,
'icon' : image})
+ except:
+ # malformed data element
+ pass
+ return items
+
+
[email protected]('/search/')
+def search():
+ items = []
+ 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:
+ items.append({'label': x['title'], 'path': plugin.url_for(
+ endpoint='playLive', name=x['user']
+ ), 'is_playable' : True})
+ return items
+
[email protected]('/showSettings/')
+def showSettings():
+ #there is probably a better way to do this
+ settings.openSettings()
+
+
+def getSwfUrl(channel_name):
+ # Helper method to grab the swf url
+ 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(downloadWebData(url))
+ 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
+ if bestIndex == -1:
+ return None
+ return data[bestIndex]
+
+
[email protected]('/playLive/<name>/')
+def playLive(name):
+ 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(downloadWebData(url))
+ 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:
+ showNotification(translation(32005),translation(32006))
+ jtvtoken = getBestJtvTokenPossible(name)
+ if jtvtoken is None:
+ showNotification(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=true' % swf_url
+ Pageurl = ' Pageurl=http://www.justin.tv/' + name
+ url = rtmp+token+swf+Pageurl
+ item = xbmcgui.ListItem(path=url)
+ xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, item)
+
+
+if __name__ == '__main__':
+ plugin.run()
diff --git a/plugin.video.twitch/resources/language/English/strings.xml
b/plugin.video.twitch/resources/language/English/strings.xml
index 67751ba..52dca61 100644
--- a/plugin.video.twitch/resources/language/English/strings.xml
+++ b/plugin.video.twitch/resources/language/English/strings.xml
@@ -1,37 +1,43 @@
-<?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>
+<?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>
+ <string id="33010">Display titles</string>
+ <string id="33011">Streamer - Stream Title</string>
+ <string id="33012">Viewers - Streamer - Stream Title</string>
+ <string id="33013">Stream Title</string>
+ <string id="33014">Streamer</string>
+
+ <string id="33100">Username</string>
+</strings>
diff --git a/plugin.video.twitch/resources/language/German/strings.xml
b/plugin.video.twitch/resources/language/German/strings.xml
index d3e8315..efc1f79 100644
--- a/plugin.video.twitch/resources/language/German/strings.xml
+++ b/plugin.video.twitch/resources/language/German/strings.xml
@@ -1,36 +1,43 @@
-<?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>
+<?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>
+ <string id="33010">Stream-Bezeichnung</string>
+ <string id="33011">Streamer - Status</string>
+ <string id="33012">Zuschauerzahl - Streamer - Status</string>
+ <string id="33013">Status</string>
+ <string id="33014">Streamer</string>
+
+ <string id="33100">Benutzername</string>
+</strings>
diff --git a/plugin.video.twitch/resources/settings.xml
b/plugin.video.twitch/resources/settings.xml
index c6e5de9..8056a0e 100644
--- a/plugin.video.twitch/resources/settings.xml
+++ b/plugin.video.twitch/resources/settings.xml
@@ -2,9 +2,11 @@
<settings>
<!-- General -->
<category label="General">
- <setting id="username" type="text" label="Username" default="" />
+ <setting id="username" type="text" label="33100" default="" />
<!-- Video Quality -->
<setting id="video" type="enum" label="33000"
lvalues="33001|33002|33003|33004" default="0" />
+ <!-- Title Display -->
+ <setting id="titledisplay" type="enum" label="33010"
lvalues="33011|33012|33013|33014" default="0" />
</category>
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=923ff507934be2129acce2eca9947e63046cb235
-----------------------------------------------------------------------
Summary of changes:
.../LICENSE.txt | 0
plugin.program.rpcalendar/Mayan-calendar.jpg | Bin 0 -> 125954 bytes
plugin.program.rpcalendar/addon.py | 136 ++++
plugin.program.rpcalendar/addon.xml | 19 +
plugin.program.rpcalendar/changelog.txt | 2 +
plugin.program.rpcalendar/fanart.jpg | Bin 0 -> 203563 bytes
plugin.program.rpcalendar/icon.png | Bin 0 -> 98216 bytes
.../resources/__init__.py | 0
.../resources/language/English/strings.xml | 16 +
.../resources/media/background.jpg | Bin 0 -> 681682 bytes
plugin.video.twitch/README.md | 27 +
plugin.video.twitch/addon.xml | 9 +-
plugin.video.twitch/changelog.txt | 16 +-
plugin.video.twitch/default.py | 679 ++++++++++----------
.../resources/language/English/strings.xml | 80 ++--
.../resources/language/German/strings.xml | 79 ++-
.../resources/language/Polish/strings.xml | 43 ++
plugin.video.twitch/resources/settings.xml | 4 +-
18 files changed, 678 insertions(+), 432 deletions(-)
copy {plugin.audio.booksshouldbefree_com =>
plugin.program.rpcalendar}/LICENSE.txt (100%)
create mode 100644 plugin.program.rpcalendar/Mayan-calendar.jpg
create mode 100644 plugin.program.rpcalendar/addon.py
create mode 100644 plugin.program.rpcalendar/addon.xml
create mode 100644 plugin.program.rpcalendar/changelog.txt
create mode 100644 plugin.program.rpcalendar/fanart.jpg
create mode 100644 plugin.program.rpcalendar/icon.png
copy {plugin.image.iphoto => plugin.program.rpcalendar}/resources/__init__.py
(100%)
create mode 100644
plugin.program.rpcalendar/resources/language/English/strings.xml
create mode 100644 plugin.program.rpcalendar/resources/media/background.jpg
create mode 100644 plugin.video.twitch/README.md
create mode 100644 plugin.video.twitch/resources/language/Polish/strings.xml
hooks/post-receive
--
Plugins
------------------------------------------------------------------------------
Minimize network downtime and maximize team effectiveness.
Reduce network management and security costs.Learn how to hire
the most talented Cisco Certified professionals. Visit the
Employer Resources Portal
http://www.cisco.com/web/learning/employer_resources/index.html
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons