Move py files to lib
parent
0a0013e706
commit
ea1d155015
@ -1,161 +1,161 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import requests
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
|
||||
import six
|
||||
from six.moves import urllib
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
PLUGIN_URL = sys.argv[0]
|
||||
|
||||
ADDON = xbmcaddon.Addon()
|
||||
ADDON_ICON = ADDON.getAddonInfo('icon')
|
||||
ADDON_NAME = ADDON.getAddonInfo('name')
|
||||
|
||||
#language
|
||||
__language__ = ADDON.getLocalizedString
|
||||
|
||||
# Disable urllib3's "InsecureRequestWarning: Unverified HTTPS request is being made" warnings
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
reqs = requests.session()
|
||||
|
||||
|
||||
def request_get( url, data=None, extraHeaders=None ):
|
||||
|
||||
""" makes a request """
|
||||
|
||||
try:
|
||||
|
||||
# headers
|
||||
my_headers = {
|
||||
'Accept-Language': 'en-gb,en;q=0.5',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
|
||||
'Referer': url,
|
||||
'Cache-Control': 'no-cache',
|
||||
'Pragma': 'no-cache',
|
||||
'DNT': '1'
|
||||
}
|
||||
|
||||
# add extra headers
|
||||
if extraHeaders:
|
||||
my_headers.update(extraHeaders)
|
||||
|
||||
# get stored cookie string
|
||||
cookies = ADDON.getSetting('cookies')
|
||||
|
||||
# split cookies into dictionary
|
||||
if cookies:
|
||||
cookie_dict = json.loads( cookies )
|
||||
else:
|
||||
cookie_dict = None
|
||||
|
||||
# make request
|
||||
if data:
|
||||
response = reqs.post(url, data=data, headers=my_headers, verify=False, cookies=cookie_dict, timeout=10)
|
||||
else:
|
||||
response = reqs.get(url, headers=my_headers, verify=False, cookies=cookie_dict, timeout=10)
|
||||
|
||||
if response.cookies.get_dict():
|
||||
if cookie_dict:
|
||||
cookie_dict.update( response.cookies.get_dict() )
|
||||
else:
|
||||
cookie_dict = response.cookies.get_dict()
|
||||
|
||||
# store cookies
|
||||
ADDON.setSetting('cookies', json.dumps(cookie_dict))
|
||||
|
||||
return response.text
|
||||
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
def build_url(query):
|
||||
|
||||
"""
|
||||
Helper function to build a Kodi xbmcgui.ListItem URL
|
||||
:param query: Dictionary of url parameters to put in the URL
|
||||
:returns: A formatted and urlencoded URL string
|
||||
"""
|
||||
|
||||
return (PLUGIN_URL + '?' + urllib.parse.urlencode({
|
||||
k: v.encode('utf-8') if isinstance(v, six.text_type)
|
||||
else unicode(v, errors='ignore').encode('utf-8')
|
||||
for k, v in query.items()
|
||||
}))
|
||||
|
||||
|
||||
def notify( message, name=False, iconimage=False, timeShown=5000 ):
|
||||
|
||||
""" Show notfication to user """
|
||||
|
||||
if not name:
|
||||
name = ADDON_NAME
|
||||
|
||||
if not iconimage:
|
||||
iconimage = ADDON_ICON
|
||||
|
||||
xbmc.executebuiltin('Notification(%s, %s, %d, %s)' % (name, message, timeShown, iconimage))
|
||||
|
||||
def view_set( name ):
|
||||
|
||||
""" sets view """
|
||||
|
||||
views = {
|
||||
'fanart': 502,
|
||||
'wall': 500,
|
||||
'widelist': 55,
|
||||
'infowall': 54,
|
||||
'shift': 53,
|
||||
'poster': 51,
|
||||
'list': 50,
|
||||
}
|
||||
|
||||
view_num = views.get( name.lower(), 0 )
|
||||
|
||||
if view_num > 0:
|
||||
try:
|
||||
xbmc.executebuiltin('Container.SetViewMode(' + str( view_num ) + ')')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def get_string( string_id ):
|
||||
|
||||
""" gets language string based upon id """
|
||||
|
||||
if string_id >= 30000:
|
||||
return __language__( string_id )
|
||||
else:
|
||||
return xbmc.getLocalizedString( string_id )
|
||||
|
||||
def get_date_formatted( format_id, year, month, day ):
|
||||
|
||||
""" puts date into format based upon setting """
|
||||
|
||||
if format_id == '1':
|
||||
return month + '/' + day + '/' + year
|
||||
if format_id == '2':
|
||||
return day + '/' + month + '/' + year
|
||||
else:
|
||||
return year + '/' + month + '/' + day
|
||||
|
||||
def get_params():
|
||||
|
||||
""" gets params from request """
|
||||
|
||||
return dict(urllib.parse.parse_qsl(sys.argv[2][1:], keep_blank_values=True))
|
||||
|
||||
def clean_text( text ):
|
||||
|
||||
""" Removes characters that can cause trouble """
|
||||
|
||||
return text.encode('ascii', 'ignore').decode('ascii').strip()
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import requests
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
|
||||
import six
|
||||
from six.moves import urllib
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
PLUGIN_URL = sys.argv[0]
|
||||
|
||||
ADDON = xbmcaddon.Addon()
|
||||
ADDON_ICON = ADDON.getAddonInfo('icon')
|
||||
ADDON_NAME = ADDON.getAddonInfo('name')
|
||||
|
||||
#language
|
||||
__language__ = ADDON.getLocalizedString
|
||||
|
||||
# Disable urllib3's "InsecureRequestWarning: Unverified HTTPS request is being made" warnings
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
reqs = requests.session()
|
||||
|
||||
|
||||
def request_get( url, data=None, extraHeaders=None ):
|
||||
|
||||
""" makes a request """
|
||||
|
||||
try:
|
||||
|
||||
# headers
|
||||
my_headers = {
|
||||
'Accept-Language': 'en-gb,en;q=0.5',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
|
||||
'Referer': url,
|
||||
'Cache-Control': 'no-cache',
|
||||
'Pragma': 'no-cache',
|
||||
'DNT': '1'
|
||||
}
|
||||
|
||||
# add extra headers
|
||||
if extraHeaders:
|
||||
my_headers.update(extraHeaders)
|
||||
|
||||
# get stored cookie string
|
||||
cookies = ADDON.getSetting('cookies')
|
||||
|
||||
# split cookies into dictionary
|
||||
if cookies:
|
||||
cookie_dict = json.loads( cookies )
|
||||
else:
|
||||
cookie_dict = None
|
||||
|
||||
# make request
|
||||
if data:
|
||||
response = reqs.post(url, data=data, headers=my_headers, verify=False, cookies=cookie_dict, timeout=10)
|
||||
else:
|
||||
response = reqs.get(url, headers=my_headers, verify=False, cookies=cookie_dict, timeout=10)
|
||||
|
||||
if response.cookies.get_dict():
|
||||
if cookie_dict:
|
||||
cookie_dict.update( response.cookies.get_dict() )
|
||||
else:
|
||||
cookie_dict = response.cookies.get_dict()
|
||||
|
||||
# store cookies
|
||||
ADDON.setSetting('cookies', json.dumps(cookie_dict))
|
||||
|
||||
return response.text
|
||||
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
def build_url(query):
|
||||
|
||||
"""
|
||||
Helper function to build a Kodi xbmcgui.ListItem URL
|
||||
:param query: Dictionary of url parameters to put in the URL
|
||||
:returns: A formatted and urlencoded URL string
|
||||
"""
|
||||
|
||||
return (PLUGIN_URL + '?' + urllib.parse.urlencode({
|
||||
k: v.encode('utf-8') if isinstance(v, six.text_type)
|
||||
else unicode(v, errors='ignore').encode('utf-8')
|
||||
for k, v in query.items()
|
||||
}))
|
||||
|
||||
|
||||
def notify( message, name=False, iconimage=False, timeShown=5000 ):
|
||||
|
||||
""" Show notfication to user """
|
||||
|
||||
if not name:
|
||||
name = ADDON_NAME
|
||||
|
||||
if not iconimage:
|
||||
iconimage = ADDON_ICON
|
||||
|
||||
xbmc.executebuiltin('Notification(%s, %s, %d, %s)' % (name, message, timeShown, iconimage))
|
||||
|
||||
def view_set( name ):
|
||||
|
||||
""" sets view """
|
||||
|
||||
views = {
|
||||
'fanart': 502,
|
||||
'wall': 500,
|
||||
'widelist': 55,
|
||||
'infowall': 54,
|
||||
'shift': 53,
|
||||
'poster': 51,
|
||||
'list': 50,
|
||||
}
|
||||
|
||||
view_num = views.get( name.lower(), 0 )
|
||||
|
||||
if view_num > 0:
|
||||
try:
|
||||
xbmc.executebuiltin('Container.SetViewMode(' + str( view_num ) + ')')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def get_string( string_id ):
|
||||
|
||||
""" gets language string based upon id """
|
||||
|
||||
if string_id >= 30000:
|
||||
return __language__( string_id )
|
||||
else:
|
||||
return xbmc.getLocalizedString( string_id )
|
||||
|
||||
def get_date_formatted( format_id, year, month, day ):
|
||||
|
||||
""" puts date into format based upon setting """
|
||||
|
||||
if format_id == '1':
|
||||
return month + '/' + day + '/' + year
|
||||
if format_id == '2':
|
||||
return day + '/' + month + '/' + year
|
||||
else:
|
||||
return year + '/' + month + '/' + day
|
||||
|
||||
def get_params():
|
||||
|
||||
""" gets params from request """
|
||||
|
||||
return dict(urllib.parse.parse_qsl(sys.argv[2][1:], keep_blank_values=True))
|
||||
|
||||
def clean_text( text ):
|
||||
|
||||
""" Removes characters that can cause trouble """
|
||||
|
||||
return text.encode('ascii', 'ignore').decode('ascii').strip()
|
@ -1,312 +1,312 @@
|
||||
"""
|
||||
MD5Ex class
|
||||
Converted from JS to python by Azzy9
|
||||
This is a class to generate hashes that is used by the Rumble platform
|
||||
"""
|
||||
|
||||
class MD5Ex:
|
||||
|
||||
hex = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' ]
|
||||
|
||||
def bit_shift( self, val1, val2, direction = 'r', zero_fill = False ):
|
||||
|
||||
""" bit_shift method to allow zer filled bitshift which is not supported by python """
|
||||
|
||||
if direction == 'l':
|
||||
return val1 << val2
|
||||
|
||||
if direction == 'r' and zero_fill is True:
|
||||
return (val1 % 0x100000000) >> val2
|
||||
|
||||
return val1 >> val2
|
||||
|
||||
def char_code_at( self, str_in, pos ):
|
||||
|
||||
""" essentially the ord method but with validation that is required """
|
||||
|
||||
if pos < len( str_in ):
|
||||
return ord( str_in[pos] )
|
||||
|
||||
return 0
|
||||
|
||||
def hash( self, n ):
|
||||
return self.binHex( self.binHash( self.strBin(n), len(n) << 3))
|
||||
|
||||
def hashUTF8( self, n ):
|
||||
return self.hash(self.encUTF8(n))
|
||||
|
||||
def hashRaw( self, n ):
|
||||
return self.binStr(self.binHash(self.strBin(n), len(n) << 3))
|
||||
|
||||
def hashRawUTF8( self, n ):
|
||||
return self.hashRaw(self.encUTF8(n))
|
||||
|
||||
def hashStretch( self, n, h, i ):
|
||||
return self.binHex(self.binHashStretch(n, h, i))
|
||||
|
||||
def binHashStretch( self, n, h, i ):
|
||||
|
||||
e = self.encUTF8(n)
|
||||
g = h + e
|
||||
o = 32 + len(e) << 3
|
||||
a = self.strBin(e)
|
||||
u = len(a)
|
||||
g = self.binHash(self.strBin(g), len(g) << 3)
|
||||
if not i:
|
||||
i = 1024
|
||||
r = 0
|
||||
|
||||
while r < i:
|
||||
g = self.binHexBin(g)
|
||||
t = 0
|
||||
while t < u:
|
||||
g[8 + t] = a[t]
|
||||
t = t + 1
|
||||
g = self.binHash(g, o)
|
||||
r += 1
|
||||
|
||||
return g
|
||||
|
||||
def encUTF8( self, n ):
|
||||
|
||||
# return string
|
||||
r_str = ''
|
||||
# character pos
|
||||
char_pos = 0
|
||||
# string length
|
||||
str_len = len(n) - 1
|
||||
|
||||
while char_pos <= str_len:
|
||||
|
||||
h = self.char_code_at(n, char_pos)
|
||||
char_pos += 1
|
||||
i = self.char_code_at(n, char_pos)
|
||||
|
||||
if char_pos < str_len and 55296 <= h and h <= 56319 and 56320 <= i and i <= 57343:
|
||||
h = 65536 + self.bit_shift((1023 & h), 10, 'l') + (1023 & i)
|
||||
char_pos +=1
|
||||
|
||||
if h <= 127:
|
||||
r_str += chr(h)
|
||||
else:
|
||||
if h <= 2047:
|
||||
r_str += chr(192 | self.bit_shift( h, 6, 'r', True ) & 31, 128 | 63 & h)
|
||||
else:
|
||||
if h <= 65535:
|
||||
r_str += chr(224 | self.bit_shift( h, 12, 'r', True ) & 15, 128 | self.bit_shift( h, 6, 'r', True ) & 63, 128 | 63 & h)
|
||||
else:
|
||||
if h <= 2097151:
|
||||
r_str += chr(240 | self.bit_shift( h, 18, 'r', True ) & 7, 128 | self.bit_shift( h, 12, 'r', True ) & 63, 128 | self.bit_shift( h, 6, 'r', True ) & 63, 128 | 63 & h)
|
||||
|
||||
return r_str
|
||||
|
||||
def strBin( self, n ):
|
||||
|
||||
""" String to Binary """
|
||||
|
||||
i = self.bit_shift( len(n), 3, 'l' )
|
||||
r = {}
|
||||
h = 0
|
||||
|
||||
while h < i:
|
||||
tmp = self.bit_shift( h, 5 )
|
||||
r[tmp] = r.get(tmp, 0) | self.bit_shift( (255 & self.char_code_at( n, self.bit_shift( h, 3 ))), (31 & h), 'l' )
|
||||
h += 8
|
||||
|
||||
return r
|
||||
|
||||
def binHex( self, n ):
|
||||
|
||||
""" Binary to Hex """
|
||||
|
||||
t = ''
|
||||
f = self.bit_shift( len(n), 5, 'l' )
|
||||
r = 0
|
||||
|
||||
while r < f:
|
||||
h = self.bit_shift( n.get( self.bit_shift( r, 5 ), 0 ), (31 & r), 'r', True ) & 255
|
||||
i = self.bit_shift( h, 4, 'r', True ) & 15
|
||||
h &= 15
|
||||
t += self.hex[i] + self.hex[h]
|
||||
r += 8
|
||||
|
||||
return t
|
||||
|
||||
def binStr( self, n ):
|
||||
|
||||
""" Binary to String """
|
||||
|
||||
r = ''
|
||||
t = self.bit_shift( len(n), 5, 'l' )
|
||||
i = 0
|
||||
|
||||
while i < t:
|
||||
h = self.bit_shift( n.get( self.bit_shift( i, 5 ), 0 ), (31 & i), 'r', True ) & 255
|
||||
r += chr(h)
|
||||
i += 8
|
||||
|
||||
return r
|
||||
|
||||
def binHexBin( self, n ):
|
||||
|
||||
t = self.bit_shift( len(n), 5, 'l' )
|
||||
f = {}
|
||||
r = 0
|
||||
|
||||
while r < t:
|
||||
|
||||
h = self.bit_shift( n.get( self.bit_shift( r, 5 ), 0 ), (31 & r), 'r', True ) & 255
|
||||
i = self.bit_shift( h, 4, 'r', True ) & 15
|
||||
h &= 15
|
||||
|
||||
tmp2 = 48
|
||||
if 9 < i:
|
||||
tmp2 = 87
|
||||
|
||||
tmp3 = 48
|
||||
if 9 < h:
|
||||
tmp3 = 87
|
||||
|
||||
tmp = self.bit_shift( r, 4 )
|
||||
f[tmp] = f.get(tmp, 0) | self.bit_shift( tmp2 + i + self.bit_shift( (tmp3 + h), 8, 'l'), self.bit_shift((15 & r), 1, 'l'), 'l' )
|
||||
r += 8
|
||||
|
||||
return f
|
||||
|
||||
def fghi( self, n, h, i, r, t, f, e, g ):
|
||||
|
||||
"""
|
||||
method that is used by ff,gg,hh,ii
|
||||
This was originally duplicated code in each method
|
||||
reduced code by creating a n ew method for it
|
||||
"""
|
||||
|
||||
o = (65535 & n) + (65535 & g) + (65535 & t) + (65535 & e)
|
||||
g = self.bit_shift( self.bit_shift( n, 16 ) + self.bit_shift( g, 16, 'r') + self.bit_shift( t, 16 ) + self.bit_shift( e, 16 ) + self.bit_shift( o, 16 ), 16, 'l' )
|
||||
g = g | 65535 & o
|
||||
g = self.bit_shift( g, f, 'l' ) | self.bit_shift( g, ( 32 - f ), 'r', True )
|
||||
o = (65535 & g) + (65535 & h)
|
||||
g = self.bit_shift( self.bit_shift( g, 16 ) + self.bit_shift( h, 16 ) + self.bit_shift( o, 16 ), 16, 'l' )
|
||||
|
||||
return g | 65535 & o
|
||||
|
||||
def ff( self, n, h, i, r, t, f, e ):
|
||||
|
||||
g = h & i | ~h & r
|
||||
return self.fghi(n, h, i, r, t, f, e, g)
|
||||
|
||||
def gg( self, n, h, i, r, t, f, e ):
|
||||
|
||||
g = h & r | i & ~r
|
||||
return self.fghi(n, h, i, r, t, f, e, g)
|
||||
|
||||
def hh( self, n, h, i, r, t, f, e ):
|
||||
|
||||
g = h ^ i ^ r
|
||||
return self.fghi(n, h, i, r, t, f, e, g)
|
||||
|
||||
def ii( self, n, h, i, r, t, f, e ):
|
||||
|
||||
g = i ^ (h | ~r)
|
||||
return self.fghi(n, h, i, r, t, f, e, g)
|
||||
|
||||
def binHash( self, n, h ):
|
||||
|
||||
""" Binary to Hash """
|
||||
|
||||
a = 1732584193
|
||||
u = -271733879
|
||||
s = -1732584194
|
||||
c = 271733878
|
||||
|
||||
tmp = self.bit_shift( h, 5 )
|
||||
n[ tmp ] = n.get( tmp, 0 ) | self.bit_shift( 128, (31 & h), 'l' )
|
||||
tmp = 14 + self.bit_shift( ( h + 64 ), self.bit_shift( 9, 4, 'l' ), 'r', True )
|
||||
n[ tmp ] = h
|
||||
i = len(n)
|
||||
r = 0
|
||||
|
||||
while r < i:
|
||||
|
||||
t = a
|
||||
f = u
|
||||
e = s
|
||||
g = c
|
||||
|
||||
a = self.ff(a, u, s, c, n.get((r + 0), 0), 7, -680876936)
|
||||
c = self.ff(c, a, u, s, n.get((r + 1), 0), 12, -389564586)
|
||||
s = self.ff(s, c, a, u, n.get((r + 2), 0), 17, 606105819)
|
||||
u = self.ff(u, s, c, a, n.get((r + 3), 0), 22, -1044525330)
|
||||
a = self.ff(a, u, s, c, n.get((r + 4), 0), 7, -176418897)
|
||||
c = self.ff(c, a, u, s, n.get((r + 5), 0), 12, 1200080426)
|
||||
s = self.ff(s, c, a, u, n.get((r + 6), 0), 17, -1473231341)
|
||||
u = self.ff(u, s, c, a, n.get((r + 7), 0), 22, -45705983)
|
||||
a = self.ff(a, u, s, c, n.get((r + 8), 0), 7, 1770035416)
|
||||
c = self.ff(c, a, u, s, n.get((r + 9), 0), 12, -1958414417)
|
||||
s = self.ff(s, c, a, u, n.get((r + 10), 0), 17, -42063)
|
||||
u = self.ff(u, s, c, a, n.get((r + 11), 0), 22, -1990404162)
|
||||
a = self.ff(a, u, s, c, n.get((r + 12), 0), 7, 1804603682)
|
||||
c = self.ff(c, a, u, s, n.get((r + 13), 0), 12, -40341101)
|
||||
s = self.ff(s, c, a, u, n.get((r + 14), 0), 17, -1502002290)
|
||||
u = self.ff(u, s, c, a, n.get((r + 15), 0), 22, 1236535329)
|
||||
a = self.gg(a, u, s, c, n.get((r + 1), 0), 5, -165796510)
|
||||
c = self.gg(c, a, u, s, n.get((r + 6), 0), 9, -1069501632)
|
||||
s = self.gg(s, c, a, u, n.get((r + 11), 0), 14, 643717713)
|
||||
u = self.gg(u, s, c, a, n.get((r + 0), 0), 20, -373897302)
|
||||
a = self.gg(a, u, s, c, n.get((r + 5), 0), 5, -701558691)
|
||||
c = self.gg(c, a, u, s, n.get((r + 10), 0), 9, 38016083)
|
||||
s = self.gg(s, c, a, u, n.get((r + 15), 0), 14, -660478335)
|
||||
u = self.gg(u, s, c, a, n.get((r + 4), 0), 20, -405537848)
|
||||
a = self.gg(a, u, s, c, n.get((r + 9), 0), 5, 568446438)
|
||||
c = self.gg(c, a, u, s, n.get((r + 14), 0), 9, -1019803690)
|
||||
s = self.gg(s, c, a, u, n.get((r + 3), 0), 14, -187363961)
|
||||
u = self.gg(u, s, c, a, n.get((r + 8), 0), 20, 1163531501)
|
||||
a = self.gg(a, u, s, c, n.get((r + 13), 0), 5, -1444681467)
|
||||
c = self.gg(c, a, u, s, n.get((r + 2), 0), 9, -51403784)
|
||||
s = self.gg(s, c, a, u, n.get((r + 7), 0), 14, 1735328473)
|
||||
u = self.gg(u, s, c, a, n.get((r + 12), 0), 20, -1926607734)
|
||||
a = self.hh(a, u, s, c, n.get((r + 5), 0), 4, -378558)
|
||||
c = self.hh(c, a, u, s, n.get((r + 8), 0), 11, -2022574463)
|
||||
s = self.hh(s, c, a, u, n.get((r + 11), 0), 16, 1839030562)
|
||||
u = self.hh(u, s, c, a, n.get((r + 14), 0), 23, -35309556)
|
||||
a = self.hh(a, u, s, c, n.get((r + 1), 0), 4, -1530992060)
|
||||
c = self.hh(c, a, u, s, n.get((r + 4), 0), 11, 1272893353)
|
||||
s = self.hh(s, c, a, u, n.get((r + 7), 0), 16, -155497632)
|
||||
u = self.hh(u, s, c, a, n.get((r + 10), 0), 23, -1094730640)
|
||||
a = self.hh(a, u, s, c, n.get((r + 13), 0), 4, 681279174)
|
||||
c = self.hh(c, a, u, s, n.get((r + 0), 0), 11, -358537222)
|
||||
s = self.hh(s, c, a, u, n.get((r + 3), 0), 16, -722521979)
|
||||
u = self.hh(u, s, c, a, n.get((r + 6), 0), 23, 76029189)
|
||||
a = self.hh(a, u, s, c, n.get((r + 9), 0), 4, -640364487)
|
||||
c = self.hh(c, a, u, s, n.get((r + 12), 0), 11, -421815835)
|
||||
s = self.hh(s, c, a, u, n.get((r + 15), 0), 16, 530742520)
|
||||
u = self.hh(u, s, c, a, n.get((r + 2), 0), 23, -995338651)
|
||||
a = self.ii(a, u, s, c, n.get((r + 0), 0), 6, -198630844)
|
||||
c = self.ii(c, a, u, s, n.get((r + 7), 0), 10, 1126891415)
|
||||
s = self.ii(s, c, a, u, n.get((r + 14), 0), 15, -1416354905)
|
||||
u = self.ii(u, s, c, a, n.get((r + 5), 0), 21, -57434055)
|
||||
a = self.ii(a, u, s, c, n.get((r + 12), 0), 6, 1700485571)
|
||||
c = self.ii(c, a, u, s, n.get((r + 3), 0), 10, -1894986606)
|
||||
s = self.ii(s, c, a, u, n.get((r + 10), 0), 15, -1051523)
|
||||
u = self.ii(u, s, c, a, n.get((r + 1), 0), 21, -2054922799)
|
||||
a = self.ii(a, u, s, c, n.get((r + 8), 0), 6, 1873313359)
|
||||
c = self.ii(c, a, u, s, n.get((r + 15), 0), 10, -30611744)
|
||||
s = self.ii(s, c, a, u, n.get((r + 6), 0), 15, -1560198380)
|
||||
u = self.ii(u, s, c, a, n.get((r + 13), 0), 21, 1309151649)
|
||||
a = self.ii(a, u, s, c, n.get((r + 4), 0), 6, -145523070)
|
||||
c = self.ii(c, a, u, s, n.get((r + 11), 0), 10, -1120210379)
|
||||
s = self.ii(s, c, a, u, n.get((r + 2), 0), 15, 718787259)
|
||||
u = self.ii(u, s, c, a, n.get((r + 9), 0), 21, -343485551)
|
||||
|
||||
o = (65535 & a) + (65535 & t)
|
||||
a = self.bit_shift( ( self.bit_shift( a, 16 ) + self.bit_shift( t, 16 ) + self.bit_shift( o, 16 ) ), 16, 'l' ) | 65535 & o
|
||||
o = (65535 & u) + (65535 & f)
|
||||
u = self.bit_shift( ( self.bit_shift( u, 16 ) + self.bit_shift( f, 16 ) + self.bit_shift( o, 16 ) ), 16, 'l' ) | 65535 & o
|
||||
o = (65535 & s) + (65535 & e)
|
||||
s = self.bit_shift( ( self.bit_shift( s, 16 ) + self.bit_shift( e, 16 ) + self.bit_shift( o, 16 ) ), 16, 'l' ) | 65535 & o
|
||||
o = (65535 & c) + (65535 & g)
|
||||
c = self.bit_shift( ( self.bit_shift( c, 16 ) + self.bit_shift( g, 16 ) + self.bit_shift( o, 16 ) ), 16, 'l' ) | 65535 & o
|
||||
|
||||
r += 16
|
||||
|
||||
return {0:a, 1:u, 2:s, 3:c}
|
||||
"""
|
||||
MD5Ex class
|
||||
Converted from JS to python by Azzy9
|
||||
This is a class to generate hashes that is used by the Rumble platform
|
||||
"""
|
||||
|
||||
class MD5Ex:
|
||||
|
||||
hex = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' ]
|
||||
|
||||
def bit_shift( self, val1, val2, direction = 'r', zero_fill = False ):
|
||||
|
||||
""" bit_shift method to allow zer filled bitshift which is not supported by python """
|
||||
|
||||
if direction == 'l':
|
||||
return val1 << val2
|
||||
|
||||
if direction == 'r' and zero_fill is True:
|
||||
return (val1 % 0x100000000) >> val2
|
||||
|
||||
return val1 >> val2
|
||||
|
||||
def char_code_at( self, str_in, pos ):
|
||||
|
||||
""" essentially the ord method but with validation that is required """
|
||||
|
||||
if pos < len( str_in ):
|
||||
return ord( str_in[pos] )
|
||||
|
||||
return 0
|
||||
|
||||
def hash( self, n ):
|
||||
return self.binHex( self.binHash( self.strBin(n), len(n) << 3))
|
||||
|
||||
def hashUTF8( self, n ):
|
||||
return self.hash(self.encUTF8(n))
|
||||
|
||||
def hashRaw( self, n ):
|
||||
return self.binStr(self.binHash(self.strBin(n), len(n) << 3))
|
||||
|
||||
def hashRawUTF8( self, n ):
|
||||
return self.hashRaw(self.encUTF8(n))
|
||||
|
||||
def hashStretch( self, n, h, i ):
|
||||
return self.binHex(self.binHashStretch(n, h, i))
|
||||
|
||||
def binHashStretch( self, n, h, i ):
|
||||
|
||||
e = self.encUTF8(n)
|
||||
g = h + e
|
||||
o = 32 + len(e) << 3
|
||||
a = self.strBin(e)
|
||||
u = len(a)
|
||||
g = self.binHash(self.strBin(g), len(g) << 3)
|
||||
if not i:
|
||||
i = 1024
|
||||
r = 0
|
||||
|
||||
while r < i:
|
||||
g = self.binHexBin(g)
|
||||
t = 0
|
||||
while t < u:
|
||||
g[8 + t] = a[t]
|
||||
t = t + 1
|
||||
g = self.binHash(g, o)
|
||||
r += 1
|
||||
|
||||
return g
|
||||
|
||||
def encUTF8( self, n ):
|
||||
|
||||
# return string
|
||||
r_str = ''
|
||||
# character pos
|
||||
char_pos = 0
|
||||
# string length
|
||||
str_len = len(n) - 1
|
||||
|
||||
while char_pos <= str_len:
|
||||
|
||||
h = self.char_code_at(n, char_pos)
|
||||
char_pos += 1
|
||||
i = self.char_code_at(n, char_pos)
|
||||
|
||||
if char_pos < str_len and 55296 <= h and h <= 56319 and 56320 <= i and i <= 57343:
|
||||
h = 65536 + self.bit_shift((1023 & h), 10, 'l') + (1023 & i)
|
||||
char_pos +=1
|
||||
|
||||
if h <= 127:
|
||||
r_str += chr(h)
|
||||
else:
|
||||
if h <= 2047:
|
||||
r_str += chr(192 | self.bit_shift( h, 6, 'r', True ) & 31, 128 | 63 & h)
|
||||
else:
|
||||
if h <= 65535:
|
||||
r_str += chr(224 | self.bit_shift( h, 12, 'r', True ) & 15, 128 | self.bit_shift( h, 6, 'r', True ) & 63, 128 | 63 & h)
|
||||
else:
|
||||
if h <= 2097151:
|
||||
r_str += chr(240 | self.bit_shift( h, 18, 'r', True ) & 7, 128 | self.bit_shift( h, 12, 'r', True ) & 63, 128 | self.bit_shift( h, 6, 'r', True ) & 63, 128 | 63 & h)
|
||||
|
||||
return r_str
|
||||
|
||||
def strBin( self, n ):
|
||||
|
||||
""" String to Binary """
|
||||
|
||||
i = self.bit_shift( len(n), 3, 'l' )
|
||||
r = {}
|
||||
h = 0
|
||||
|
||||
while h < i:
|
||||
tmp = self.bit_shift( h, 5 )
|
||||
r[tmp] = r.get(tmp, 0) | self.bit_shift( (255 & self.char_code_at( n, self.bit_shift( h, 3 ))), (31 & h), 'l' )
|
||||
h += 8
|
||||
|
||||
return r
|
||||
|
||||
def binHex( self, n ):
|
||||
|
||||
""" Binary to Hex """
|
||||
|
||||
t = ''
|
||||
f = self.bit_shift( len(n), 5, 'l' )
|
||||
r = 0
|
||||
|
||||
while r < f:
|
||||
h = self.bit_shift( n.get( self.bit_shift( r, 5 ), 0 ), (31 & r), 'r', True ) & 255
|
||||
i = self.bit_shift( h, 4, 'r', True ) & 15
|
||||
h &= 15
|
||||
t += self.hex[i] + self.hex[h]
|
||||
r += 8
|
||||
|
||||
return t
|
||||
|
||||
def binStr( self, n ):
|
||||
|
||||
""" Binary to String """
|
||||
|
||||
r = ''
|
||||
t = self.bit_shift( len(n), 5, 'l' )
|
||||
i = 0
|
||||
|
||||
while i < t:
|
||||
h = self.bit_shift( n.get( self.bit_shift( i, 5 ), 0 ), (31 & i), 'r', True ) & 255
|
||||
r += chr(h)
|
||||
i += 8
|
||||
|
||||
return r
|
||||
|
||||
def binHexBin( self, n ):
|
||||
|
||||
t = self.bit_shift( len(n), 5, 'l' )
|
||||
f = {}
|
||||
r = 0
|
||||
|
||||
while r < t:
|
||||
|
||||
h = self.bit_shift( n.get( self.bit_shift( r, 5 ), 0 ), (31 & r), 'r', True ) & 255
|
||||
i = self.bit_shift( h, 4, 'r', True ) & 15
|
||||
h &= 15
|
||||
|
||||
tmp2 = 48
|
||||
if 9 < i:
|
||||
tmp2 = 87
|
||||
|
||||
tmp3 = 48
|
||||
if 9 < h:
|
||||
tmp3 = 87
|
||||
|
||||
tmp = self.bit_shift( r, 4 )
|
||||
f[tmp] = f.get(tmp, 0) | self.bit_shift( tmp2 + i + self.bit_shift( (tmp3 + h), 8, 'l'), self.bit_shift((15 & r), 1, 'l'), 'l' )
|
||||
r += 8
|
||||
|
||||
return f
|
||||
|
||||
def fghi( self, n, h, i, r, t, f, e, g ):
|
||||
|
||||
"""
|
||||
method that is used by ff,gg,hh,ii
|
||||
This was originally duplicated code in each method
|
||||
reduced code by creating a n ew method for it
|
||||
"""
|
||||
|
||||
o = (65535 & n) + (65535 & g) + (65535 & t) + (65535 & e)
|
||||
g = self.bit_shift( self.bit_shift( n, 16 ) + self.bit_shift( g, 16, 'r') + self.bit_shift( t, 16 ) + self.bit_shift( e, 16 ) + self.bit_shift( o, 16 ), 16, 'l' )
|
||||
g = g | 65535 & o
|
||||
g = self.bit_shift( g, f, 'l' ) | self.bit_shift( g, ( 32 - f ), 'r', True )
|
||||
o = (65535 & g) + (65535 & h)
|
||||
g = self.bit_shift( self.bit_shift( g, 16 ) + self.bit_shift( h, 16 ) + self.bit_shift( o, 16 ), 16, 'l' )
|
||||
|
||||
return g | 65535 & o
|
||||
|
||||
def ff( self, n, h, i, r, t, f, e ):
|
||||
|
||||
g = h & i | ~h & r
|
||||
return self.fghi(n, h, i, r, t, f, e, g)
|
||||
|
||||
def gg( self, n, h, i, r, t, f, e ):
|
||||
|
||||
g = h & r | i & ~r
|
||||
return self.fghi(n, h, i, r, t, f, e, g)
|
||||
|
||||
def hh( self, n, h, i, r, t, f, e ):
|
||||
|
||||
g = h ^ i ^ r
|
||||
return self.fghi(n, h, i, r, t, f, e, g)
|
||||
|
||||
def ii( self, n, h, i, r, t, f, e ):
|
||||
|
||||
g = i ^ (h | ~r)
|
||||
return self.fghi(n, h, i, r, t, f, e, g)
|
||||
|
||||
def binHash( self, n, h ):
|
||||
|
||||
""" Binary to Hash """
|
||||
|
||||
a = 1732584193
|
||||
u = -271733879
|
||||
s = -1732584194
|
||||
c = 271733878
|
||||
|
||||
tmp = self.bit_shift( h, 5 )
|
||||
n[ tmp ] = n.get( tmp, 0 ) | self.bit_shift( 128, (31 & h), 'l' )
|
||||
tmp = 14 + self.bit_shift( ( h + 64 ), self.bit_shift( 9, 4, 'l' ), 'r', True )
|
||||
n[ tmp ] = h
|
||||
i = len(n)
|
||||
r = 0
|
||||
|
||||
while r < i:
|
||||
|
||||
t = a
|
||||
f = u
|
||||
e = s
|
||||
g = c
|
||||
|
||||
a = self.ff(a, u, s, c, n.get((r + 0), 0), 7, -680876936)
|
||||
c = self.ff(c, a, u, s, n.get((r + 1), 0), 12, -389564586)
|
||||
s = self.ff(s, c, a, u, n.get((r + 2), 0), 17, 606105819)
|
||||
u = self.ff(u, s, c, a, n.get((r + 3), 0), 22, -1044525330)
|
||||
a = self.ff(a, u, s, c, n.get((r + 4), 0), 7, -176418897)
|
||||
c = self.ff(c, a, u, s, n.get((r + 5), 0), 12, 1200080426)
|
||||
s = self.ff(s, c, a, u, n.get((r + 6), 0), 17, -1473231341)
|
||||
u = self.ff(u, s, c, a, n.get((r + 7), 0), 22, -45705983)
|
||||
a = self.ff(a, u, s, c, n.get((r + 8), 0), 7, 1770035416)
|
||||
c = self.ff(c, a, u, s, n.get((r + 9), 0), 12, -1958414417)
|
||||
s = self.ff(s, c, a, u, n.get((r + 10), 0), 17, -42063)
|
||||
u = self.ff(u, s, c, a, n.get((r + 11), 0), 22, -1990404162)
|
||||
a = self.ff(a, u, s, c, n.get((r + 12), 0), 7, 1804603682)
|
||||
c = self.ff(c, a, u, s, n.get((r + 13), 0), 12, -40341101)
|
||||
s = self.ff(s, c, a, u, n.get((r + 14), 0), 17, -1502002290)
|
||||
u = self.ff(u, s, c, a, n.get((r + 15), 0), 22, 1236535329)
|
||||
a = self.gg(a, u, s, c, n.get((r + 1), 0), 5, -165796510)
|
||||
c = self.gg(c, a, u, s, n.get((r + 6), 0), 9, -1069501632)
|
||||
s = self.gg(s, c, a, u, n.get((r + 11), 0), 14, 643717713)
|
||||
u = self.gg(u, s, c, a, n.get((r + 0), 0), 20, -373897302)
|
||||
a = self.gg(a, u, s, c, n.get((r + 5), 0), 5, -701558691)
|
||||
c = self.gg(c, a, u, s, n.get((r + 10), 0), 9, 38016083)
|
||||
s = self.gg(s, c, a, u, n.get((r + 15), 0), 14, -660478335)
|
||||
u = self.gg(u, s, c, a, n.get((r + 4), 0), 20, -405537848)
|
||||
a = self.gg(a, u, s, c, n.get((r + 9), 0), 5, 568446438)
|
||||
c = self.gg(c, a, u, s, n.get((r + 14), 0), 9, -1019803690)
|
||||
s = self.gg(s, c, a, u, n.get((r + 3), 0), 14, -187363961)
|
||||
u = self.gg(u, s, c, a, n.get((r + 8), 0), 20, 1163531501)
|
||||
a = self.gg(a, u, s, c, n.get((r + 13), 0), 5, -1444681467)
|
||||
c = self.gg(c, a, u, s, n.get((r + 2), 0), 9, -51403784)
|
||||
s = self.gg(s, c, a, u, n.get((r + 7), 0), 14, 1735328473)
|
||||
u = self.gg(u, s, c, a, n.get((r + 12), 0), 20, -1926607734)
|
||||
a = self.hh(a, u, s, c, n.get((r + 5), 0), 4, -378558)
|
||||
c = self.hh(c, a, u, s, n.get((r + 8), 0), 11, -2022574463)
|
||||
s = self.hh(s, c, a, u, n.get((r + 11), 0), 16, 1839030562)
|
||||
u = self.hh(u, s, c, a, n.get((r + 14), 0), 23, -35309556)
|
||||
a = self.hh(a, u, s, c, n.get((r + 1), 0), 4, -1530992060)
|
||||
c = self.hh(c, a, u, s, n.get((r + 4), 0), 11, 1272893353)
|
||||
s = self.hh(s, c, a, u, n.get((r + 7), 0), 16, -155497632)
|
||||
u = self.hh(u, s, c, a, n.get((r + 10), 0), 23, -1094730640)
|
||||
a = self.hh(a, u, s, c, n.get((r + 13), 0), 4, 681279174)
|
||||
c = self.hh(c, a, u, s, n.get((r + 0), 0), 11, -358537222)
|
||||
s = self.hh(s, c, a, u, n.get((r + 3), 0), 16, -722521979)
|
||||
u = self.hh(u, s, c, a, n.get((r + 6), 0), 23, 76029189)
|
||||
a = self.hh(a, u, s, c, n.get((r + 9), 0), 4, -640364487)
|
||||
c = self.hh(c, a, u, s, n.get((r + 12), 0), 11, -421815835)
|
||||
s = self.hh(s, c, a, u, n.get((r + 15), 0), 16, 530742520)
|
||||
u = self.hh(u, s, c, a, n.get((r + 2), 0), 23, -995338651)
|
||||
a = self.ii(a, u, s, c, n.get((r + 0), 0), 6, -198630844)
|
||||
c = self.ii(c, a, u, s, n.get((r + 7), 0), 10, 1126891415)
|
||||
s = self.ii(s, c, a, u, n.get((r + 14), 0), 15, -1416354905)
|
||||
u = self.ii(u, s, c, a, n.get((r + 5), 0), 21, -57434055)
|
||||
a = self.ii(a, u, s, c, n.get((r + 12), 0), 6, 1700485571)
|
||||
c = self.ii(c, a, u, s, n.get((r + 3), 0), 10, -1894986606)
|
||||
s = self.ii(s, c, a, u, n.get((r + 10), 0), 15, -1051523)
|
||||
u = self.ii(u, s, c, a, n.get((r + 1), 0), 21, -2054922799)
|
||||
a = self.ii(a, u, s, c, n.get((r + 8), 0), 6, 1873313359)
|
||||
c = self.ii(c, a, u, s, n.get((r + 15), 0), 10, -30611744)
|
||||
s = self.ii(s, c, a, u, n.get((r + 6), 0), 15, -1560198380)
|
||||
u = self.ii(u, s, c, a, n.get((r + 13), 0), 21, 1309151649)
|
||||
a = self.ii(a, u, s, c, n.get((r + 4), 0), 6, -145523070)
|
||||
c = self.ii(c, a, u, s, n.get((r + 11), 0), 10, -1120210379)
|
||||
s = self.ii(s, c, a, u, n.get((r + 2), 0), 15, 718787259)
|
||||
u = self.ii(u, s, c, a, n.get((r + 9), 0), 21, -343485551)
|
||||
|
||||
o = (65535 & a) + (65535 & t)
|
||||
a = self.bit_shift( ( self.bit_shift( a, 16 ) + self.bit_shift( t, 16 ) + self.bit_shift( o, 16 ) ), 16, 'l' ) | 65535 & o
|
||||
o = (65535 & u) + (65535 & f)
|
||||
u = self.bit_shift( ( self.bit_shift( u, 16 ) + self.bit_shift( f, 16 ) + self.bit_shift( o, 16 ) ), 16, 'l' ) | 65535 & o
|
||||
o = (65535 & s) + (65535 & e)
|
||||
s = self.bit_shift( ( self.bit_shift( s, 16 ) + self.bit_shift( e, 16 ) + self.bit_shift( o, 16 ) ), 16, 'l' ) | 65535 & o
|
||||
o = (65535 & c) + (65535 & g)
|
||||
c = self.bit_shift( ( self.bit_shift( c, 16 ) + self.bit_shift( g, 16 ) + self.bit_shift( o, 16 ) ), 16, 'l' ) | 65535 & o
|
||||
|
||||
r += 16
|
||||
|
||||
return {0:a, 1:u, 2:s, 3:c}
|
@ -1,172 +1,172 @@
|
||||
"""
|
||||
Rumble User Class
|
||||
Created by Azzy9
|
||||
Class to handle all the rumble subscription methods
|
||||
"""
|
||||
|
||||
import math
|
||||
import time
|
||||
|
||||
import xbmcaddon
|
||||
|
||||
from resources.general import *
|
||||
from resources.md5ex import MD5Ex
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
ADDON = xbmcaddon.Addon()
|
||||
|
||||
class rumbleUser:
|
||||
|
||||
""" main rumble user class """
|
||||
|
||||
baseUrl = 'https://rumble.com'
|
||||
username = ''
|
||||
password = ''
|
||||
session = ''
|
||||
expiry = ''
|
||||
|
||||
def __init__( self ):
|
||||
|
||||
""" Construct to get the saved details """
|
||||
|
||||
self.getLoginDetails()
|
||||
|
||||
def getLoginDetails( self ):
|
||||
|
||||
""" get the saved login details """
|
||||
|
||||
self.username = ADDON.getSetting( 'username' )
|
||||
self.password = ADDON.getSetting( 'password' )
|
||||
self.session = ADDON.getSetting( 'session' )
|
||||
self.expiry = ADDON.getSetting( 'expiry' )
|
||||
|
||||
if self.expiry:
|
||||
self.expiry = float( self.expiry )
|
||||
|
||||
def hasLoginDetails( self ):
|
||||
|
||||
""" if there is login details """
|
||||
|
||||
return ( self.username and self.password )
|
||||
|
||||
def setSessionDetails( self ):
|
||||
|
||||
"""
|
||||
sets the session details
|
||||
Used for login in & when token is expired
|
||||
"""
|
||||
|
||||
ADDON.setSetting( 'session', self.session )
|
||||
ADDON.setSetting( 'expiry', str( self.expiry ) )
|
||||
self.setSessionCookie()
|
||||
|
||||
def resetSessionDetails( self ):
|
||||
|
||||
""" resets the session details to force a login """
|
||||
|
||||
self.session = ''
|
||||
self.expiry = ''
|
||||
self.setSessionDetails()
|
||||
|
||||
def hasSession( self, login=True ):
|
||||
|
||||
""" resets the session details to force a login """
|
||||
|
||||
has_session = self.session and self.expiry and self.expiry > time.time()
|
||||
if not has_session and login and self.hasLoginDetails():
|
||||
self.login()
|
||||
return self.hasSession(False)
|
||||
return has_session
|
||||
|
||||
def getSalts( self ):
|
||||
|
||||
"""
|
||||
method to get the salts from rumble
|
||||
these are used to generate the login hashes
|
||||
"""
|
||||
|
||||
if self.hasLoginDetails():
|
||||
# gets salts
|
||||
data = request_get(
|
||||
self.baseUrl + '/service.php?name=user.get_salts',
|
||||
{'username': self.username},
|
||||
[ ( 'Referer', self.baseUrl ), ( 'Content-type', 'application/x-www-form-urlencoded' ) ]
|
||||
)
|
||||
if data:
|
||||
salts = json.loads(data)['data']['salts']
|
||||
if salts:
|
||||
return salts
|
||||
return False
|
||||
|
||||
def login( self ):
|
||||
|
||||
""" method to generate the hashes and login """
|
||||
|
||||
salts = self.getSalts()
|
||||
if salts:
|
||||
login_hash = MD5Ex()
|
||||
hashes = login_hash.hash( login_hash.hashStretch( self.password, salts[0], 128) + salts[1] ) + ',' + login_hash.hashStretch( self.password, salts[2], 128 ) + ',' + salts[1]
|
||||
|
||||
# login
|
||||
data = request_get(
|
||||
self.baseUrl + '/service.php?name=user.login',
|
||||
{'username': self.username, 'password_hashes': hashes},
|
||||
[ ( 'Referer', self.baseUrl ), ( 'Content-type', 'application/x-www-form-urlencoded' ) ]
|
||||
)
|
||||
|
||||
if data:
|
||||
session = json.loads(data)['data']['session']
|
||||
if session:
|
||||
self.session = session
|
||||
# Expiry is 30 Days
|
||||
self.expiry = math.floor( time.time() ) + 2592000
|
||||
self.setSessionDetails()
|
||||
return session
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def setSessionCookie( self ):
|
||||
|
||||
if self.session:
|
||||
# get stored cookie string
|
||||
cookies = ADDON.getSetting('cookies')
|
||||
|
||||
# split cookies into dictionary
|
||||
if cookies:
|
||||
cookieDict = json.loads( cookies )
|
||||
else:
|
||||
cookieDict = {}
|
||||
|
||||
cookieDict[ 'u_s' ] = self.session
|
||||
|
||||
# store cookies
|
||||
ADDON.setSetting('cookies', json.dumps(cookieDict))
|
||||
else:
|
||||
ADDON.setSetting('cookies', '')
|
||||
|
||||
def subscribe( self, action, action_type, name ):
|
||||
|
||||
""" method to subscribe and unsubscribe to a channel or user """
|
||||
|
||||
if self.hasSession():
|
||||
|
||||
post_content = {
|
||||
'slug': name,
|
||||
'type': action_type,
|
||||
'action': action,
|
||||
}
|
||||
|
||||
headers = {
|
||||
'Referer': self.baseUrl + name,
|
||||
'Content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
|
||||
data = request_get( self.baseUrl + '/service.php?api=2&name=user.subscribe', post_content, headers )
|
||||
return data
|
||||
|
||||
return False
|
||||
"""
|
||||
Rumble User Class
|
||||
Created by Azzy9
|
||||
Class to handle all the rumble subscription methods
|
||||
"""
|
||||
|
||||
import math
|
||||
import time
|
||||
|
||||
import xbmcaddon
|
||||
|
||||
from lib.general import *
|
||||
from lib.md5ex import MD5Ex
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
ADDON = xbmcaddon.Addon()
|
||||
|
||||
class rumbleUser:
|
||||
|
||||
""" main rumble user class """
|
||||
|
||||
baseUrl = 'https://rumble.com'
|
||||
username = ''
|
||||
password = ''
|
||||
session = ''
|
||||
expiry = ''
|
||||
|
||||
def __init__( self ):
|
||||
|
||||
""" Construct to get the saved details """
|
||||
|
||||
self.getLoginDetails()
|
||||
|
||||
def getLoginDetails( self ):
|
||||
|
||||
""" get the saved login details """
|
||||
|
||||
self.username = ADDON.getSetting( 'username' )
|
||||
self.password = ADDON.getSetting( 'password' )
|
||||
self.session = ADDON.getSetting( 'session' )
|
||||
self.expiry = ADDON.getSetting( 'expiry' )
|
||||
|
||||
if self.expiry:
|
||||
self.expiry = float( self.expiry )
|
||||
|
||||
def hasLoginDetails( self ):
|
||||
|
||||
""" if there is login details """
|
||||
|
||||
return ( self.username and self.password )
|
||||
|
||||
def setSessionDetails( self ):
|
||||
|
||||
"""
|
||||
sets the session details
|
||||
Used for login in & when token is expired
|
||||
"""
|
||||
|
||||
ADDON.setSetting( 'session', self.session )
|
||||
ADDON.setSetting( 'expiry', str( self.expiry ) )
|
||||
self.setSessionCookie()
|
||||
|
||||
def resetSessionDetails( self ):
|
||||
|
||||
""" resets the session details to force a login """
|
||||
|
||||
self.session = ''
|
||||
self.expiry = ''
|
||||
self.setSessionDetails()
|
||||
|
||||
def hasSession( self, login=True ):
|
||||
|
||||
""" resets the session details to force a login """
|
||||
|
||||
has_session = self.session and self.expiry and self.expiry > time.time()
|
||||
if not has_session and login and self.hasLoginDetails():
|
||||
self.login()
|
||||
return self.hasSession(False)
|
||||
return has_session
|
||||
|
||||
def getSalts( self ):
|
||||
|
||||
"""
|
||||
method to get the salts from rumble
|
||||
these are used to generate the login hashes
|
||||
"""
|
||||
|
||||
if self.hasLoginDetails():
|
||||
# gets salts
|
||||
data = request_get(
|
||||
self.baseUrl + '/service.php?name=user.get_salts',
|
||||
{'username': self.username},
|
||||
[ ( 'Referer', self.baseUrl ), ( 'Content-type', 'application/x-www-form-urlencoded' ) ]
|
||||
)
|
||||
if data:
|
||||
salts = json.loads(data)['data']['salts']
|
||||
if salts:
|
||||
return salts
|
||||
return False
|
||||
|
||||
def login( self ):
|
||||
|
||||
""" method to generate the hashes and login """
|
||||
|
||||
salts = self.getSalts()
|
||||
if salts:
|
||||
login_hash = MD5Ex()
|
||||
hashes = login_hash.hash( login_hash.hashStretch( self.password, salts[0], 128) + salts[1] ) + ',' + login_hash.hashStretch( self.password, salts[2], 128 ) + ',' + salts[1]
|
||||
|
||||
# login
|
||||
data = request_get(
|
||||
self.baseUrl + '/service.php?name=user.login',
|
||||
{'username': self.username, 'password_hashes': hashes},
|
||||
[ ( 'Referer', self.baseUrl ), ( 'Content-type', 'application/x-www-form-urlencoded' ) ]
|
||||
)
|
||||
|
||||
if data:
|
||||
session = json.loads(data)['data']['session']
|
||||
if session:
|
||||
self.session = session
|
||||
# Expiry is 30 Days
|
||||
self.expiry = math.floor( time.time() ) + 2592000
|
||||
self.setSessionDetails()
|
||||
return session
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def setSessionCookie( self ):
|
||||
|
||||
if self.session:
|
||||
# get stored cookie string
|
||||
cookies = ADDON.getSetting('cookies')
|
||||
|
||||
# split cookies into dictionary
|
||||
if cookies:
|
||||
cookieDict = json.loads( cookies )
|
||||
else:
|
||||
cookieDict = {}
|
||||
|
||||
cookieDict[ 'u_s' ] = self.session
|
||||
|
||||
# store cookies
|
||||
ADDON.setSetting('cookies', json.dumps(cookieDict))
|
||||
else:
|
||||
ADDON.setSetting('cookies', '')
|
||||
|
||||
def subscribe( self, action, action_type, name ):
|
||||
|
||||
""" method to subscribe and unsubscribe to a channel or user """
|
||||
|
||||
if self.hasSession():
|
||||
|
||||
post_content = {
|
||||
'slug': name,
|
||||
'type': action_type,
|
||||
'action': action,
|
||||
}
|
||||
|
||||
headers = {
|
||||
'Referer': self.baseUrl + name,
|
||||
'Content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
|
||||
data = request_get( self.baseUrl + '/service.php?api=2&name=user.subscribe', post_content, headers )
|
||||
return data
|
||||
|
||||
return False
|
Loading…
Reference in New Issue