{"slug": "i-automated-a-tiktok-campaign-for-my-app-by-editing-capcut-s-project-files", "title": "I Automated a TikTok Campaign for My App by Editing CapCut's Project Files Directly", "summary": "A developer built Judge Me, an Android app for voting on \"Am I the jerk?\"-style dilemmas, and automated a 14-day TikTok and Instagram Reels campaign by directly editing CapCut's draft_content.json project files. The pipeline uses edge-tts word-boundary timestamps to generate word-timed captions, re-aligning bare timed words against the punctuated script to fix captions that bled across sentences, and programmatically assembles hook text, background clips, voiceover, and a vote-screen outro. The stated goal is 500+ Play Store installs in 14 days or a single video exceeding 50k views.", "body_md": "I shipped **Judge Me**, a small Android app where people read \"Am I the jerk?\"-style dilemmas and vote: *you were right*, *you were wrong*, *both of you messed up*, or *it's complicated*. The app works. Nobody knows it exists.\n\nSo I'm running a 14-day experiment: short vertical videos on TikTok and Instagram Reels, one per day, each telling one dilemma from the app and ending with \"go vote.\" The goal is simple and measurable: **500+ Play Store installs in 14 days, or one video over 50k views.** If neither happens, I stop and try something else.\n\nThis post is about the boring-but-interesting part: how I made producing a video take ~5 minutes of my time instead of an hour, with no paid tools.\n\nEach video looks like this:\n\n| Time | What's on screen | \n|---|---|\n| 0–2 s | Big hook text (first sentence of the story) | \n| 2 s → end−4 s | Background clip + AI voiceover + 2–3 word captions | \n| Last 4 s | \"Right or wrong? YOU decide.\" + screenshot of the app's vote screen | \n\nScripts are 100–130 words, first person, short sentences, ending with \"So… was I wrong?\". I use [edge-tts](https://github.com/rany2/edge-tts), which is free and — crucially — streams **word boundary events** with timestamps alongside the audio.\n\n```\ncomm = edge_tts.Communicate(text, \"en-US-GuyNeural\", rate=\"+12%\", boundary=\"WordBoundary\")\nasync for chunk in comm.stream():\n    if chunk[\"type\"] == \"audio\":\n        f.write(chunk[\"data\"])\n    elif chunk[\"type\"] == \"WordBoundary\":\n        start = chunk[\"offset\"] // 10_000  # 100ns ticks → ms\n        words.append({\"text\": chunk[\"text\"], \"start_ms\": start,\n                      \"end_ms\": start + chunk[\"duration\"] // 10_000})\n```\n\nThat gives me an MP3 plus a JSON list of every word and when it's spoken. Captions come for free.\n\nMy first captions looked like `star She launched` and `reviews So I` — chunks bleeding across sentences. The boundary events return bare words, so my \"break on punctuation\" rule never fired.\n\nFix: re-align the timed words against the original script tokens (which do have punctuation), then chunk in two passes — split on clause boundaries first, then divide each clause into balanced groups so you never get a lonely one-word chunk:\n\n``` python\ndef chunk_words(words, max_words=3, max_chars=20):\n    clauses, cur = [], []\n    for w in words:\n        cur.append(w)\n        if w[\"text\"][-1:] in \".!?,;:…\":\n            clauses.append(cur); cur = []\n    if cur: clauses.append(cur)\n\n    chunks = []\n    for cl in clauses:\n        k = -(-len(cl) // max_words)          # ceil\n        while True:                            # balance sizes, respect char limit\n            size, extra = divmod(len(cl), k)\n            parts, i = [], 0\n            for j in range(k):\n                step = size + (j < extra)\n                parts.append(cl[i:i+step]); i += step\n            if all(len(\" \".join(x[\"text\"] for x in p)) <= max_chars for p in parts) or k >= len(cl):\n                break\n            k += 1\n        chunks.extend(parts)\n    return chunks\n```\n\nBefore: `They showed up | late.`\n\nAfter: `They showed | up late.`\n\nSmall thing, but captions are most of what people actually read on mute.\n\nThis is the part that made the whole pipeline possible. CapCut desktop stores each project as a folder containing `draft_content.json` — tracks, segments, materials, text styles, all in plain JSON. (Some versions encrypt it; mine, 9.6 on Windows, didn't. **Check yours before building on this.**)\n\nThe structure, simplified:\n\n```\ntracks[]            → video / audio / text tracks, each with segments[]\nsegments[]          → material_id + target_timerange {start, duration} in µs + clip transform\nmaterials.texts[]   → text content (as an embedded JSON string!) + style\nmaterials.videos[]  → file paths for clips and images\nmaterials.audios[]  → file paths for audio\n```\n\nMy approach:\n\n`HOOK_TEXT`, `SUB_1`, `VOTE_TEXT`, plus the background, audio, and vote-screen image.\nThe one non-obvious detail: the text content lives in a JSON *string* inside the JSON, with a character `range` for styling. Change the text without updating the range and the styling breaks.\n\n``` python\ndef set_text(mat, text):\n    c = json.loads(mat[\"content\"])\n    c[\"text\"] = text\n    for st in c[\"styles\"]:\n        st[\"range\"] = [0, len(text)]\n    mat[\"content\"] = json.dumps(c, ensure_ascii=False)\n```\n\nThen I open CapCut, glance at the timeline, and hit Export. That's my whole manual step.\n\nOnce one video worked, I generated 10 separate CapCut projects in one go — copy the template folder, give it a new `draft_id`, register it in CapCut's `root_meta_info.json`, render the content. CapCut picked them all up in its project list. Ten videos, ten exports, done in one sitting.\n\n`.locked` file in the project folder tells you it's open.\nMy first attempt was to have an AI agent with desktop control build the template inside CapCut by clicking. It was slower and flakier than I expected: CapCut's media panel didn't respond to synthetic mouse events at all (couldn't drag a text layer onto the timeline), and the agent's own window kept stealing focus. After a few rounds I switched to \"just edit the files,\" which took less time than the clicking attempts had.\n\nLesson: if an app has a readable file format, editing the file beats automating the UI almost every time.\n\nPlan said \"link in bio.\" TikTok said no — clickable bio links need 1,000 followers on a personal account, and the business account switch wasn't available to me without verification. Plain-text URLs in the bio aren't clickable.\n\nSo the end card now says **\"Vote free: search 'Judge Me AITA' on Google Play\"** — I checked that exact search ranks the app first. The downside: I lose UTM attribution on TikTok and have to infer it from Play Console's search-traffic numbers. Instagram still gets a proper tracked link.\n\nThe experiment starts this week. I'll post the results — views, installs, what hooks worked, and whether 03:00 scheduling actually mattered — when the 14 days are up, including if it flops.\n\nIf you're an indie dev sitting on an app nobody knows about, the takeaway isn't \"use CapCut.\" It's: **find the fixed structure in your marketing content, and turn the repetitive part into data.**\n\n*Judge Me is on [Google Play](https://play.google.com/store/apps/details?id=com.noktastudio.judgeme&referrer=utm_source%3Ddevto). I build in public as [@fatihbuilds](https://x.com/fatihbuilds).*", "url": "https://wpnews.pro/news/i-automated-a-tiktok-campaign-for-my-app-by-editing-capcut-s-project-files", "canonical_source": "https://dev.to/fatihbuilds/i-automated-a-tiktok-campaign-for-my-app-by-editing-capcuts-project-files-directly-2bog", "published_at": "2026-10-19 19:23:29+00:00", "updated_at": "2026-10-19 19:44:39.725144+00:00", "lang": "en", "topics": ["ai-tools"], "entities": ["Judge Me", "CapCut", "TikTok", "Instagram Reels", "Google Play", "edge-tts"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/i-automated-a-tiktok-campaign-for-my-app-by-editing-capcut-s-project-files", "markdown": "https://wpnews.pro/news/i-automated-a-tiktok-campaign-for-my-app-by-editing-capcut-s-project-files.md", "text": "https://wpnews.pro/news/i-automated-a-tiktok-campaign-for-my-app-by-editing-capcut-s-project-files.txt", "jsonld": "https://wpnews.pro/news/i-automated-a-tiktok-campaign-for-my-app-by-editing-capcut-s-project-files.jsonld"}}