#!/usr/bin/env node /** * Post a 6-slide TikTok slideshow via Postiz API. * * Usage: node post-to-tiktok.js --config --dir --caption "caption text" --title "post title" * * Uploads slide1.png through slide6.png, then creates a TikTok slideshow post. * Posts as SELF_ONLY (draft) by default — user adds music then publishes. */ const fs = require('fs'); const path = require('path'); const args = process.argv.slice(2); function getArg(name) { const idx = args.indexOf(`--${name}`); return idx !== -1 ? args[idx + 1] : null; } const configPath = getArg('config'); const dir = getArg('dir'); const caption = getArg('caption'); const title = getArg('title') || ''; if (!configPath || !dir || !caption) { console.error('Usage: node post-to-tiktok.js --config --dir --caption "text" [--title "text"]'); process.exit(1); } const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); const BASE_URL = 'https://api.postiz.com/public/v1'; async function uploadImage(filePath) { const form = new FormData(); const blob = new Blob([fs.readFileSync(filePath)], { type: 'image/png' }); form.append('file', blob, path.basename(filePath)); const res = await fetch(`${BASE_URL}/upload`, { method: 'POST', headers: { 'Authorization': config.postiz.apiKey }, body: form }); return res.json(); } (async () => { console.log('šŸ“¤ Uploading slides...'); const images = []; for (let i = 1; i <= 6; i++) { const filePath = path.join(dir, `slide${i}.png`); if (!fs.existsSync(filePath)) { console.error(` āŒ Missing: ${filePath}`); process.exit(1); } console.log(` Uploading slide ${i}...`); const resp = await uploadImage(filePath); if (resp.error) { console.error(` āŒ Upload error: ${JSON.stringify(resp.error)}`); process.exit(1); } images.push({ id: resp.id, path: resp.path }); console.log(` āœ… ${resp.id}`); // Rate limit buffer if (i < 6) await new Promise(r => setTimeout(r, 1500)); } console.log('\nšŸ“± Creating TikTok post...'); const privacy = config.posting?.privacyLevel || 'SELF_ONLY'; const postRes = await fetch(`${BASE_URL}/posts`, { method: 'POST', headers: { 'Authorization': config.postiz.apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'now', date: new Date().toISOString(), shortLink: false, tags: [], posts: [{ integration: { id: config.postiz.integrationId }, value: [{ content: caption, image: images }], settings: { __type: 'tiktok', title: title, privacy_level: privacy, duet: false, stitch: false, comment: true, autoAddMusic: 'no', brand_content_toggle: false, brand_organic_toggle: false, video_made_with_ai: true, content_posting_method: 'UPLOAD' } }] }) }); const result = await postRes.json(); console.log('āœ… Posted!', JSON.stringify(result)); // Save metadata const metaPath = path.join(dir, 'meta.json'); const meta = { postId: result[0]?.postId, caption, title, privacy, postedAt: new Date().toISOString(), images: images.length }; fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2)); console.log(`šŸ“‹ Metadata saved to ${metaPath}`); })();