Coding project for recreational purposes utilizing Python and the MoviePy library.
I developed this Python script to transform nostalgic sports videos from YouTube into short TikTok-friendly clips. The idea came from wanting to share memorable football and F1 moments in a vertical format that's more accessible on mobile. The script automatically downloads a video, crops it to a 9:16 aspect ratio, and creates a few 10-second highlight clips. Finally, it merges the clips into a single vertical video ready for posting. I structured this code by combining my own research with help from ChatGPT, using it to explore new libraries like yt_dlp and moviepy. This project blends my interest in coding with my passion for sports and video editing.
Code
# Importing libraries
from moviepy.editor import VideoFileClip, concatenate_videoclips, clips_array
import yt_dlp, random, cv2
# Variables
num_videos = 3
video_name = "F1_2004_Spa-Francorchamps"
video_url = "https://www.youtube.com/watch?v=PCFv0KZ2VpU&ab_channel=FORMULA1"
# Base path
base_path = f"C:\\Users\\User\\OneDrive\\Desktop\\{video_name}"
# File paths
original_video_path = f"{base_path}\\{video_name}.mp4"
crop_video_path = f"{base_path}\\{video_name}_crop.mp4"
clip_video_path = f"{base_path}\\{video_name}_clip_{{}}.mp4"
final_video_path = f"{base_path}\\{video_name}_final.mp4"
# Download original video from YouTube
ydl_opts_video = {
'format': 'bestvideo',
'postprocessors': [{
'key': 'FFmpegVideoConvertor',
'preferedformat': 'mp4',
}],
'outtmpl': original_video_path,
'postprocessors_args': ['-an']
}
with yt_dlp.YoutubeDL(ydl_opts_video) as ydl:
ydl.download([video_url])
# Crop video to a 9:16 aspect ratio
def crop_to_9_16(input_path, output_path):
video = VideoFileClip(input_path)
target_aspect_ratio = 9 / 16
video_width, video_height = video.size
video_aspect_ratio = video_width / video_height
if video_aspect_ratio > target_aspect_ratio:
new_width = int(video_height * target_aspect_ratio)
x_center = video_width // 2
x1 = x_center - new_width // 2
x2 = x_center + new_width // 2
video_cropped = video.crop(x1=x1, y1=0, x2=x2, y2=video_height)
else:
new_height = int(video_width / target_aspect_ratio)
y_center = video_height // 2
y1 = y_center - new_height // 2
y2 = y_center + new_height // 2
video_cropped = video.crop(x1=0, y1=y1, x2=video_width, y2=y2)
video_cropped.write_videofile(output_path, codec="libx264")
video.close()
video_cropped.close()
crop_to_9_16(original_video_path, crop_video_path)
# Cut video into multiple 10-seconds clips
video = VideoFileClip(crop_video_path)
duration_video = video.duration
cut_duration = 10
for i in range(num_videos):
cuts = []
start_time = random.uniform(0, duration_video - cut_duration)
cut = video.subclip(start_time, start_time + cut_duration)
cuts.append(cut)
final_clip = concatenate_videoclips(cuts)
output_path_clip = clip_video_path.format(i + 1)
final_clip.write_videofile(output_path_clip, codec="libx264", audio_codec="aac")
final_clip.close()
video.close()
# Combine all generated clips into one final video
clips_to_merge = []
for i in range(num_videos):
clip_path = clip_video_path.format(i + 1)
clip = VideoFileClip(clip_path)
clips_to_merge.append(clip)
final_merged_video = concatenate_videoclips(clips_to_merge)
final_merged_video.write_videofile(final_video_path, codec="libx264", audio_codec="aac")
for clip in clips_to_merge:
clip.close()
final_merged_video.close()