def get_api_client(self, credentials_dict=None) -> Resource or None:
     if credentials_dict is None:
         if 'youtube_api_credentials' not in self.cached_data_handler.getDict(
         ):
             return None
         info(
             "Found Youtube Account login in. Getting Youtube Upload Client."
         )
         credentials_dict = self.cached_data_handler.getValue(
             'youtube_api_credentials')
     return self.__build__(credentials_dict)
 def loadDataFile(self):
     data_folder = join(getcwd(), "Data")
     if not exists(data_folder):
         mkdir(data_folder)
     if not exists(join(data_folder, self.yml_name)):
         with io.open(join(data_folder, self.yml_name), 'w', encoding='utf8') as outfile:
             outfile.write(yaml.dump(self.defaults))
         info("Created Data.yml (Holds information like list of channels to check if live and record)")
         self._cache = self.defaults
     else:
         with open(join(data_folder, self.yml_name), 'r', encoding='utf8') as stream:
             self._cache = yaml.load(stream, Loader=yaml.FullLoader)
 def YoutubeTestUpload(self):
     channel_id = request.args.get('channel_id')
     if channel_id is None:
         return Response("You need Channel_ID in args.",
                         status='client-error',
                         status_code=400)
     ok, message = self.process_Handler.upload_test_run(channel_id)
     if ok:
         info("{0} has been added for test uploading.".format(channel_id))
         return Response(None)
     else:
         return Response(message, status="server-error", status_code=500)
def loadServer(process_handler,
               cached_data_handler,
               port,
               youtube_api_handler,
               cert=None,
               key=None):
    try:
        from gevent.pywsgi import WSGIServer as web_server
    except ImportError:
        error_warning("Get gevent package! Unable to run.")
        web_server = None
    if web_server:
        ssl_args = dict()
        if cert:
            ssl_args['certfile'] = cert
        if key:
            ssl_args['keyfile'] = key
        app = Server(__name__, process_handler, cached_data_handler,
                     youtube_api_handler)

        @app.before_request
        def before_request():
            user_agent = request.headers.get('User-Agent')
            client_header = request.headers.get('Client')
            if not (user_agent
                    and 'WEB-CLIENT' in user_agent) and not client_header:
                rule = request.url_rule
                if rule is not None:
                    url = rule.rule
                    if not ('login' in url and request.args.get('unlockCode')
                            is not None) and 'callback' not in url:
                        return '', 403

        http_server = web_server(('0.0.0.0', port), app, **ssl_args)

        info("Starting server. Hosted on port: {0}!".format(port))
        http_server.serve_forever()
    def __resumable_upload(self, insert_request, file_location):
        response = None
        error = None
        retry = 0
        while response is None:
            httperror = HttpError
            try:
                info("Uploading file...")
                status, response = insert_request.next_chunk()
                if response:
                    if 'id' in response:
                        info(
                            file_location +
                            " was successfully uploaded with video id of '%s'."
                            % response['id'])
                        return response['id']
                    else:
                        warning(
                            "The upload failed with an unexpected response: %s"
                            % response)
            except httperror as e:
                if e.resp.status in self.RETRIABLE_STATUS_CODES:
                    error = "A retriable HTTP error %d occurred:\n%s" % (
                        e.resp.status, e.content)
                else:
                    raise
            except (IOError, client.NotConnected, client.IncompleteRead,
                    client.ImproperConnectionState, client.CannotSendRequest,
                    client.CannotSendHeader, client.ResponseNotReady,
                    client.BadStatusLine) as e:
                error = "A retriable error occurred: %s" % e

            if error is not None:
                warning(error)
                retry += 1
                if retry > self.MAX_RETRIES:
                    info("No longer attempting to retry. Couldn't upload {0}.".
                         format(file_location))
                else:
                    max_sleep = 2**retry
                    sleep_seconds = random.random() * max_sleep
                    warning("Sleeping %f seconds and then retrying upload..." %
                            sleep_seconds)
                    sleep(sleep_seconds)
    def uploadYouTube():
        try:
            # youtube_api_handler.initialize_upload()
            def get_upload_settings():
                upload_settings = youtube_api_handler.getCacheDataHandler(
                ).getValue('UploadSettings')
                channel_name = video_data.get('channel_name')
                if channel_name:
                    if channel_name in upload_settings:
                        return upload_settings[channel_name]
                return upload_settings[None]

            def _replace_variables(text):
                class DataDict(dict):
                    """
                        Taken from and
                        have been edited: https://stackoverflow.com/a/11023271
                    """
                    def __missing__(self, key):
                        return ''

                now = video_data.get('start_date')  # type: datetime
                timezone = getTimeZone()
                if text is not None:
                    text = text.format(**DataDict(
                        VIDEO_ID=video_id,
                        FILENAME=file_locations[0],
                        CHANNEL_ID=video_data.get('channel_id'),
                        CHANNEL_NAME=video_data.get('channel_name'),
                        START_DATE_MONTH=str(now.month),
                        START_DATE_DAY=str(now.day),
                        START_DATE_YEAR=str(now.year),
                        START_DATE="{0}/{1}/{2}".format(
                            now.month, now.day, now.year),
                        START_TIME=str(now.strftime("%I:%M %p")),
                        TIMEZONE=timezone if timezone is not None else '',
                        TITLE=str(video_data.get('title')),
                        DESCRIPTION=str(video_data.get('description'))))
                    if text is None:
                        return "[FAILED TO REPLACE VARIABLES]"
                return text

            settings = get_upload_settings()

            if youtube_api_handler.getCacheDataHandler().getValue(
                    'UploadLiveStreams') is True:
                upload_video_id = youtube_api_handler.initialize_upload(
                    file_locations[0], _replace_variables(settings['title']),
                    _replace_variables('\n'.join(settings['description'])),
                    _replace_variables(settings['tags']),
                    settings['CategoryID'], settings['privacyStatus'])
                sleep(3)
                if youtube_api_handler.getCacheDataHandler().getValue(
                        'UploadThumbnail') is True:
                    info("Uploading Thumbnail for {0}".format(
                        video_data.get('channel_name')))
                    youtube_api_handler.upload_thumbnail(upload_video_id, None)
                    # TODO Get Auto Uploading thumbnails! working again!
                    info("Thumbnail Done Uploading!")
                return [True, None]
        except:
            traceback_ = traceback.format_exc()
            if 'quota' in traceback_ and 'usage' in traceback_:
                return [
                    False,
                    "YouTube API Quota has been exceeded. Waiting until YouTube API Quota resets."
                ]
            error_warning(traceback_)
            warning("Unable to upload stream to Youtube.")
            return [False, traceback]
    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()))
    def remove_channel(self):
        def searchChannel():
            channel_dict_ = self.process_Handler.channels_dict.get(
                channel_identifier)
            if channel_dict_ is None:
                channel_array = [
                    channel_ for channel_ in self.process_Handler.channels_dict
                    if channel_identifier.casefold() ==
                    self.process_Handler.channels_dict.get(
                        channel_)['class'].get('channel_name').casefold()
                ]
                if channel_array is None or len(channel_array) == 0:
                    return [channel_identifier, None]
                return channel_array[
                    0], self.process_Handler.channels_dict.get(
                        channel_array[0])
            return channel_identifier, channel_dict_

        args = request.args  # type: ImmutableMultiDict
        channel_identifier = args.get("channel_id")
        if channel_identifier is None:
            channel_identifier = args.get("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 is None:
            return Response(
                "You need {0} in args.".format("channel_identifier"),
                status="client-error",
                status_code=400)

        channel_identifier, channel_dict = searchChannel()
        if channel_dict is None:
            return Response(
                "{0} hasn't been added to the channel list, so it can't be removed."
                .format(channel_identifier),
                status="server-error",
                status_code=500)
        if 'error' not in channel_dict:
            channel_dict['class'].close()
            thread_class = channel_dict['thread_class']
            try:
                thread_class.terminate()
                sleep(1)
                if thread_class.is_alive():
                    return Response("Unable to Terminate.",
                                    status="server-error",
                                    status_code=500)
            except Exception as e:
                error_warning(traceback.format_exc())
                return Response("Unable to remove channel. {0}".format(str(e)),
                                status="server-error",
                                status_code=500)
        platform_name = channel_dict['class'].get('platform_name')
        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_.remove(channel_identifier)
        channels.update({platform_name.upper(): list_})
        self.cached_data_handler.setValue("channels", channels)
        del self.process_Handler.channels_dict[channel_identifier]
        sleep(.01)
        info("{0} has been removed.".format(channel_identifier))
        return Response(None)
    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)