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)