Skip to content

jaganganesh/quotes-content-engine

Repository files navigation

Quotes Content Engine

An automated quote-video engine for Instagram, TikTok, and YouTube.

It fetches a quote, selects a background image, picks a local background-music track, renders centered text over a dark gradient, and exports a 10-second vertical video. Platform payloads are generated in a shared structure modeled after anime-content-engine, while Instagram and YouTube workflows follow the publishing patterns from reels-engine and shorts-engine.

Architecture

The repository is organized around the same top-level split used in anime-content-engine:

  • config/constant.js for shared runtime constants
  • constants/ for fonts, music, image fallback, and platform definitions
  • services/ for quote fetch, image fetch, audio selection, rendering, video assembly, attribution formatting, and metadata generation
  • modules/ for platform-facing entrypoints and publisher integrations
  • scripts/ for local utility commands, including token helpers under scripts/tokens/
  • data/memory/ for per-platform content memory snapshots used to reduce recent repeats
  • .github/workflows/ for scheduled automation
  • utils/ for logging, env parsing, randomization, downloads, and delay helpers

Generation Flow

The shared automation flow does this:

  1. Fetch a quote from ZenQuotes with retry support
  2. Fetch a portrait background from Unsplash, or fall back to resources/images/background.jpg
  3. Pick a local background-music .wav file from resources/music
  4. Render a dark gradient text overlay
  5. Export a 10-second vertical MP4 with FFmpeg
  6. Build platform-aware metadata with structured attribution
  7. Record the generated content in per-platform memory after a successful publish

Generated files are written to:

  • output/<platform>.mp4
  • output/payload.<platform>.json
  • output/temp/

Payloads keep the existing video contract while now carrying:

  • a shared content object for future content types
  • structured image and audio attribution data
  • a backward-compatible sound alias for the selected background-music asset
  • platform-specific postContent fields for titles, descriptions, captions, tags, and hashtags

Platform Memory

Each remote platform keeps its own 90-day memory file in data/memory/:

  • youtube.json
  • instagram.json
  • tiktok.json

Duplicate checks happen before generation, but memory is only finalized after a successful publish. In GitHub Actions, the updated platform memory file is committed back to the repository so the memory survives across runs. Repository workflow permissions must allow contents: write for memory commits and issues: write for TikTok draft reminders.

Commands

npm install

# Local proof-of-concept generation only
npm run generate:local

# Generate platform packages
npm run generate:instagram
npm run generate:tiktok
npm run generate:youtube
npm run generate:all

# Publish flows used by GitHub Actions
npm run post:instagram
npm run post:tiktok
npm run post:youtube

# Local OAuth token helpers
npm run token:instagram
npm run token:tiktok
npm run token:youtube

# Cleanup
npm run flush:results
npm run memory:flush
npm run memory:flush:youtube
npm run memory:flush:instagram
npm run memory:flush:tiktok

# Formatting and linting
npm run format
npm run lint

Local Workflow Runs

If you want to run the GitHub Actions locally, use act.

Examples:

# TikTok generate-and-publish workflow
act workflow_dispatch -W .github/workflows/tiktok-post-content.yml \
  -s TIKTOK_CLIENT_KEY='your-client-key' \
  -s TIKTOK_CLIENT_SECRET='your-client-secret' \
  -s TIKTOK_REFRESH_TOKEN='your-refresh-token' \
  -s UNSPLASH_ACCESS_KEY='your-unsplash-key'

# YouTube generate-and-publish workflow
act workflow_dispatch -W .github/workflows/youtube-post-content.yml \
  -s CLIENT_SECRET_JSON='{"installed":{"client_id":"...","client_secret":"...","redirect_uris":["http://localhost"]}}' \
  -s REFRESH_TOKEN='your-refresh-token' \
  -s UNSPLASH_ACCESS_KEY='your-unsplash-key'

# Instagram generate-and-publish workflow
act workflow_dispatch -W .github/workflows/instagram-post-content.yml \
  -s INSTAGRAM_USER_ID='your-instagram-user-id' \
  -s INSTAGRAM_ACCESS_TOKEN='your-access-token' \
  -s UNSPLASH_ACCESS_KEY='your-unsplash-key'

The Instagram workflow now prefers resumable file upload from output/instagram.mp4, which avoids Meta needing to fetch a public video_url. GitHub release/CDN steps are only used when INSTAGRAM_UPLOAD_SOURCE=url. Artifact upload steps are still skipped in local act runs to avoid GitHub-only behavior.

Metadata Strategy

Metadata is now generated through a shared content pipeline with platform-specific strategy:

  • YouTube favors concise, keyword-aware titles and readable descriptions with attribution and a small hashtag set
  • Instagram favors polished captions with a readable hook, the quote, a light prompt, and a tighter hashtag mix
  • TikTok favors short, searchable captions with a compact hook and relevant niche hashtags

Hashtags are selected from platform-specific core and rotational pools, deduplicated, and kept intentionally small. The system avoids generic TikTok growth-bait tags like #fyp.

Environment Variables

UNSPLASH_ACCESS_KEY=

# Instagram publishing
INSTAGRAM_USER_ID=
INSTAGRAM_ACCESS_TOKEN=
INSTAGRAM_LONG_LIVED_ACCESS_TOKEN=
INSTAGRAM_SHORT_LIVED_ACCESS_TOKEN=
INSTAGRAM_APP_ID=
INSTAGRAM_APP_SECRET=
INSTAGRAM_UPLOAD_SOURCE=
INSTAGRAM_VIDEO_PATH=
INSTAGRAM_VIDEO_URL=

# YouTube publishing
CLIENT_SECRET_JSON=
REFRESH_TOKEN=
YOUTUBE_VIDEO_PATH=

# TikTok publishing
TIKTOK_CLIENT_KEY=
TIKTOK_CLIENT_SECRET=
TIKTOK_REFRESH_TOKEN=
TIKTOK_VIDEO_PATH=
TIKTOK_POST_TITLE=

# Optional local overrides
QUOTE_TEXT=
QUOTE_AUTHOR=
MUSIC_ID=

Workflows

  • instagram-post-content.yml Generates the reel and publishes it via the Instagram Graph API using resumable file upload by default. URL-based upload remains available when INSTAGRAM_UPLOAD_SOURCE=url.
  • youtube-post-content.yml Generates the short and uploads it directly through the YouTube Data API.
  • tiktok-post-content.yml Generates the TikTok-ready package, refreshes a user access token from TIKTOK_REFRESH_TOKEN, uploads the MP4 into TikTok draft flow, and creates or updates a GitHub issue when the draft is ready for manual publish.

Posting Schedule

GitHub Actions scheduled workflows run in UTC. The workflow cron expressions below are aligned to Pacific Daylight Time (UTC-7) and will shift by one hour during Pacific Standard Time unless the schedules are adjusted later.

Platform Intended PT Workflow UTC Cron DST Note
YouTube Tuesday 6:00 PM PT 0 1 * * 3 PDT-aligned; shifts during PST
YouTube Wednesday 7:00 PM PT 0 2 * * 4 PDT-aligned; shifts during PST
YouTube Friday 1:00 PM PT 0 20 * * 5 PDT-aligned; shifts during PST
YouTube Saturday 11:00 AM PT 0 18 * * 6 PDT-aligned; shifts during PST
TikTok Monday 6:00 PM PT 0 1 * * 2 PDT-aligned; shifts during PST
TikTok Tuesday 6:00 PM PT 0 1 * * 3 PDT-aligned; shifts during PST
TikTok Wednesday 6:00 PM PT 0 1 * * 4 PDT-aligned; shifts during PST
TikTok Thursday 6:00 PM PT 0 1 * * 5 PDT-aligned; shifts during PST
TikTok Friday 4:00 PM PT 0 23 * * 5 PDT-aligned; shifts during PST
Instagram Tuesday 5:00 PM PT 0 0 * * 3 PDT-aligned; shifts during PST
Instagram Wednesday 5:00 PM PT 0 0 * * 4 PDT-aligned; shifts during PST
Instagram Thursday 4:30 PM PT 30 23 * * 4 PDT-aligned; shifts during PST
Instagram Friday 4:00 PM PT 0 23 * * 5 PDT-aligned; shifts during PST
Instagram Saturday 11:00 AM PT 0 18 * * 6 PDT-aligned; shifts during PST
Instagram Sunday 1:00 PM PT 0 20 * * 0 PDT-aligned; shifts during PST

Notes

  • Logging uses structured JSON events through utils/logEvent.js
  • Metadata is generated through shared builders with platform-specific title, caption, description, hashtag, and tag strategies
  • Each remote platform keeps its own 90-day memory file under data/memory/ to reduce exact and near-duplicate posts
  • GitHub Actions commit only the relevant memory JSON file after a successful publish so memory persists across runs
  • If Unsplash is unavailable, the engine falls back to the bundled local background image
  • Instagram publishing defaults to INSTAGRAM_UPLOAD_SOURCE=file, which is more reliable in GitHub Actions because Meta does not need to fetch the reel from a public URL
  • TikTok uploads currently go to draft, and the workflow opens or updates a GitHub issue as the manual publish reminder
  • Close the TikTok draft issue after you review the draft in TikTok and publish it manually
  • TikTok may rotate the refresh token during token refresh; if the workflow logs a rotation warning, update the TIKTOK_REFRESH_TOKEN GitHub secret before the next run

Roadmap

  • Add optional Piper voiceover generation as a separate audio layer
  • Extend the audio mix stage to support background music plus voiceover output
  • Reuse the shared metadata and attribution pipeline for additional content types beyond quotes

About

Automated short-form video generation and publishing system that creates quote-based content with dynamic visuals, music, and metadata, and distributes it to YouTube, Instagram, and TikTok using GitHub Actions.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Contributors