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.

Every post includes a visual by default. If you pass images: in the command, those files are used as-is. Otherwise, the skill generates images with Freepik Mystic and applies text overlays using Pillow via image_overlay.py. All rendered images are uploaded to Blotato before the approval block is shown, so the URLs in Step 6 are stable and ready to publish.

Visual types by platform

Each platform has a fixed format and dimensions. LinkedIn
  • One image, aspect ratio 4:5 (1080×1350 px)
  • A hook overlay is rendered at the bottom of the image — a distilled version of the post’s first line, 8–12 words — so the image stops the scroll before a viewer reads the caption.
Instagram — single image
  • One image, aspect ratio 1:1 (1080×1080 px)
  • A title overlay is rendered at the bottom of the image — a distilled hook of 8–10 words.
Instagram — carousel
  • Three images, all 1:1 (1080×1080 px), with fixed roles:
SlideRoleOverlay content
1HookLarge centered title (max 10 words) + “Desliza →” (ES) or “Swipe →” (EN)
2InfoSmall heading (“CLAVES” / “KEY POINTS”) + 3–5 short bullet points
3Credits”VIDEO ORIGINAL” / “ORIGINAL VIDEO” + video title + channel name + “Link en bio 🔗” / “Link in bio 🔗“

Image generation with Freepik Mystic

Images are generated by calling fp.generate_image():
def generate_image(
    prompt: str,
    *,
    api_key: str,
    aspect_ratio: str = "square_1_1",
    model: str = "realism",
) -> list[str]:
For carousels, fp.generate_carousel() calls generate_image() sequentially for each prompt, skipping any slide that fails without breaking the rest. Prompt rules Claude writes all prompts in English — Mystic produces better results with English descriptions. Every prompt follows these constraints:
  • No text requested. Mystic cannot render copy reliably. The modifier "no text, no typography, no logos, no watermarks" is appended to every prompt.
  • Negative space for overlays. Prompts specify where the overlay will land:
    • LinkedIn 4:5: "composition with negative space at the bottom for overlay text"
    • Instagram single: "composition with negative space at the bottom for overlay text"
    • Carousel slide 1: centered composition
    • Carousel slide 3: simple, low-saturation composition
  • Under 300 characters per prompt. Prompts describe a concrete scene — style, lighting, composition, palette — not an abstract idea.
  • Content-related. Each prompt is derived from the video’s title, transcript, keyPoints, and chapters so the visual relates to what the video is actually about.
Aspect ratios
Platformaspect_ratio value
Instagram (single or carousel)"square_1_1"
LinkedIn"social_post_4_5"

Text overlay with Pillow (image_overlay.py)

image_overlay.py exposes five renderer functions. Each downloads the base image from the Mystic URL, crops it to the target size, applies a gradient for readability, renders text with Pillow, and returns PNG bytes.
ov.render_hook(base_url, title, *, lang="es") -> bytes
Instagram carousel slide 1. Large centered title with automatic font scaling if the text overflows, plus “Desliza →” or “Swipe →” at the bottom.
ov.render_info(base_url, body_lines, *, lang="es", heading=None) -> bytes
Instagram carousel slide 2. body_lines is a list of 3–5 strings (≤80 characters each). If heading is None, defaults to “CLAVES” (ES) or “KEY POINTS” (EN).
ov.render_credits(base_url, channel, video_title, *, lang="es") -> bytes
Instagram carousel slide 3. channel comes from content["channel"] returned by Step 1.
ov.render_single(base_url, title, *, lang="es") -> bytes
Instagram single image. Title is rendered left-aligned at the bottom over a strong bottom gradient.
ov.render_linkedin_hook(base_url, title, *, lang="es") -> bytes
LinkedIn 4:5. Operates on a 1080×1350 canvas. Title is rendered left-aligned at the bottom over a gradient. Font resolution order The renderers resolve fonts in this order, stopping at the first match:
  1. OVERLAY_FONT_PATH environment variable (must point to a .ttf or .otf file)
  2. font-bold.ttf / font.ttf in the scripts/ directory
  3. System fonts:
    • Windows: arialbd.ttf / arial.ttfsegoeuib.ttf / segoeui.ttf
    • macOS: /System/Library/Fonts/Helvetica.ttc
    • Linux: DejaVuSans-Bold / DejaVuSans → LiberationSans-Bold / LiberationSans-Regular
  4. Pillow’s default bitmap font (last resort — prints a warning, quality is reduced)
To use a custom typeface, copy your .ttf to scripts/font-bold.ttf (and optionally scripts/font.ttf), or set OVERLAY_FONT_PATH to the full path. All five renderers return PNG bytes. These are passed to bc.upload_media_local() to obtain a Blotato-hosted public URL for use in the mediaUrls of a post.

Custom images

When images: is provided in the command, AI generation and overlays are both skipped entirely.
  • Local paths are uploaded to Blotato with bc.upload_media_local() to get public URLs.
  • Public URLs are used as-is.
  • For Instagram carousel, all provided images are used as the carousel slides.
  • For Instagram single and LinkedIn, only the first image is used.

Error handling

The skill degrades gracefully when any part of the visual pipeline fails.
FailureWhat happens
fp.generate_image() raises an exceptionmedia_urls = [] for that platform; post publishes as text-only with an [aviso]
Pillow not installed (import PIL fails)[aviso] Pillow no instalado — publicando la base limpia de Mystic sin overlay. Proceeds with the clean Mystic URL
ov.render_*() raises an exceptionWarns, uses the clean Mystic URL as fallback
bc.upload_media_local() failsWarns, uses the Freepik CDN URL directly (note: Freepik URLs may expire; this is an acceptable fallback)
Carousel has fewer than 2 successful slidesDegrades to a single image using the first available slide
Freepik CDN URLs used as fallbacks are not permanently hosted and may expire. If bc.upload_media_local() fails consistently, check that you have not exceeded Blotato’s presigned upload rate limit (10 requests/minute).

Build docs developers (and LLMs) love