Automated YouTube Pipeline: Python, edge-tts, and MoviePy A developer built a zero-cost automated YouTube pipeline using Python, Microsoft's edge-tts neural TTS, and MoviePy 1.0.3 to create faceless videos for the SaaS product WhaleTrack, turning live site data into 1080p videos without a production budget. The workflow uses Puppeteer for live screenshots, edge-tts with the 'Andrew' voice for audio, and a custom Ken Burns effect for dynamic visuals, all assembled via MoviePy. Automated YouTube Pipeline: Python, edge-tts, and MoviePy Zero cost and one day of coding is all it took to build a faceless YouTube channel for my SaaS, WhaleTrack. Instead of messing with Premiere or hiring a designer, I just scripted the whole thing to turn live site data into videos. The Tech Stack edge-tts : Microsoft's neural TTS. I used the 'Andrew' voice—it's free, doesn't need an API key, and sounds surprisingly human. moviepy 1.0.3 : For the heavy lifting of video assembly. Pillow : Handles the image processing. Puppeteer : Used to grab high-res screenshots of the live site. ffmpeg : The engine under the hood. The Workflow 1. Capturing Visuals I didn't want static mockups, so I used Puppeteer to screenshot the actual site. js const puppeteer = require 'puppeteer' ; const browser = await puppeteer.launch ; const page = await browser.newPage ; await page.setViewport { width: 1920, height: 1080 } ; await page.goto 'https://whaletrack.app' ; await page.screenshot { path: 'screenshots/home.png' } ; Pro tip: If your package.json is set to "type": "module", require will crash. Just name your file .cjs to avoid the headache.2. Generating Audio The edge-tts library is a hidden gem for this. python import edge tts comm = edge tts.Communicate script, voice='en-US-AndrewNeural', rate='+8%' await comm.save 'audio.mp3' 3. Adding Movement Ken Burns Effect Static images kill retention. I wrote a helper function to add a slow zoom and pan, making the screenshots feel like dynamic b-roll. python def apply ken burns img, progress, zoom from, zoom to, pan from, pan to : zoom = zoom from + zoom to - zoom from progress iw, ih = img.size crop w, crop h = int iw / zoom , int ih / zoom ox = int pan from 0 + pan to 0 - pan from 0 progress iw - crop w oy = int pan from 1 + pan to 1 - pan from 1 progress ih - crop h return img.crop ox, oy, ox + crop w, oy + crop h .resize 1920, 1080 , Image.LANCZOS 4. Final Assembly I used MoviePy to glue the generated audio and the animated frames together. python from moviepy.editor import VideoClip, AudioFileClip def make frame t : progress = t / duration frame = apply ken burns bg image, progress, 1.0, 1.12, 0,0 , 0.03,0.02 return np.array frame clip = VideoClip make frame, duration=duration clip = clip.set audio AudioFileClip 'audio.mp3' The result is a full 1080p video produced entirely by a Python script. It's a solid AI workflow for anyone wanting to scale content without a production budget. Next World-Model-Optimizer: Cutting LLM Costs via Distillation → /en/threads/3913/ All Replies (3) G Have you considered how render determinism will affect this? Live screenshots are honest, but a tiny CSS tweak could break tomorrow's video. I prefer using saved screenshot fixtures in the pipeline, then running a separate refresh-assets step only when intentional site changes happen. 0 J Did something similar with a news bot, but moviepy can be a pain with memory leaks. 0 M how are you handling the subtitles? moviepy usually makes those a nightmare to align. 0