100 lines
3.5 KiB
Python
100 lines
3.5 KiB
Python
#!/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() |