#!/usr/bin/env python3 import argparse import sys from pathlib import Path from moviepy import VideoFileClip def convert_to_short(input_path): input_file = Path(input_path) output_path = f"{input_file.stem}_shorts{input_file.suffix}" # Load the video file clip = VideoFileClip(input_path) # 1. Check video duration if clip.duration >= 60: print(f"āŒ Error: Video is {clip.duration:.2f}s long. It must be under 60 seconds.") clip.close() return False print(f"āœ… Video length check passed ({clip.duration:.2f}s). Processing...") # 2. Calculate the target width for a 9:16 aspect ratio based on height target_height = clip.h target_width = int(target_height * (9 / 16)) # 3. Crop the center of the video # x_center centers the crop horizontally short_clip = clip.crop(width=target_width, height=target_height, x_center=clip.w / 2, y_center=clip.h / 2) # Optional: Resize to standard YouTube Short resolution (1080x1920) if short_clip.h != 1920: short_clip = short_clip.resize(newsize=(1080, 1920)) # 4. Export the final video file short_clip.write_videofile( output_path, codec="libx264", audio_codec="aac", fps=clip.fps ) # Clean up files clip.close() short_clip.close() print(f"šŸŽ‰ Success! Short saved as: {output_path}") return True def upload_shorts(): """Loops over the downloaded videos entries and uploaded them to youtube.""" print("Uploading Shorts...") unuploaded_shorts = DB.get_unuploaded() categoryId = CategoryId.GAMING for slug, record_date, title, game_name, clip_by, views, downloaded, uploaded_yt in unuploaded_shorts: print(f"Slug: {slug} | Date: {record_date} | Game: {game_name} | By: {clip_by} | Views: {views} | Title: {title}") file_path = f"save/clips/{slug}/{slug}_shorts.mp4" title = title description = f"Game: {game_name}, Cliped By: {clip_by}, on {record_date}, #Shorts #Clips #Twitch Every Friday and Sunday @7:30 EST https://twitch.tv/teampgp" categoryId = CategoryId.GAMING privatcyStatus = 'private' tags = ['shorts', 'gaming', 'TeamPGP', f'{game_name}', f'{clip_by}', 'twitch_clips', 'clips', 'Level1Techs', 'twitch'] output = uploader.upload_video(file_path, title, categoryId, description, privatcyStatus, tags) if output is True: print(f"Slug: {slug} | Was successfully uploaded.") DB.mark_as_uploaded(slug) else: print(f"Slug: {slug} | Upload Process failed.") def main(): # Set up the command-line argument parser parser = argparse.ArgumentParser(description="TeamPGP Clip Processing and Upload Pipeline") # Add optional arguments parser.add_argument('--convert', type=str, metavar='CLIP_PATH', help='Path to a video file to convert to a 9:16 Short') parser.add_argument('--upload', action='store_true', help='Process and upload pending Shorts in the database to YouTube') args = parser.parse_args() # If no flags are provided, show help text and exit if not args.convert and not args.upload: parser.print_help() sys.exit("\nāŒ Error: You must provide at least one action flag (--convert or --upload).") # Execute conversion step if path is provided if args.convert: convert_to_short(args.convert) # Execute database upload step if flag is provided if args.upload: upload_shorts() if __name__ == "__main__": main()