Advertisement
kofii12345

c+vod tv

Mar 10th, 2021
2,147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.24 KB | None | 0 0
  1. try:  # Python 3
  2.     from http.server import BaseHTTPRequestHandler
  3. except ImportError:  # Python 2
  4.     from BaseHTTPServer import BaseHTTPRequestHandler
  5.  
  6. try:  # Python 3
  7.     from socketserver import TCPServer
  8. except ImportError:  # Python 2
  9.     from SocketServer import TCPServer
  10.  
  11. try:  # Python 3
  12.     from urllib.parse import parse_qs, urlparse, urlencode, quote, unquote
  13. except ImportError:  # Python 2
  14.     from urlparse import urlparse, parse_qs
  15.     from urllib import urlencode, quote, unquote
  16.  
  17. import re
  18.  
  19. import xbmcaddon
  20. import socket
  21. from contextlib import closing
  22.  
  23. addon = xbmcaddon.Addon(id='plugin.video.canalplusvod')
  24. import requests
  25. import urllib3
  26. import xbmc, time
  27. import json
  28.  
  29. requests.packages.urllib3.disable_warnings()
  30. requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
  31. import ssl
  32.  
  33. try:
  34.     _create_unverified_https_context = ssl._create_unverified_context
  35. except AttributeError:
  36.     pass
  37. else:
  38.     ssl._create_default_https_context = _create_unverified_https_context
  39.  
  40. import sys
  41.  
  42. PY3 = sys.version_info >= (3, 0, 0)
  43. __addon__ = xbmcaddon.Addon()
  44. __scriptname__ = __addon__.getAddonInfo('name')
  45. sess = requests.Session()
  46. proxyport = addon.getSetting('proxyport')
  47.  
  48.  
  49. def log(msg=None, ex=None):
  50.     if ex:
  51.         level = xbmc.LOGERROR
  52.     else:
  53.         level = xbmc.LOGINFO
  54.     xbmc.log((u"### [%s] - %s" % (__scriptname__, msg)), level=level)
  55.  
  56.  
  57. def czas():
  58.     import datetime
  59.     now = datetime.datetime.now()
  60.     czas = now.strftime('%Y-%m-%dT%H:%M:%SZ')
  61.     from datetime import datetime
  62.     import time
  63.     try:
  64.         format_date = datetime.strptime(czas, '%Y-%m-%dT%H:%M:%SZ')
  65.     except TypeError:
  66.         format_date = datetime(*(time.strptime(czas, '%Y-%m-%dT%H:%M:%SZ')[0:6]))
  67.  
  68.     def to_timestamp(a_date):
  69.         from datetime import datetime
  70.         try:
  71.             import pytz
  72.         except:
  73.             pass
  74.         if a_date.tzinfo:
  75.             epoch = datetime(1970, 1, 1, tzinfo=pytz.UTC)
  76.             diff = a_date.astimezone(pytz.UTC) - epoch
  77.         else:
  78.             epoch = datetime(1970, 1, 1)
  79.             diff = a_date - epoch
  80.         return int(diff.total_seconds()) * 1000
  81.  
  82.     tst4 = to_timestamp(format_date)
  83.  
  84.     return int(tst4)
  85.  
  86.  
  87. def get_addon():
  88.     return addon
  89.  
  90.  
  91. def set_setting(key, value):
  92.     return get_addon().setSetting(key, value)
  93.  
  94.  
  95. def get_setting(key):
  96.     return get_addon().getSetting(key)
  97.  
  98.  
  99. def dialog_progress():
  100.     return xbmcgui.DialogProgress()
  101.  
  102.  
  103. def xbmc_sleep(time):
  104.     return xbmc.sleep(time)
  105.  
  106.  
  107. def getRequests(url, data="", headers={}, params={}, allo=None):
  108.     if data:
  109.         if allo:
  110.             content = sess.get(url, headers=headers, data=data, params=params, verify=False).url
  111.         else:
  112.             content = sess.post(url, headers=headers, data=data, params=params, verify=False)  # .json()
  113.             try:
  114.                 content = content.json()
  115.             except:
  116.                 content = content.text
  117.     else:
  118.         if allo:
  119.             content = sess.get(url, headers=headers, params=params, verify=False).url
  120.         else:
  121.             content = sess.get(url, headers=headers, params=params, verify=False)
  122.             try:
  123.                 content = content.json()
  124.             except:
  125.                 content = content.text
  126.     return content
  127.  
  128.  
  129. def PLchar(char):
  130.     if type(char) is not str:
  131.         char = char.encode('utf-8')
  132.     char = char.replace('\\u0105', '\xc4\x85').replace('\\u0104', '\xc4\x84')
  133.     char = char.replace('\\u0107', '\xc4\x87').replace('\\u0106', '\xc4\x86')
  134.     char = char.replace('\\u0119', '\xc4\x99').replace('\\u0118', '\xc4\x98')
  135.     char = char.replace('\\u0142', '\xc5\x82').replace('\\u0141', '\xc5\x81')
  136.     char = char.replace('\\u0144', '\xc5\x84').replace('\\u0144', '\xc5\x83')
  137.     char = char.replace('\\u00f3', '\xc3\xb3').replace('\\u00d3', '\xc3\x93')
  138.     char = char.replace('\\u015b', '\xc5\x9b').replace('\\u015a', '\xc5\x9a')
  139.     char = char.replace('\\u017a', '\xc5\xba').replace('\\u0179', '\xc5\xb9')
  140.     char = char.replace('\\u017c', '\xc5\xbc').replace('\\u017b', '\xc5\xbb')
  141.     char = char.replace('’', "'")
  142.     char = char.replace('–', "-")
  143.     char = char.replace('…', "...")
  144.     char = char.replace('„', '"').replace('”', '"')
  145.     char = char.replace('[…]', "...")
  146.     char = char.replace('&', "&")
  147.     char = char.replace(''', "'")
  148.     char = char.replace('"', '"')
  149.     char = char.replace(' ', ".").replace('&', '&')
  150.     return char
  151.  
  152.  
  153. class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
  154.     PASStoken = get_setting('PASStoken')
  155.     PASSid = get_setting('PASSid')
  156.     clientid = get_setting('clientid')
  157.     portailId = get_setting('portailId')
  158.     OAUTH = 'https://logowanie.pl.canalplus.com/login'  # 'https://dev.canalplus.com/pl/oauth'
  159.     CREATE_TOKEN = 'https://pass-api-v2.canal-plus.com/provider/services/PL/public/createToken'
  160.     DEVID = addon.getSetting('devid')
  161.     MACROel = get_setting('MACROel')
  162.     MICROel = get_setting('MICROel')
  163.     EPGid = get_setting('EPGid')
  164.     DEVICE_ID = addon.getSetting('device_id')
  165.     HODORheaders = {
  166.         'Host': 'hodor.canalplus.pro',
  167.         'user-agent': 'myCANAL/ 4.6.6 (440010924) - Android/9 - android - SM-J330F',
  168.     }
  169.     CMStoken = get_setting('CMStoken')
  170.  
  171.     def gen_hex_code(self, myrange=6):
  172.         import random
  173.         return ''.join([random.choice('0123456789abcdef') for x in range(myrange)])
  174.  
  175.     def TVinit(self):
  176.         self.RefreshPassToken()
  177.         headers = {
  178.             'User-Agent': 'myCANAL/4.6.6(440010924) - Android/9 - android - SM-J330F',
  179.             'Content-Type': 'application/json; charset=utf-8',
  180.             'Host': 'secure-mobiletv.canal-plus.com',
  181.         }
  182.  
  183.         headers = {
  184.             'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0',
  185.             'Accept': 'application/json, text/plain, */*',
  186.             'Accept-Language': 'pl,en-US;q=0.7,en;q=0.3',
  187.             'Content-Type': 'application/json;charset=utf-8',
  188.             'Origin': 'https://www.canalplus.com',
  189.             'DNT': '1',
  190.             'Connection': 'keep-alive',
  191.             'Referer': 'https://www.canalplus.com/', }
  192.  
  193.         import time
  194.         ts = int(time.time()) * 100
  195.         a = str(ts)
  196.         b = str(czas())
  197.  
  198.         if not self.DEVID:
  199.             self.DEVID = '%s-%s' % (b, self.gen_hex_code(12))
  200.             set_setting('devid', self.DEVID)
  201.  
  202.         zzzDEVID = '%s-%s' % (b, self.gen_hex_code(12))
  203.  
  204.         ptok = get_setting('PASStoken')  # split('PL=')[-1]
  205.  
  206.         data = {"ServiceRequest": {
  207.             "InData": {"PassData": {"Id": 0, "Token": ptok}, "UserKeyId": self.DEVICE_ID, "DeviceKeyId": self.DEVID,
  208.                        "PDSData": {"GroupTypes": "1;4"}}}}
  209.  
  210.         data = json.dumps(data)
  211.         # epgs = self.epgLive()
  212.  
  213.         urlk = 'https://secure-webtv.canal-plus.com/WebPortal/ottlivetv/api/V4/zones/cppol/devices/3/apps/1/jobs/InitLiveTV'
  214.  
  215.         response = sess.post(urlk, headers=headers, data=data, verify=False).json()
  216.  
  217.         outdata = response["ServiceResponse"]["OutData"]
  218.         self.LIVEtoken = outdata["LiveToken"]
  219.         set_setting('livetoken', self.LIVEtoken)
  220.         grupy = outdata["PDS"]["ChannelsGroups"]["ChannelsGroup"]
  221.         out = []
  222.         for grupa in grupy:
  223.             channels = grupa["Channels"]
  224.             for channel in channels:
  225.                 epgid_ = channel["EpgId"]
  226.                 # try:
  227.                 #     plot = epgs[str(epgid_)]['title']
  228.                 # except:
  229.                 #     plot = ''
  230.  
  231.                 tytul_ = channel["Name"]
  232.                 urllogo_ = channel["LogoUrl"]
  233.  
  234.                 urlpage_ = channel["WSXUrl"]
  235.                 urlpage_ = urlpage_ + '|' + epgid_
  236.                 out.append({"title": PLchar(tytul_), "url": urlpage_, 'image': urllogo_, "code": '', "plot": '',
  237.                             'typ': 'live'})
  238.         return out
  239.  
  240.     def RefreshPassToken(self):
  241.         headers = {
  242.             'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 9; SM-J330F Build/PPR1.180610.011)',
  243.             'Host': 'pass-api-v2.canal-plus.com',
  244.         }
  245.  
  246.         data = {
  247.             'analytics': 'true',
  248.             'noCache': 'false',
  249.  
  250.             'passId': self.PASSid,
  251.             'vect': 'Internet',
  252.             'media': 'Android Phone',
  253.             'trackingPub': 'true',
  254.             'portailId': self.portailId
  255.         }
  256.         data = {
  257.  
  258.             'noCache': 'false',
  259.  
  260.             'passId': self.PASSid,
  261.             'deviceId': self.DEVID,
  262.  
  263.             'vect': 'Internet',
  264.             'media': 'PC',
  265.  
  266.             'portailId': 'vbdTj7eb6aM.',
  267.             'zone': 'cppol'
  268.         }
  269.  
  270.         headers = {
  271.             'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0',
  272.             'Accept': '*/*',
  273.             'Accept-Language': 'pl,en-US;q=0.7,en;q=0.3',
  274.             'Content-Type': 'application/x-www-form-urlencoded',
  275.             'Origin': 'https://www.canalplus.com',
  276.             'Connection': 'keep-alive',
  277.         }
  278.  
  279.         response = sess.post(self.CREATE_TOKEN, headers=headers, data=data, verify=False).json()
  280.  
  281.         self.PASSid = response["response"]["passId"]
  282.         self.PASStoken = response["response"]["passToken"]
  283.         a11 = self.PASSid
  284.         a22 = self.PASStoken
  285.         set_setting('PASSid', a11)
  286.         set_setting('PASStoken', a22)
  287.  
  288.         params = (
  289.             ('appLocation', 'PL'),
  290.             ('offerZone', 'cppol'),
  291.             ('isActivated', '1'),
  292.             ('collectUserData', '1'),
  293.             ('pdsNormal', '[' + self.EPGid + ']'),
  294.             ('macros', self.MACROel),
  295.             ('micros', self.MICROel),
  296.             ('isAuthenticated', '1'),
  297.             ('paired', '0'),
  298.         )
  299.         response = getRequests('https://hodor.canalplus.pro/api/v2/mycanalint/authenticate.json/android/4.1',
  300.                                headers=self.HODORheaders, params=params)
  301.  
  302.         self.CMStoken = response['token']
  303.         set_setting('CMStoken', self.CMStoken)
  304.  
  305.         return
  306.  
  307.     def do_GET(self):
  308.         """Handle http get requests, used for manifest"""
  309.         path = self.path  # Path with parameters received from request e.g. "/manifest?id=234324"
  310.         print('HTTP GET Request received to {}'.format(path))
  311.         if '/manifest' not in path:
  312.             self.send_response(404)
  313.             self.end_headers()
  314.             return
  315.         try:
  316.             # Call your method to do the magic to generate DASH manifest data
  317.             manifest_data = b'my manifest data'
  318.             self.send_response(200)
  319.             self.send_header('Content-type', 'application/xml')
  320.             self.end_headers()
  321.             self.wfile.write(manifest_data)
  322.         except Exception:
  323.             self.send_response(500)
  324.             self.end_headers()
  325.  
  326.     def do_POST(self):
  327.         """Handle http post requests, used for license"""
  328.         path = self.path  # Path with parameters received from request e.g. "/license?id=234324"
  329.         print('HTTP POST Request received to {}'.format(path))
  330.         if '/license' not in path:
  331.             self.send_response(404)
  332.             self.end_headers()
  333.             return
  334.  
  335.         length = int(self.headers.get('content-length', 0))
  336.         isa_data = self.rfile.read(length).decode('utf-8').split('!')
  337.         challenge = isa_data[0]
  338.  
  339.         log(path)
  340.  
  341.         if 'cense=' in path:
  342.             path2 = path.split('cense=')[-1]
  343.  
  344.             licurl = (addon.getSetting('licurl'))
  345.  
  346.             ab = eval(addon.getSetting('hea'))
  347.             result = requests.post(url=licurl, headers=ab, data=challenge, verify=False).content
  348.             if PY3:
  349.                 result = result.decode(encoding='utf-8', errors='strict')
  350.             licens = re.findall('ontentid=".+?">(.+?)<', result)[0]
  351.             if PY3:
  352.                 licens = licens.encode(encoding='utf-8', errors='strict')
  353.         elif 'censetv=' in path:
  354.             path2 = path.split('censetv=')[-1]
  355.  
  356.             licurl = (addon.getSetting('lictvurl'))
  357.             ab = eval(addon.getSetting('heatv'))
  358.             result = requests.post(url=licurl, headers=ab, data=challenge, verify=False).json()
  359.  
  360.             log(result)
  361.  
  362.             if int(result['ServiceResponse']['Status']) < 0:
  363.                 self.TVinit()
  364.                 result = requests.post(url=licurl, headers=ab, data=challenge, verify=False).json()
  365.  
  366.             licens = result['ServiceResponse']['OutData']['LicenseInfo']
  367.             if PY3:
  368.                 licens = licens.encode(encoding='utf-8', errors='strict')
  369.  
  370.         self.send_response(200)
  371.         self.end_headers()
  372.  
  373.         self.wfile.write(licens)
  374.  
  375.  
  376. def find_free_port():
  377.     with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
  378.         s.bind(('', 0))
  379.         s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  380.         addon.setSetting('proxyport', str(s.getsockname()[1]))
  381.         return s.getsockname()[1]
  382.  
  383.  
  384. address = '127.0.0.1'  # Localhost
  385.  
  386. port = find_free_port()
  387.  
  388. server_inst = TCPServer((address, port), SimpleHTTPRequestHandler)
  389. # The follow line is only for test purpose, you have to implement a way to stop the http service!
  390. server_inst.serve_forever()
  391.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement