Como gerei mais de 200 thumbnails em menos de 20 minutos com Python
Eu estava trabalhando em um projeto que envolvia uma base de dados contendo diversos vídeos em formato MP4 armazenados no Firebase. A necessidade principal era exibir a miniatura (thumbnail) desses vídeos no aplicativo, mas sem comprometer a performance e sobrecarregar o processamento.
Após uma investigação aprofundada e várias tentativas, desenvolvi uma solução automatizada usando Python e Firebase, que simplifica significativamente este processo.
Todo o código mostrado aqui está disponível no Colab.
Passo 1: Configuração das dependências
import os
import firebase_admin
from firebase_admin import credentials, firestore
from google.cloud import storage
import requests
from moviepy.editor import VideoFileClip
import tempfile
Passo 2: Configuração do firebase O código, disponível no Colab, requer a configuração das seguintes dependências:
# Defina o caminho para o arquivo JSON da chave privada do Google
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/content/example.json"
# Inicialize o Firebase Admin apenas se ainda não tiver sido inicializado
if not firebase_admin._apps:
cred = credentials.Certificate("/content/example.json")
firebase_admin.initialize_app()
# criando instância do Firestore e Cloud Storage
db = firestore.client()
firebase_bucket_name = 'BUCKET_DO_DATABASE_AQUI'
client = storage.Client()
bucket = client.get_bucket(bucket_or_name = firebase_bucket_name)
Passo 3: Criação das funções Temos 4 funções auxiliares que fazem cada parte do processo de forma isolada.
- download_video: Baixa vídeos a partir de URLs fornecidas.
- generate_thumbnail: Usa moviepy para extrair e salvar um frame como thumbnail.
- upload_thumbnail_to_storage: Carrega o thumbnail gerado no Firebase Storage.
- update_document_with_thumbnail: Atualiza o documento Firestore com a URL do thumbnail gerado.
# Função para baixar um vídeo da URL fornecida
def download_video(url):
temp_video_path = tempfile.NamedTemporaryFile(delete=False).name
response = requests.get(url)
with open(temp_video_path, 'wb') as file:
file.write(response.content)
return temp_video_path
# Função para gerar um thumbnail do vídeo
def generate_thumbnail(video_path):
temp_thumbnail_path = tempfile.NamedTemporaryFile(suffix='.png', delete=False).name
with VideoFileClip(video_path) as clip:
clip.save_frame(temp_thumbnail_path, t=1)
return temp_thumbnail_path
# Função para carregar o thumbnail gerado para o Firebase Storage
def upload_thumbnail_to_storage(bucket_name, local_thumbnail_path, thumbnail_storage_path):
with open(local_thumbnail_path, 'rb') as image_file:
blob = bucket.blob(thumbnail_storage_path)
blob.upload_from_file(image_file, content_type='image/png')
blob.make_public()
file_url = blob.public_url
return file_url
# Função para atualizar o documento Firestore com a URL do thumbnail
def update_document_with_thumbnail(document_id, thumbnail_url):
video_ref = db.collection('videos').document(document_id)
video_ref.update({'thumb': thumbnail_url})
Passo 4: Criação da função principal
def process_all_videos():
db = firestore.Client()
videos_ref = db.collection('videos') #Collection onde estão os dados que quero atualizar
snapshot = videos_ref.get()
if not snapshot:
return 'Nenhum vídeo encontrado.'
for doc in snapshot:
video_id = doc.id
video_data = doc.to_dict()
video_url = video_data['videoUrl'] # Campo de referência para o vídeo ao qual quero criar a thumb
local_video_path = download_video(video_url)
local_thumbnail_path = generate_thumbnail(local_video_path)
thumbnail_storage_path = f'thumbs/{video_id}.png'
thumbnail_url = upload_thumbnail_to_storage(firebase_bucket_name, local_thumbnail_path, thumbnail_storage_path)
update_document_with_thumbnail(video_id, thumbnail_url)
os.remove(local_video_path)
os.remove(local_thumbnail_path)
return 'Todos os vídeos foram processados.'
O Algoritmo demorou 17 minutos para gerar 210 thumbnails de forma automática para todos os registros que tenho no Firebase, um feito que manualmente levaria horas, se não dias, para completar.
Interessante, o método "generate_thumbnail" você sempre está utilizando o parâmetro t=1 , não seria o caso de avaliar se nesse momento o video tem de fato alguma imagem "útil" para thumbnail? Uma tela preta,por exemplo, neste momento poderia prejudicar o resultado do método.