Files
video-pipeline/modules/yt_poster.py

104 lines
3.5 KiB
Python

"""
yt_poster.py
Handles video uploads to YouTube using the YouTube Data API.
This module includes logic for setting titles, descriptions, tags, and
privacy status. It integrates with description generation tools and supports
automatic metadata based on the video type (e.g., montage).
Requires authentication via OAuth 2.0 and expects a valid token.pickle file.
Author: Llama Chile Shop
"""
import os
from pathlib import Path
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from googleapiclient.http import MediaFileUpload
from modules.title_utils import generate_montage_title, generate_output_filename
from modules.description_utils import generate_montage_description
from modules.config import DEBUG
def upload_video(file_path: Path, is_vertical: bool, stream_date: str, description: str = None, private: bool = DEBUG) -> str:
"""
Uploads a video file to YouTube.
Args:
file_path (str): Full path to the rendered video file.
is_vertical (bool): True if video is vertical format (9:16), else widescreen (16:9).
stream_date (str): Date of the stream in YYYY.MM.DD or YYYY.MM.DD.N format.
Returns:
str: URL of the uploaded YouTube video.
"""
try:
# Build title I have this:"and description
file_path = str(file_path)
session_name = Path(file_path).parents[1].name
title = generate_montage_title(session_name)
if not description:
description = str(generate_montage_description())
# Construct tags and privacy status
tags = ["Fortnite", "Zero Build", "Solo", "Gramps", "CoolHandGramps"]
privacy_status = "private" if private else "public"
# Authenticate
from authorize_youtube import get_authenticated_service
youtube = get_authenticated_service()
body = {
"snippet": {
"title": title,
"description": description,
"tags": tags,
"categoryId": "20", # Gaming
},
"status": {
"privacyStatus": privacy_status,
"selfDeclaredMadeForKids": False,
}
}
# media = MediaFileUpload(file_path, chunksize=-1, resumable=True)
media = MediaFileUpload(str(file_path), chunksize=-1, resumable=True)
if DEBUG:
print("🔍 DEBUGGING upload_video")
print(f" • file_path: {file_path} ({type(file_path)})")
print(f" • is_vertical: {is_vertical}")
print(f" • stream_date: {stream_date}")
print(f" • private: {private}")
print(f" • title: {title}")
print(f" • description: {description}")
print(f" • tags: {tags}")
print(f" • categoryId: {'20'} (should be int or str)")
request = youtube.videos().insert(
part="snippet,status",
body=body,
media_body=media
)
response = None
while response is None:
status, response = request.next_chunk()
if status:
print(f"🟡 Uploading: {int(status.progress() * 100)}%")
print(f"✅ Upload complete: https://youtu.be/{response['id']}")
return f"https://youtu.be/{response['id']}"
except HttpError as e:
print(f"❌ YouTube API error: {e}")
return ""
except Exception as e:
print(f"❌ Unexpected error during upload: {e}")
return ""