Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Zoen-DEV/repurpose-youtube-video/llms.txt

Use this file to discover all available pages before exploring further.

image_overlay.py applies text overlays onto Freepik-generated images using Pillow. It fetches the base image from a URL, resizes and center-crops it to the target canvas, adds a black-to-transparent gradient for text legibility, and renders the text at the appropriate position and size. All functions return PNG bytes ready to pass to bc.upload_media_local(). Requires: Pillow
python -m pip install Pillow

Setup

import image_overlay as ov
If Pillow is not installed, importing the module raises RuntimeError with installation instructions. The skill catches this and falls back to the clean Freepik image.

ov.render_hook(base_url, title, *, lang="es") -> bytes

Instagram carousel slide 1 — Hook. Renders a bold title centered on the canvas with a full-image gradient overlay, and a “Desliza →” / “Swipe →” subline at the bottom. Canvas: 1080×1080.
base_url
string
required
Freepik image URL returned by fp.generate_image() or fp.generate_carousel().
title
string
required
Hook title to render large and centered. Keep to a maximum of 10 words for readability. Font auto-scales down if the text overflows 4 lines.
lang
string
default:"es"
"es" renders the subline as "Desliza →"; "en" renders "Swipe →".
Returns PNG bytes.

ov.render_info(base_url, body_lines, *, lang="es", heading=None) -> bytes

Instagram carousel slide 2 — Info. Renders a small heading followed by bullet points. Canvas: 1080×1080.
base_url
string
required
Freepik image URL.
body_lines
string[]
required
List of 3–5 bullet point strings. Each line is word-wrapped to fit the canvas. Maximum 80 characters per line recommended for clean wrapping.
lang
string
default:"es"
Controls the default heading: "es" uses "CLAVES", "en" uses "KEY POINTS". Has no effect if heading is provided.
heading
string
Custom heading text. When provided, overrides the default "CLAVES" / "KEY POINTS" label.
Returns PNG bytes.

ov.render_credits(base_url, channel, video_title, *, lang="es") -> bytes

Instagram carousel slide 3 — Credits. Renders a centered attribution block: label, video title, channel name, and a call-to-action. Canvas: 1080×1080.
base_url
string
required
Freepik image URL.
channel
string
required
YouTube channel name. Pass content["channel"] from the Step 1 extraction result.
video_title
string
required
Original video title. Pass content["title"] from the Step 1 extraction result. Long titles are auto-wrapped and the font scales down to fit within 4 lines.
lang
string
default:"es"
"es" renders "VIDEO ORIGINAL" / "Link en bio 🔗"; "en" renders "ORIGINAL VIDEO" / "Link in bio 🔗".
Returns PNG bytes.

ov.render_single(base_url, title, *, lang="es") -> bytes

Instagram single image. Renders a title overlay at the bottom of the image over a bottom gradient. Canvas: 1080×1080.
base_url
string
required
Freepik image URL.
title
string
required
Title text to render at the bottom. Maximum 8–10 words recommended. Font auto-scales down if the text overflows 3 lines.
lang
string
default:"es"
Reserved for future use; currently has no effect on the single-image renderer.
Returns PNG bytes.

ov.render_linkedin_hook(base_url, title, *, lang="es") -> bytes

LinkedIn 4:5 image. Renders a hook text overlay at the bottom of a 4:5 canvas over a strong bottom gradient. Canvas: 1080×1350.
base_url
string
required
Freepik image URL. The base image is fetched and center-cropped to 1080×1350 automatically.
title
string
required
Hook text distilled from the first line of the LinkedIn post. Maximum 8–12 words. The goal is to stop the scroll: the image hook should make the viewer want to read the caption. Font auto-scales down if the text overflows 4 lines.
lang
string
default:"es"
Reserved for future use; currently has no effect on the LinkedIn renderer.
Returns PNG bytes.

Font resolution order

The script resolves fonts in this order, stopping at the first match:
  1. OVERLAY_FONT_PATH environment variable — must point to a .ttf or .otf file. Used as-is for both regular and bold variants.
  2. font-bold.ttf / font.ttf next to the script in scripts/ — drop-in override. Place your own typeface here with these names.
  3. System fonts:
    • Windows: arialbd.ttf / arial.ttf
    • macOS: /System/Library/Fonts/Helvetica.ttc
    • Linux: DejaVuSans-Bold.ttf / DejaVuSans.ttf, then LiberationSans-Bold.ttf / LiberationSans-Regular.ttf
  4. Pillow’s default bitmap font — last resort. Prints [aviso] No se encontró ninguna fuente del sistema — usando fuente bitmap por defecto (calidad reducida). The output will look rough; see Troubleshooting for the fix.

Usage pattern

The typical flow for each renderer is: render to PNG bytes, upload to Blotato, fall back to the clean Freepik URL if either step fails.
try:
    png_bytes = ov.render_linkedin_hook(base_url, hook_text, lang=lang)
    public_url = bc.upload_media_local(png_bytes, "linkedin-hook.png", api_key=cfg["api_key"])
    linkedin_media_urls = [public_url]
except Exception as e:
    print(f"[aviso] Overlay failed ({e}) — using clean Mystic image.")
    linkedin_media_urls = [base_url]
The same pattern applies to all five renderers. For carousel slides the loop processes each (filename, render_fn) pair with base_urls[i].

Build docs developers (and LLMs) love