IntegrationsAdvanced

How to Build an End-to-End Script-to-Upload Pipeline with Claude and the API

Stitch script writing, metadata generation, captioning, and upload into one command that takes a topic and a video file.

12 minAdvanced

Each earlier guide handled one step. This one connects them: given a topic and a finished MP4, a single command drafts a script for reference, generates the title and description, transcribes captions, uploads the video, and attaches the SRT. It is the assembly line for a one-person channel.

What you need

  • Completed setup from the API key, upload, scripting, and captions guides
  • An Anthropic API key and client_secret.json in the folder
  • Whisper and ffmpeg installed
  • A topic string and the path to your rendered MP4

Step 1: Outline the flow

The orchestrator calls helpers you already wrote. Keeping each step in its own function means one failure (say captions) does not lose the upload, and you can re-run a single stage.

pipeline flow
topic + final.mp4
|
1. Claude -> title + description (JSON)
2. Whisper -> final.srt
3. API -> upload video (private)
4. API -> attach caption track
5. print -> Studio link
One command moves a topic and file through five stages.

Step 2: Generate metadata with Claude

Ask Claude for the title and description as JSON so the rest of the pipeline can use them without parsing prose.

pipeline.py
import os, json, subprocess
from anthropic import Anthropic
from googleapiclient.http import MediaFileUpload
from upload import service  # auth helper from the upload guide

ai = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

def metadata(topic):
    msg = ai.messages.create(
        model="claude-opus-4-5", max_tokens=600,
        system="Return JSON {title (<60 chars), description}.",
        messages=[{"role": "user", "content": f"Video topic: {topic}"}],
    )
    return json.loads(msg.content[0].text)

Step 3: Caption, upload, and attach

Shell out to Whisper for the SRT, upload the video with the generated metadata, then insert the caption track against the new video id.

pipeline.py
def run(topic, mp4):
    meta = metadata(topic)

    srt = mp4.rsplit(".", 1)[0] + ".srt"
    subprocess.run(["whisper", mp4, "--model", "small",
                    "--output_format", "srt"], check=True)

    yt = service()
    body = {
        "snippet": {"title": meta["title"],
                    "description": meta["description"], "categoryId": "22"},
        "status": {"privacyStatus": "private"},
    }
    media = MediaFileUpload(mp4, chunksize=-1, resumable=True)
    req = yt.videos().insert(part="snippet,status", body=body, media_body=media)
    res = None
    while res is None:
        _, res = req.next_chunk()
    vid = res["id"]

    cap_body = {"snippet": {"videoId": vid, "language": "en",
                            "name": "English (Whisper)", "isDraft": False}}
    yt.captions().insert(part="snippet", body=cap_body,
        media_body=MediaFileUpload(srt, mimetype="application/octet-stream")).execute()

    print("Live (private):", f"https://studio.youtube.com/video/{vid}/edit")

if __name__ == "__main__":
    run("Fixing a wobbly chair in 10 minutes", "final.mp4")
zsh — pipeline
$python pipeline.py
Writing SRT: final.srt
uploading... 100%
Live (private): https://studio.youtube.com/video/dQw4w9WgXcQ/edit
$
Watch your daily quota
One run spends roughly 1,600 units on the upload plus around 400 on the caption insert. Two or three full runs is fine on the default 10,000 unit budget; a daily batch may need a quota increase.
Always review before publishing
The pipeline leaves the video Private on purpose. Open the Studio link, check the title, thumbnail, and captions, then publish or schedule with publishAt.

Result

A single command takes a topic and a file and returns a Studio link to a captioned, titled, private video ready for your final review. Wrap it in a loop over a folder and you have a true publishing assembly line.

Watch related tutorials

Tags
#pipeline#claude#api#automation#youtube