Esempio n. 1
0
    def play(self, channel):
        manifest_url = self.get_manifest(channel)
        device_id = PluginCache.get_by_key("device_id")
        customer_id = PluginCache.get_by_key("entitlements")["customer_id"]

        is_helper = inputstreamhelper.Helper(PROTOCOL, drm=DRM)
        if is_helper.check_inputstream():
            from addon import plugin
            play_item = xbmcgui.ListItem(path=manifest_url)
            play_item.setMimeType('application/xml+dash')
            play_item.setContentLookup(False)

            if kodi_version_major() >= 19:
                play_item.setProperty('inputstream', is_helper.inputstream_addon)
            else:
                play_item.setProperty('inputstreamaddon', is_helper.inputstream_addon)

            play_item.setProperty('inputstream.adaptive.manifest_type', PROTOCOL)
            play_item.setProperty('inputstream.adaptive.license_type', DRM)
            play_item.setProperty('inputstream.adaptive.manifest_update_parameter', 'full')
            play_item.setProperty('inputstream.adaptive.license_key',
                                  '%(url)s|Content-Type=text/plain;charset=UTF-8&User-Agent=%(ua)s|b{%(payload)s}|JBlicense'
                                  % dict(
                                      url=LICENSE_URL,
                                      ua=quote(USER_AGENT),
                                      payload=widevine_payload_package(device_id, customer_id),
                                  ))
            play_item.setProperty('inputstream.adaptive.license_flags', "persistent_storage")
            xbmcplugin.setResolvedUrl(plugin.handle, True, listitem=play_item)
    def __init__(self):
        """PlayerInfo initialisation"""
        self.resumepoints = ResumePoints()
        self.apihelper = ApiHelper(Favorites(), self.resumepoints)
        self.last_pos = None
        self.listen = False
        self.paused = False
        self.total = 100
        self.positionthread = None
        self.quit = Event()

        self.asset_str = None
        # FIXME On Kodi 17, use ListItem.Filenameandpath because Player.FilenameAndPath returns the stream manifest url and
        # this definitely breaks "Up Next" on Kodi 17, but this is not supported or available through the Kodi add-on repo anyway
        self.path_infolabel = 'ListItem.Filenameandpath' if kodi_version_major(
        ) < 18 else 'Player.FilenameAndPath'
        self.path = None
        self.title = None
        self.ep_id = None
        self.episode_id = None
        self.episode_title = None
        self.video_id = None
        from random import randint
        self.thread_id = randint(1, 10001)
        log(3, '[PlayerInfo {id}] Initialized', id=self.thread_id)
        super(PlayerInfo, self).__init__()
    def _version_check(self):
        first_run, settings_version, addon_version = self._first_run()
        if first_run:
            # 2.0.0 version: changed plugin:// url interface: show warning that Kodi favourites and what-was-watched will break
            if settings_version == '' and has_credentials():
                ok_dialog(localize(30978), localize(30979))

            if addon_version == '2.2.1':
                # 2.2.1 version: changed artwork: delete old cached artwork
                delete_cached_thumbnail(get_addon_info('fanart').replace('.png', '.jpg'))
                delete_cached_thumbnail(get_addon_info('icon'))
                # 2.2.1 version: moved tokens: delete old tokens
                from tokenresolver import TokenResolver
                TokenResolver().delete_tokens()

            # Make user aware that timeshift functionality will not work without ISA when user starts up the first time
            if settings_version == '' and kodi_version_major() > 17 and not has_inputstream_adaptive():
                ok_dialog(message=localize(30988))
 def _handle_bad_stream_error(protocol, code=None, reason=None):
     """Show a localized error message in Kodi GUI for a failing VRT NU stream based on protocol: hls, hls_aes, mpeg_dash)
         message: VRT NU stream <stream_type> problem, try again with (InputStream Adaptive) (and) (DRM) enabled/disabled:
             30959=and DRM, 30960=disabled, 30961=enabled
    """
     # HLS AES DRM failed
     if protocol == 'hls_aes' and not supports_drm():
         message = localize(30962, protocol=protocol.upper(), version=kodi_version_major())
     elif protocol == 'hls_aes' and not has_inputstream_adaptive() and not get_setting_bool('usedrm', default=True):
         message = localize(30958, protocol=protocol.upper(), component=localize(30959), state=localize(30961))
     elif protocol == 'hls_aes' and has_inputstream_adaptive():
         message = localize(30958, protocol=protocol.upper(), component='Widevine DRM', state=localize(30961))
     elif protocol == 'hls_aes' and get_setting_bool('usedrm', default=True):
         message = localize(30958, protocol=protocol.upper(), component='InputStream Adaptive', state=localize(30961))
     else:
         message = localize(30958, protocol=protocol.upper(), component='InputStream Adaptive', state=localize(30960))
     heading = 'HTTP Error {code}: {reason}'.format(code=code, reason=reason) if code and reason else None
     log_error('Unable to play stream. {error}', error=heading)
     ok_dialog(heading=heading, message=message)
     end_of_directory()
Esempio n. 5
0
    def get_stream(self, video, roaming=False, api_data=None):
        """Main streamservice function"""
        if not api_data:
            api_data = self._get_api_data(video)

        stream_json = self._get_stream_json(api_data, roaming)

        if not stream_json:

            # Roaming token failed
            if roaming:
                message = localize(
                    30964
                )  # Geoblock error: Cannot be played, need Belgian phone number validation
                return self._handle_stream_api_error(message)
            # X-VRT-Token failed
            message = localize(
                30963)  # You need a VRT NU account to play this stream.
            return self._handle_stream_api_error(message)

        if 'targetUrls' in stream_json:

            # DRM support for ketnet junior/uplynk streaming service
            uplynk = 'uplynk.com' in stream_json.get('targetUrls')[0].get(
                'url')

            vudrm_token = stream_json.get('drm')
            vualto_license_url = stream_json.get(
                'vualto_license_url') or self._get_vualto_license_url()
            drm_stream = (vudrm_token or uplynk)

            # Select streaming protocol
            if not drm_stream and has_inputstream_adaptive():
                protocol = 'mpeg_dash'
            elif drm_stream and self._can_play_drm:
                protocol = 'mpeg_dash'
            elif vudrm_token:
                protocol = 'hls_aes'
            else:
                protocol = 'hls'

            # Get stream manifest url
            manifest_url = next((stream.get('url')
                                 for stream in stream_json.get('targetUrls')
                                 if stream.get('type') == protocol), None)

            # Failed to get compatible manifest url, ask user to toggle "Use Widevine DRM"
            if manifest_url is None:
                available_protocols = [
                    stream.get('type')
                    for stream in stream_json.get('targetUrls')
                ]
                if protocol not in available_protocols:
                    error_json = {
                        'message':
                        '%s is not available for this stream, please try toggling the "Use Widevine DRM" setting'
                        % protocol
                    }
                    message = localize(
                        30989)  # Failed to load a compatible stream
                    return self._handle_stream_api_error(message, error_json)
            else:

                # External virtual subclip, live-to-VOD from past 24 hours archived livestream (airdate feature)
                if video.get('start_date') and video.get('end_date'):
                    manifest_url += '?t=' + video.get(
                        'start_date') + '-' + video.get('end_date')

                # Fix virtual subclip
                from datetime import timedelta
                duration = timedelta(
                    milliseconds=stream_json.get('duration', 0))
                manifest_url = self._fix_virtualsubclip(manifest_url, duration)

                # Prepare stream for Kodi player
                if protocol == 'mpeg_dash' and drm_stream:
                    log(2, 'Protocol: mpeg_dash drm')
                    if vudrm_token:
                        encryption_json = '{{"token":"{0}","drm_info":[D{{SSM}}],"kid":"{{KID}}"}}'.format(
                            vudrm_token)
                        license_key = self._get_license_key(
                            key_url=vualto_license_url,
                            key_type='D',
                            key_value=encryption_json,
                            key_headers={
                                'Content-Type': 'text/plain;charset=UTF-8'
                            })
                    else:
                        license_key = self._get_license_key(
                            key_url=self._UPLYNK_LICENSE_URL, key_type='R')

                    stream = StreamURLS(manifest_url,
                                        license_key=license_key,
                                        use_inputstream_adaptive=True)
                elif protocol == 'mpeg_dash':
                    log(2, 'Protocol: mpeg_dash')
                    stream = StreamURLS(manifest_url,
                                        use_inputstream_adaptive=True)
                else:
                    log(2, 'Protocol: {protocol}', protocol=protocol)
                    # Fix 720p quality for HLS livestreams
                    manifest_url = manifest_url.replace(
                        '.m3u8?', '.m3u8?hd&'
                    ) if '.m3u8?' in manifest_url else manifest_url + '?hd'
                    # Play HLS directly in Kodi Player on Kodi 17
                    if kodi_version_major(
                    ) < 18 or not has_inputstream_adaptive():
                        stream = self._select_hls_substreams(
                            manifest_url, protocol)
                    else:
                        stream = StreamURLS(manifest_url,
                                            use_inputstream_adaptive=True)
                return stream

        # VRT Geoblock: failed to get stream, now try again with roaming enabled
        if stream_json.get('code') in self._GEOBLOCK_ERROR_CODES:
            log_error('VRT Geoblock: {msg}', msg=stream_json.get('message'))
            if not roaming:
                return self.get_stream(video, roaming=True, api_data=api_data)

            if stream_json.get('code') == self._INVALID_LOCATION:
                message = localize(
                    30965
                )  # Geoblock error: Blocked on your geographical location based on your IP address
                return self._handle_stream_api_error(message, stream_json)

            if stream_json.get('code') == self._BELGIUM_ONLY:
                message = localize(
                    30973
                )  # Geoblock error: This program can only be played from EU
                return self._handle_stream_api_error(message, stream_json)

            message = localize(
                30964
            )  # Geoblock error: Cannot be played, need Belgian phone number validation
            return self._handle_stream_api_error(message, stream_json)
        if stream_json.get('code') == 'VIDEO_NOT_FOUND':
            # Refresh listing
            invalidate_caches('*.json')
            container_reload()
            message = localize(30987)  # No stream found
            return self._handle_stream_api_error(message, stream_json)
        if stream_json.get('code') == 'ERROR_AGE_RESTRICTED':
            message = localize(
                30990
            )  # Cannot be played, VRT NU account not allowed to access 12+ content
            return self._handle_stream_api_error(message, stream_json)

        # Failed to get stream, handle error
        message = localize(30954)  # Whoops something went wrong
        return self._handle_stream_api_error(message, stream_json)
    def onPlayBackStarted(self):  # pylint: disable=invalid-name
        """Called when user starts playing a file"""
        self.path = getInfoLabel(self.path_infolabel)
        if self.path.startswith('plugin://plugin.video.vrt.nu/'):
            self.listen = True
        else:
            self.listen = False
            return

        log(3, '[PlayerInfo {id}] Event onPlayBackStarted', id=self.thread_id)

        # Set property to let wait_for_resumepoints function know that update resume is busy
        set_property('vrtnu_resumepoints', 'busy')

        # Update previous episode when using "Up Next"
        if self.path.startswith('plugin://plugin.video.vrt.nu/play/upnext'):
            self.push_position(position=self.last_pos, total=self.total)

        # Reset episode data
        self.video_id = None
        self.episode_id = None
        self.episode_title = None
        self.asset_str = None
        self.title = None

        ep_id = play_url_to_id(self.path)

        # Avoid setting resumepoints for livestreams
        for channel in CHANNELS:
            if ep_id.get('video_id') and ep_id.get('video_id') == channel.get(
                    'live_stream_id'):
                log(3,
                    '[PlayerInfo {id}] Avoid setting resumepoints for livestream {video_id}',
                    id=self.thread_id,
                    video_id=ep_id.get('video_id'))
                self.listen = False

                # Reset vrtnu_resumepoints property before return
                set_property('vrtnu_resumepoints', None)
                return

        # Get episode data needed to update resumepoints from VRT NU Search API
        episode = self.apihelper.get_single_episode_data(
            video_id=ep_id.get('video_id'),
            whatson_id=ep_id.get('whatson_id'),
            video_url=ep_id.get('video_url'))

        # Avoid setting resumepoints without episode data
        if episode is None:
            # Reset vrtnu_resumepoints property before return
            set_property('vrtnu_resumepoints', None)
            return

        from metadata import Metadata
        self.video_id = episode.get('videoId') or None
        self.episode_id = episode.get('episodeId') or None
        self.episode_title = episode.get('title') or None
        self.asset_str = Metadata(None, None).get_asset_str(episode)
        self.title = episode.get('program')

        # Kodi 17 doesn't have onAVStarted
        if kodi_version_major() < 18:
            self.onAVStarted()