diff --git a/addon.xml b/addon.xml index 5fce132..a8d8f49 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -39,6 +39,9 @@ - auswahl zwishen DASH und SmoothStreaming. SmoothStreaming hat zwar die bessere Qualität, funktioniert momentan aber nicht. 1.3.3: - Start/Verfügbarkeitsdatum repariert, wenn es mehrere Ausstrahlungen gab +1.3.4: +- Einstellung hinzugefügt, um immer den Puls4 Key bei abfragen aus der Mediathek zu verwenden. Zum zeitpunkt des releases dieser Version bekommt man somit Videos mit höherer Auflösung +- Einstellung hinzugefügt, um Videos wie der Webplayer auf der prosiebenmaxx Webseite abzurufen. Dies ist langsamer, resultiert aber manchmal mit höher Aufgelösten Videos resources/icon.png diff --git a/changelog.txt b/changelog.txt index c1a5455..9f3f2a1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -57,4 +57,8 @@ v1.3.2: - try to fix Playready support - choose between DASH and SmoothStreaming. SmoothStreaming should give better quality, but doesn't work currently. v1.3.3: -- fix start/availability dates if there were multiple air dates \ No newline at end of file +- fix start/availability dates if there were multiple air dates +v1.3.4: +- add option to always use the puls4 request key on vod content. as of release of this version this results in higher resolution videos +- add option to request videos like the player on the prosiebenmaxx website, this is slower, but sometimes gives higher resolution videos + diff --git a/resources/language/resource.language.de_de/strings.po b/resources/language/resource.language.de_de/strings.po index cb2eadf..7cfb5c8 100644 --- a/resources/language/resource.language.de_de/strings.po +++ b/resources/language/resource.language.de_de/strings.po @@ -242,3 +242,11 @@ msgstr "behalte Staffel und Episoden Nummer im Videotitel" msgctxt "#32116" msgid "PLAYREADY with SmoothStreaming (Android only)" msgstr "PLAYREADY mit SmoothStreaming (nur Android)" + +msgctxt "#32117" +msgid "request video like the website instead of the app(slower)" +msgstr "Frage videos wie die Webseite ab, anstatt wie die App(langsamer)" + +msgctxt "#32118" +msgid "always use the puls4 key for VOD(sometimes better quality)" +msgstr "Verwende immer den Puls4 Key für die Mediathek[CR](manchmal bessere Qualität)" \ No newline at end of file diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index 930931b..5fc2b48 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -241,4 +241,12 @@ msgstr "" msgctxt "#32116" msgid "PLAYREADY with SmoothStreaming (Android only)" -msgstr "" \ No newline at end of file +msgstr "" + +msgctxt "#32117" +msgid "request video like the website instead of the app(slower)" +msgstr "" + +msgctxt "#32118" +msgid "always use the puls4 key for VOD(sometimes better quality)" +msgstr "" diff --git a/resources/lib/plugin.py b/resources/lib/plugin.py index e9cf672..98e2ad6 100644 --- a/resources/lib/plugin.py +++ b/resources/lib/plugin.py @@ -766,29 +766,118 @@ def play_video(video_id, channel='', disable_old_format=False): if '_' in video_id: video_id = video_id.split('_')[1] config_url = '' + racoon = False if channel == 'All Channels Feed' or channel == '': # no channel info guess by id - if not video_id.isdigit(): + if not video_id.isdigit() or kodiutils.get_setting_as_bool('always_puls4'): #probalby a video from puls4 or atv config_url = ids.get_livestream_config_url('puls4_and_atv_at') else: - config_url = ids.get_livestream_config_url('austrian_tv') + if kodiutils.get_setting_as_bool('use_racoon'): + config_url = ids.get_livestream_config_url('prosieben_maxx_at') + racoon = True + else: + config_url = ids.get_livestream_config_url('austrian_tv') else: - if channel == 'PULS 4' or channel == 'ATV': + if channel == 'PULS 4' or channel == 'ATV' or kodiutils.get_setting_as_bool('always_puls4'): config_url = ids.get_livestream_config_url('puls4_and_atv_at') else: config_url = ids.get_livestream_config_url('austrian_tv') - config = json.loads(get_url(config_url, cache=True, critical=True)) + config = {} + + data = None + + if not racoon: + config = json.loads(get_url(config_url, cache=True, critical=True)) + data = get_source(config, video_id, disable_old_format) + if data =='disable_old_format': + play_video(video_id, channel=channel, disable_old_format=True) + return + else: + config_data = get_url(config_url, cache=True, critical=False) + if config_data: + config = json.loads(config_data) + data = get_source_racoon(config, video_id) + + playitem = ListItem('none') + + if data == None: + setResolvedUrl(plugin.handle, False, playitem) + return + + log('selected non drm format: ' + kodiutils.get_setting('non_drm_format')) + log('media url: ' + data['video_url']) + if not data['protected'] and (kodiutils.get_setting_as_int('non_drm_format') == 2 or kodiutils.get_setting_as_int('non_drm_format') == 3): + playitem = ListItem(label=xbmc.getInfoLabel('Container.ShowTitle'), path=data['video_url']+'|User-Agent=' + ids.user_agent_video) + setResolvedUrl(plugin.handle, True, playitem) + else: + is_helper = None + try: + is_helper = inputstreamhelper.Helper(data['protocol'], drm=data['drm']) + except Exception as e: + if str(e) == 'UnsupportedDRMScheme' and data['drm'] == 'com.microsoft.playready': + is_helper = inputstreamhelper.Helper(data['protocol'], drm=None) + pass + else: + kodiutils.notification('ERROR', kodiutils.get_string(32018).format(data['drm'])) + #check for inputstream_addon + inputstream_installed = False + if is_helper: + inputstream_installed = is_helper._has_inputstream() + + if is_helper and not inputstream_installed: + # ask to install inputstream + xbmc.executebuiltin('InstallAddon({})'.format(is_helper.inputstream_addon), True) + inputstream_installed = is_helper._has_inputstream() + + if is_helper and inputstream_installed and is_helper.check_inputstream(): + version = xbmcaddon.Addon('inputstream.adaptive').getAddonInfo('version') + if not data['protected'] and kodiutils.get_setting_as_int('non_drm_format') == 0 and LooseVersion(version) < LooseVersion('2.2.2'): + # inputstream to old cannot play mpd + # switch to hls + kodiutils.set_setting('non_drm_format', 1) + play_video(video_id, channel) + elif data['protected'] and LooseVersion(version) < LooseVersion('2.2.2'): + # inputstream to old cannot play mpd + xbmcgui.Dialog().ok(heading=kodiutils.get_string(32023), line1=kodiutils.get_string(32024)) + setResolvedUrl(plugin.handle, False, ListItem(label='none')) + else: + playitem = ListItem(label=xbmc.getInfoLabel('Container.ShowTitle'), path=data['video_url']+'|User-Agent=' + ids.user_agent_video) + playitem.setProperty('inputstreamaddon', is_helper.inputstream_addon) + playitem.setProperty('inputstream.adaptive.manifest_type', data['protocol']) + if data['protected']: + log('license url: {0}?token={1}'.format(data['license_url'], data['license_token'])) + playitem.setProperty('inputstream.adaptive.license_type', data['drm']) + if (data['drm'] == 'com.microsoft.playready'): + playitem.setProperty('inputstream.adaptive.license_key', data['license_url'] + '?token=' + data['license_token'] +'|User-Agent=' + ids.user_agent_video + '&Content-Type=text/xml' +'|R{SSM}|') + else: + playitem.setProperty('inputstream.adaptive.license_key', data['license_url'] + '?token=' + data['license_token'] +'|User-Agent=' + ids.user_agent_video +'|R{SSM}|') + setResolvedUrl(plugin.handle, True, playitem) + else: + if data['drm']: + kodiutils.notification('ERROR', kodiutils.get_string(32019).format(data['drm'])) + setResolvedUrl(plugin.handle, False, playitem) + else: + if xbmcgui.Dialog().yesno(heading=kodiutils.get_string(32020), line1=kodiutils.get_string(32021), line2=kodiutils.get_string(32022).format(kodiutils.get_string(32110))): + if LooseVersion('18.0') > LooseVersion(xbmc.getInfoLabel('System.BuildVersion')): + kodiutils.set_setting('non_drm_format', 3) + else: + kodiutils.set_setting('non_drm_format', 2) + play_video(video_id, channel) + else: + setResolvedUrl(plugin.handle, False, playitem) + +def get_source(config, video_id, disable_old_format): + data = {'video_url':'', 'protocol': '', 'protected':False, 'drm': '', 'license_url': '', 'license_token': ''} mdsV2 = config['mdsclient']['mdsV2'] sources_request_url = mdsV2['baseUrl']+'vas/live/v2/videos?access_token=%s&client_location=null&client_name=%s&ids=%s' % (mdsV2['accessToken'], mdsV2['clientName'], video_id) sources_request = json.loads(get_url(sources_request_url, critical=True)) log('sources_request: ' + str(sources_request)) - protected = sources_request[0]['is_protected'] + data['protected'] = sources_request[0]['is_protected'] mpd_id = [] m3u8_id = [] ism_id = [] mp4_id = [] - protocol = '' for source in sources_request[0]['sources']: if source['mimetype'] == 'text/xml': ism_id.append(source['id']) @@ -799,38 +888,38 @@ def play_video(video_id, channel='', disable_old_format=False): if source['mimetype'] == 'video/mp4': mp4_id.append(source['id']) drm = None - if not protected: + if not data['protected']: if kodiutils.get_setting_as_int('non_drm_format') == 0: source_id = mpd_id - protocol = 'mpd' + data['protocol'] = 'mpd' elif kodiutils.get_setting_as_int('non_drm_format') == 3: source_id = mp4_id - protocol = 'mp4' + data['protocol'] = 'mp4' else: source_id = m3u8_id - protocol = 'hls' + data['protocol'] = 'hls' else: if kodiutils.get_setting('drm') == '0': source_id = mpd_id - protocol = 'mpd' + data['protocol'] = 'mpd' drm_name = 'widevine' - drm = 'com.widevine.alpha' + data['drm'] = 'com.widevine.alpha' elif kodiutils.get_setting('drm') == '1': source_id = mpd_id - protocol = 'mpd' + data['protocol'] = 'mpd' drm_name = 'playready' - drm = 'com.microsoft.playready' + data['drm'] = 'com.microsoft.playready' else: source_id = ism_id - protocol = 'ism' + data['protocol'] = 'ism' drm_name = 'playready' - drm = 'com.microsoft.playready' + data['drm'] = 'com.microsoft.playready' - if protected and LooseVersion('18.0') > LooseVersion(xbmc.getInfoLabel('System.BuildVersion')): + if data['protected'] and LooseVersion('18.0') > LooseVersion(xbmc.getInfoLabel('System.BuildVersion')): log('version is: ' + xbmc.getInfoLabel('System.BuildVersion')) kodiutils.notification('ERROR', kodiutils.get_string(32025)) setResolvedUrl(plugin.handle, False, ListItem('none')) - return + return None server_request_token = get_video_server_request_token(access_token=mdsV2['accessToken'], client_location='null', client_name=mdsV2['clientName'], video_id=video_id, salt=mdsV2['salt']) server_request_url = mdsV2['baseUrl']+'vas/live/v2/videos/%s/sources?access_token=%s&client_id=%s&client_location=null&client_name=%s' % (video_id, mdsV2['accessToken'], server_request_token, mdsV2['clientName']) @@ -839,7 +928,7 @@ def play_video(video_id, channel='', disable_old_format=False): start = '' end = '' - if protected and kodiutils.get_setting('drm') == '0' and kodiutils.get_setting_as_bool('oldformat') and not disable_old_format: + if data['protected'] and kodiutils.get_setting('drm') == '0' and kodiutils.get_setting_as_bool('oldformat') and not disable_old_format: start = '0' end = '999999999' source_url_request = {} @@ -847,85 +936,109 @@ def play_video(video_id, channel='', disable_old_format=False): source_url_request_token = get_video_source_request_token(access_token=mdsV2['accessToken'], client_location='null', client_name=mdsV2['clientName'], server_id= server_id, source_id=s_id, video_id=video_id, salt=mdsV2['salt'], start=start, end=end) source_url_request_url = mdsV2['baseUrl']+'vas/live/v2/videos/%s/sources/url?access_token=%s&client_id=%s&client_location=null&client_name=%s&secure_delivery=true&server_id=%s&source_ids=%s' % (video_id, mdsV2['accessToken'], source_url_request_token, mdsV2['clientName'], server_id, s_id) - if protected and kodiutils.get_setting('drm') == '0'and kodiutils.get_setting_as_bool('oldformat') and not disable_old_format: + if data['protected'] and kodiutils.get_setting('drm') == '0'and kodiutils.get_setting_as_bool('oldformat') and not disable_old_format: source_url_request_url += '&subclip_start=0&subclip_end=999999999' source_url_request = json.loads(get_url(source_url_request_url, critical=True)) if not 'status_code' in source_url_request or source_url_request['status_code'] != 0: log('error on video request: ' + str(source_url_request)) - if protected and kodiutils.get_setting('drm') == '0' and kodiutils.get_setting_as_bool('oldformat') and not disable_old_format: - play_video(video_id, channel=channel, disable_old_format=True) - return + if data['protected'] and kodiutils.get_setting('drm') == '0' and kodiutils.get_setting_as_bool('oldformat') and not disable_old_format: + return 'disable_old_format' kodiutils.notification('ERROR', 'code: {0}'.format(source_url_request['status_code'])) return sys.exit(0) - if protected: + data['video_url'] = source_url_request['sources'][0]['url'] + if data['protected']: + data['license_url'] = source_url_request['drm']['licenseAcquisitionUrl'] + data['license_token'] = source_url_request['drm']['token'] if drm_name == source_url_request['drm']['type']: break else: break + log('{0}'.format(data)) + return data - playitem = ListItem('none') - log('selected non drm format: ' + kodiutils.get_setting('non_drm_format')) - log('media url: ' + source_url_request['sources'][0]['url']) - if not protected and (kodiutils.get_setting_as_int('non_drm_format') == 2 or kodiutils.get_setting_as_int('non_drm_format') == 3): - playitem = ListItem(label=xbmc.getInfoLabel('Container.ShowTitle'), path=source_url_request['sources'][0]['url']+'|User-Agent=' + ids.user_agent_video) - setResolvedUrl(plugin.handle, True, playitem) - else: - is_helper = None - try: - is_helper = inputstreamhelper.Helper(protocol, drm=drm) - except Exception as e: - if str(e) == 'UnsupportedDRMScheme' and drm == 'com.microsoft.playready': - is_helper = inputstreamhelper.Helper(protocol, drm=None) - pass - else: - kodiutils.notification('ERROR', kodiutils.get_string(32018).format(drm)) - #check for inputstream_addon - inputstream_installed = False - if is_helper: - inputstream_installed = is_helper._has_inputstream() - - if is_helper and not inputstream_installed: - # ask to install inputstream - xbmc.executebuiltin('InstallAddon({})'.format(is_helper.inputstream_addon), True) - inputstream_installed = is_helper._has_inputstream() - - if is_helper and inputstream_installed and is_helper.check_inputstream(): - version = xbmcaddon.Addon('inputstream.adaptive').getAddonInfo('version') - if not protected and kodiutils.get_setting_as_int('non_drm_format') == 0 and LooseVersion(version) < LooseVersion('2.2.2'): - # inputstream to old cannot play mpd - # switch to hls - kodiutils.set_setting('non_drm_format', 1) - play_video(video_id, channel) - elif protected and LooseVersion(version) < LooseVersion('2.2.2'): - # inputstream to old cannot play mpd - xbmcgui.Dialog().ok(heading=kodiutils.get_string(32023), line1=kodiutils.get_string(32024)) - setResolvedUrl(plugin.handle, False, ListItem(label='none')) +def get_source_racoon(config, video_id): + from racoonhash import RacoonHash + data = {'video_url':'', 'protocol': '', 'protected':False, 'drm': '', 'license_url': '', 'license_token': ''} + if not config: + config = {'racoon': { 'liveBaseUrl' : '//vas.live.p7s1video.net/2.0', 'vodBaseUrl': '//vas-v4.p7s1video.net/4.0'}} + config['racoon']['access_id'] = 'x_prosiebenmaxx-at' + config['racoon']['encryption_key'] = 'diQua9poopaetheephoogheehoocaevo' + config['racoon']['initializing_vector'] = 'Ahvah3pahgoophahniengeyeecaibahd' + + racoon = RacoonHash() + racoon.update(config['racoon']['encryption_key'] + video_id + config['racoon']['initializing_vector'] + config['racoon']['access_id']); + client_token = racoon.hex(); + + protocol_request = json.loads(get_url('https:'+config['racoon']['vodBaseUrl']+'/getprotocols?access_id={0}&video_id={1}&client_token={2}'.format(config['racoon']['access_id'], video_id, client_token), critical=True)) + + data['protected'] = protocol_request['is_protected'] + formatsDRM = '' + for key, protocol in protocol_request['protocols'].items(): + for drm in protocol['drm']: + if formatsDRM == '': + formatsDRM += key + ':' + drm; else: - playitem = ListItem(label=xbmc.getInfoLabel('Container.ShowTitle'), path=source_url_request['sources'][0]['url']+'|User-Agent=' + ids.user_agent_video) - playitem.setProperty('inputstreamaddon', is_helper.inputstream_addon) - playitem.setProperty('inputstream.adaptive.manifest_type', protocol) - if protected: - log('license url: {0}?token={1}'.format(source_url_request['drm']['licenseAcquisitionUrl'], source_url_request['drm']['token'])) - playitem.setProperty('inputstream.adaptive.license_type', drm) - if (drm == 'com.microsoft.playready'): - playitem.setProperty('inputstream.adaptive.license_key', source_url_request['drm']['licenseAcquisitionUrl'] + '?token=' + source_url_request['drm']['token'] +'|User-Agent=' + ids.user_agent_video + '&Content-Type=text/xml' +'|R{SSM}|') - else: - playitem.setProperty('inputstream.adaptive.license_key', source_url_request['drm']['licenseAcquisitionUrl'] + '?token=' + source_url_request['drm']['token'] +'|User-Agent=' + ids.user_agent_video +'|R{SSM}|') - setResolvedUrl(plugin.handle, True, playitem) + formatsDRM += ',' + key + ':' + drm; + + server_token = protocol_request['server_token'] + racoon.reset(); + racoon.update(config['racoon']['encryption_key'] + video_id + config['racoon']['initializing_vector'] + config['racoon']['access_id'] + server_token + formatsDRM); + client_token = racoon.hex(); + + urls_request = json.loads(get_url('https:'+config['racoon']['vodBaseUrl']+'/geturls?server_token={0}&access_id={1}&video_id={2}&protocols={3}&client_token={4}'.format(server_token, config['racoon']['access_id'], video_id, formatsDRM, client_token), critical=True)) + + if not data['protected']: + if kodiutils.get_setting_as_int('non_drm_format') == 0: + data['protocol'] = 'mpd' + try: + data['video_url'] = urls_request['urls']['dash']['clear']['url'] + except: + return None + elif kodiutils.get_setting_as_int('non_drm_format') == 3: + data['protocol'] = 'mp4' + try: + data['video_url'] = urls_request['urls']['progressive']['clear']['url'] + except: + return None else: - if drm: - kodiutils.notification('ERROR', kodiutils.get_string(32019).format(drm)) - setResolvedUrl(plugin.handle, False, playitem) - else: - if xbmcgui.Dialog().yesno(heading=kodiutils.get_string(32020), line1=kodiutils.get_string(32021), line2=kodiutils.get_string(32022).format(kodiutils.get_string(32110))): - if LooseVersion('18.0') > LooseVersion(xbmc.getInfoLabel('System.BuildVersion')): - kodiutils.set_setting('non_drm_format', 3) - else: - kodiutils.set_setting('non_drm_format', 2) - play_video(video_id, channel) - else: - setResolvedUrl(plugin.handle, False, playitem) + data['protocol'] = 'hls' + try: + data['video_url'] = urls_request['urls']['hls']['clear']['url'] + except: + return None + else: + if kodiutils.get_setting('drm') == '0': + data['protocol'] = 'mpd' + drm_name = 'widevine' + try: + data['video_url'] = urls_request['urls']['dash']['widevine']['url'] + data['license_url'] = urls_request['urls']['dash']['widevine']['drm']['licenseAcquisitionUrl'] + data['license_token'] = urls_request['urls']['dash']['widevine']['drm']['token'] + except: + return None + data['drm'] = 'com.widevine.alpha' + elif kodiutils.get_setting('drm') == '1': + data['protocol'] = 'mpd' + drm_name = 'playready' + try: + data['video_url'] = urls_request['urls']['dash']['playready']['url'] + data['license_url'] = urls_request['urls']['dash']['playready']['drm']['licenseAcquisitionUrl'] + data['license_token'] = urls_request['urls']['dash']['playready']['drm']['token'] + except: + return None + data['drm'] = 'com.microsoft.playready' + else: + data['protocol'] = 'ism' + drm_name = 'playready' + try: + data['video_url'] = urls_request['urls']['hss']['playready']['url'] + data['license_url'] = urls_request['urls']['hss']['playready']['drm']['licenseAcquisitionUrl'] + data['license_token'] = urls_request['urls']['hss']['playready']['drm']['token'] + except: + return None + data['drm'] = 'com.microsoft.playready' + return data def utc_to_local(dt): if time.localtime().tm_isdst: return dt - timedelta(seconds=time.altzone) diff --git a/resources/lib/racoonhash.py b/resources/lib/racoonhash.py new file mode 100644 index 0000000..db3c73b --- /dev/null +++ b/resources/lib/racoonhash.py @@ -0,0 +1,463 @@ +# usage create -> update() -> hex() +try: + class Long64(long): + def __init__(self, num=long(0)): # initialising + self.num = self.cap(num) + def __str__(self): + return str(self.num) + def __repr__(self): + return "Long6464(" + self.__str__() + ")" + + def __lt__(self, other): + return self.num < self.val(other) + def __le__(self, other): + return self.num <= self.val(other) + def __eq__(self, other): + return self.num == self.val(other) + def __ne__(self, other): + return self.num != self.val(other) + def __gt__(self, other): + return self.num > self.val(other) + def __ge__(self, other): + return self.num >= self.val(other) + + def __add__(self, other): + return Long64(self.cap(self.num + self.val(other))) + def __sub__(self, other): + return Long64(self.cap(self.num - self.val(other))) + def __mul__(self, other): + return Long64(self.cap(self.num * self.val(other))) + def __floordiv__(self, other): + return Long64(self.cap(self.num // self.val(other))) + def __mod__(self, other): + return Long64(self.cap(self.num % self.val(other))) + def __divmod__(self, other): + return NotImplemented + def __pow__(self, other): + return Long64(self.cap(self.num ** self.val(other))) + def __lshift__(self, other): + return Long64(self.cap(self.num << self.val(other))) + def __rshift__(self, other): + if self.num < 0: + return Long64(self.cap(((self.num & 9223372036854775807)+9223372036854775808) >> self.val(other))) + else: + return Long64(self.cap(self.num >> self.val(other))) + def __and__(self, other): + return Long64(self.cap(self.num & self.val(other))) + def __xor__(self, other): + return Long64(self.cap(self.num ^ self.val(other))) + def __or__(self, other): + return Long64(self.cap(self.num | self.val(other))) + @staticmethod + def cap(num): # a method that handles an overflow/underflow + if num > 9223372036854775807 or num < -9223372036854775808: + if (num & 9223372036854775808) == 9223372036854775808: + #negative + leftover = num & 9223372036854775807 + return -9223372036854775808 + leftover#~(9223372036854775808) + else: + #positv + return num & 9223372036854775807 + return num + @staticmethod + def val(other): + if isinstance(other, Long64) or isinstance(other, Int32): + return other.num + return other + + class Int32(long): + def __init__(self, num=long(0)): # initialising + self.num = self.cap(num) + def __str__(self): + return str(self.num) + def __repr__(self): + return "Int32(" + self.__str__() + ")" + + def __lt__(self, other): + return self.num < self.val(other) + def __le__(self, other): + return self.num <= self.val(other) + def __eq__(self, other): + return self.num == self.val(other) + def __ne__(self, other): + return self.num != self.val(other) + def __gt__(self, other): + return self.num > self.val(other) + def __ge__(self, other): + return self.num >= self.val(other) + + def __add__(self, other): + return Int32(self.cap(self.num + self.val(other))) + def __sub__(self, other): + return Int32(self.cap(self.num - self.val(other))) + def __mul__(self, other): + return Int32(self.cap(self.num * self.val(other))) + def __floordiv__(self, other): + return Int32(self.cap(self.num // self.val(other))) + def __mod__(self, other): + return Int32(self.cap(self.num % self.val(other))) + def __divmod__(self, other): + return NotImplemented + def __pow__(self, other): + return Int32(self.cap(self.num ** self.val(other))) + def __lshift__(self, other): + return Int32(self.cap(self.num << self.val(other))) + def __rshift__(self, other): + if self.num < 0: + return Int32(self.cap(((self.num & 2147483647)+2147483648) >> self.val(other))) + else: + return Int32(self.cap(self.num >> self.val(other))) + def __and__(self, other): + return Int32(self.cap(self.num & self.val(other))) + def __xor__(self, other): + return Int32(self.cap(self.num ^ self.val(other))) + def __or__(self, other): + return Int32(self.cap(self.num | self.val(other))) + @staticmethod + def cap(num): # a method that handles an overflow/underflow + if num > 2147483647 or num < -2147483648: + if (num & 2147483648) == 2147483648: + #negative + leftover = num & 2147483647 + return -2147483648 + leftover#~(2147483648) + else: + #positv + return num & 2147483647 + return num + @staticmethod + def val(other): + if isinstance(other, Long64) or isinstance(other, Int32): + return other.num + return other +except NameError: + class Long64(int): + def __init__(self, num=int(0)): # initialising + self.num = self.cap(num) + def __str__(self): + return str(self.num) + def __repr__(self): + return "Long64(" + self.__str__() + ")" + + def __lt__(self, other): + return self.num < self.val(other) + def __le__(self, other): + return self.num <= self.val(other) + def __eq__(self, other): + return self.num == self.val(other) + def __ne__(self, other): + return self.num != self.val(other) + def __gt__(self, other): + return self.num > self.val(other) + def __ge__(self, other): + return self.num >= self.val(other) + + def __add__(self, other): + return Long64(self.cap(self.num + self.val(other))) + def __sub__(self, other): + return Long64(self.cap(self.num - self.val(other))) + def __mul__(self, other): + return Long64(self.cap(self.num * self.val(other))) + def __floordiv__(self, other): + return Long64(self.cap(self.num // self.val(other))) + def __mod__(self, other): + return Long64(self.cap(self.num % self.val(other))) + def __divmod__(self, other): + return NotImplemented + def __pow__(self, other): + return Long64(self.cap(self.num ** self.val(other))) + def __lshift__(self, other): + return Long64(self.cap(self.num << self.val(other))) + def __rshift__(self, other): + if self.num < 0: + return Long64(self.cap(((self.num & 9223372036854775807)+9223372036854775808) >> self.val(other))) + else: + return Long64(self.cap(self.num >> self.val(other))) + def __and__(self, other): + return Long64(self.cap(self.num & self.val(other))) + def __xor__(self, other): + return Long64(self.cap(self.num ^ self.val(other))) + def __or__(self, other): + return Long64(self.cap(self.num | self.val(other))) + @staticmethod + def cap(num): # a method that handles an overflow/underflow + if num > 9223372036854775807 or num < -9223372036854775808: + if (num & 9223372036854775808) == 9223372036854775808: + #negative + leftover = num & 9223372036854775807 + return -9223372036854775808 + leftover#~(9223372036854775808) + else: + #positv + return num & 9223372036854775807 + return num + @staticmethod + def val(other): + if isinstance(other, Long64) or isinstance(other, Int32): + return other.num + return other + + class Int32(int): + def __init__(self, num=int(0)): # initialising + self.num = self.cap(num) + def __str__(self): + return str(self.num) + def __repr__(self): + return "Int32(" + self.__str__() + ")" + + def __lt__(self, other): + return self.num < self.val(other) + def __le__(self, other): + return self.num <= self.val(other) + def __eq__(self, other): + return self.num == self.val(other) + def __ne__(self, other): + return self.num != self.val(other) + def __gt__(self, other): + return self.num > self.val(other) + def __ge__(self, other): + return self.num >= self.val(other) + + def __add__(self, other): + return Int32(self.cap(self.num + self.val(other))) + def __sub__(self, other): + return Int32(self.cap(self.num - self.val(other))) + def __mul__(self, other): + return Int32(self.cap(self.num * self.val(other))) + def __floordiv__(self, other): + return Int32(self.cap(self.num // self.val(other))) + def __mod__(self, other): + return Int32(self.cap(self.num % self.val(other))) + def __divmod__(self, other): + return NotImplemented + def __pow__(self, other): + return Int32(self.cap(self.num ** self.val(other))) + def __lshift__(self, other): + return Int32(self.cap(self.num << self.val(other))) + def __rshift__(self, other): + if self.num < 0: + return Int32(self.cap(((self.num & 2147483647)+2147483648) >> self.val(other))) + else: + return Int32(self.cap(self.num >> self.val(other))) + def __and__(self, other): + return Int32(self.cap(self.num & self.val(other))) + def __xor__(self, other): + return Int32(self.cap(self.num ^ self.val(other))) + def __or__(self, other): + return Int32(self.cap(self.num | self.val(other))) + @staticmethod + def cap(num): # a method that handles an overflow/underflow + if num > 2147483647 or num < -2147483648: + if (num & 2147483648) == 2147483648: + #negative + leftover = num & 2147483647 + return -2147483648 + leftover#~(2147483648) + else: + #positv + return num & 2147483647 + return num + @staticmethod + def val(other): + if isinstance(other, Long64) or isinstance(other, Int32): + return other.num + return other + + +class RacoonHash: + + h0 = Long64(0) + h1 = Long64(0) + h2 = Long64(0) + h3 = Long64(0) + h4 = Long64(0) + + finalized = False + + block = Long64(0) + blocks = [] + _0x90a0de = [Long64(-2147483648), Long64(8388608), Long64(32768), Long64(128)] + _0x4b6ca9 = [Int32(24), Int32(16), Int32(8), Int32(0)] + _0x29b497 = ["0" ,"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"] + lastByteIndex = Int32(0) + hBytes = Long64(0) + bytes = Long64(0) + start = Int32(0) + + hashed = False + + def __init__(self): # _0x4ba53c + self.reset() + + def update(self, x): # x = String + if not self.finalized: + e = Int32(0) + t = Int32(0) + cur = Int32(0) + r = Int32(len(x)) + n = self.blocks + + while (cur < r): + if self.hashed: + self.hashed = False + n[0] = self.block + n[16] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = n[7] = n[8] = n[9] = n[10] = n[11] = n[12] = n[13] = n[14] = n[15] = Long64(0) + t = self.start + while (cur < r and t < 64): + #todo + n[t >> 2] |= ord(x[cur]) << self._0x4b6ca9[3 & t] + t += 1 + cur += 1 + else: + t = self.start + while (cur < r and t < 64): + e = ord(x[cur]) + if (e < 128): + #todo + n[t >> 2] |= e << self._0x4b6ca9[3 & t] + t += 1 + else: + if (e < 2048): + #todo + n[t >> 2] |= (192 | e >> 6) << self._0x4b6ca9[3 & t] + t += 1 + else: + if (e < 55296 or 57344 <= e): + #todo + n[t >> 2] |= (224 | e >> 12) << self._0x4b6ca9[3 & t] + t += 1 + else: + cur += 1 + e = 65536 + ((1023 & e) << 10 | 1023 & ord(x[cur])) + #todo + n[t >> 2] |= (240 | e >> 18) << self._0x4b6ca9[3 & t] + t += 1 + #todo + n[t >> 2] |= (128 | e >> 12 & 63) << self._0x4b6ca9[3 & t] + t += 1 + #todo + n[t >> 2] |= (128 | e >> 6 & 63) << self._0x4b6ca9[3 & t] + t += 1 + #todo + n[t >> 2] |= (128 | 63 & e) << self._0x4b6ca9[3 & t] + t += 1 + cur += 1 + + self.lastByteIndex = t + self.bytes += t - self.start + if (64 <= t): + self.block = n[16] + self.start = t - 64 + self.hash() + self.hashed = True + else: + self.start = t + if (Long64(4294967295) < self.bytes): + self.hBytes += self.bytes / Long64(4294967296) + self.bytes = self.bytes % Long64(4294967296) + + def finalizeHash(self): #0x8f + if not self.finalized: + self.finalized = True; + x = self.blocks + a = self.lastByteIndex + x[16] = self.block + x[a >> 2] |= self._0x90a0de[3 & a] + self.block = x[16] + if (56 <= a and (self.hashed or self.hash())): + x[0] = self.block + x[16] = x[1] = x[2] = x[3] = x[4] = x[5] = x[6] = x[7] = x[8] = x[9] = x[10] = x[11] = x[12] = x[13] = x[14] = x[15] = 0 + x[14] = self.hBytes << 3 | self.bytes >> 29; + x[15] = self.bytes << 3; + self.hash() + + def hash(self): # returns boolean // 0x8e + temp = Long64(0) # a + var0 = Int32(self.h0) # e + var1 = Int32(self.h1) # t + var2 = Int32(self.h2) # _ + var3 = Int32(self.h3) # r + var4 = Int32(self.h4) # n + i = [] + for index in range(0, len(self.blocks)): + i.append(Int32(self.blocks[index])) + + for x in range(16, 80): + temp = Long64(i[x - 3] ^ i[x - 8] ^ i[x - 14] ^ i[x - 16]) + i.insert(x, (Int32(temp) << 1 | Int32(temp) >> 31)) + + for x in range(0, 20, 5): + var4 = (var0 << 5 | var0 >> 27) + (var1 & var2 | ~var1 & var3) + var4 + Int32(1518500249) + i[x] + var1 = var1 << 30 | var1 >> 2 + var3 = ((var4) << 5 | var4 >> 27) + (var0 & (var1) | ~var0 & var2) + var3 + Int32(1518500249) + i[x + 1] + var0 = var0 << 30 | var0 >> 2 + var2 = ((var3) << 5 | var3 >> 27) + (var4 & (var0) | ~var4 & var1) + var2 + Int32(1518500249) + i[x + 2] + var4 = var4 << 30 | var4 >> 2 + var1 = ((var2) << 5 | var2 >> 27) + (var3 & (var4) | ~var3 & var0) + var1 + Int32(1518500249) + i[x + 3] + var3 = var3 << 30 | var3 >> 2 + var0 = ((var1) << 5 | var1 >> 27) + (var2 & (var3) | ~var2 & var4) + var0 + Int32(1518500249) + i[x + 4] + var2 = var2 << 30 | var2 >> 2 + + for x in range(20, 40, 5): + var4 = (var0 << 5 | var0 >> 27) + (var1 ^ var2 ^ var3) + var4 + Int32(1859775393) + i[x] + var1 = var1 << 30 | var1 >> 2 + var3 = ((var4) << 5 | var4 >> 27) + (var0 ^ (var1) ^ var2) + var3 + Int32(1859775393) + i[x + 1] + var0 = var0 << 30 | var0 >> 2 + var2 = ((var3) << 5 | var3 >> 27) + (var4 ^ (var0) ^ var1) + var2 + Int32(1859775393) + i[x + 2] + var4 = var4 << 30 | var4 >> 2 + var1 = ((var2) << 5 | var2 >> 27) + (var3 ^ (var4) ^ var0) + var1 + Int32(1859775393) + i[x + 3] + var3 = var3 << 30 | var3 >> 2 + var0 = ((var1) << 5 | var1 >> 27) + (var2 ^ (var3) ^ var4) + var0 + Int32(1859775393) + i[x + 4] + var2 = var2 << 30 | var2 >> 2 + + for x in range(40, 60, 5): + var4 = (var0 << 5 | var0 >> 27) + (var1 & var2 | var1 & var3 | var2 & var3) + var4 - Int32(1894007588) + i[x] + var1 = var1 << 30 | var1 >> 2 + var3 = ((var4) << 5 | var4 >> 27) + (var0 & (var1) | var0 & var2 | var1 & var2) + var3 - Int32(1894007588) + i[x + 1] + var0 = var0 << 30 | var0 >> 2 + var2 = ((var3) << 5 | var3 >> 27) + (var4 & (var0) | var4 & var1 | var0 & var1) + var2 - Int32(1894007588) + i[x + 2] + var4 = var4 << 30 | var4 >> 2 + var1 = ((var2) << 5 | var2 >> 27) + (var3 & (var4) | var3 & var0 | var4 & var0) + var1 - Int32(1894007588) + i[x + 3] + var3 = var3 << 30 | var3 >> 2 + var0 = ((var1) << 5 | var1 >> 27) + (var2 & (var3) | var2 & var4 | var3 & var4) + var0 - Int32(1894007588) + i[x + 4] + var2 = var2 << 30 | var2 >> 2 + + for x in range(60, 80, 5): + var4 = (var0 << 5 | var0 >> 27) + (var1 ^ var2 ^ var3) + var4 - Int32(899497514) + i[x] + var1 = var1 << 30 | var1 >> 2 + var3 = ((var4) << 5 | var4 >> 27) + (var0 ^ (var1) ^ var2) + var3 - Int32(899497514) + i[x + 1] + var0 = var0 << 30 | var0 >> 2 + var2 = ((var3) << 5 | var3 >> 27) + (var4 ^ (var0) ^ var1) + var2 - Int32(899497514) + i[x + 2] + var4 = var4 << 30 | var4 >> 2 + var1 = ((var2) << 5 | var2 >> 27) + (var3 ^ (var4) ^ var0) + var1 - Int32(899497514) + i[x + 3] + var3 = var3 << 30 | var3 >> 2 + var0 = ((var1) << 5 | var1 >> 27) + (var2 ^ (var3) ^ var4) + var0 - Int32(899497514) + i[x + 4] + var2 = var2 << 30 | var2 >> 2 + + self.h0 = Long64(Int32(self.h0 + var0)) + self.h1 = Long64(Int32(self.h1 + var1)) + self.h2 = Long64(Int32(self.h2 + var2)) + self.h3 = Long64(Int32(self.h3 + var3)) + self.h4 = Long64(Int32(self.h4 + var4)) + + return True + + def hex(self): # retuns string// 0x7b + self.finalizeHash() + x = self.h0 + a = self.h1 + e = self.h2 + t = self.h3 + l = self.h4 + + return self._0x29b497[Int32(x >> 28 & 15)] + self._0x29b497[Int32(x >> 24 & 15)] + self._0x29b497[Int32(x >> 20 & 15)] + self._0x29b497[Int32(x >> 16 & 15)] + self._0x29b497[Int32(x >> 12 & 15)] + self._0x29b497[Int32(x >> 8 & 15)] + self._0x29b497[Int32(x >> 4 & 15)] + self._0x29b497[Int32(15 & x)] + self._0x29b497[Int32(a >> 28 & 15)] + self._0x29b497[Int32(a >> 24 & 15)] + self._0x29b497[Int32(a >> 20 & 15)] + self._0x29b497[Int32(a >> 16 & 15)] + self._0x29b497[Int32(a >> 12 & 15)] + self._0x29b497[Int32(a >> 8 & 15)] + self._0x29b497[Int32(a >> 4 & 15)] + self._0x29b497[Int32(15 & a)] + self._0x29b497[Int32(e >> 28 & 15)] + self._0x29b497[Int32(e >> 24 & 15)] + self._0x29b497[Int32(e >> 20 & 15)] + self._0x29b497[Int32(e >> 16 & 15)] + self._0x29b497[Int32(e >> 12 & 15)] + self._0x29b497[Int32(e >> 8 & 15)] + self._0x29b497[Int32(e >> 4 & 15)] + self._0x29b497[Int32(15 & e)] + self._0x29b497[Int32(t >> 28 & 15)] + self._0x29b497[Int32(t >> 24 & 15)] + self._0x29b497[Int32(t >> 20 & 15)] + self._0x29b497[Int32(t >> 16 & 15)] + self._0x29b497[Int32(t >> 12 & 15)] + self._0x29b497[Int32(t >> 8 & 15)] + self._0x29b497[Int32(t >> 4 & 15)] + self._0x29b497[Int32(15 & t)] + self._0x29b497[Int32(l >> 28 & 15)] + self._0x29b497[Int32(l >> 24 & 15)] + self._0x29b497[Int32(l >> 20 & 15)] + self._0x29b497[Int32(l >> 16 & 15)] + self._0x29b497[Int32(l >> 12 & 15)] + self._0x29b497[Int32(l >> 8 & 15)] + self._0x29b497[Int32(l >> 4 & 15)] + self._0x29b497[Int32(15 & l)] + + def reset(self): + self.blocks = [Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0), Long64(0)] + self.h0 = Long64(1732584193) + self.h1 = Long64(4023233417) + self.h2 = Long64(2562383102) + self.h3 = Long64(271733878) + self.h4 = Long64(3285377520) + self.block = Long64(0) + self.bytes = Long64(0) + self.hBytes = Long64(0) + self.start = Int32(0) + self.finalized = self.hashed = False; diff --git a/resources/settings.xml b/resources/settings.xml index 2ae275d..ae65b8c 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -4,6 +4,8 @@ + +