Пример #1
0
def get_url(url,
            config,
            additional_headers=None,
            additional_query_string=None,
            post_data=None):

    response_content = ''
    xbmc_helper.log_debug('get_url - url: ' + url + ' headers: ' +
                          dumps(additional_headers) + ' qs: ' +
                          dumps(additional_query_string) + ' post_data: ' +
                          dumps(post_data))

    try:
        headers = {
            'Accept-Encoding': 'gzip, deflate',
            'User-Agent': config['USER_AGENT'],
        }

        if additional_headers is not None:
            headers.update(additional_headers)

        if additional_query_string is not None:

            if url.find('?') is not -1:
                url += '&' + urlencode(additional_query_string)
            else:
                url += '?' + urlencode(additional_query_string)

        if post_data is not None:
            request = Request(url,
                              data=post_data.encode('utf-8'),
                              headers=headers)
        else:
            request = Request(url, headers=headers)

        response = urlopen(request, timeout=40)

        if response.info().get('Content-Encoding') == 'gzip':
            response_content = compat._decode(
                GzipFile(fileobj=BytesIO(response.read())).read())
        else:
            response_content = compat._decode(response.read())

    except Exception as e:

        xbmc_helper.log_error('Failed to load url: ' + url + ' headers: ' +
                              dumps(additional_headers) + ' qs: ' +
                              dumps(additional_query_string) + ' post_data: ' +
                              dumps(post_data) + 'Exception: ' + str(e))
        pass

    return response_content
Пример #2
0
    def query(self, query_path):

        query = '.'
        for query_param in query_path:
            query += '/' + self.mpd_tree_ns + query_param

        try:
            mpd_element = self.mpd_tree.find(query)
            return mpd_element
        except Exception as e:
            xbmc_helper.log_debug('Could not query mpd - Exception: ' + str(e))
            pass

        return None
Пример #3
0
def play_video(video_id, stream_type='VOD'):

    xbmc_helper.log_debug('play_video: video_id: ' + video_id)
    list_item = ListItem()
    video_data = libjoyn.get_video_data(video_id, stream_type)

    if (video_data['streamingFormat'] == 'dash'):
        if libjoyn.set_mpd_props(list_item, video_data['videoUrl'],
                                 stream_type) is not False:
            if 'drm' in video_data.keys() and video_data[
                    'drm'] == 'widevine' and 'licenseUrl' in video_data.keys():
                list_item.setProperty(
                    CONST['INPUTSTREAM_ADDON'] + '.license_type',
                    'com.widevine.alpha')
                list_item.setProperty(
                    CONST['INPUTSTREAM_ADDON'] + '.license_key',
                    video_data['licenseUrl'] + '|' +
                    request_helper.get_header_string(
                        {
                            'User-Agent': libjoyn.config['USER_AGENT'],
                            'Content-Type': 'application/octet-stream'
                        }) + '|R{SSM}|')
                list_item.setProperty(
                    CONST['INPUTSTREAM_ADDON'] + '.stream_headers',
                    request_helper.get_header_string(
                        {'User-Agent': libjoyn.config['USER_AGENT']}))
                if xbmc_helper.get_bool_setting(
                        'checkdrmcert'
                ) is True and 'certificateUrl' in video_data.keys():
                    list_item.setProperty(
                        CONST['INPUTSTREAM_ADDON'] + '.server_certificate',
                        video_data['certificateUrl'] + '|' +
                        request_helper.get_header_string(
                            {'User-Agent': libjoyn.config['USER_AGENT']}))
        else:
            xbmc_helper.notification(
                'Fehler', 'Konnte keine gültigen Video-Stream finden.',
                default_icon)
            xbmc_helper.log_error('Could not get valid MPD')

    else:
        return list_item.setPath(
            path=video_data['videoUrl'] + '|' +
            request_helper.get_header_string(
                {'User-Agent': libjoyn.config['USER_AGENT']}))

    setResolvedUrl(pluginhandle, True, list_item)
Пример #4
0
def fetch_categories(categories, stream_type='VOD'):

    xbmc_helper.log_debug('fetch_categories - multithreading : ' +
                          str(multi_threading))
    fetch_results = []

    #before threading can be done, the first request needs to be done seperatly to initialize the thread context for urlib and stuff
    frst_fetch_result = libjoyn.get_json_by_type('FETCH', {}, {},
                                                 categories[0])
    if len(categories) > 1:
        if multi_threading is True:
            thread_count = cpu_count() - 1
            xbmc_helper.log_debug('fetch_categories - number of threads : ' +
                                  str(thread_count))
            thread_pool = ThreadPool(thread_count)
            fetch_results = thread_pool.map(
                partial(libjoyn.get_json_by_type, 'FETCH', {}, {}),
                categories[1:])
            thread_pool.close()
            thread_pool.join()
        else:
            for category in categories[1:]:
                fetch_results.append(
                    libjoyn.get_json_by_type('FETCH', {}, {}, category))

        fetch_results.insert(0, frst_fetch_result)
    else:
        fetch_results = [frst_fetch_result]

    for category in fetch_results:
        for tvshow in category['data']:
            tv_show_id = str(tvshow['id'])
            if 'metadata' in tvshow.keys() and 'de' in tvshow['metadata'].keys(
            ):
                extracted_metadata = libjoyn.extract_metadata(
                    metadata=tvshow['metadata']['de'], selection_type='TVSHOW')
                add_dir(mode='season',
                        tv_show_id=tv_show_id,
                        metadata=extracted_metadata,
                        parent_fanart=default_fanart)
    endOfDirectory(handle=pluginhandle)
Пример #5
0
def videos(tv_show_id, season_id, fanart_img):

    xbmc_helper.log_debug('video : tv_show_id: ' + tv_show_id + 'season_id: ' +
                          season_id)
    videos = libjoyn.get_json_by_type('VIDEO', {
        'tvShowId': tv_show_id,
        'seasonId': season_id
    })

    for video in videos['data']:
        video_id = video['id']

        for metadata_lang, metadata_values in video['metadata'].items():
            if metadata_lang == 'de':
                extracted_metadata = libjoyn.extract_metadata(
                    metadata=metadata_values, selection_type='VIDEO')
                if 'broadcastDate' in metadata_values.keys():
                    extracted_metadata['infoLabels'].update({
                        'Aired':
                        datetime.utcfromtimestamp(
                            metadata_values['broadcastDate']).strftime(
                                '%Y-%m-%d')
                    })
                break

        extracted_metadata['infoLabels'].update({'Genre': []})
        if 'tvShow' in video.keys():
            if 'genres' in video['tvShow'].keys():
                for genre in video['tvShow']['genres']:
                    extracted_metadata['infoLabels']['Genre'].append(
                        genre['title'])
            if 'titles' in video['tvShow'].keys():
                for title_key, title_value in video['tvShow']['titles'].items(
                ):
                    if title_key == 'default':
                        extracted_metadata['infoLabels'].update({
                            'TVShowTitle':
                            HTMLParser().unescape(title_value)
                        })
                        break

        if 'season' in video.keys():
            if 'titles' in video['season'].keys():
                for season_title_key, season_title_value in video['season'][
                        'titles'].items():
                    if season_title_key == 'default':
                        extracted_metadata['infoLabels'].update(
                            {'Season': season_title_value})
                        break

        if 'episode' in video.keys() and 'number' in video['episode'].keys():
            extracted_metadata['infoLabels'].update(
                {'Episode': 'Episode ' + str(video['episode']['number'])})

        if 'duration' in video.keys():
            extracted_metadata['infoLabels'].update(
                {'Duration': (video['duration'] / 1000)})

        extracted_metadata['infoLabels'].update({'mediatype': 'episode'})
        add_link(mode='play_video',
                 metadata=extracted_metadata,
                 video_id=video_id,
                 parent_fanart=fanart_img)

    endOfDirectory(pluginhandle)
Пример #6
0
    def set_mpd_props(self, list_item, url, stream_type='VOD'):

        xbmc_helper.log_debug('get_mpd_path : ' + url + 'stream_type: ' +
                              stream_type)
        mpdparser = None

        ##strip out the filter parameter
        parts = urlparse(url)
        query_dict = parse_qs(parts.query)

        if 'filter' in query_dict.keys():
            query_dict.update({'filter': ''})
            new_parts = list(parts)
            new_parts[4] = urlencode(query_dict)
            new_mpd_url = urlunparse(new_parts)
            xbmc_helper.log_debug('Stripped out filter from mpd url is ' +
                                  new_mpd_url)
            try:
                mpdparser = mpd_parser(new_mpd_url, self.config)
            except Exception as e:
                xbmc_helper.log_debug('Invalid MPD - Exception: ' + str(e))
                pass

        if mpdparser is None or mpdparser.mpd_tree is None:
            try:
                mpdparser = mpd_parser(url, self.config)
            except Exception as e:
                xbmc_helper.log_error('Invalid Orginal MPD - Exception: ' +
                                      str(e))

        if mpdparser is not None and mpdparser.mpd_tree is not None:

            list_item.setProperty('inputstreamaddon',
                                  CONST['INPUTSTREAM_ADDON'])
            list_item.setProperty(
                CONST['INPUTSTREAM_ADDON'] + '.manifest_type', 'mpd')

            if stream_type == 'LIVE':
                list_item.setProperty(
                    CONST['INPUTSTREAM_ADDON'] + '.manifest_update_parameter',
                    'full')

            toplevel_base_url = None

            # the mpd has a Base URL at toplevel at a remote location
            # inputstream adaptive currently can't handle this correctly
            # it's known that this Base URL can be used to retrieve a 'better' mpd
            toplevel_base_url_res = mpdparser.get_toplevel_base_url()
            if toplevel_base_url_res is not None and toplevel_base_url_res.startswith(
                    'http'):
                xbmc_helper.log_debug(
                    'Found MPD with Base URL at toplevel : ' +
                    toplevel_base_url_res)
                toplevel_base_url = toplevel_base_url_res

            if toplevel_base_url is not None:
                if stream_type == 'VOD':
                    new_mpd_url = toplevel_base_url + '.mpd?filter='
                    try:
                        test_mpdparser = mpd_parser(new_mpd_url, self.config)
                        if test_mpdparser.mpd_tree is not None:
                            mpdparser = test_mpdparser
                            toplevel_base_url = None
                            toplevel_base_url_res = mpdparser.get_toplevel_base_url(
                            )
                            if toplevel_base_url_res is not None and toplevel_base_url_res.startswith(
                                    'http'):
                                xbmc_helper.log_debug(
                                    'Found MPD with Base URL at toplevel in REPLACED url: '
                                    + toplevel_base_url_res + 'URL: ' +
                                    new_mpd_url)
                                toplevel_base_url = toplevel_base_url_res
                            else:
                                toplevel_base_url = None
                    except Exception as e:
                        xbmc_helper.log_debug('Invalid MPD - Exception: ' +
                                              str(e))
                        pass

                elif stream_type == 'LIVE':
                    period_base_url_res = mpdparser.query_node_value(
                        ['Period', 'BaseURL'])
                    if period_base_url_res is not None and period_base_url_res.startswith(
                            '/') and period_base_url_res.endswith('/'):
                        new_mpd_url = toplevel_base_url + period_base_url_res + 'cenc-default.mpd'

                        try:
                            test_mpdparser = mpd_parser(
                                new_mpd_url, self.config)
                            if test_mpdparser.mpd_tree is not None:
                                mpdparser = test_mpdparser
                                toplevel_base_url = None
                                toplevel_base_url_res = mpdparser.get_toplevel_base_url(
                                )
                                if toplevel_base_url_res is not None and toplevel_base_url_res.startswith(
                                        'http'):
                                    xbmc_helper.log_debug(
                                        'Found MPD with Base URL at toplevel in REPLACED url: '
                                        + toplevel_base_url_res + 'URL: ' +
                                        new_mpd_url)
                                    toplevel_base_url = toplevel_base_url_res
                                else:
                                    toplevel_base_url = None
                        except Exception as e:
                            xbmc_helper.log_debug('Invalid MPD - Exception: ' +
                                                  str(e))
                            pass

            if toplevel_base_url is not None:
                xbmc_helper.log_debug(
                    'Writing MPD file to local disc, since it has a remote top Level Base URL ...'
                )
                sha_1 = sha1()
                sha_1.update(mpdparser.mpd_url)

                mpd_filepath = xbmc_helper.get_file_path(
                    CONST['TEMP_DIR'],
                    sha_1.hexdigest() + '.mpd')
                with open(mpd_filepath, 'w') as mpd_filepath_out:
                    mpd_filepath_out.write(mpdparser.mpd_contents)

                xbmc_helper.log_debug('Local MPD filepath is: ' + mpd_filepath)
                list_item.setPath(mpd_filepath)

            else:
                list_item.setPath(
                    mpdparser.mpd_url + '|' + request_helper.get_header_string(
                        {'User-Agent': self.config['USER_AGENT']}))

            return True

        return False
Пример #7
0
    def get_config(default_icon):

        recreate_config = True
        config = {}
        cached_config = None

        expire_config_mins = xbmc_helper.get_int_setting('configcachemins')
        if expire_config_mins is not None:
            confg_cache_res = cache.get_json('CONFIG',
                                             (expire_config_mins * 60))
        else:
            confg_cache_res = cache.get_json('CONFIG')

        if confg_cache_res['data'] is not None:
            cached_config = confg_cache_res['data']

        if confg_cache_res['is_expired'] is False:
            recreate_config = False
            config = cached_config

        if recreate_config == True:
            xbmc_helper.log_debug('get_config(): create config')
            config = {
                'CONFIG': {
                    'header_7TV_key_web': None,
                    'header_7TV_key': None,
                    'SevenTV_player_config_url': None
                },
                'PLAYER_CONFIG': {},
                'PSF_CONFIG': {},
                'PSF_VARS': {},
                'PSF_CLIENT_CONFIG': {},
                'IS_ANDROID': False,
            }

            os_uname = compat._uname_list()
            #android
            if os_uname[0] == 'Linux' and 'KODI_ANDROID_LIBS' in environ:
                config[
                    'USER_AGENT'] = 'Mozilla/5.0 (Linux Android 8.1.0 Nexus 6P Build/OPM6.171019.030.B1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36'
                config['IS_ANDROID'] = True
            # linux on arm uses widevine from chromeos
            elif os_uname[0] == 'Linux' and os_uname[4].lower().find(
                    'arm') is not -1:
                config['USER_AGENT'] = 'Mozilla/5.0 (X11 CrOS ' + os_uname[
                    4] + ' 4537.56.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.38 Safari/537.36'
            elif os_uname[0] == 'Linux':
                config['USER_AGENT'] = 'Mozilla/5.0 (X11 Linux ' + os_uname[
                    4] + ') AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
            else:
                config[
                    'USER_AGENT'] = 'Mozilla/5.0 (Windows NT 10.0 Win64 x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'

            html_content = request_helper.get_url(CONST['BASE_URL'], config)
            for match in findall(
                    '<script type="text/javascript" src="(.*?)"></script>',
                    html_content):
                if match.find('/main') is not -1:
                    main_js = request_helper.get_url(CONST['BASE_URL'] + match,
                                                     config)
                    for key in config['CONFIG']:
                        find_str = key + ':"'
                        start = main_js.find(find_str)
                        length = main_js[start:].find('",')
                        config['CONFIG'][key] = main_js[(
                            start + len(find_str)):(start + length)]

            config['PLAYER_CONFIG'] = request_helper.get_json_response(
                url=config['CONFIG']['SevenTV_player_config_url'],
                config=config)

            config['PSF_CONFIG'] = request_helper.get_json_response(
                url=CONST['PSF_CONFIG_URL'], config=config)

            psf_vars = request_helper.get_url(CONST['PSF_URL'], config)
            find_str = 'call(this,['
            start = psf_vars.find(find_str + '"exports')
            length = psf_vars[start:].rfind('])')
            psf_vars = psf_vars[(start + len(find_str)):(start +
                                                         length)].split(',')
            for i in range(len(psf_vars)):
                psf_vars[i] = psf_vars[i][1:-1]
            config['PSF_VARS'] = psf_vars

            if (cached_config is not None and
                    cached_config['PSF_VARS'][CONST['PSF_VARS_IDX']['SECRET']]
                    == config['PSF_VARS'][CONST['PSF_VARS_IDX']['SECRET']]
                    and cached_config['PLAYER_CONFIG']['toolkit']['psf']
                    == config['PLAYER_CONFIG']['toolkit']['psf']):
                config['PSF_CLIENT_CONFIG'] = cached_config[
                    'PSF_CLIENT_CONFIG']
            else:
                try:
                    config['PSF_CLIENT_CONFIG'] = loads(
                        compat._decode(
                            b64decode(
                                lib_joyn.decrypt(
                                    lib_joyn.uc_string_to_long_array(
                                        config['PSF_VARS'][
                                            CONST['PSF_VARS_IDX']['SECRET']]),
                                    lib_joyn.uc_string_to_long_array(
                                        lib_joyn.uc_slices_to_string(
                                            lib_joyn.uc_slice(
                                                config['PLAYER_CONFIG']
                                                ['toolkit']['psf'])))))))

                except Exception as e:
                    xbmc_helper.notification(
                        'Fehler',
                        'Konfiguration konnte nicht entschlüsselt werden.',
                        default_icon)
                    xbmc_helper.log_error('Could not decrypt config: ' +
                                          str(e))
                    exit(0)

            cache.set_json('CONFIG', config)

        return config