Generate Thumbnails from Remote Videos using Python
Tags: webdev, programming, python, api
Published: 2023-11-24 13:24:24

A customer of mine is running a video tube using **WordPress** and obv a PHP environment. 

The machine running his CMS comes without FFMPEG module, meaning that it's practically impossible to: manipulate videos and mostly take screenshot at specific duration to generate the thumbnail.

In a first implementation of his custom plugin I was using a free API service that provided a GET endpoint accepting:

- Video Source
- Duration at which get the screenshot/image

So you're now thinking: **the problem is solved.** 

Yep, but **just for 2 weeks**. In fact this API service **went down** 4 days ago and my customer remained without a Video-to-Image service and the ability to generate thumbs for his videos.

## Creating your own Video to Image Script
I than decided to create my own service with API endpoint to generate Images from Remote Videos. 

Hopefully this wont go down.

The concept is really simple, we're going to create a Python Script and run it on a machine that provide us FFMpeg library (out there you can find a lot of free services to run your python code). 

Manipulating videos using **FFMPEG is pretty easy** and you can use the Python based library or run it as a command using subprocess ( the approach used in this tutorial ).

This is the command we're going to use:

`ffmpeg -y -i [video_source] -ss [seconds formatted] -vframes 1 -f image2 [image_path]`

The -y command let us overwrite the image file once generated, since the script doesn’t provide dynamic naming.

Before writing down this script I searched a lot on Github for a build-in solution, but all the video thumbnail generator comes without an API endpoint, that is the main feature I needed. 

So at that point I decided to create my own.

Lets see the code:
```python
from flask import Flask, request, send_file
import subprocess

app = Flask(__name__)

@app.route('/screenshot', methods=['GET'])
def get_screenshot():
    video_source = request.args.get('video_source')
    seconds = request.args.get('seconds', default = 0, type = int)
    filePath = "results/image1.jpg";
    subprocess.call(['ffmpeg', '-y', '-i', video_source, '-ss', seconds_to_time_format(seconds), '-vframes', '1', '-f', 'image2', filePath])
    return send_file(f"./{filePath}", mimetype="image/jpg" )

def seconds_to_time_format(seconds):
    hours = seconds // 3600
    seconds %= 3600
    minutes = seconds // 60
    seconds %= 60
    return "%02d:%02d:%02d" % (hours, minutes, seconds)

if __name__ == '__main__':
    app.run(debug=True)
```

As you can see, the code is really super simple, comes without proper parameters validations and so on. 

It's not a big deal since I do validation before sending the request and I send these requests in a synchronous way, but feel free to add all the needed controls you need.

We uses Flask to easily create a Webserver and provide a /screenshot GET Endpoint. 

This endpoint accepts just 2 parameters: the remote video source and the seconds at which get the image.

Then a file path ( static ) is defined and using subprocess we run the ffmpeg script on the remote video. 

The second method is just for formatting integer seconds in to the proper format ( 00:00:00 ).

##How to run the Script
Running the script is pretty easy, you just have to navigate in to the script's folder and run python3 start.py. 

At that point the webserver will be initialized on the port 5000 and by navigating to http://localhost:5000/screenshot you'll be able to send your request.

Here's a request example: 
`http://localhost:5000/screenshot?seconds=100&video_source=https://remote-source/video_name.mp4`

That's all. Once the script has done its job, you'll receive as response the newly generated thumbnail.

You can fork the script from there: [API Video Thumbnailer](https://github.com/Hiutaky/api-video-thumbnailer)