def on_message(self, reply_: dict):
     if reply_:
         reply('FROM TWITCH -> {0}'.format(reply_))
         message_type = try_get(reply_, lambda x: x['type'], str) or ''
         message_data = parse_json(
             try_get(reply_, lambda x: x['data']['message'], str)) or {}
         if "MESSAGE" in message_type:
             data_message_type = try_get(message_data,
                                         lambda x: x['type']) or ''
             if 'stream-up' in data_message_type:
                 self.live_streaming = True
                 self.broadcast_id = try_get(
                     message_data, lambda x: x['data']['broadcast_id'], int)
                 self.live_streaming, hls = self.getTwitchStreamInfo()
                 if hls is not None:
                     self.StreamFormat = get_format_from_data(
                         hls,
                         self.cachedDataHandler.getValue(
                             'recordingResolution'))
                     self.start_recording(self.StreamFormat)
             if 'stream-down' in data_message_type:
                 self.live_streaming = False
                 self.stop_recording()
             if 'viewcount' in data_message_type:
                 self.viewers = try_get(message_data,
                                        lambda x: x['viewers'], int)
         if "RESPONSE" in message_type:
             pass
def get_schedule_time(liveStreamAbilityRenderer):
    offlineSlate = try_get(liveStreamAbilityRenderer,
                           lambda x: x['offlineSlate'], dict)
    liveStreamOfflineSlateRenderer = try_get(
        offlineSlate, lambda x: x['liveStreamOfflineSlateRenderer'], dict)
    if liveStreamOfflineSlateRenderer:
        return try_get(liveStreamOfflineSlateRenderer,
                       lambda x: x['subtitleText']['simpleText'], str)
    return None
def get_thumbnail(liveStreamAbilityRenderer):
    offlineSlate = try_get(
        liveStreamAbilityRenderer,
        lambda x: x['liveStreamabilityRenderer']['offlineSlate'], dict)
    thumbnail_list = try_get(
        offlineSlate, lambda x: x['liveStreamOfflineSlateRenderer'][
            'thumbnail']['thumbnails'], list)
    if thumbnail_list:
        return get_highest_thumbnail(thumbnail_list)
    return None
 def formatDidYouMean(didYouMeanContent):
     didYouMeanRenderer = didYouMeanContent.get("didYouMeanRenderer")
     didYouMean = {
         'didYouMean':
         try_get(didYouMeanRenderer,
                 lambda x: x['didYouMean']['runs'][0]['text'], str),
         'correctedQuery':
         try_get(didYouMeanRenderer,
                 lambda x: x['correctedQuery']['runs'][0]['text'], str)
     }
     return didYouMean
 def getSettingsValue(ServiceSettings, settings_nameLook, name=None):
     for service in ServiceSettings:
         service_name = try_get(service, lambda x: x['key'], str)
         if service_name is not None and service_name in settings_nameLook:
             value = try_get(service, lambda x: x['value'], str)
             if name:
                 if not value:
                     warning("Something happened when finding the " + name)
                     return None
             return value
     return None
 def formatChannel(channel):
     return {
         'channel_identifier':
         try_get(channel, lambda x: x['displayName'], str),
         'channel_name':
         try_get(channel, lambda x: x['displayName'], str),
         'channel_image':
         try_get(channel, lambda x: x['profileImageURL'], str),
         'follower_count':
         str(try_get(channel, lambda x: x['followers']['totalCount'], int)),
         'platform':
         'TWITCH'
     }
Ejemplo n.º 7
0
    def run_server(self, cert=None, key=None):
        key = try_get(self.cachedDataHandler, lambda x: x.getValue('ssl_key'),
                      str) if not None else key
        cert = try_get(self.cachedDataHandler,
                       lambda x: x.getValue('ssl_cert'),
                       str) if not None else cert

        loadServer(self,
                   self.cachedDataHandler,
                   self.serverPort,
                   self.youtube_api_handler,
                   cert=cert,
                   key=key)
def get_unix_schedule_time(liveStreamAbilityRenderer) -> int or None:
    offlineSlate = try_get(liveStreamAbilityRenderer,
                           lambda x: x['offlineSlate'], dict)
    liveStreamOfflineSlateRenderer = try_get(
        offlineSlate, lambda x: x['liveStreamOfflineSlateRenderer'],
        dict)  # type: dict
    if liveStreamOfflineSlateRenderer:
        scheduledStartTime = liveStreamOfflineSlateRenderer.get(
            "scheduledStartTime")
        if scheduledStartTime:
            try:
                return int(scheduledStartTime)
            except ValueError:
                return None
    return None
 def getServiceSettings(serviceTrackingParamsList, service_nameLook):
     if serviceTrackingParamsList:
         for service in serviceTrackingParamsList:
             service_name = try_get(service, lambda x: x['service'], str)
             if service_name is not None and service_name in service_nameLook:
                 return service
     return None
def find_client_id(website_string):
    client_id = try_get(
        re.findall(r'\"Client-ID\":\"(.+?)\".', website_string),
        lambda x: x[0], str)
    if client_id is None:
        return [False, "Unable to find client id."]
    return [True, client_id]
def get_poll_delay_ms(liveStreamAbilityRenderer, channel_Class):
    pollDelayMs = try_get(liveStreamAbilityRenderer,
                          lambda x: x['pollDelayMs'], str)
    if pollDelayMs:
        return int(pollDelayMs)
    elif channel_Class.pollDelayMs:
        return channel_Class.pollDelayMs
    else:
        return 9500
    def loadVideoData(self):
        url = "https://www.twitch.tv/{0}".format(self.channel_name)
        download_object = download_website(url,
                                           CookieDict=self.sharedCookieDict)
        if download_object.status_code == 404:
            return [
                False,
                "Failed getting Twitch Data! \"{0}\" doesn't exist as a channel name!"
                .format(self.channel_name)
            ]
        if download_object.text is None:
            return [
                False, "Failed getting Youtube Data from the internet! "
                "This means there is no good internet available!"
            ]
        if self.globalVariables.get("client_id") is None:
            verbose("Getting Client ID. [TWITCH]")
            okay, client_id = find_client_id(download_object.text)
            if okay is False:
                warning(client_id)
            self.globalVariables.set("client_id", client_id)
        verbose('Getting Channel ID. [TWITCH]')

        self.access_token = self.__callAPI__(
            'api/channels/{0}/access_token?{1}&oauth_token'.format(
                self.channel_name,
                urlencode({
                    'need_https': 'true',
                    'platform': 'web',
                    'player_backend': 'mediaplayer',
                    'player_type': 'site'
                })))

        token = parse_json(self.access_token['token'])
        self.channel_id = try_get(token, lambda x: x['channel_id'])

        # website_dict = self.__callAPI__('kraken/channels/{0}'.format(
        #     self.channel_name))
        # self.channel_image = try_get(website_dict, lambda x: x['logo'])
        # self.channel_id = try_get(website_dict, lambda x: x['_id'], int)

        self.live_streaming, hls = self.getTwitchStreamInfo()

        if hls is not None:
            self.StreamFormat = get_format_from_data(
                hls, self.cachedDataHandler.getValue('recordingResolution'))

        if not self.channel_id:
            return [False, "Unable to find Channel ID."]
        return [True, "OK"]
 def formatChannel(channelContent):
     channelRenderer = channelContent.get("channelRenderer")
     channel_image = None
     channelImageFormats = try_get(channelRenderer,
                                   lambda x: x['thumbnail']['thumbnails'],
                                   list)
     if channelImageFormats is not None:
         channel_image = "https:{0}".format(
             max(channelImageFormats,
                 key=lambda x: x.get("height")).get("url"))
     channel = {
         'channel_identifier':
         try_get(channelRenderer, lambda x: x['channelId'], str),
         'channel_name':
         try_get(channelRenderer, lambda x: x['title']['simpleText'], str),
         'follower_count':
         try_get(channelRenderer,
                 lambda x: x['subscriberCountText']['simpleText'], str),
         'channel_image':
         channel_image,
         'platform':
         'YOUTUBE'
     }
     return channel
    def get_video_info(self):
        """
        Gets the stream info from channelClass.
        Looked at for reference:
        https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/youtube.py#L1675
        """
        url_arguments = {'html5': 1, 'video_id': self.video_id}
        if self.globalVariables.get("ps") is not None:
            url_arguments.update({'ps': self.globalVariables.get("ps")})
        url_arguments.update({'eurl': ''})
        url_arguments.update({'hl': 'en_US'})
        if self.globalVariables.get("client_name") is not None:
            url_arguments.update(
                {'c': self.globalVariables.get("client_name")})
        if self.globalVariables.get("cbr") is not None:
            url_arguments.update({'cbr': self.globalVariables.get("cbr")})
        if self.globalVariables.get("client_version") is not None:
            url_arguments.update(
                {'cver': self.globalVariables.get("client_version")})
        if self.globalVariables.get("client_os") is not None:
            url_arguments.update(
                {'cos': self.globalVariables.get("client_os")})
        if self.globalVariables.get("client_os_version") is not None:
            url_arguments.update(
                {'cosver': self.globalVariables.get("client_os_version")})
        if self.cpn is not None:
            url_arguments.update({'cpn': self.cpn})

        downloadClass = download_website(
            'https://www.youtube.com/get_video_info?{0}'.format(
                urlencode(url_arguments)),
            CookieDict=self.sharedCookieDict)
        video_info_website = downloadClass.text

        video_info = parse_qs(video_info_website)
        player_response = parse_json(
            try_get(video_info, lambda x: x['player_response'][0], str))
        if player_response:
            video_details = try_get(player_response,
                                    lambda x: x['videoDetails'], dict)
            if "streamingData" not in player_response:
                warning("No StreamingData, Youtube bugged out!")
                return None
            manifest_url = str(
                try_get(player_response,
                        lambda x: x['streamingData']['hlsManifestUrl'], str))
            if not manifest_url:
                warning("Unable to find HLS Manifest URL.")
                return None
            downloadOBJECT = download_website(manifest_url,
                                              CookieDict=self.sharedCookieDict)
            if downloadOBJECT.status_code != 200:
                return None
            hls = downloadOBJECT.parse_m3u8_formats()
            if len(hls.formats) == 0:
                warning(
                    "There were no formats found! Even when the streamer is live."
                )
                return None
            return {
                'formats': hls,
                'manifest_url': manifest_url,
                'video_details': video_details,
            }
        return None
def searchChannels(search, CookieDict, globalVariables):
    """
    :type CookieDict: dict
    :type globalVariables: GlobalVariables
    """
    def formatChannel(channel):
        return {
            'channel_identifier':
            try_get(channel, lambda x: x['displayName'], str),
            'channel_name':
            try_get(channel, lambda x: x['displayName'], str),
            'channel_image':
            try_get(channel, lambda x: x['profileImageURL'], str),
            'follower_count':
            str(try_get(channel, lambda x: x['followers']['totalCount'], int)),
            'platform':
            'TWITCH'
        }

    referer = 'https://www.twitch.tv/search?term={0}&type=channels'.format(
        search)
    client_id = globalVariables.get("client_id")
    if client_id is None:
        verbose("Getting Client ID. [TWITCH]")
        downloadOBJECT = download_website(referer, CookieDict=CookieDict)
        okay, client_id = find_client_id(downloadOBJECT.text)
        if okay is False:
            warning(client_id)
        globalVariables.set("client_id", client_id)
    data = [{
        "operationName": "SearchResultsPage_SearchResults",
        "variables": {
            "query": search,
            "options": {
                "targets": [{
                    "index": "CHANNEL"
                }]
            }
        },
        "extensions": {
            "persistedQuery": {
                "version":
                1,
                "sha256Hash":
                '1d3ca64005f07f8e34a33677d119ba8601e7deac745ea127e67b7925535ed735'
            }
        }
    }]  # TODO: reverse the sha265Hash. :p
    downloadOBJECT = download_website('https://gql.twitch.tv/gql',
                                      RequestMethod='POST',
                                      data=data,
                                      headers={
                                          'Origin': 'https://www.twitch.tv',
                                          'Referer': referer,
                                          'Client-Id': client_id,
                                          'Content-Length': '225'
                                      },
                                      CookieDict=CookieDict)
    data = try_get(downloadOBJECT.parse_json(), lambda x: x[0]['data'], dict)
    items = try_get(data, lambda x: x['searchFor']['channels']['items'], list)
    channels = list(map(formatChannel, items))
    return [True, {'channels': channels}]
    def channel_thread(self):
        if self.StreamFormat is not None:
            if self.start_recording(self.StreamFormat,
                                    StartIndex0=self.enableDVR):
                if self.TestUpload is True:
                    warning("Test Upload Enabled For {0}".format(
                        self.channel_name))
                    sleep(10)
                    self.EncoderClass.stop_recording()
                    self.add_youtube_queue()
                    exit(0)

        if self.live_streaming is not None:
            sleep(self.pollDelayMs / 1000)
        try:
            while self.stop_heartbeat is False:
                # LOOP
                self.live_streaming = self.is_live()
                # HEARTBEAT ERROR
                if self.live_streaming == -1:
                    # IF CRASHED.
                    info("Error on Heartbeat on {0}! Trying again ...".format(
                        self.channel_name))
                    sleep(1)
                # INTERNET OFFLiNE.
                elif self.live_streaming is None:
                    warning("INTERNET OFFLINE")
                    sleep(2.4)
                # FALSE
                elif self.live_streaming is False:
                    # TURN OFF RECORDING IF FFMPEG IS STILL ALIVE.
                    if self.EncoderClass.running is True:
                        x = Thread(target=self.stop_recording)
                        x.daemon = True
                        x.start()
                    if self.privateStream is False:
                        info("{0} is not live!".format(self.channel_name))
                    else:
                        info(
                            "{0}'s channel live streaming is currently private/unlisted!"
                            .format(self.channel_name))
                    sleep(self.pollDelayMs / 1000 - self.speed_up_heartbeat)
                # LIVE
                elif self.live_streaming is True:
                    # IF FFMPEG IS NOT ALIVE THEN TURN ON RECORDING.
                    if self.EncoderClass.running is not True:
                        video_details = self.get_video_info()
                        formats = video_details.get("formats")
                        videoDetails = video_details.get("video_details")
                        format_ = get_format_from_data(
                            formats,
                            self.cachedDataHandler.getValue(
                                'recordingResolution'))
                        self.StreamFormat = format_
                        self.title = try_get(videoDetails,
                                             lambda x: x['title'], str)
                        self.description = try_get(
                            videoDetails, lambda x: x['shortDescription'], str)
                        self.dvr_enabled = try_get(
                            videoDetails, lambda x: x['isLiveDvrEnabled'],
                            bool)
                        x = Thread(target=self.start_recording,
                                   args=(format_, ))
                        x.daemon = True
                        x.start()
                    sleep(self.pollDelayMs / 1000 - self.speed_up_heartbeat)
                # REPEAT (END OF LOOP)
        except:
            self.crashed_traceback = traceback.format_exc()
            crash_warning("{0}:\n{1}".format(self.channel_name,
                                             traceback.format_exc()))
Ejemplo n.º 17
0
                            default=None)
        parser.add_argument('-d', '--enable-debug', action='store_true')

        parser_args = parser.parse_args()

        # Setup Things.
        setupStreamsFolder()
        setupSharedVariables()

        cached_data_handler = get_cached_data_handler()

        youtube_channel_ids = cached_data_handler.getValue('channels_YOUTUBE')
        twitch_channel_names = cached_data_handler.getValue('channels_TWITCH')

        # FOR SSL
        key = try_get(cached_data_handler, lambda x: x.getValue('ssl_key'),
                      str)
        cert = try_get(cached_data_handler, lambda x: x.getValue('ssl_cert'),
                       str)

        note(
            "The delay between checking if channels are live is given by YouTube. The delay may change."
        )

        if not check_internet():
            stopped("Not able to access the internet!")

        if parser_args.enable_debug:
            enable_debug()

        if parser_args.port:
            port = parser_args.port[0]
def searchChannels(search, CookieDict):
    def formatChannel(channelContent):
        channelRenderer = channelContent.get("channelRenderer")
        channel_image = None
        channelImageFormats = try_get(channelRenderer,
                                      lambda x: x['thumbnail']['thumbnails'],
                                      list)
        if channelImageFormats is not None:
            channel_image = "https:{0}".format(
                max(channelImageFormats,
                    key=lambda x: x.get("height")).get("url"))
        channel = {
            'channel_identifier':
            try_get(channelRenderer, lambda x: x['channelId'], str),
            'channel_name':
            try_get(channelRenderer, lambda x: x['title']['simpleText'], str),
            'follower_count':
            try_get(channelRenderer,
                    lambda x: x['subscriberCountText']['simpleText'], str),
            'channel_image':
            channel_image,
            'platform':
            'YOUTUBE'
        }
        return channel

    def formatDidYouMean(didYouMeanContent):
        didYouMeanRenderer = didYouMeanContent.get("didYouMeanRenderer")
        didYouMean = {
            'didYouMean':
            try_get(didYouMeanRenderer,
                    lambda x: x['didYouMean']['runs'][0]['text'], str),
            'correctedQuery':
            try_get(didYouMeanRenderer,
                    lambda x: x['correctedQuery']['runs'][0]['text'], str)
        }
        return didYouMean

    # For some stupid reason, YouTube will only provide Searches on BR Content Encoding
    downloadOBJECT = download_website(
        "https://www.youtube.com/results?{0}".format(
            urlencode({
                'search_query': search,
                'sp': 'EgIQAg%3D%3D'
            })),
        headers={
            'Accept-Encoding': 'gzip, deflate, br',
            'Accept': '*/*',
        },
        CookieDict=CookieDict)
    if downloadOBJECT.response_headers.get('Content-Encoding') == 'br':
        # Check for support for that.
        try:
            import brotli
        except ImportError:
            return [
                False,
                'No Support for BR Content Encoding on Server. Required Packages: requests, brotlipy.'
            ]
    websiteString = downloadOBJECT.text
    youtube_initial_data = get_yt_initial_data(websiteString)
    if youtube_initial_data is None:
        return [False, 'Unable to find YouTube initial data.']
    contents = try_get(
        youtube_initial_data,
        lambda x: x['contents']['twoColumnSearchResultsRenderer'][
            'primaryContents']['sectionListRenderer']['contents'], list)
    if contents is None:
        return [False, 'Unable to find contents.']
    itemSectionRenderer = try_get([
        content for content in contents
        if content.get("itemSectionRenderer") is not None
    ] or [], lambda x: x[0], dict).get("itemSectionRenderer")
    if itemSectionRenderer is None:
        return [False, 'Unable to find itemSectionRenderer.']
    contents = itemSectionRenderer.get("contents")
    if itemSectionRenderer is None:
        return [False, "Unable to find itemSectionRenderer contents."]
    channels = list(
        map(formatChannel, [x for x in contents if 'channelRenderer' in x]))
    response = {'channels': channels}
    didYouMean = list(
        map(formatDidYouMean,
            [x for x in contents if 'didYouMeanRenderer' in x]))
    if len(didYouMean) > 0:
        response.update({'didYouMean': didYouMean})
    return [True, response]
def get_video_id(liveStreamAbilityRenderer):
    videoID = try_get(liveStreamAbilityRenderer, lambda x: x['videoId'], str)
    return videoID
def get_broadcast_id(liveStreamAbilityRenderer):
    broadcastId = try_get(liveStreamAbilityRenderer,
                          lambda x: x['broadcastId'], str)
    return broadcastId
def is_live(channel_Class, CookieDict=None, globalVariables=None, json=None):
    """

    Checks if channel is live using the normal Youtube heartbeat.
    Also sets heartbeat related variables.

    :type CookieDict: dict
    :type channel_Class: TemplateChannel
    :type globalVariables: GlobalVariables

    """

    if globalVariables is None:
        globalVariables = TempGlobalVariables()

    try:
        if json is None:
            referer_url = 'https://www.youtube.com/channel/{0}/live'.format(
                channel_Class.channel_id)
            headers = {
                'Accept': "*/*",
                'Accept-Language': 'en-US,en;q=0.9',
                'dnt': '1',
                'referer': referer_url,
                'x-youtube-client-name': '1'
            }
            url_arguments = {
                'video_id':
                channel_Class.video_id,
                'heartbeat_token':
                '',
                'c':
                (globalVariables.get("client_name")
                 if globalVariables.get("client_name") is not None else 'WEB'),
                'sequence_number':
                str(channel_Class.sequence_number)
            }
            if globalVariables.get("account_playback_token") is not None:
                headers.update({
                    'x-youtube-identity-token':
                    globalVariables.get("account_playback_token")
                })
            if globalVariables.get("page_build_label") is not None:
                headers.update({
                    'x-youtube-page-label':
                    globalVariables.get("page_build_label")
                })
            if globalVariables.get("page_cl") is not None:
                headers.update(
                    {'x-youtube-page-cl': globalVariables.get("page_cl")})
            if globalVariables.get("variants_checksum") is not None:
                headers.update({
                    'x-youtube-variants-checksum':
                    globalVariables.get("variants_checksum")
                })
            if globalVariables.get("utf_offset") is not None:
                headers.update({
                    'x-youtube-utc-offset':
                    str(globalVariables.get("utf_offset"))
                })
                url_arguments.update({
                    'utc_offset_minutes':
                    str(globalVariables.get("utf_offset"))
                })
            if globalVariables.get("client_version") is not None:
                headers.update({
                    'x-youtube-client-version':
                    globalVariables.get("client_version")
                })
                url_arguments.update(
                    {'cver': str(globalVariables.get("client_version"))})
            if globalVariables.get("timezone") is not None:
                url_arguments.update(
                    {'time_zone': str(globalVariables.get("timezone"))})
            if channel_Class.cpn is not None:
                url_arguments.update({'cpn': channel_Class.cpn})

            websiteClass = download_website(
                'https://www.youtube.com/heartbeat?{0}'.format(
                    urlencode(url_arguments)),
                headers=headers,
                CookieDict=CookieDict)
            CookieDict.update(websiteClass.cookies)
            if websiteClass.text is None:
                return None
            json = websiteClass.parse_json()

        channel_Class.sequence_number += 1
        reply('FROM YOUTUBE -> {0}'.format(json))

        # SETTING VARIABLES
        liveStreamAbilityRenderer = try_get(
            json,
            lambda x: x['liveStreamability']['liveStreamabilityRenderer'],
            dict)
        if liveStreamAbilityRenderer:
            thumbnail = get_thumbnail(liveStreamAbilityRenderer)
            if thumbnail:
                channel_Class.thumbnail_url = thumbnail
            channel_Class.pollDelayMs = get_poll_delay_ms(
                liveStreamAbilityRenderer, channel_Class)
            channel_Class.live_scheduled = get_unix_schedule_time(
                liveStreamAbilityRenderer) is not None
            channel_Class.broadcast_id = get_broadcast_id(
                liveStreamAbilityRenderer)
            video_id = get_video_id(liveStreamAbilityRenderer)
            if video_id:
                if video_id != channel_Class.video_id:
                    channel_Class.add_youtube_queue(
                    )  # just in case something happens.
                    channel_Class.video_id = video_id

        if channel_Class.live_scheduled is True:
            channel_Class.live_scheduled_timeString = get_schedule_time(
                liveStreamAbilityRenderer)
            unix_time = get_unix_schedule_time(liveStreamAbilityRenderer)
            if unix_time:
                channel_Class.live_scheduled_time = datetime.fromtimestamp(
                    unix_time)

        if 'stop_heartbeat' in json:
            channel_Class.add_youtube_queue()
            channel_Class.loadVideoData()
            return False

        if try_get(liveStreamAbilityRenderer, lambda x: x['displayEndscreen'],
                   bool):
            last_video_id = channel_Class.video_id
            channel_Class.loadVideoData()
            # CHECK IF A VIDEO ID CHANGE BEFORE ADDING.
            if last_video_id != channel_Class.video_id:
                channel_Class.add_youtube_queue()
            return False

        status = try_get(json, lambda x: x['status'], str)  # type: str
        if status:  # Sometimes status is removed and causes an error.
            if "OK" in status.upper():
                return True
            if "STOP" in status.upper():
                channel_Class.add_youtube_queue()
                channel_Class.loadVideoData()
                return False
            if "ERROR" in status.upper():
                warning("Getting the Live Data, failed on Youtube's Side. "
                        "Youtube Replied with: {0}.".format(json['reason']))
                return False
            if "LIVE_STREAM_OFFLINE" in status.upper():
                return False
            warning(
                "The Program couldn't find any value that matches the normal heartbeat. Returning False."
            )
        return False
    except KeyboardInterrupt:
        pass
    except BrokenPipeError:
        exit()
    except Exception:
        warning("Error occurred when doing Heartbeat.")
        error_warning(traceback.format_exc())
        return -1
    def loadVideoData(self, video_id=None):
        self.video_id = video_id
        if video_id:
            url = "https://www.youtube.com/watch?v={0}".format(video_id)
        else:
            url = "https://www.youtube.com/channel/{0}/live".format(
                self.channel_id)

        website_object = download_website(url,
                                          CookieDict=self.sharedCookieDict)
        # self.sharedCookieDict.update(websiteClass.cookies)
        if website_object.text is None:
            return [
                False, "Failed getting Youtube Data from the internet! "
                "This means there is no good internet available!"
            ]
        if website_object.status_code == 404:
            return [
                False,
                "Failed getting Youtube Data! \"{0}\" doesn't exist as a channel id!"
                .format(self.channel_id)
            ]
        website_string = website_object.text

        endpoint_type = get_endpoint_type(website_string)
        if endpoint_type:
            if endpoint_type == 'browse':
                array = re.findall(r'property="og:title" content="(.+?)"',
                                   website_string)
                if array:
                    channel_name = array[0]
                    warning(
                        "{0} has the live stream "
                        "currently unlisted or private, or only for members. "
                        "Using safeguard. This may not be the best to leave on.\n"
                        .format(channel_name))
                    self.channel_name = channel_name
                    self.video_id = None
                    self.privateStream = True
            else:
                if not endpoint_type == 'watch':
                    warning("Unrecognized endpoint type. Endpoint Type: {0}.".
                            format(endpoint_type))
                verbose("Getting Video ID.")
                youtube_initial_data = get_yt_initial_data(website_string)
                yt_player_config = try_get(
                    get_yt_player_config(website_string), lambda x: x, dict)
                player_response = parse_json(
                    try_get(yt_player_config,
                            lambda x: x['args']['player_response'], str))
                videoDetails = try_get(player_response,
                                       lambda x: x['videoDetails'], dict)
                if yt_player_config and videoDetails:
                    if "isLiveContent" in videoDetails and \
                            videoDetails['isLiveContent'] and \
                            ("isLive" in videoDetails or "isUpcoming" in videoDetails):
                        self.channel_name = try_get(videoDetails,
                                                    lambda x: x['author'], str)
                        self.video_id = try_get(videoDetails,
                                                lambda x: x['videoId'], str)
                        self.privateStream = False
                        if not self.channel_id:
                            self.channel_id = try_get(videoDetails,
                                                      lambda x: x['channelId'],
                                                      str)
                    else:
                        return [
                            False,
                            "Found a stream, the stream seemed to be a non-live stream."
                        ]
                else:
                    return [
                        False,
                        "Unable to get yt player config, and videoDetails."
                    ]
                contents = try_get(
                    youtube_initial_data,
                    lambda x: x['contents']['twoColumnWatchNextResults'][
                        'results']['results']['contents'], list)
                videoSecondaryInfoRenderer = try_get([
                    content for content in contents
                    if content.get("videoSecondaryInfoRenderer") is not None
                ], lambda x: x[0], dict).get("videoSecondaryInfoRenderer")
                channelImageFormats = try_get(
                    videoSecondaryInfoRenderer, lambda x: x['owner'][
                        'videoOwnerRenderer']['thumbnail']['thumbnails'], list)
                if channelImageFormats is not None:
                    self.channel_image = max(
                        channelImageFormats,
                        key=lambda x: x.get("height")).get("url")
                if not self.privateStream:
                    # TO AVOID REPEATING REQUESTS.
                    if player_response:
                        # playabilityStatus is legit heartbeat all over again..
                        playabilityStatus = try_get(
                            player_response, lambda x: x['playabilityStatus'],
                            dict)
                        status = try_get(playabilityStatus,
                                         lambda x: x['status'],
                                         str)  # type: str
                        reason = try_get(playabilityStatus,
                                         lambda x: x['reason'],
                                         str)  # type: str
                        if playabilityStatus and status:
                            if 'OK' in status.upper():
                                if reason and 'ended' in reason:
                                    return [False, reason]

                                streamingData = try_get(
                                    player_response,
                                    lambda x: x['streamingData'], dict)
                                if streamingData:
                                    if 'licenseInfos' in streamingData:
                                        licenseInfo = streamingData.get(
                                            'licenseInfos')
                                        drmFamilies = map(
                                            lambda x: x.get('drmFamily'),
                                            licenseInfo)
                                        return [
                                            False,
                                            "This live stream contains DRM and cannot be recorded.\n"
                                            "DRM Families: {0}".format(
                                                ', '.join(drmFamilies))
                                        ]
                                    manifest_url = str(
                                        try_get(streamingData,
                                                lambda x: x['hlsManifestUrl'],
                                                str))
                                    if not manifest_url:
                                        return [
                                            False,
                                            "Unable to find HLS Manifest URL."
                                        ]
                                    downloadOBJECT = download_website(
                                        manifest_url,
                                        CookieDict=self.sharedCookieDict)
                                    hls = downloadOBJECT.parse_m3u8_formats()
                                    if len(hls.formats) == 0:
                                        return [
                                            False,
                                            "There were no formats found! Even when the streamer is live."
                                        ]
                                    format_ = get_format_from_data(
                                        hls,
                                        self.cachedDataHandler.getValue(
                                            'recordingResolution'))
                                    if not videoDetails:
                                        videoDetails = try_get(
                                            player_response,
                                            lambda x: x['videoDetails'], dict)
                                    thumbnails = try_get(
                                        videoDetails,
                                        lambda x: x['thumbnail']['thumbnails'],
                                        list)
                                    if thumbnails:
                                        self.thumbnail_url = get_highest_thumbnail(
                                            thumbnails)
                                    self.dvr_enabled = try_get(
                                        videoDetails,
                                        lambda x: x['isLiveDvrEnabled'], bool)
                                    self.StreamFormat = format_
                                    self.title = try_get(
                                        videoDetails, lambda x: x['title'],
                                        str)
                                    self.description = videoDetails[
                                        'shortDescription']
                                else:
                                    return [
                                        False,
                                        "No StreamingData, YouTube bugged out!"
                                    ]
                            self.live_streaming = self.is_live(
                                json=playabilityStatus)
                    # GET YOUTUBE GLOBAL VARIABLES
                    if self.globalVariables.get(
                            "checkedYouTubeVariables") is None:

                        def getSettingsValue(ServiceSettings,
                                             settings_nameLook,
                                             name=None):
                            for service in ServiceSettings:
                                service_name = try_get(service,
                                                       lambda x: x['key'], str)
                                if service_name is not None and service_name in settings_nameLook:
                                    value = try_get(service,
                                                    lambda x: x['value'], str)
                                    if name:
                                        if not value:
                                            warning(
                                                "Something happened when finding the "
                                                + name)
                                            return None
                                    return value
                            return None

                        def getServiceSettings(serviceTrackingParamsList,
                                               service_nameLook):
                            if serviceTrackingParamsList:
                                for service in serviceTrackingParamsList:
                                    service_name = try_get(
                                        service, lambda x: x['service'], str)
                                    if service_name is not None and service_name in service_nameLook:
                                        return service
                            return None

                        if self.globalVariables.get(
                                "alreadyChecked"
                        ) is False or self.globalVariables.get(
                                "alreadyChecked") is None:
                            verbose("Getting Global YouTube Variables.")
                            e_catcher = getServiceSettings(
                                try_get(
                                    youtube_initial_data,
                                    lambda x: x['responseContext'][
                                        'serviceTrackingParams'], list),
                                "ECATCHER")
                            account_playback_token = try_get(
                                yt_player_config, lambda x: x['args'][
                                    'account_playback_token'][:-1], str)
                            ps = try_get(yt_player_config,
                                         lambda x: x['args']['ps'], str)
                            cbr = try_get(yt_player_config,
                                          lambda x: x['args']['cbr'])
                            client_os = try_get(yt_player_config,
                                                lambda x: x['args']['cos'])
                            client_os_version = try_get(
                                yt_player_config,
                                lambda x: x['args']['cosver'])
                            if account_playback_token is None:
                                warning(
                                    "Unable to find account playback token in the YouTube player config."
                                )
                            if ps is None:
                                warning(
                                    "Unable to find ps in the YouTube player config."
                                )
                            if cbr is None:
                                warning(
                                    "Unable to find cbr in the YouTube player config."
                                )
                            if client_os is None:
                                warning(
                                    "Unable to find Client OS in the YouTube player config."
                                )
                            if client_os_version is None:
                                warning(
                                    "Unable to find Client OS Version in the YouTube player config."
                                )
                            self.globalVariables.set("checkedYouTubeVariables",
                                                     None)
                            if not youtube_initial_data:
                                warning(
                                    "Unable to get Youtube Initial Data. Cannot find all Youtube Variables."
                                )
                            elif e_catcher is None:
                                warning(
                                    "Unable to get ECATCHER service data in Youtube Initial Data. "
                                    "Cannot find all Youtube Variables.")
                            else:
                                params = try_get(e_catcher,
                                                 lambda x: x['params'], list)
                                page_build_label = getSettingsValue(
                                    params,
                                    'innertube.build.label',
                                    name="Page Build Label")
                                page_cl = getSettingsValue(
                                    params,
                                    'innertube.build.changelist',
                                    name="Page CL")
                                variants_checksum = getSettingsValue(
                                    params,
                                    'innertube.build.variants.checksum',
                                    name="Variants Checksum")
                                client_version = getSettingsValue(
                                    params,
                                    'client.version',
                                    name="Client Version")
                                client_name = getSettingsValue(
                                    params, 'client.name', name="Client Name")
                                self.globalVariables.set(
                                    "page_build_label", page_build_label)
                                self.globalVariables.set("page_cl", page_cl)
                                self.globalVariables.set(
                                    "client_version", client_version)
                                self.globalVariables.set(
                                    "client_name", client_name)
                                self.globalVariables.set(
                                    "variants_checksum", variants_checksum)
                            self.globalVariables.set("ps", ps)
                            self.globalVariables.set("cbr", cbr)
                            self.globalVariables.set("client_os", client_os)
                            self.globalVariables.set("client_os_version",
                                                     client_os_version)
                            self.globalVariables.set("account_playback_token",
                                                     account_playback_token)
                            self.globalVariables.set("utf_offset",
                                                     get_utc_offset())
                            self.globalVariables.set("timezone", getTimeZone())
                            self.globalVariables.set("alreadyChecked", True)

        # ONLY WORKS IF LOGGED IN
        self.sponsor_on_channel = self.get_sponsor_channel(
            html_code=website_string)

        self.cpn = self.generate_cpn()
        return [True, "OK"]
    def add_channel(self, platform_name: str):
        if platform_name.upper() not in self.process_Handler.platforms:
            return Response("Unknown Platform: {0}.".format(platform_name),
                            status="client-error",
                            status_code=404)
        if request.method == 'GET':
            return Response("Bad Request.",
                            status='client-error',
                            status_code=400)
        if request.method == 'POST':
            content_type = request.headers.get("Content-Type")
            if content_type:
                if 'application/json' in content_type:
                    json = request.get_json()  # type: dict
                    channel_holder_class = None

                    dvr_recording = try_get(
                        json, lambda x: x['dvr_recording']) or False
                    session_id = try_get(json, lambda x: x['SessionID'], str)
                    channel_identifier = try_get(
                        json, lambda x: x['channel_identifier'])
                    test_upload = try_get(json,
                                          lambda x: x['test_upload']) or False
                    if session_id:
                        if session_id not in self.sessions:
                            return Response(
                                "Unknown Session ID. The Session ID might have expired.",
                                status="client-error",
                                status_code=404)
                        sessionStuff = self.sessions.get(
                            session_id)  # type: dict
                        channel_holder_class = sessionStuff.get('class')
                        channel_identifier = sessionStuff.get(
                            'channel_identifier')
                        if channel_identifier in self.process_Handler.channels_dict:
                            return Response("Channel Already in list!",
                                            status="server-error",
                                            status_code=500)
                    if channel_identifier:
                        if channel_identifier == '':
                            return Response(
                                'You need to specify a valid {0}.'.format(
                                    "channel_identifier"),
                                status='client-error',
                                status_code=400)
                        if channel_identifier in self.process_Handler.channels_dict:
                            return Response("Channel Already in list!",
                                            status="server-error",
                                            status_code=500)

                        if channel_holder_class is None:
                            channel_identifier = channel_holder_class
                        ok, message = self.process_Handler.run_channel(
                            channel_holder_class,
                            platform=platform_name,
                            enableDVR=dvr_recording,
                            testUpload=test_upload)

                        if not ok:
                            return Response(message,
                                            status="server-error",
                                            status_code=500)
                        elif ok:
                            channels = self.cached_data_handler.getValue(
                                "channels")
                            if channels is None:
                                channels = {}
                            if platform_name.upper() not in channels:
                                channels.update({platform_name.upper(): []})
                            list_ = channels.get(
                                platform_name.upper())  # type: list
                            list_.append(channel_identifier)
                            channels.update({platform_name.upper(): list_})
                            self.cached_data_handler.setValue(
                                "channels", channels)
                            info("{0} has been added to the list of channels.".
                                 format(channel_identifier))
                            return Response(None)
                    return Response("You need {0} in response.".format(
                        "channel_identifier"),
                                    status="client-error",
                                    status_code=400)
            return Response("Bad Request.",
                            status='client-error',
                            status_code=400)