Automating Content Creation with Python: Editing with MoviePy

viniciusenari

Vinicius Koji Enari

Posted on January 25, 2023

Automating Content Creation with Python: Editing with MoviePy

This is a continuation of a multi-part series on building a YouTube content creation bot that utilizes Twitch clips. If you have yet to see it, be sure to start with the first part.

Compiling the Clips into a Video

With the clips downloaded, the next step is to merge them into a single video. I used the MoviePy Python library. The editing process involves three steps:

  1. Create overlays for each clip with the broadcaster's title and name.
  2. Superimpose the overlay on the top of the corresponding clip.
  3. Concatenate all the clips together to produce a single video.

This way, you will have a final video with the title, and broadcaster name on every clip and all clips merged into one video.

Creating Overlays

I used the Python library Pillow to create the overlays for the clips. Although MoviePy also allows adding text to clips, it relies on the ImageMagick library, which requires manual installation. I preferred Pillow as it is easier to install, although it may be less efficient.

I made a transparent image of 1980x1080 resolution to create an overlay with Pillow. I added the title and broadcaster's name at the bottom left corner. If the title is too long, it will be truncated, and a "..." will be added to the end. After an overlay is created, it is saved in a dedicated directory.

Here's an example of the code:

from PIL import Image, ImageDraw, ImageFont

def create_overlay(self, clip_content):
    title = clip_content.title
    broadcaster_name = clip_content.broadcaster_name
    if len(title) > 40: title = title[:40] + '...'

    # Create a 1980x1080 transparent image
    overlay = Image.new('RGBA', (1920, 1080), color = (255,255,255,0))

    # Load fonts and create font objects
    fnt_clip_name = ImageFont.truetype(font_clip_name, 62)
    fnt_streamer_name = ImageFont.truetype(font_broadcaster, 50)

    d = ImageDraw.Draw(overlay)

    d.text((100, 930), title, font=fnt_clip_name, stroke_width=3, stroke_fill=(0, 0, 0), fill=(255, 255, 255))
    d.text((100, 1000), broadcaster_name, font=fnt_streamer_name, stroke_width=3, stroke_fill=(0, 0, 0), fill=(255, 255, 255))

    if not os.path.exists('files/overlays'): os.makedirs('files/overlays')
    filename = clip_content.title.replace(" ", "_").replace("/","_").lower()
    overlay.save(f'files/overlays/{filename}.png')
Enter fullscreen mode Exit fullscreen mode

Superimposing the Overlay

Using the MoviePy library, I superimposed the overlays on the clips. The process is straightforward: I created a MoviePy VideoFileClip and ImageClip, for the clip and overlay. Then, I combined them into a CompositeVideoClip.

from moviepy.editor import VideoFileClip, ImageClip, CompositeVideoClip

def create_video(self, clip_content):
    clip = VideoFileClip(clip_content.path, target_resolution=(1080, 1980))
    filename = clip_content.title.replace(" ", "_").replace("/","_").lower()
    img_clip = ImageClip(f'files/overlays/{filename}.png').set_duration(5)
    video = CompositeVideoClip([clip, img_clip])
    return video
Enter fullscreen mode Exit fullscreen mode

Resulting in the following:
Example clip with overlay

Concatenating the Clips

Now that all individual clips have an overlay, the next step is to concatenate them. The MoviePy library offers the concatenate_videoclips function, which, when used on an array of MoviePy clip objects, returns a single clip composed of all the other clips played one after another. Using the method='compose' parameter ensures that if the clips have different resolutions, MoviePy will resize them to result in a seamless final product.

The final step is to convert the clip object into an actual video file. The write_videofile method is used to do that. It takes various parameters such as fps, codec, threads, preset, and bitrate. The values for these parameters have been chosen after experimenting to find the best results. It's worth noting that what worked for me may not be the best for others, so one should experiment with different parameters to find the best results for their specific use case.

Here is the code for concatenating the clips. I create an overlay for each clip, superimpose it to the clip, and append it to an array. It then concatenates all clips on the array and writes a video file from the concatenated clip.

from moviepy.editor import concatenate_videoclips

render_settings = {
    'fps' : 60,
    'codec' : "mpeg4",
    'threads' : 8,
    'preset' : "ultrafast",
    'bitrate' : '20000k'
}

def create_video_compilation(self, clips, amount):
    for clip in clips[:amount]:
        self.create_overlay(clip)
        self.clips.append(self.create_video(clip))

    video = concatenate_videoclips(self.clips, method='compose')
    if not os.path.exists('files/youtube'): os.makedirs('files/youtube')
    video.write_videofile(f'files/youtube/video.mp4', fps = render_settings['fps'], codec = render_settings['codec'], threads = render_settings['threads'], preset = render_settings['preset'], bitrate = render_settings['bitrate'])
Enter fullscreen mode Exit fullscreen mode

Conclusion

In the article, I covered how to use MoviePy to edit videos and create a compilation from before downloaded clips. In the next part, I will cover how you can use the Youtube API to upload videos with a custom title, description, thumbnail, and tags. Remember to leave a comment if you have any questions.

💖 💪 🙅 🚩
viniciusenari
Vinicius Koji Enari

Posted on January 25, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related