[object Object]

← back to Dw Slideshow Gen

postiz: multi-channel draft staging (--channel all|a,b), pickIntegrations, single upload fanned to N channels

95bb63bc3564a405e2abb763baa20fcad52d1675 · 2026-06-29 10:50:08 -0700 · Steve Abrams

Files touched

Diff

commit 95bb63bc3564a405e2abb763baa20fcad52d1675
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 29 10:50:08 2026 -0700

    postiz: multi-channel draft staging (--channel all|a,b), pickIntegrations, single upload fanned to N channels
---
 index.js    |  7 ++++---
 lib/post.js | 22 ++++++++++++----------
 2 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/index.js b/index.js
index 3610110..a1e7da4 100644
--- a/index.js
+++ b/index.js
@@ -104,12 +104,13 @@ if (cmd === 'post') {
     console.error(`  [post] ${pkg.spec_id}: local draft package (${pkg.slides} slides) -> ${pkg.zipPath || pkg.pkgDir}  ($0, no network)`)
     if (!a.postiz) continue
     const r = await stageToPostiz(dir, process.env, { confirm: a.confirm, channel: a.channel, schedule: a.schedule })
+    const chNames = (r.channels || []).map(c => `${c.identifier}(${c.name})`).join(', ')
     if (r.gated) console.error(`  [post] ${pkg.spec_id}: Postiz skipped — ${r.reason}`)
     else if (r.error) console.error(`  [post] ${pkg.spec_id}: Postiz error — ${r.error}`)
     else if (r.dryRun) {
-      console.error(`  [post] ${pkg.spec_id}: DRY-RUN ${r.type} → ${r.channel.identifier} (${r.channel.name}), ${r.images} images. Add --confirm to stage. Body:`)
-      console.error('  ' + JSON.stringify(r.body).replace(/\n/g, ' ').slice(0, 600))
-    } else if (r.staged) console.error(`  [post] ${pkg.spec_id}: Postiz ${r.type} STAGED → ${r.channel.identifier} (${r.channel.name}) postId=${r.postId} — review/publish at platform.postiz.com`)
+      console.error(`  [post] ${pkg.spec_id}: DRY-RUN ${r.type} → ${chNames}, ${r.images} images. Add --confirm to stage. Body:`)
+      console.error('  ' + JSON.stringify(r.body).replace(/\n/g, ' ').slice(0, 700))
+    } else if (r.staged) console.error(`  [post] ${pkg.spec_id}: Postiz ${r.type} STAGED → ${chNames} postIds=${(r.postIds || []).join(',')} — review/publish at platform.postiz.com`)
   }
   console.error([
     '',
diff --git a/lib/post.js b/lib/post.js
index af45846..840385c 100644
--- a/lib/post.js
+++ b/lib/post.js
@@ -73,29 +73,31 @@ export async function stageToPostiz(renderDir, env, opts = {}) {
   const dateISO = opts.schedule || new Date().toISOString()
   const client = new Postiz(apiKey)
 
-  // pick channel (read-only)
-  let integration
+  // pick channel(s) (read-only). --channel all|a,b -> multiple
+  let chosen
   try {
     const list = await client.integrations()
-    integration = pickIntegration(list, opts.channel)
+    chosen = pickIntegrations(list, opts.channel)
   } catch (e) { return { staged: false, error: `integrations: ${e.message}` } }
-  if (!integration) return { staged: false, gated: true, reason: 'no connected channels — connect TikTok in Postiz first' }
+  if (!chosen.length) return { staged: false, gated: true, reason: 'no connected channels — connect a channel in Postiz first' }
 
+  const ids = chosen.map(c => c.id)
+  // schedule needs per-provider settings, so it only supports ONE channel here; draft is multi.
   const mkBody = media => opts.schedule
-    ? buildScheduleBody({ integrationId: integration.id, identifier: integration.identifier, content, media, dateISO, tiktok: opts.tiktok })
-    : buildDraftBody({ integrationId: integration.id, content, media, dateISO })
+    ? buildScheduleBody({ integrationId: ids[0], identifier: chosen[0].identifier, content, media, dateISO, tiktok: opts.tiktok })
+    : buildDraftBodyMulti({ integrationIds: ids, content, media, dateISO })
 
   // dry-run: show the body with placeholder media, no upload, no post
   if (!opts.confirm) {
     const placeholder = m.png_paths.map((p, i) => ({ id: `<upload_${i + 1}>`, path: `https://uploads.postiz.com/${path.basename(p)}` }))
-    return { staged: false, dryRun: true, channel: integration, type: opts.schedule ? 'schedule' : 'draft',
+    return { staged: false, dryRun: true, channels: chosen, type: opts.schedule ? 'schedule' : 'draft',
       images: m.png_paths.length, body: mkBody(placeholder) }
   }
 
-  // live: upload each PNG, then create the post
+  // live: upload each PNG once (shared across channels), then create the post
   const media = []
   for (const p of m.png_paths) media.push(await client.upload(p))
   const created = await client.createPost(mkBody(media))
-  const postId = Array.isArray(created) ? created[0]?.postId || created[0]?.id : created.id || created.postId
-  return { staged: true, type: opts.schedule ? 'schedule' : 'draft', channel: integration, postId, raw: created }
+  const ids2 = (Array.isArray(created) ? created : [created]).map(x => x?.postId || x?.id).filter(Boolean)
+  return { staged: true, type: opts.schedule ? 'schedule' : 'draft', channels: chosen, postIds: ids2, raw: created }
 }

← 5481d94 auto-save: 2026-06-29T10:48:32 (4 files) — lib/post.js lib/p  ·  back to Dw Slideshow Gen  ·  postiz: per-provider settings in draft body (hosted API requ 0b44dfb →