| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
0 parents commit 0d26c2e
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + { | ||
| 2 | + "files": {} | ||
| 3 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,6 @@ | |||
| 1 | + # Ignore replit files | ||
| 2 | + .replit | ||
| 3 | + .env | ||
| 4 | + | ||
| 5 | + # Ignore venv folder | ||
| 6 | + venv/ | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,152 @@ | |||
| 1 | + import os | ||
| 2 | + import sys | ||
| 3 | + import time | ||
| 4 | + from PIL import Image, ImageDraw, ImageFont | ||
| 5 | + import subprocess | ||
| 6 | + import threading | ||
| 7 | + from google.oauth2.credentials import Credentials | ||
| 8 | + from google_auth_oauthlib.flow import InstalledAppFlow | ||
| 9 | + from googleapiclient.errors import HttpError | ||
| 10 | + from googleapiclient.discovery import build | ||
| 11 | + | ||
| 12 | + def get_authenticated_service(): | ||
| 13 | + """ | ||
| 14 | + Authenticate and build the YouTube service using Replit secrets for authentication. | ||
| 15 | + | ||
| 16 | + Returns: | ||
| 17 | + A YouTube service object authenticated with the credentials obtained from Replit secrets. | ||
| 18 | + """ | ||
| 19 | + client_id = os.environ['GOOGLE_CLIENT_ID'] | ||
| 20 | + client_secret = os.environ['GOOGLE_CLIENT_SECRET'] | ||
| 21 | + refresh_token = os.environ['GOOGLE_REFRESH_TOKEN'] | ||
| 22 | + SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl'] | ||
| 23 | + | ||
| 24 | + flow = InstalledAppFlow.from_client_config( | ||
| 25 | + { | ||
| 26 | + "installed": { | ||
| 27 | + "client_id": client_id, | ||
| 28 | + "client_secret": client_secret, | ||
| 29 | + "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob"], | ||
| 30 | + } | ||
| 31 | + }, | ||
| 32 | + scopes=SCOPES, | ||
| 33 | + ) | ||
| 34 | + credentials = Credentials.from_authorized_user_info(info=flow.run_local_server()['tokens']) | ||
| 35 | + | ||
| 36 | + # Use the refresh token to refresh the credentials if they expire | ||
| 37 | + credentials.set_refresh_token(refresh_token) | ||
| 38 | + | ||
| 39 | + # Build the YouTube service with the authenticated credentials | ||
| 40 | + return build('youtube', 'v3', credentials=credentials) | ||
| 41 | + | ||
| 42 | + def create_live_event(youtube, title, description, start_time, end_time): | ||
| 43 | + """ | ||
| 44 | + Create a new live broadcast event on YouTube. | ||
| 45 | + | ||
| 46 | + Args: | ||
| 47 | + youtube: A YouTube service object. | ||
| 48 | + title: A string containing the title of the live broadcast. | ||
| 49 | + description: A string containing the description of the live broadcast. | ||
| 50 | + start_time: A string containing the start time of the live broadcast in ISO 8601 format. | ||
| 51 | + end_time: A string containing the end time of the live broadcast in ISO 8601 format. | ||
| 52 | + | ||
| 53 | + Returns: | ||
| 54 | + A tuple containing the ID of the new live broadcast event and the ID of the associated live chat. | ||
| 55 | + """ | ||
| 56 | + event = youtube.liveBroadcasts().insert( | ||
| 57 | + part="snippet,status", | ||
| 58 | + body=dict( | ||
| 59 | + snippet=dict( | ||
| 60 | + title=title, | ||
| 61 | + description=description, | ||
| 62 | + scheduledStartTime=start_time, | ||
| 63 | + scheduledEndTime=end_time | ||
| 64 | + ), | ||
| 65 | + status=dict( | ||
| 66 | + privacyStatus="unlisted" | ||
| 67 | + ) | ||
| 68 | + ) | ||
| 69 | + ).execute() | ||
| 70 | + | ||
| 71 | + return event["id"], event["snippet"]["liveChatId"] | ||
| 72 | + | ||
| 73 | + def stream_console_output_to_youtube(youtube, stream_id): | ||
| 74 | + """ | ||
| 75 | + Stream console output to a YouTube live broadcast using ffmpeg. | ||
| 76 | + | ||
| 77 | + Args: | ||
| 78 | + youtube: A YouTube service object. | ||
| 79 | + stream_id: A string containing the ID of the YouTube live broadcast stream. | ||
| 80 | + """ | ||
| 81 | + # Set the appropriate paths for your system | ||
| 82 | + FFMPEG_BIN = "ffmpeg" | ||
| 83 | + | ||
| 84 | + # Parameters for the video stream | ||
| 85 | + width, height = 640, 480 | ||
| 86 | + fps = 30 | ||
| 87 | + | ||
| 88 | + def generate_frames(): | ||
| 89 | + font = ImageFont.truetype("arial.ttf", 20) | ||
| 90 | + text_color = (255, 255, 255) | ||
| 91 | + draw = ImageDraw.Draw(Image.new('RGB', (width, height))) | ||
| 92 | + | ||
| 93 | + while True: | ||
| 94 | + frame = Image.new('RGB', (width, height), (0, 0, 0)) | ||
| 95 | + | ||
| 96 | + # Capture console output | ||
| 97 | + console_output = "Your console output here" | ||
| 98 | + y = 30 | ||
| 99 | + for line in console_output.split('\n'): | ||
| 100 | + draw.text((10, y), line, font=font, fill=text_color) | ||
| 101 | + y += 30 | ||
| 102 | + | ||
| 103 | + yield frame | ||
| 104 | + time.sleep(1 / fps) | ||
| 105 | + | ||
| 106 | + frame_generator = generate_frames() | ||
| 107 | + command = [FFMPEG_BIN, | ||
| 108 | + '-y', '-loglevel', 'error', | ||
| 109 | + '-f', 'rawvideo', | ||
| 110 | + '-pixel_format', 'rgb24', | ||
| 111 | + '-video_size', f'{width}x{height}', | ||
| 112 | + '-framerate', str(fps), | ||
| 113 | + '-i', '-', | ||
| 114 | + '-c:v', 'libx264', | ||
| 115 | + '-preset', 'ultrafast', | ||
| 116 | + '-tune', 'zerolatency', | ||
| 117 | + '-b:v', '2500k', | ||
| 118 | + '-maxrate', '2500k', | ||
| 119 | + '-bufsize', '5000k', | ||
| 120 | + '-pix_fmt', 'yuv420p', | ||
| 121 | + '-g', str(fps), | ||
| 122 | + '-c:a', 'aac', | ||
| 123 | + '-b:a', '128k', | ||
| 124 | + '-ar', '44100', | ||
| 125 | + '-ac', '2', | ||
| 126 | + '-f', 'flv', | ||
| 127 | + f"rtmp://a.rtmp.youtube.com/live2/{stream_id}"] | ||
| 128 | + | ||
| 129 | + proc = subprocess.Popen(command, stdin=subprocess.PIPE) | ||
| 130 | + | ||
| 131 | + while True: | ||
| 132 | + frame = next(frame_generator) | ||
| 133 | + proc.stdin.write(frame.tobytes()) | ||
| 134 | + | ||
| 135 | + if __name__ == "__main__": | ||
| 136 | + # Authenticate the YouTube service | ||
| 137 | + youtube = get_authenticated_service() | ||
| 138 | + | ||
| 139 | + # Create a new live event and get the event ID and live chat ID | ||
| 140 | + event_id, live_chat_id = create_live_event(youtube, "Console Output Live Stream", "Live streaming console output", "2023-03-26T00:00:00Z", "2023-03-26T01:00:00Z") | ||
| 141 | + | ||
| 142 | + # Print the live event ID and live chat ID | ||
| 143 | + print(f"Live Event ID: {event_id}, Live Chat ID: {live_chat_id}") | ||
| 144 | + | ||
| 145 | + # Get the stream ID from your live event | ||
| 146 | + stream_id = youtube.liveBroadcasts().list( | ||
| 147 | + part="cdn", | ||
| 148 | + id=event_id | ||
| 149 | + ).execute()["items"][0]["cdn"]["ingestionInfo"]["streamName"] | ||
| 150 | + | ||
| 151 | + # Stream console output to YouTube | ||
| 152 | + stream_console_output_to_youtube(youtube, stream_id) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments