2019-06-29, 05:50
I think this addon is dead.
(2019-07-16, 19:44)kodaksmith Wrote: YouRecently I located the Pull Request mentioned in post 369, applied the changes on a RPi3 with LibreELEC 8.2.5 (Kodi 17.6), and was able to play more shows than previously, but not all shows. As far as I can tell the PR does not implement the new authentication method mentioned earlier in this thread.
Interested parties might try to manually duplicate the commits in the PR for proposed PBS ThinkTV.org 3.0.17.
(2019-07-28, 03:14)jdf76 Wrote:(2019-07-16, 19:44)kodaksmith Wrote: YouRecently I located the Pull Request mentioned in post 369, applied the changes on a RPi3 with LibreELEC 8.2.5 (Kodi 17.6), and was able to play more shows than previously, but not all shows. As far as I can tell the PR does not implement the new authentication method mentioned earlier in this thread.You could try and fork it and start a split off the original. Just a thought.
Interested parties might try to manually duplicate the commits in the PR for proposed PBS ThinkTV.org 3.0.17.
Thanks very much for your post. I did what you suggest above, manually apply the changes from github, and the addon is back in a working state! I've mostly checked NOVA, and almost all episodes seem to be available.
Only one quibble/question: the stream I get seems to be limited to 720p. No 1080.
(2019-07-16, 19:44)kodaksmith Wrote: Recently I located the Pull Request mentioned in post 369, applied the changes on a RPi3 with LibreELEC 8.2.5 (Kodi 17.6), and was able to play more shows than previously, but not all shows. As far as I can tell the PR does not implement the new authentication method mentioned earlier in this thread.
Interested parties might try to manually duplicate the commits in the PR for proposed PBS ThinkTV.org 3.0.17.
----- End of file -----python:
# -*- coding: utf-8 -*-
# KodiAddon PBS ThinkTV
#
from t1mlib import t1mAddon
import json
import re
import os
import urllib
import urllib2
import cookielib
import xbmcplugin
import datetime
import xbmc
import xbmcgui
import HTMLParser
import sys
try:
from urllib import quote # Python 2.X
except ImportError:
from urllib.parse import quote # Python 3+
h = HTMLParser.HTMLParser()
UTF8 = 'utf-8'
showsPerPage = 24 # number of shows returned per page by PBS
class myAddon(t1mAddon):
def doPBSLogin(self):
return()
def getPBSCookie(self):
html = self.getRequest('https://localization.services.pbs.org/localize/auto/cookie/')
a = json.loads(html)
a = a['cookie']
b = re.compile('\["(.+?)".+?\["(.+?)"', re.DOTALL).search(a)
if b is not None:
station, station_id = b.groups()
cookie = 'pbsol.sta_extended=%s; pbsol.station=%s; pbsol.station_id=%s; pbskids.localized=%s' % (quote(a),station, station_id, station)
else:
cookie = ''
return(cookie)
def getAddonMenu(self,url,ilist):
addonLanguage = self.addon.getLocalizedString
self.doPBSLogin()
#xheaders = self.defaultHeaders.copy()
#xheaders["Referer"] = "http://www.pbs.org/shows/?genre=All&title=&station=false&alphabetically=true&layout=grid"
#xheaders["X-Requested-With"] = "XMLHttpRequest"
#html = self.getRequest('http://www.pbs.org/shows-page/0/?genre=&title=&callsign=&alphabetically=true', None, xheaders)
#xbmc.log("html: "+html, xbmc.LOGNOTICE)
#a = json.loads(html)
#for b in a['genres'][1:]:
#ilist = self.addMenuItem(b['title'],'GS', ilist, str(b['id'])+'|0', self.addonIcon, self.addonFanart, None, isFolder=True)
genres = [ ['Arts & Music', 'arts-and-music']
, ['Culture', 'culture']
, ['Drama', 'drama']
, ['Food', 'food']
, ['History', 'history']
, ['Home & How-To', 'home-and-howto']
, ['Indie Films', 'indie-films']
, ['News & Public Affairs', 'news-and-public-affairs']
, ['Science & Nature', 'science-and-nature']
]
url = 'https://www.pbs.org/shows/?search=culture&source=all-sources&sortBy=a-z&genre='
for a in range(len(genres)):
genrename = genres[a][0]
genreurl = url+genres[a][1]+'|0'
ilist = self.addMenuItem(genrename,'GS', ilist, genreurl, self.addonIcon, self.addonFanart, None, isFolder=True)
if self.addon.getSetting('enable_login') == 'true':
pbsol = self.addon.getSetting('pbsol')
if pbsol != '':
xheaders = self.defaultHeaders.copy()
xheaders['X-Requested-With'] = 'XMLHttpRequest'
html = self.getRequest('http://www.pbs.org/shows-page/0/?genre=&title=&callsign=%s&alphabetically=true' % pbsol, None, xheaders)
if len(html) > 0:
a = json.loads(html)
if len(a['results']['content']) > 0:
ilist = self.addMenuItem(addonLanguage(30048) ,'GS', ilist, 'localpbs' , self.addonIcon, self.addonFanart, None, isFolder=True)
html = self.getRequest('https://www.pbs.org/favorite-shows-page/1/')
if len(html) > 0:
a = json.loads(html)
if a['totalResults'] > 0:
ilist = self.addMenuItem(addonLanguage(30004),'GS', ilist, 'favorites' , self.addonIcon, self.addonFanart, None, isFolder=True)
xheaders = self.defaultHeaders.copy()
xheaders['X-Requested-With'] = 'XMLHttpRequest'
html = self.getRequest('https://www.pbs.org/watchlist/page/1/', None, xheaders)
if len(html) > 0:
a = json.loads(html)
if a.get('videos') is not None:
if len(a['videos']) > 0:
ilist = self.addMenuItem(addonLanguage(30005) ,'GM', ilist, 'pbswatchlist' , self.addonIcon, self.addonFanart, None, isFolder=True)
ilist = self.addMenuItem(addonLanguage(30051) ,'GS', ilist, 'pbssearch' , self.addonIcon, self.addonFanart, None, isFolder=True)
return ilist
def getAddonShows(self,url,ilist):
pgNum = ''
addonLanguage = self.addon.getLocalizedString
self.doPBSLogin()
gsurl = url
if gsurl == 'favorites':
html = self.getRequest('http://www.pbs.org/favorite-shows-page/1/')
a = json.loads(html)
cats = a['content']
elif gsurl == 'localpbs':
xheaders = self.defaultHeaders.copy()
xheaders['X-Requested-With'] = 'XMLHttpRequest'
pbsol = self.addon.getSetting('pbsol')
html = self.getRequest('http://www.pbs.org/shows-page/0/?genre=&title=&callsign=%s&alphabetically=true' % (pbsol), None, xheaders)
a = json.loads(html)
cats = a['results']['content']
elif gsurl == 'pbssearch':
keyb = xbmc.Keyboard(self.addon.getSetting('last_search'), addonLanguage(30051))
keyb.doModal()
if (keyb.isConfirmed()):
answer = keyb.getText()
if len(answer) == 0:
return (ilist)
self.addon.setSetting('last_search', answer)
answer = answer.replace(' ','+')
xheaders = self.defaultHeaders.copy()
xheaders['X-Requested-With'] = 'XMLHttpRequest'
html = self.getRequest('http://www.pbs.org/search-videos/?callsign=WNET&page=1&q=%s&rank=relevance' % (answer), None, xheaders)
a = json.loads(html)
cats = a['results']['articles']
else:
genreUrl, pgNum = url.split('|',1)
xheaders = self.defaultHeaders.copy()
xheaders['X-Requested-With'] = 'XMLHttpRequest'
html = self.getRequest('http://www.pbs.org/shows-page/%s/?genre=%s&title=&callsign=&alphabetically=true' % (pgNum, genreUrl), None, xheaders)
a = json.loads(html)
cats = a['results']['content']
for i, (b) in list(enumerate(cats, start=1)):
if gsurl == 'pbssearch':
url = b['url']
else:
url = b.get('url')
if url is None:
url = b['id']
name = b['title']
thumb = b['image']
if thumb == None :
thumb = self.addonIcon
fanart = b['image']
if fanart == None:
fanart = self.addonFanart
infoList = {}
infoList['TVShowTitle'] = name
infoList['Title'] = name
infoList['Studio'] = b.get('producer')
genres = b.get('genre_titles')
if genres != [] and genres is not None:
infoList['Genre'] = genres[0]
infoList['Episode'] = b.get('video_count')
infoList['Plot'] = b.get('description')
if self.addon.getSetting('enable_login') == 'true':
if gsurl == 'favorites':
contextMenu = [(addonLanguage(30006),'XBMC.Container.Update(%s?mode=DF&url=RF%s)' % (sys.argv[0], url))]
else:
contextMenu = [(addonLanguage(30007),'XBMC.RunPlugin(%s?mode=DF&url=AF%s)' % (sys.argv[0], url))]
else:
contextMenu = None
if gsurl == 'pbssearch':
infoList['mediatype'] = 'episode'
ilist = self.addMenuItem(name,'GV', ilist, url, thumb, fanart, infoList, isFolder=False)
else:
infoList['mediatype'] = 'tvshow'
ilist = self.addMenuItem(name,'GC', ilist, url, thumb, fanart, infoList, isFolder=True, cm=contextMenu)
if pgNum != '':
ilist = self.addMenuItem('[COLOR blue]%s[/COLOR]' % addonLanguage(30050),'GS', ilist, genreUrl+'|'+str(int(pgNum)+1), self.addonIcon, self.addonFanart, None, isFolder=True)
return(ilist)
def getAddonCats(self,url,ilist):
addonLanguage = self.addon.getLocalizedString
self.doPBSLogin()
thumb = xbmc.getInfoLabel('ListItem.Art(thumb)')
fanart = xbmc.getInfoLabel('ListItem.Art(fanart)')
infoList = {}
infoList['TVShowTitle'] = xbmc.getInfoLabel('ListItem.TVShowTitle')
infoList['Title'] = infoList['TVShowTitle']
infoList['mediatype'] = 'tvshow'
xheaders = self.defaultHeaders.copy()
xheaders['Cookie'] = self.getPBSCookie()
html = self.getRequest('https://www.pbs.org%s' % url, None, xheaders)
seasons = re.compile('"name": " Season (.+?)"', re.DOTALL).findall(html)
if not seasons:
ilist = self.addMenuItem('%s' % (addonLanguage(30045)),'GE', ilist, '%s|%s|1' %(url, 'episodes'), thumb, fanart, infoList, isFolder=True)
else:
for season in seasons:
season = season.strip()
surl = 'episodes/season/'+season
ilist = self.addMenuItem('Season %s' % season,'GE', ilist, '%s|%s|1' %(url, surl), thumb, fanart, infoList, isFolder=True)
ilist = self.addMenuItem('Specials','GE', ilist, '%s|%s|1' %(url, 'specials'), thumb, fanart, infoList, isFolder=True)
ilist = self.addMenuItem('Extras','GE', ilist, '%s|%s|1' %(url, 'extras'), thumb, fanart, infoList, isFolder=True)
ilist = self.addMenuItem('Collections','GE', ilist, '%s|%s|1' %(url, 'collections'), thumb, fanart, infoList, isFolder=True)
return(ilist)
def getAddonEpisodes(self,url,ilist):
self.doPBSLogin()
addonLanguage = self.addon.getLocalizedString
url, stype, pageNum = url.split('|',2)
sname = url
xheaders = self.defaultHeaders.copy()
xheaders['Cookie'] = self.getPBSCookie()
html = self.getRequest('https://www.pbs.org%s%s/?page=%s' % (url, stype, pageNum), None, xheaders)
epis = re.compile('<article class="video-summary">.+?data-srcset="(.+?)".+?alt="(.+?)".+?class="description">(.+?)<.+?data-video-slug="(.+?)"',re.DOTALL).findall(html)
if not epis:
epis = re.compile('<div class="video-summary".+?data-video-slug="(.+?)".+?data-srcset="(.+?)".+?alt="(.+?)".+?class="description">(.+?)<',re.DOTALL).findall(html)
for i, (url, imgs, name, plot) in list(enumerate(epis, start=1)):
name = h.unescape(name.decode(UTF8))
name = name.replace('Video thumbnail: ','',1)
plot=plot.strip()
infoList = {}
imgs = imgs.split(',')
thumb = '%s.jpg' % (imgs[2].split('.jpg',1)[0].strip())
fanart = '%s.jpg' % (imgs[len(imgs)-1].split('.jpg',1)[0].strip())
infoList['Title'] = name
infoList['Plot'] = h.unescape(plot.decode(UTF8))
infoList['mediatype'] = 'episode'
infoList['TVShowTitle'] = xbmc.getInfoLabel('ListItem.TVShowTitle')
if self.addon.getSetting('enable_login') == 'true':
contextMenu = [(addonLanguage(30008),'XBMC.RunPlugin(%s?mode=DF&url=AW%s)' % (sys.argv[0], url))]
else:
contextMenu = None
ilist = self.addMenuItem(name,'GV', ilist, url, thumb, fanart, infoList, isFolder=False, cm=contextMenu)
if i >= showsPerPage:
ilist = self.addMenuItem('[COLOR blue]%s[/COLOR]' % addonLanguage(30050),'GE', ilist, '%s|%s|%s' %(sname, stype, str(int(pageNum)+1)), self.addonIcon, self.addonFanart, None, isFolder=True)
return(ilist)
def getAddonMovies(self,url,ilist):
addonLanguage = self.addon.getLocalizedString
xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
self.doPBSLogin()
xheaders = self.defaultHeaders.copy()
xheaders['X-Requested-With'] = 'XMLHttpRequest'
html = self.getRequest('https://www.pbs.org/watchlist/page/1/', None, xheaders)
a = json.loads(html)
epis = a['videos']
for i, b in list(enumerate(epis, start=1)):
infoList = {}
name = b['title']
plot = b['description']
duration = b['duration']
t = 0
for dur in duration.split(':'):
if dur.strip().isdigit():
t = t*60 + int(dur.strip())
if t != 0:
infoList['duration'] = t
thumb = b['image']
fanart = b['image']
infoList['TVShowTitle'] = b['show']['title']
infoList['Title'] = name
infoList['Plot'] = plot
infoList['mediatype'] = 'episode'
url = str(b['id'])
contextMenu = [(addonLanguage(30009),'XBMC.Container.Update(%s?mode=DF&url=RW%s)' % (sys.argv[0], url))]
ilist = self.addMenuItem(name,'GV', ilist, url, thumb, fanart, infoList, isFolder=False, cm=contextMenu)
return(ilist)
def doFunction(self, url):
self.doPBSLogin()
func = url[0:2]
url = url[2:]
if func == 'AW':
html = self.getRequest('http://www.pbs.org/profile/addFavoriteVideo/%s/' % url)
elif func == 'AF':
html = self.getRequest('http://www.pbs.org/profile/addFavoriteProgram/%s/' % url)
elif func == 'RW':
html = self.getRequest('http://www.pbs.org/profile/removeFavoriteVideo/%s/' % url)
elif func == 'RF':
html = self.getRequest('http://www.pbs.org/profile/removeFavoriteProgram/%s/' % url)
try:
a = json.loads(html)
xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( self.addonName, a['errorMessage'] , 4000) )
except: pass
def getAddonVideo(self,url):
xheaders = self.defaultHeaders.copy()
xheaders['X-Requested-With'] = 'XMLHttpRequest'
if not url.startswith('/video'):
html = self.getRequest('http://www.pbs.org/video/%s/' % (url), None, xheaders)
else:
html = self.getRequest('http://www.pbs.org%s' % (url), None, xheaders)
url = re.compile("id: '(.+?)'", re.DOTALL).search(html).group(1)
addonLanguage = self.addon.getLocalizedString
pbs_uid = self.addon.getSetting('pbs_uid')
pg = self.getRequest('https://player.pbs.org/viralplayer/%s/?uid=%s' % (url, pbs_uid))
pg = re.compile('window.videoBridge = (.+?);\n', re.DOTALL).search(pg).group(1)
a = json.loads(pg)
if not a is None:
# url = a['recommended_encoding']['url']
suburl = a['cc'].get('SRT')
urls = a['encodings']
url = ''
for xurl in urls:
pg = self.getRequest('%s?format=json' % xurl)
xurl = json.loads(pg)['url']
if xurl.endswith('.m3u8'):
if url.endswith('800k.m3u8') or url.endswith('.mp4'):
url = xurl
break
else:
url = xurl
else:
if not url.endswith('.m3u8'):
url = xurl
else:
xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( self.addonName, addonLanguage(30049) , 4000) )
return
# if 'mp4:' in url:
# url = 'http://ga.video.cdn.pbs.org/%s' % url.split('mp4:',1)[1]
liz = xbmcgui.ListItem(path = url)
if not suburl is None:
subfile = self.procConvertSubtitles(suburl)
liz.setSubtitles([(subfile)])
if ('.m3u8' in url):
liz.setProperty('inputstreamaddon','inputstream.adaptive')
liz.setProperty('inputstream.adaptive.manifest_type','hls')
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)