# -*- coding: utf-8 -*- # Copyright: (c) 2022, Joaopa # GNU General Public License v2.0+ (see LICENSE.txt or https://www.gnu.org/licenses/gpl-2.0.txt) # This file is part of Catch-up TV & More from __future__ import unicode_literals import re import json import base64 import xbmc import urlquick import urllib import time import ctypes import math from codequick import Listitem, Resolver, Route, Script import urlquick from resources.lib import download, web_utils, resolver_proxy from resources.lib.menu_utils import item_post_treatment from resources.lib.kodi_utils import get_kodi_version, get_selected_item_art, get_selected_item_label, get_selected_item_info, INPUTSTREAM_PROP from resources.lib.menu_utils import item_post_treatment from resources.lib import resolver_proxy, web_utils CORONA_URL = 'https://corona.channel5.com/shows/' BASIS_URL = CORONA_URL + '%s/seasons' URL_SEASONS = BASIS_URL + '.json' URL_EPISODES = BASIS_URL + '/%s/episodes.json' FEEDS_API = 'https://feeds-api.channel5.com/collections/%s/concise.json' ONEOFF = 'https://corona.channel5.com/shows/%s/episodes/next.json' URL_VIEW_ALL = CORONA_URL + 'search.json' URL_WATCHABLE = 'https://corona.channel5.com/watchables/search.json' IMG_URL = 'https://api-images.channel5.com/otis/images/episode/%s/320x180.jpg' SHOW_IMG_URL = 'https://api-images.channel5.com/otis/images/show/%s/320x180.jpg' GENERIC_HEADERS = {"User-Agent": web_utils.get_random_ua()} LICC_URL = 'https://cassie.channel5.com/api/v2/media/my5desktopng/%s.json?timestamp=%s' KEYURL = "https://player.akamaized.net/html5player/core/html5-c5-player.js" CERT_URL = 'https://c5apps.channel5.com/wv/c5-wv-app-cert-20170524.bin' feeds_api_params = { 'vod_available': 'my5desktop', 'friendly': '1' } view_api_params = { 'platform': 'my5desktop', 'friendly': '1' } lic_headers = { 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0', 'Referer': 'https://www.channel5.com/', 'Content-Type': '', } # Some Sttaic Arrays # Not sure where S4B comes from, statically defined for now S4B = [99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210,205,12,19,236,95,151,68,23,196,167,126,61,100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161,137,13,191,230,66,104,65,153,45,15,176,84,187,22] # Not sure where G4B comes from, statically defined for now G4B = [1374988112,2118214995,437757123,975658646,1001089995,530400753,-1392879445,1273168787,540080725,-1384747530,-1999866223,-184398811,1340463100,-987051049,641025152,-1251826801,-558802359,632953703,1172967064,1576976609,-1020300030,-2125664238,-1924753501,1809054150,59727847,361929877,-1083344149,-1789765158,-725712083,1484005843,1239443753,-1899378620,1975683434,-191989384,-1722270101,666464733,-1092530250,-259478249,-920605594,2110667444,1675577880,-451268222,-1756286112,1649639237,-1318815776,-1150570876,-25059300,-116905068,1883793496,-1891238631,-1797362553,1383856311,-1418472669,1917518562,-484470953,1716890410,-1293211641,800440835,-2033878118,-751368027,807962610,599762354,33778362,-317291940,-1966138325,-1485196142,-217582864,1315562145,1708848333,101039829,-785096161,-995688822,875451293,-1561111136,92987698,-1527321739,193195065,1080094634,1584504582,-1116860335,1042385657,-1763899843,-583137874,1306967366,-1856729675,1908694277,67556463,1615861247,429456164,-692196969,-1992277044,1742315127,-1326955843,126454664,-417768648,2043211483,-1585706425,2084704233,-125559095,0,159417987,841739592,504459436,1817866830,-49348613,260388950,1034867998,908933415,168810852,1750902305,-1688513327,607530554,202008497,-1822955761,-1259432238,463180190,-2134850225,1641816226,1517767529,470948374,-493635062,-1063245083,1008918595,303765277,235474187,-225720403,766945465,337553864,1475418501,-1351284916,-291906117,-1551933187,-150919521,1551037884,1147550661,1543208500,-1958532746,-886847780,-1225917336,-1192955549,-684598070,1113818384,328671808,-2067394272,-2058738563,-759480840,-1359400431,-953573011,496906059,-592301837,226906860,2009195472,733156972,-1452230247,294930682,1206477858,-1459843900,-1594867942,1451044056,573804783,-2025238841,-650587711,-1932877058,-1730933962,-1493859889,-1518674392,-625504730,1068351396,742039012,1350078989,1784663195,1417561698,-158526526,-1864845080,775550814,-2101104651,-1621262146,1775276924,1876241833,-819653965,-928212677,270040487,-392404114,-616842373,-853116919,1851332852,-325404927,-2091935064,-426414491,-1426069890,566021896,-283776794,-1159226407,1248802510,-358676012,699432150,832877231,708780849,-962227152,899835584,1951317047,-58537306,-527380304,866637845,-251357110,1106041591,2144161806,395441711,1984812685,1139781709,-861254316,-459930401,-1630423581,1282050075,-1054072904,1181045119,-1654724092,25965917,-91786125,-83148498,-1285087910,-1831087534,-384805325,1842759443,-1697160820,933301370,1509430414,-351060855,-827774994,-1218328267,-518199827,2051518780,-1663901863,1441952575,404016761,1942435775,1408749034,1610459739,-549621996,2017778566,-894438527,-1184316354,941896748,-1029488545,371049330,-1126030068,675039627,-15887039,967311729,135050206,-659233636,1683407248,2076935265,-718096784,1215061108,-793225406] # Not sure where D4B comes from, statically defined for now D4B = [-1487908364,1699970625,-1530717673,1586903591,1808481195,1173430173,1487645946,59984867,-95084496,1844882806,1989249228,1277555970,-671330331,-875051734,1149249077,-1550863006,1514790577,459744698,244860394,-1058972162,1963115311,-267222708,-1750889146,-104436781,1608975247,-1667951214,2062270317,1507497298,-2094148418,567498868,1764313568,-935031095,-1989511742,2037970062,1047239000,1910319033,1337376481,-1390940024,-1402549984,984907214,1243112415,830661914,861968209,2135253587,2011214180,-1367032981,-1608712575,731183368,1750626376,-48656571,1820824798,-122203525,-752637069,48394827,-1890065633,-1423284651,671593195,-1039978571,2073724613,145085239,-2014171096,-1515052097,1790575107,-2107839210,472615631,-1265457287,-219090169,-492745111,-187865638,-1093335547,1646252340,-24460122,1402811438,1436590835,-516815478,-344611594,-331805821,-274055072,-1626972559,273792366,-1963377119,104699613,95345982,-1119466010,-1917480620,1560637892,-730921978,369057872,-81520232,-375925059,1137477952,-1636341799,1119727848,-1954019447,1530455833,-287606328,172466556,266959938,516552836,0,-2038232704,-314035669,1890328081,1917742170,-262898,945164165,-719438418,958871085,-647755249,-1507760036,1423022939,775562294,1739656202,-418409641,-1764576018,-1851909221,-984645440,547512796,1265195639,437656594,-1173691757,719700128,-532464606,387781147,218828297,-944901493,-1464259146,-1446505442,428169201,122466165,-574886247,1627235199,648017665,-172204942,1002783846,2117360635,695634755,-958608605,-60246291,-245122844,-590686415,-2062531997,574624663,287343814,612205898,1039717051,840019705,-1586641111,793451934,821288114,1391201670,-472877119,376187827,-1181111952,1224348052,1679968233,-1933268740,1058709744,752375421,-1863376333,1321699145,-775825096,-1560376118,188127444,-2117097739,-567761542,-1910056265,-1079754835,-1645990854,-1844621192,-862229921,1180849278,331544205,-1192718120,-144822727,-1342864701,-2134991011,-1820562992,766078933,313773861,-1724135252,2108100632,1668212892,-1149510853,2013908262,418672217,-1224610662,-1700232369,1852171925,-427906305,-821550660,-387518699,-1680229657,919489135,164948639,2094410160,-1297141340,590424639,-1808742747,1723872674,-1137216434,-895026046,-793714544,-669699161,-1739919100,-621329940,1343127501,-164685935,-695372211,-1337113617,1297403050,81781910,-1243373871,-2011476886,532201772,1367295589,-368796322,895287692,1953757831,1093597963,492483431,-766340389,1446242576,1192455638,1636604631,209336225,344873464,1015671571,669961897,-919226527,-437395172,-1321436601,-547775278,1933530610,-830924780,935293895,-840281097,-1436852227,1863638845,-611944380,-209597777,-1002522264,875313188,1080017571,-1015933411,621591778,1233856572,-1790836979,24197544,-1277294580,-459482956,-1047501738,-2073986101,-1234119374,1551124588,1463996600] # Not sure where d4B comes from, statically defined for now d4B = [-190361519,1097159550,396673818,660510266,-1418998981,-1656360673,-94852180,-486304949,821712160,1986918061,-864644728,38544885,-438830001,718002117,893681702,1654886325,-1319482914,-1172609243,-368142267,-20913827,796197571,1290801793,1184342925,-738605461,-1889540349,-1835231979,1836772287,1381620373,-1098699308,1948373848,-529979063,-909622130,-1031181707,-1904641804,1480485785,-1183720153,-514869570,-2001922064,548169417,-835013507,-548792221,439452389,1362321559,1400849762,1685577905,1806599355,-2120213250,137073913,1214797936,1174215055,-563312748,2079897426,1943217067,1258480242,529487843,1437280870,-349698126,-1245576401,-981755258,923313619,679998000,-1079659997,57326082,377642221,-820237430,2041877159,133361907,1776460110,-621490843,96392454,878845905,-1493267772,777231668,-212492126,-1964953083,-152341084,-2081670901,1626319424,1906247262,1846563261,562755902,-586793578,1040559837,-423803315,1418573201,-1000536719,114585348,1343618912,-1728371687,-1108764714,1078185097,-643926169,-398279248,-1987344377,425408743,-923870343,2081048481,1108339068,-2078357000,0,-2138668279,736970802,292596766,1517440620,251657213,-2059905521,-1361764803,758720310,265905162,1554391400,1532285339,908999204,174567692,1474760595,-292105548,-1684955621,-1060810880,-601841055,2001430874,303699484,-1816524062,-1607801408,585122620,454499602,151849742,-1949848078,-1230456531,514443284,-249985705,1963412655,-1713521682,2137062819,19308535,1928707164,1715193156,-75615141,1126790795,600235211,-302225226,-453942344,836553431,1669664834,-1759363053,-971956092,1243905413,-1153566510,-114159186,698445255,-1641067747,-1305414692,-2041385971,-1042034569,-1290376149,1891211689,-1807156719,-379313593,-57883480,-264299872,2100090966,865136418,1229899655,953270745,-895287668,-737462632,-176042074,2061379749,-1215420710,-1379949505,983426092,2022837584,1607244650,2118541908,-1928084746,-658970480,972512814,-1011878526,1568718495,-795640727,-718427793,621982671,-1399243832,410887952,-1671205144,1002142683,645401037,1494807662,-1699282452,1335535747,-1787927066,-1671510,-1127282655,367585007,-409216582,1865862730,-1626745622,-1333995991,-1531793615,1059270954,-1517014842,-1570324427,1320957812,-2100648196,-1865371424,-1479011021,77089521,-321194175,-850391425,-1846137065,1305906550,-273658557,-1437772596,-1778065436,-776608866,1787304780,740276417,1699839814,1592394909,-1942659839,-2022411270,188821243,1729977011,-606973294,274084841,-699985043,-681472870,-1593017801,-132870567,322734571,-1457000754,1640576439,484830689,1202797690,-757114468,-227328171,349075736,-952647821,-137500077,-39167137,1030690015,1155237496,-1342996022,1757691577,607398968,-1556062270,499347990,-500888388,1011452712,227885567,-1476300487,213114376,-1260086056,1455525988,-880516741,850817237,1817998408,-1202240816] # Not sure where l4B comes from, statically defined for now l4B = [1347548327,1400783205,-1021700188,-1774573730,-885281941,-249586363,-1414727080,-1823743229,1428173050,-156404115,-1853305738,636813900,-61872681,-674944309,-2144979644,-1883938141,1239331162,1730525723,-1740248562,-513933632,46346101,310463728,-1551022441,-966011911,-419197089,-1793748324,-339776134,-627748263,768917123,-749177823,692707433,1150208456,1786102409,2029293177,1805211710,-584599183,-1229004465,401639597,1724457132,-1266823622,409198410,-2098914767,1620529459,1164071807,-525245321,-2068091986,486441376,-1795618773,1483753576,428819965,-2020286868,-1219331080,598438867,-495826174,1474502543,711349675,129166120,53458370,-1702443653,-1512884472,-231724921,-1306280027,-1174273174,1559041666,730517276,-1834518092,-252508174,-1588696606,-848962828,-721025602,533804130,-1966823682,-1657524653,-1599933611,839224033,1973745387,957055980,-1438621457,106852767,1371368976,-113368694,1033297158,-1361232379,1179510461,-1248766835,91341917,1862534868,-10465259,605657339,-1747534359,-863420349,2003294622,-1112479678,-2012771957,954669403,-612775698,1201765386,-377732593,-906460130,0,-2096529274,1211247597,-1407315600,1315723890,-67301633,1443857720,507358933,657861945,1678381017,560487590,-778347692,975451694,-1324610969,261314535,-759894378,-1642357871,1333838021,-1570644960,1767536459,370938394,182621114,-440360918,1128014560,487725847,185469197,-1376613433,-1188186456,-938205527,-2057834215,1286567175,-1141990947,-39616672,-1611202266,-1134791947,-985373125,878443390,1988838185,-590666810,1756818940,1673061617,-891866660,272786309,1075025698,545572369,2105887268,-120407235,296679730,1841768865,1260232239,-203640272,-334657966,-797457949,1814803222,-1716948807,-99511224,575138148,-995558260,446754879,-665420500,-282971248,-947435186,-1042728751,-24327518,915985419,-811141759,681933534,651868046,-1539330625,-466863459,223377554,-1687527476,1649704518,-1024029421,-393160520,1580087799,-175979601,-1096852096,2087309459,-1452288723,-1278270190,1003007129,-1492117379,1860738147,2077965243,164439672,-194094824,32283319,-1467789414,1709610350,2125135846,136428751,-420538904,-642062437,-833982666,-722821367,-701910916,-1355701070,824852259,818324884,-1070226842,930369212,-1493400886,-1327460144,355706840,1257309336,-146674470,243256656,790073846,-1921626666,1296297904,1422699085,-538667516,-476130891,457992840,-1195299809,2135319889,77422314,1560382517,1945798516,788204353,1521706781,1385356242,870912086,325965383,-1936009375,2050466060,-1906706412,-1981082820,-288446169,901210569,-304014107,1014646705,1503449823,1062597235,2031621326,-1082931401,-363595827,1533017514,350174575,-2038938405,-2117423117,1052338372,741876788,1606591296,1914052035,213705253,-1960297399,1107234197,1899603969,-569897805,-1663519516,-1872472383,1635502980,1893020342,1950903388,1120974935] P94 = [82,9,106,213,48,54,165,56,191,64,163,158,129,243,215,251,124,227,57,130,155,47,255,135,52,142,67,68,196,222,233,203,84,123,148,50,166,194,35,61,238,76,149,11,66,250,195,78,8,46,161,102,40,217,36,178,118,91,162,73,109,139,209,37,114,248,246,100,134,104,152,22,212,164,92,204,93,101,182,146,108,112,72,80,253,237,185,218,94,21,70,87,167,141,157,132,144,216,171,0,140,188,211,10,247,228,88,5,184,179,69,6,208,44,30,143,202,63,15,2,193,175,189,3,1,19,138,107,58,145,17,65,79,103,220,234,151,242,207,206,240,180,230,115,150,172,116,34,231,173,53,133,226,249,55,232,28,117,223,110,71,241,26,113,29,41,197,137,111,183,98,14,170,24,190,27,252,86,62,75,198,210,121,32,154,219,192,254,120,205,90,244,31,221,168,51,136,7,199,49,177,18,16,89,39,128,236,95,96,81,127,169,25,181,74,13,45,229,122,159,147,201,156,239,160,224,59,77,174,42,245,176,200,235,187,60,131,83,153,97,23,43,4,126,186,119,214,38,225,105,20,99,85,33,12,125] def arrayCopy(original): out = [None] * len(original); for x in range(0, len(original)): out[x] = original[x] return(out) def twos_comp(val, bits): """compute the 2's complement of int value val""" if (val & (1 << (bits - 1))) != 0: # if sign bit is set e.g., 8bit: 128-255 val = val - (1 << bits) # compute negative value return val # make a number like a javbascript inter only 32 bits long def u_to_l(u): return u - (1<<32) if u >= (1<<31) else u # make array23 from cassie def cassiearray(H7): L7 = [] for z0 in range(len(H7)): try: tempx= L7[z0 >> 2] except IndexError: tempx = L7.append(0) L7[z0 >> 2] |= (255 & ord(H7[z0])) << (24 - z0 % 4 * 8) return(L7) def cassieoarraymod(A23): q5N = 1240 e5N = 728 A32 = [] for x in A23: A32.append(x) for x in range(22,30): A32.append(0) A32[(e5N & 0xffffffff) >> 5] |= 128 << 24 - e5N % 32 A32.append(1240) return(A32) def init(j5A): Q6t = 16 X6t = [] f6t = [] for g6t in range(Q6t): try: tempx= j5A[g6t] except IndexError: tempx = 0 tempy = u_to_l(tempx) ^ 1549556828 tempz = u_to_l(tempx) ^ 909522486 X6t.append(u_to_l(tempy)) f6t.append(u_to_l(tempz)) return(X6t, f6t) # create auth token at last def strinigify(U8E): Z8E = 0 P8E = 32 i8E = [] S8E = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" while (Z8E < P8E): try: tempx = U8E[Z8E + 2 >> 2] except IndexError: tempx = 0 L8E = 0 while (L8E < 4 and Z8E + .75 * L8E < P8E): A8E = (U8E[Z8E >> 2] >> 24 - Z8E % 4 * 8 & 255) << 16 | (U8E[Z8E + 1 >> 2] >> 24 - (Z8E + 1) % 4 * 8 & 255) << 8 | tempx >> 24 - (Z8E + 2) % 4 * 8 & 255 i8E.append( S8E[A8E >> 6 * (3 - L8E) & 63] ) L8E += 1 Z8E += 3 # padd to 44 with = but these get stripped later so dont bother now #i8E.append("=") return(i8E) # susbstitute some characters in auth string before requesting license def change(auth): result = ''.join(str(x) for x in auth) result = result.replace("+", "-") result = result.replace("/", "_") result = re.sub(r'=={0,}$', '', result) return(result) # build array from lic key def parse(M5A): # always is the same so no need to generate each time parsemap = [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 62, None, None, None, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, None, None, None, 64, None, None, None, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, None, None, None, None, None, None, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51] j5A = [0] * 4 z5A = 0 f5A = 0 F5A = M5A.index('=') for f5A in range(F5A): if ((f5A % 4) != 0): B5A = parsemap[ord(M5A[f5A - 1])] << f5A % 4 * 2 G5A = parsemap[ord(M5A[f5A])] >> 6 - f5A % 4 * 2 Z5A = B5A | G5A temp_x = 24 - z5A % 4 * 8 j5A[z5A >> 2] |= ctypes.c_int(Z5A << temp_x).value z5A += 1 return(j5A) # all we need is array of ascii value of each character in the long story def url_parse(queryStr): i = 0 data = [] utf8=urllib.unquote(queryStr) unicodestring=unicode(utf8,'utf-8') for unicodechar in unicodestring: data.append(ord(unicodechar)) i += 1 return data def randomMath(y6k): y6kInt = int(y6k) b = int(4294967296 * (y6k - (0 | y6kInt) )) c = twos_comp(b, 32) return(c) def srState(H6k): u6k = int(math.sqrt(H6k)) Q6k = 2 state = True while (Q6k <= u6k): if ((H6k % Q6k) == 0): state = False Q6k = u6k + 2 Q6k += 1 return(state) def magic64(): B6k = [0] * 64 S6k = [0] * 64 V6k = 2 X6k = 0 while (X6k < 64): if ( srState(V6k) ): B6k[X6k] = randomMath( pow(V6k, 0.5) ) # approximating 1/3 looks okay S6k[X6k] = randomMath( pow(V6k, 0.3333333333333333)) X6k += 1 V6k += 1 return(S6k) def array32a1(a1,c8): out = [] for x in a1: out.append(x) for x in c8 : out.append(x) out.append(-2147483648) for x in range(6): out.append(0) out.append(768) return(out) def doProcessBlock(D5r,o0r,S6k,Y5k): I6k = [] a6k = D5r[0] k6k = D5r[1] M6k = D5r[2] z5k = D5r[3] c6k = D5r[4] R5k = D5r[5] f5k = D5r[6] q5k = D5r[7] for L6k in range (64): if (L6k < 16): I6k.append( o0r[L6k + Y5k] ) else: s6k = I6k[L6k - 15] h5k = (ctypes.c_int(s6k << 25).value | (s6k & 0xffffffff) >> 7) ^ (ctypes.c_int(s6k << 14).value | (s6k & 0xffffffff) >> 18) ^ (s6k & 0xffffffff) >> 3 t5k = I6k[L6k - 2] K5k = (ctypes.c_int(t5k << 15).value | (t5k & 0xffffffff) >> 17) ^ (ctypes.c_int(t5k << 13).value | (t5k & 0xffffffff) >> 19) ^ (t5k & 0xffffffff) >> 10 I6k.append( h5k + I6k[L6k - 7] + K5k + I6k[L6k - 16]) g5k = a6k & k6k ^ a6k & M6k ^ k6k & M6k P5k = (ctypes.c_int(a6k << 30).value | (a6k & 0xffffffff) >> 2) ^ (ctypes.c_int(a6k << 19).value | (a6k & 0xffffffff) >> 13) ^ (ctypes.c_int(a6k << 10).value | (a6k & 0xffffffff) >> 22) m5k = q5k + ((ctypes.c_int(c6k << 26).value | (c6k & 0xffffffff) >> 6) ^ (ctypes.c_int(c6k << 21).value | (c6k & 0xffffffff) >> 11) ^ (ctypes.c_int(c6k << 7).value | (c6k & 0xffffffff) >> 25)) + (c6k & R5k ^ ~c6k & f5k) + S6k[L6k] + I6k[L6k]; q5k = f5k f5k = R5k R5k = c6k c6k = ctypes.c_int( (z5k + m5k) ).value z5k = M6k M6k = k6k k6k = a6k a6k = ctypes.c_int(m5k + (P5k + g5k)).value # finally make new magic array of 8 D5r[0] = ctypes.c_int(D5r[0] + a6k).value D5r[1] = ctypes.c_int(D5r[1] + k6k).value D5r[2] = ctypes.c_int(D5r[2] + M6k).value D5r[3] = ctypes.c_int(D5r[3] + z5k).value D5r[4] = ctypes.c_int(D5r[4] + c6k).value D5r[5] = ctypes.c_int(D5r[5] + R5k).value D5r[6] = ctypes.c_int(D5r[6] + f5k).value D5r[7] = ctypes.c_int(D5r[7] + q5k).value return(D5r) def getdata(ui): # We need 2 things from the js file, the long string of gibberish and the short # string to OR with, # I assume short string is always 6 digits long to regexp search on # The lomg string is really long so i look for at least 3000 characters resp = urlquick.get(KEYURL) content = resp.content # short string m = re.compile(r';}}}\)\(\'(......)\'\)};').search(content) ss = m.group(1) # long string m = re.compile(r'\(\){return "(.{3000,})";\}').search(content) s = str(m.group(1)) z = url_parse(s) l = len(z) y = 0 sout = "" for x in range(l): if (y > 5): y = 0 p1 = z[x] p2 = ord(ss[y]) k = p1 ^ p2 # Only worried about printable characters for what we need if ( (k > 31) and (k < 127) ): sout = sout + chr(k) #else: # sout = sout + str(k) y = y + 1 #extract the key from sout m = re.compile(r'SSL_MA..(.{24})..(.{24})').search(sout) k1 = m.group(1) k2 = m.group(2) # we need an 8 byte array that makes magic m = re.compile(r'2689\)\]=\[(\d+),(\d+),(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\]').search(content) # lets make an array magicArray = [] for x in range(1,9): magicArray.append( twos_comp(int( m.group(x) ),32) ) fourarray = parse(k1) a1,a2 = init(fourarray) S6k = magic64() timeStamp = str( int(time.time()) ) CALL_URL = LICC_URL % (ui, timeStamp) array23 = cassiearray(CALL_URL) array32 = cassieoarraymod(array23) # iterate around doProcessBlock magicArrayF = arrayCopy(magicArray) onemagic8 = doProcessBlock(magicArrayF,a2,S6k,0) twomagic8array = arrayCopy(array32) twomagic8 = doProcessBlock(onemagic8,twomagic8array,S6k,0) threemagic8 = doProcessBlock(twomagic8,twomagic8array,S6k,16) magicArrayF = arrayCopy(magicArray) fourmagic8array = array32a1(a1,threemagic8) fourmagic8 = doProcessBlock(magicArrayF,fourmagic8array,S6k,0) fivemagic8 = doProcessBlock(fourmagic8,fourmagic8array,S6k,16) authKey = strinigify(fivemagic8) str1 = change(authKey) LICFULL_URL = CALL_URL + "&auth=" + str1 return (LICFULL_URL, k2) def ivdata(URL): resp = urlquick.get(URL, headers=GENERIC_HEADERS) root = json.loads(resp.text) iv = root['iv'] data = root['data'] return(iv, data) # For Iv and Data processing def aesToArray(key): keyArray = parse(key) return keyArray def mangle(st): #result = iv + "====" result = st result = result.replace("-", "+") result = result.replace("_", "/") return (result) def b6(iv): print("iv in function is ",iv) Z4Z = 22 p4Z = 2 Y4Z = [ None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 62, None, 62, None, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, None, None, None, None, None, None, None, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, None, None, None, None, 63, None, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 ] T4Z = 0 t4Z = [0] * 16 j4Z = 0 while (T4Z < 18): e4Z = ctypes.c_int(Y4Z[ord(iv[T4Z])] << 18).value | ctypes.c_int(Y4Z[ord(iv[T4Z+1])] << 12).value | ctypes.c_int(Y4Z[ord(iv[T4Z+2])] << 6).value | Y4Z[ord(iv[T4Z+3])] e4Z32 = (e4Z & 0xffffffff) t4Z[j4Z] = e4Z32 >> 16 & 255 j4Z += 1 t4Z[j4Z] = e4Z32 >> 8 & 255 j4Z += 1 t4Z[j4Z] = 255 & e4Z j4Z += 1 T4Z += 4 try: T4Z1 = Y4Z[ord(iv[T4Z+1])] except: T4Z1 = 0 try: T4Z2 = Y4Z[ord(iv[T4Z+2])] except: T4Z2 = 0 if (p4Z == 2): e4Z = ctypes.c_int(Y4Z[ord(iv[T4Z])] << 2).value | (T4Z1 >> 4) t4Z[j4Z] = 255 & e4Z if (p4Z == 1): e4Z = ctypes.c_int(Y4Z[ord(iv[T4Z])] << 10).value | ctypes.c_int(T4Z1 << 4).value | T4Z2 >> 2 t4Z.append(ctypes.c_int(e4Z >> 8).value & 255) t4Z.append(255 & e4z) def ivArray(N3n): d3n = [ None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 62, None, None, None, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, None, None, None, 64, None, None, None, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, None, None, None, None, None, None, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 ] f3n = 0 K3n = [0] * 4 T3n = N3n.index("=") for L3n in range(T3n): if ( (L3n % 4) != 0): D3n = ctypes.c_int(d3n[ord(N3n[L3n-1])] << L3n % 4 * 2).value o3n = (d3n[ord(N3n[L3n])] & 0xffffffff) >> 6 - L3n % 4 * 2 P3n = D3n | o3n K3n[f3n >> 2] |= ctypes.c_int(P3n << 24 - f3n % 4 * 8).value f3n += 1 return(K3n) def ivParse(N3n): l9u = len(N3n) print("l9u is ", l9u) z9u = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" d3n = [ None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 62, None, None, None, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, None, None, None, 64, None, None, None, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, None, None, None, None, None, None, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 ] D9u = "=" try: d9u = G9u.index("=") except: d9u = "-1" f3n = 0 K3n = [0] * 480 for L3n in range(l9u): if ( (L3n % 4) != 0): I9u = ctypes.c_int(d3n[ord(N3n[L3n-1])] << L3n % 4 * 2).value o3n = (d3n[ord(N3n[L3n])] & 0xffffffff) >> 6 - L3n % 4 * 2 P3n = I9u | o3n temp_x = 24 - f3n % 4 * 8 K3n[f3n >> 2] |= ctypes.c_int(P3n << temp_x).value # K3n[f3n >> 2] |= ctypes.c_int(P3n << 24 - f3n % 4 * 8).value f3n += 1 return(K3n) def ivreset(aes4) : M6B = aes4 w6B = aes4 r4B = [ 0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 ] e6B = 4 X6B = 44 k6B = [0] * 44 g6B = 0 C6B = -67372037 # javascript here was really cryptic so my python version is very drawn out for g6B in range (X6B): if (g6B < e6B): k6B[g6B] = w6B[g6B] else: C6B = k6B[g6B - 1] if (g6B % e6B): if ( (e6B > 6) & (g6B % e6B == 4) ): # e6B is sigBytes, i always see this as 4 so this code is untested temp1 = ctypes.c_int(S4B[(C6B & 0xffffffff) >> 24] << 24).value temp2 = ctypes.c_int(S4B[(C6B & 0xffffffff) >> 16 & 255] << 16).value temp3 = ctypes.c_int(S4B[(C6B & 0xffffffff) >> 8 & 255] << 8).value temp4 = S4B[255 & C6B] C6B = temp1 | temp2 | temp3 | temp4 C6B = temp1 | temp2 | temp3 | temp4 C6B ^= ctypes.c_int(r4B[g6B / e6B | 0] << 24).value k6B[g6B] = k6B[g6B - e6B] ^ C6B else: k6B[g6B] = k6B[g6B - e6B] ^ C6B else: C6B = ctypes.c_int(C6B << 8).value | (C6B & 0xffffffff) >> 24 temp1 = ctypes.c_int(S4B[(C6B & 0xffffffff) >> 24] << 24).value temp2 = ctypes.c_int(S4B[(C6B & 0xffffffff) >> 16 & 255] << 16).value temp3 = ctypes.c_int(S4B[(C6B & 0xffffffff) >> 8 & 255] << 8).value temp4 = S4B[255 & C6B] C6B = temp1 | temp2 | temp3 | temp4 C6B ^= ctypes.c_int(r4B[g6B / e6B | 0] << 24).value k6B[g6B] = k6B[g6B - e6B] ^ C6B T6B = [] for Y6B in range(X6B): g6B = X6B - Y6B if (Y6B % 4): C6B = k6B[g6B] else: C6B = k6B[g6B - 4] if ( (Y6B < 4) or (g6B <= 4)): T6B.append(C6B) else: # javascript is cryptic again, so its broken up into smaller chunks temp1 = G4B[S4B[(C6B & 0xffffffff) >> 24]] temp2 = l4B[S4B[(C6B & 0xffffffff) >> 16 & 255]] temp3 = D4B[S4B[(C6B & 0xffffffff) >> 8 & 255]] temp4 = d4B[S4B[255 & C6B]] temp = temp1 ^ temp2 ^ temp3 ^ temp4 T6B.append(temp) return(T6B) def stringify480(I0,M0): print("I0 is ", I0) print("M0 is ", M0) print("Length is ", len(I0)) s0 = [0] N0 = 0 while ( ((N0 & 0xffffffff) >> 2) < len(I0)): o0 = ( I0[(N0 & 0xffffffff) >> 2] & 0xffffffff) >> 24 - N0 % 4 * 8 & 255 if ( (o0 < 128) and (o0 > 31) ): s0.append( chr(o0) ) N0 += 1 result = ''.join(str(x) for x in s0) trimstr = result[:result.index(']}')+2] return(s0,trimstr) def dataParse(i8): dL476 = arrayCopy(i8) dF4 = [] for x in range(4): dF4.append(i8[0]) dL476.pop(0) return(dF4, dL476) def doCryptBlock(G94, d94, w94): e94 = G4B j94 = l4B r94 = D4B k94 = d4B S94 = 10 A94 = G94[w94] ^ d94[0] O94 = G94[w94 + 1] ^ d94[1] u94 = G94[w94 + 2] ^ d94[2] i94 = G94[w94 + 3] ^ d94[3] v94 = 4 V94 = 1 for V94 in range (1,10): a = e94[(A94 & 0xffffffff) >> 24] b = j94[(O94 & 0xffffffff) >> 16 & 255] c = r94[(u94 & 0xffffffff) >> 8 & 255] d = k94[255 & i94] B94 = e94[(A94 & 0xffffffff) >> 24] ^ j94[(O94 & 0xffffffff) >> 16 & 255] ^ r94[(u94 & 0xffffffff) >> 8 & 255] ^ k94[255 & i94] ^ d94[v94] v94 += 1 x94 = e94[(O94 & 0xffffffff) >> 24] ^ j94[(u94 & 0xffffffff) >> 16 & 255] ^ r94[(i94 & 0xffffffff) >> 8 & 255] ^ k94[255 & A94] ^ d94[v94] v94 += 1 Q94 = e94[(u94 & 0xffffffff) >> 24] ^ j94[(i94 & 0xffffffff) >> 16 & 255] ^ r94[(A94 & 0xffffffff) >> 8 & 255] ^ k94[255 & O94] ^ d94[v94] v94 += 1 F94 = e94[(i94 & 0xffffffff) >> 24] ^ j94[(A94 & 0xffffffff) >> 16 & 255] ^ r94[(O94 & 0xffffffff) >> 8 & 255] ^ k94[255 & u94] ^ d94[v94] v94 += 1 A94 = B94 O94 = x94 u94 = Q94 i94 = F94 B94 = ( ctypes.c_int(P94[(A94 & 0xffffffff) >> 24] << 24).value | ctypes.c_int(P94[(O94 & 0xffffffff) >> 16 & 255] << 16).value | ctypes.c_int(P94[(u94 & 0xffffffff) >> 8 & 255] << 8).value | P94[255 & i94]) ^ d94[v94] p1 = P94[(A94 & 0xffffffff) >> 24] v94 += 1 x94 = ( ctypes.c_int(P94[(O94 & 0xffffffff) >> 24] << 24).value | ctypes.c_int(P94[(u94 & 0xffffffff) >> 16 & 255] << 16).value | ctypes.c_int(P94[(i94 & 0xffffffff) >> 8 & 255] << 8).value | P94[255 & A94]) ^ d94[v94] v94 += 1 Q94 = ( ctypes.c_int(P94[(u94 & 0xffffffff) >> 24] << 24).value | ctypes.c_int(P94[(i94 & 0xffffffff) >> 16 & 255] << 16).value | ctypes.c_int(P94[(A94 & 0xffffffff) >> 8 & 255] << 8).value | P94[255 & O94]) ^ d94[v94] v94 += 1 F94 = ( ctypes.c_int(P94[(i94 & 0xffffffff) >> 24] << 24).value | ctypes.c_int(P94[(A94 & 0xffffffff) >> 16 & 255] << 16).value | ctypes.c_int(P94[(O94 & 0xffffffff) >> 8 & 255] << 8).value | P94[255 & u94]) ^ d94[v94] v94 += 1 G94[w94] = B94 G94[w94 + 1] = x94 G94[w94 + 2] = Q94 G94[w94 + 3] = F94 return(G94) def dataProcess(a480, k6, iv4): counter1 = 0 J0 = 0 tA4 = [] # 2D array to hold the pevious block previous = [[0]*0]*0 # start it off with iv4 iprevious = [] iprevious = arrayCopy(iv4) previous.append(iprevious) tempB = arrayCopy(a480) J94 = 0 F6 = 0 while (J94 < 479): p4 = [] for x in range(4): p4.append(a480[x + J94]) previous.append(p4) c94 = tempB[J94 + 1] tempB[J94 + 1] = tempB[J94 + 3] tempB[J94 + 3] = c94 tempB = doCryptBlock(tempB, k6, J94) c94 = tempB[J94 + 1] tempB[J94 + 1] = tempB[J94 + 3] tempB[J94 + 3] = c94 # get "previous" value to or with ork6 = [] for c in range(4): ork6.append(previous[counter1][c]) for r6 in range(4): tempB[F6 + r6] ^= ork6[r6] J94 += 4 F6 += 4 counter1 += 1 pg6 = [] for c in range(4): pg6.append(a480[476 + c]) offs = 255 & tempB[479] return(tempB, pg6, offs) # this is probably really inefficient code, json habdling still confussess me def getUseful(s): licUrl = [] streamUrl = [] fixed = s[1:] keyserver = 'NA' streamUrl ='NA' subtitile = 'NA' data = json.loads(fixed) for x in data['assets']: try: for d in x['renditions']: if 'hwdash' in d['url']: streamUrl = d['url'] subtitile = x['subtitleurl'] if 'widevine' in x['keyserver']: keyserver = x['keyserver'] except: pass return (streamUrl, keyserver, subtitile) def part2(iv, aesKey, rdata): aesFour = aesToArray(aesKey) ivMangle = mangle(iv) b6(iv) ivFourArray = ivArray(ivMangle) dataMangle = mangle(rdata) data480 = ivParse(dataMangle) aes44 = ivreset(aesFour) (dataFirst4, dataLast476) = dataParse(data480) (newdata480, lastprevious, offset) = dataProcess(data480, aes44, ivFourArray) parseLength = 1920 - offset aarray, astring = stringify480(newdata480, parseLength) (stream, drmurl, sub) = getUseful(astring) return (stream, drmurl, sub) @Route.register def list_categories(plugin, **kwargs): resp = urlquick.get(FEEDS_API % 'PLC_My5SubGenreBrowsePageSubNav', headers=GENERIC_HEADERS, params=feeds_api_params) root = json.loads(resp.text) for i in range(int(root['total_items'])): try: item = Listitem() item_id = 1 item.label = root['filters']['contents'][i]['title'] browse_name = root['filters']['contents'][i]['id'] item.set_callback(list_subcategories, item_id=item_id, browse_name=browse_name) item_post_treatment(item) yield item except: pass @Route.register def list_subcategories(plugin, item_id, browse_name, **kwargs): resp = urlquick.get(FEEDS_API % browse_name, headers=GENERIC_HEADERS, params=feeds_api_params) root = json.loads(resp.text) item_number = int(root['total_items']) if root['filters']['type'] == 'Collection': offset = 0 for i in range(item_number): try: item = Listitem() item.label = root['filters']['contents'][i]['title'] browse_name = root['filters']['contents'][i]['id'] item.set_callback(list_collections, item_id=item_id, browse_name=browse_name, offset=offset) item_post_treatment(item) yield item except: pass else: ids = root['filters']['ids'] watchable_params = '?limit=%s&offset=0s&platform=my5desktop&friendly=1' % str(item_number) for i in range(item_number): try: watchable_params = watchable_params + '&ids[]=%s' % ids[i] except: pass s = URL_WATCHABLE + watchable_params resp = urlquick.get(URL_WATCHABLE + watchable_params, headers=GENERIC_HEADERS) root = json.loads(resp.text) for watchable in root['watchables']: try: item = Listitem() item.label = watchable['sh_title'] item.info['plot'] = watchable['s_desc'] t = int(int(watchable['len']) // 1000) item.info['duration'] = t item.art['thumb'] = item.art['landscape'] = SHOW_IMG_URL % watchable['sh_id'] #fname = watchable['f_name'] #season_f_name = watchable['sea_f_name'] show_id = watchable['id'] item.set_callback(get_video_url, item_id=item_id, fname="fname", season_f_name="season_f_name", show_id=show_id, standalone="no") item_post_treatment(item) yield item except: pass @Route.register def list_watchables(plugin, itemid, browse_name, offset, item_number, ids): return False @Route.register def list_collections(plugin, item_id, browse_name, offset, **kwargs): resp = urlquick.get(FEEDS_API % browse_name, headers=GENERIC_HEADERS, params=feeds_api_params) root = json.loads(resp.text) subgenre = root['filters']['vod_subgenres'] view_all_params = { 'platform': 'my5desktop', 'friendly': '1', 'limit': '10', 'offset': offset, 'vod_subgenres[]': subgenre } resp = urlquick.get(URL_VIEW_ALL, headers=GENERIC_HEADERS, params=view_all_params) root = json.loads(resp.text) for emission in root['shows']: try: standalone = emission['standalone'] standalone = "yes" except: standalone = "no" if (standalone == "yes"): item = Listitem() item.label = emission['title'] item.info['plot'] = emission['s_desc'] fname = emission['f_name'] picture_id = emission['id'] item.art['thumb'] = item.art['landscape'] = SHOW_IMG_URL % picture_id item.set_callback(get_video_url, item_id=item_id, fname=fname, season_f_name="", show_id="show_id", standalone="yes") item_post_treatment(item) yield item else: try: item = Listitem() title = emission['title'] item.label = title item.info['plot'] = emission['s_desc'] fname = emission['f_name'] picture_id = emission['id'] item.art['thumb'] = item.art['landscape'] = SHOW_IMG_URL % picture_id item.set_callback(list_seasons, item_id=item_id, fname=fname, pid=picture_id, title=title) item_post_treatment(item) yield item except: pass if 'next_page_url' in root: offset = str(int(offset) + int(view_all_params['limit'])) yield Listitem.next_page(item_id=item_id, browse_name=browse_name, offset=offset) @Route.register def list_seasons(plugin, item_id, fname, pid, title, **kwargs): resp = urlquick.get(URL_SEASONS % fname, headers=GENERIC_HEADERS, params=view_api_params) if resp.ok: root = json.loads(resp.text) for season in root['seasons']: try: item = Listitem() season_number = season['seasonNumber'] item.label = title + '\nSeason ' + season_number picture_id = pid item.art['thumb'] = item.art['landscape'] = SHOW_IMG_URL % picture_id item.set_callback(list_episodes, item_id=item_id, fname=fname, season_number=season_number) item_post_treatment(item) yield item except: pass @Route.register def list_episodes(plugin, item_id, fname, season_number, **kwargs): resp = urlquick.get(URL_EPISODES % (fname, season_number), headers=GENERIC_HEADERS, params=view_api_params) root = json.loads(resp.text) for episode in root['episodes']: try: item = Listitem() picture_id = episode['id'] item.art['thumb'] = item.art['landscape'] = IMG_URL % picture_id item.label = episode['title'] item.info['plot'] = episode['s_desc'] t = int(int(episode['len']) // 1000) item.info['duration'] = t season_f_name = episode['sea_f_name'] fname = episode['f_name'] show_id = episode['id'] item.set_callback(get_video_url, item_id=item_id, fname=fname, season_f_name=season_f_name, show_id=show_id, standalone="no") item_post_treatment(item) yield item except: pass @Resolver.register def get_video_url(plugin, item_id, fname, season_f_name, show_id, standalone, **kwargs): # for a onceoff/stanalone we still dont have showid so we get it now if (standalone == "yes"): resp = urlquick.get(ONEOFF % fname, headers=GENERIC_HEADERS, params=view_api_params) if resp.ok: root = json.loads(resp.text) try: show_id = root['id'] except: pass LICFULL_URL, aesKey = getdata(show_id) (iv,data)=ivdata(LICFULL_URL) (stream,drmurl,suburl) = part2(iv,aesKey,data) xbmc.log("Stream : %s" % stream, level=xbmc.LOGERROR) xbmc.log("Licensce : %s" % drmurl, level=xbmc.LOGERROR) # get server certiticate data and b64 it resp = urlquick.get(CERT_URL) content = resp.content cert_data = (base64.b64encode(content)).decode('ascii') stream_headers = urllib.urlencode(lic_headers) license_url = '%s|%s|R{SSM}|' % (drmurl, stream_headers) item = Listitem() item.path = stream item.label = get_selected_item_label() item.art.update(get_selected_item_art()) item.info.update(get_selected_item_info()) item.property[INPUTSTREAM_PROP] = 'inputstream.adaptive' item.property['inputstream.adaptive.manifest_type'] = 'mpd' item.property[ 'inputstream.adaptive.license_type'] = 'com.widevine.alpha' item.property[ 'inputstream.adaptive.server_certificate'] = cert_data item.property['inputstream.adaptive.license_key'] = license_url return item