Advertisement
Guest User

tvo scraper.py for both Kodi 18 and higher (both Python 2 and 3)

a guest
Dec 30th, 2023
85
0
240 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.70 KB | Source Code | 0 0
  1. # -*- coding: utf-8 -*-
  2. # TV Ontario Kodi Video Addon
  3. #
  4. from t1mlib import t1mAddon
  5. import json
  6. import re
  7. import os
  8. import xbmc
  9. import xbmcplugin
  10. import xbmcgui
  11. import sys
  12. import requests
  13.  
  14. URL_GRAPHQL_SERVER = "https://hmy0rc1bo2.execute-api.ca-central-1.amazonaws.com/graphql"
  15. USERAGENT = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36'
  16. HEADERS = {'User-Agent': USERAGENT,
  17.            'origin': 'https://www.tvo.org',
  18.            'referer': 'https://www.tvo.org/',
  19.            'Accept': "application/json, text/javascript, text/html,*/*",
  20.            'Accept-Encoding': 'gzip,deflate,sdch',
  21.            'Accept-Language': 'en-US,en;q=0.8'}
  22. PAGESIZE = 20
  23.  
  24. class myAddon(t1mAddon):
  25.  
  26.   def getAddonMenu(self, url, ilist):
  27.       json_data = {
  28.         'operationName': 'SeriesAndDocsNav',
  29.         'variables': {},
  30.         'query': 'query SeriesAndDocsNav {\n  getTVOOrgCategoriesMenu {\n    categoryTitle\n    path\n    __typename\n  }\n}\n',
  31.       }
  32.       response = requests.post(URL_GRAPHQL_SERVER, headers=HEADERS, json=json_data)
  33.       cats_js = json.loads(response.text)
  34.       for cat in cats_js["data"]["getTVOOrgCategoriesMenu"]:
  35.         name = cat["categoryTitle"]
  36.         url = name
  37.         # Append starting "after" position
  38.         url = url
  39.         infoList = {'mediatype':'tvshow',
  40.                     'Title': cat["categoryTitle"],
  41.                     'Plot': cat["path"]}
  42.         # Skip entries that are not 'SeriesDocsCategory', but instead are 'SeriesDocsFilterContent'
  43.         if (name != 'All' and name != 'Series' and name != 'Docs' and name != 'A-Z'):
  44.           ilist = self.addMenuItem(name, 'GS', ilist, url+'|0', self.addonIcon, self.addonFanart, infoList, isFolder=True)
  45.       return(ilist)
  46.  
  47.   def getAddonShows(self, url, ilist):
  48.       # Split into relative list position and category url
  49.       caturl = url.split('|', 1)[0]
  50.       position = url.split('|', 1)[1]
  51.       json_data = {
  52.         'operationName': 'SeriesDocsCategory',
  53.         'variables': {
  54.           'category': caturl,
  55.           'first': int(PAGESIZE),
  56.           'after': int(position),
  57.         },
  58.         'query': 'query SeriesDocsCategory($category: String!, $first: Int, $after: Int) {\n  categoryData: getTVOOrgCategoriesByName(\n    name: $category\n    first: $first\n    after: $after\n  ) {\n    categoryTitle\n    path\n    totalItems\n    content {\n      programTitle\n      path\n      imageSrc\n      imageAlt\n      episode\n      episodeTitle\n      program {\n        coverImage\n        featuredImage\n        __typename\n      }\n      __typename\n    }\n    __typename\n  }\n}\n',
  59.       }
  60.       response = requests.post(URL_GRAPHQL_SERVER, headers=HEADERS, json=json_data)
  61.       shows_js = json.loads(response.text)
  62.  
  63.       # Get total shows in category
  64.       numShows = shows_js["data"]["categoryData"][0]["totalItems"]
  65.  
  66.       # Loop though shows in category
  67.       for show in shows_js["data"]["categoryData"][0]["content"]:
  68.           episodes = show["episode"]
  69.           if (int(episodes) > 1):
  70.             name = "%s (Series)" % (show["programTitle"])
  71.           else:
  72.             name = show["programTitle"]
  73.           url = show["path"]
  74.           thumb = show["imageSrc"]
  75.           plot = show["path"]
  76.           infoList= {'mediatype': 'tvshow',
  77.                      'Title': name,
  78.                      'Plot': plot}
  79.           if (int(episodes) > 1):
  80.             ilist = self.addMenuItem(name, 'GE', ilist, url, thumb, thumb, infoList, isFolder=True)
  81.           else:
  82.             ilist = self.addMenuItem(name, 'GM', ilist, url, thumb, thumb, infoList, isFolder=True)
  83.       # Add "MORE" prompt if more shows to list
  84.       if ((int(position)+int(PAGESIZE)) < numShows):
  85.           nextUrl = caturl + '|' + str(int(int(position)+int(PAGESIZE)))
  86.           ilist = self.addMenuItem('[COLOR red]MORE[/COLOR]', 'GS', ilist, nextUrl, self.addonIcon, self.addonFanart, {}, isFolder=True)
  87.       return(ilist)
  88.  
  89.  
  90.   def getAddonEpisodes(self, url, ilist):
  91.       self.defaultVidStream['width']  = 640
  92.       self.defaultVidStream['height'] = 480
  93.       json_data = {
  94.         'operationName': 'ProgramOverview',
  95.         'variables': {
  96.           'slug': url,
  97.         },
  98.         'query': 'query ProgramOverview($slug: String) {\n  getTVOOrgProgramOverview(slug: $slug) {\n    title\n    tvoOriginal\n    description\n    summary\n    featuredImage\n    imageAlt\n    ctaText\n    uuid\n    nodeUrl\n    totalEpisodes\n    seasons {\n      season\n      totalEpisodes\n      seasonEpisodes\n      episodes {\n        episodeTitle\n        imageSrc\n        imageAlt\n        path\n        duration\n        episode\n        description\n        airDate\n        videoSource {\n          brightcoveRefId\n          __typename\n        }\n        __typename\n      }\n      __typename\n    }\n    __typename\n  }\n}\n',
  99.       }
  100.       response = requests.post(URL_GRAPHQL_SERVER, headers=HEADERS, json=json_data)
  101.       episodes_js = json.loads(response.text)
  102.  
  103.       show_title= episodes_js["data"]["getTVOOrgProgramOverview"]["title"]
  104.       # Loop though seasons
  105.       sdata_js = episodes_js["data"]["getTVOOrgProgramOverview"]["seasons"]
  106.       for j in sdata_js:
  107.           season   = j["season"]
  108.           edata_js = j["episodes"]
  109.           for k in edata_js:
  110.             episode = k["episode"]
  111.             name    = 's%se%s - %s' % (str(season), str(episode), k["episodeTitle"])
  112.             url     = k["path"]
  113.             thumb   = k["imageSrc"]
  114.             plot    = k["description"]
  115.             timetmp = k["duration"]
  116.             if timetmp.count(':') == 0:
  117.               duration = timetmp
  118.             else:
  119.               if timetmp.count(':') == 1:
  120.                 timetmp = "0:" + timetmp
  121.               # Calculate time in seconds
  122.               duration = sum(x * int(t) for x, t in zip([3600, 60, 1], timetmp.split(":")))
  123.             infoList= {'mediatype': 'episode',
  124.                        'TVShowTitle': show_title,
  125.                        'Title': name,
  126.                        'Duration': duration,
  127.                        'Plot': plot}
  128.             ilist = self.addMenuItem(name, 'GV', ilist, url, thumb, thumb, infoList, isFolder=False)
  129.       return(ilist)
  130.  
  131.   def getAddonMovies(self, url, ilist):
  132.       json_data = {
  133.         'operationName': 'getVideo',
  134.         'variables': {
  135.           'slug': url,
  136.         },
  137.         'query': 'query getVideo($slug: String) {\n  getTVOOrgVideo(slug: $slug) {\n    uuid\n    nid\n    isSingle\n    tvoOriginal\n    nodeUrl\n    assetUrl\n    thumbnail\n    title\n    airingTime\n    broadcastRating\n    contentCategory\n    isDoNotDisplayRelatedContent\n    mostRecentOptOut\n    firstAiringTime\n    publishedAt\n    ageGroups\n    telescopeAssetId\n    hasCC\n    hasDV\n    openInNewWindow\n    metaTags\n    videoSource {\n      brightcoveRefId\n      dvBrightcoveRefId\n      __typename\n    }\n    program {\n      uuid\n      nodeUrl\n      title\n      isAppearInAllRelatedVideos\n      promotion\n      featuredImage\n      isInvisible\n      metaTags\n      notAvailableMsg\n      openInNewWindow\n      description\n      summary\n      coverImage\n      telescopeAssetId\n      imageAlt\n      __typename\n    }\n    programOrder\n    relatedContentLink\n    relatedProgramTitle\n    season\n    strand\n    tags\n    tagLinks\n    description\n    summary\n    episode\n    transcript\n    length\n    __typename\n  }\n}\n',
  138.       }
  139.       response = requests.post(URL_GRAPHQL_SERVER, headers=HEADERS, json=json_data)
  140.       movie_js = json.loads(response.text)
  141.  
  142.       dtl = movie_js["data"]["getTVOOrgVideo"]
  143.       name    = dtl["title"]
  144.       url     = dtl["nodeUrl"]
  145.       thumb   = dtl["thumbnail"]
  146.       plot    = dtl["description"]
  147.       timetmp = dtl["length"]
  148.       if timetmp.count(':') == 0:
  149.         duration = timetmp
  150.       else:
  151.         if timetmp.count(':') == 1:
  152.           timetmp = "0:" + timetmp
  153.           # Calculate time in seconds
  154.         duration = sum(x * int(t) for x, t in zip([3600, 60, 1], timetmp.split(":")))
  155.       infoList= {'mediatype': 'movie',
  156.                  'Title': name,
  157.                  'Duration': duration,
  158.                  'Plot': plot}
  159.       ilist = self.addMenuItem(name, 'GV', ilist, url, thumb, thumb, infoList, isFolder=False)
  160.       return(ilist)
  161.  
  162.   def getAddonVideo(self, url):
  163.       json_data = {
  164.         'operationName': 'getVideo',
  165.         'variables': {
  166.           'slug': url,
  167.         },
  168.         'query': 'query getVideo($slug: String) {\n  getTVOOrgVideo(slug: $slug) {\n    uuid\n    nid\n    isSingle\n    tvoOriginal\n    nodeUrl\n    assetUrl\n    thumbnail\n    title\n    airingTime\n    broadcastRating\n    contentCategory\n    isDoNotDisplayRelatedContent\n    mostRecentOptOut\n    firstAiringTime\n    publishedAt\n    ageGroups\n    telescopeAssetId\n    hasCC\n    hasDV\n    openInNewWindow\n    metaTags\n    videoSource {\n      brightcoveRefId\n      dvBrightcoveRefId\n      __typename\n    }\n    program {\n      uuid\n      nodeUrl\n      title\n      isAppearInAllRelatedVideos\n      promotion\n      featuredImage\n      isInvisible\n      metaTags\n      notAvailableMsg\n      openInNewWindow\n      description\n      summary\n      coverImage\n      telescopeAssetId\n      imageAlt\n      __typename\n    }\n    programOrder\n    relatedContentLink\n    relatedProgramTitle\n    season\n    strand\n    tags\n    tagLinks\n    description\n    summary\n    episode\n    transcript\n    length\n    __typename\n  }\n}\n',
  169.       }
  170.       response = requests.post(URL_GRAPHQL_SERVER, headers=HEADERS, json=json_data)
  171.       video_js = json.loads(response.text)
  172.  
  173.       # Play video
  174.       vidurl = video_js["data"]["getTVOOrgVideo"]["assetUrl"]
  175.       if vidurl == '':
  176.         return False
  177.       liz = xbmcgui.ListItem(path=vidurl)
  178.       xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
  179.  
  180.       ###
  181.       ### Retrieve BrightCove credentials, Closed Captions and Play video
  182.       ###
  183.       ##URL_BRIGHTCOVE_DETAILS = 'http://www.tvo.org/static/js/15.3a3bcacf.chunk.js'
  184.       ##URL_BRIGHTCOVE_POLICY_KEY = 'http://players.brightcove.net/%s/%s_default/index.min.js'
  185.       #URL_BRIGHTCOVE_VIDEO_JSON = 'https://edge.api.brightcove.com/' \
  186.       #                            'playback/v1/accounts/%s/videos/%s'
  187.       ### data_account, video_id
  188.       #
  189.       ### AccountId, PlayerId
  190.       ##html = requests.get(URL_BRIGHTCOVE_DETAILS, headers=self.defaultHeaders).text
  191.       ##xbmc.log(msg='%s = %s' % ('DEBUG GAV html', str(html)), level=xbmc.LOGDEBUG)
  192.       ###URL_GRAPHQL_SERVER = re.compile('GQL_END_POINT:"(.+?)"',re.DOTALL).search(html).group(1)
  193.       ##BC_PLAYER_ACCOUNT = re.compile('BRIGHTCOVE_PLAYER_ACCOUNT:"(.+?)"',re.DOTALL).search(html).group(1)
  194.       ##BC_PLAYER_KEY = re.compile('BRIGHTCOVE_PLAYER_KEY:"(.*?)"',re.DOTALL).search(html).group(1)
  195.       ##BC_POLICY_KEY = re.compile('BRIGHTCOVE_POLICY_KEY:"(.*?)"',re.DOTALL).search(html).group(1)
  196.       #BC_PLAYER_ACCOUNT = "18140038001"
  197.       #BC_PLAYER_KEY = "HEy9xYDa7"
  198.       #BC_POLICY_KEY = "BCpkADawqM3GcA9H_gBNu1EPAEzHOmt9V6K6mOV7VWq1gPo3nGbZYy2Jcwhn8Pfs2Wx0D7Wq1zrWfiMOhNBJBlVq5SzWZZk_ec22WqI-JAksHAz9Zrvv-0JX4G4"
  199.       #
  200.       ## Get BrightCove data
  201.       #data_video_id   = video_js["data"]["getTVOOrgVideo"]["videoSource"]["brightcoveRefId"]
  202.       #xbmc.log(msg='%s = %s' % ('DEBUG GAV data_video_id', str(data_video_id)), level=xbmc.LOGDEBUG)
  203.       #bcurl = URL_BRIGHTCOVE_VIDEO_JSON % (BC_PLAYER_ACCOUNT, data_video_id)
  204.       #bcpolicykey = 'application/json;pk=%s' % BC_POLICY_KEY
  205.       #uheaders = self.defaultHeaders.copy()
  206.       #uheaders['Accept'] = bcpolicykey
  207.       #resp = requests.get(bcurl, headers=uheaders).text
  208.       #xbmc.log(msg='%s = %s' % ('DEBUG GAV resp', str(resp)), level=xbmc.LOGDEBUG)
  209.       #json_parser = json.loads(resp)
  210.       #vidurl = ''
  211.       #if 'sources' in json_parser:
  212.       #  for url in json_parser["sources"]:
  213.       #      if 'src' in url:
  214.       #          # DEBUG if 'm3u8' in url["src"]:
  215.       #          if 'main.mp4' in url["src"]:
  216.       #              vidurl = url["src"]
  217.       #if vidurl == '':
  218.       #  return False
  219.       #suburl = ''
  220.       #if 'text_tracks' in json_parser:
  221.       #  for url in json_parser["text_tracks"]:
  222.       #      if 'src' in url:
  223.       #          if 'text/vtt' in url["src"] and 'captions' in url["kind"]:
  224.       #              suburl = url["src"]
  225.       #              suburl = suburl.replace("http://", "https://")
  226.       #xbmc.log(msg='%s = %s' % ('DEBUG GAV vidurl', str(vidurl)), level=xbmc.LOGDEBUG)
  227.       #xbmc.log(msg='%s = %s' % ('DEBUG GAV suburl', str(suburl)), level=xbmc.LOGDEBUG)
  228.       #liz = xbmcgui.ListItem(path=vidurl)
  229.       #if suburl != '':
  230.       #  liz.setSubtitles([suburl])
  231.       #xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
  232.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement