A desktop-first workflow for preparing photography posts, generating or polishing captions, scheduling them locally or online, and publishing to multiple social platforms with operational checks.
Scope note: this page documents the implemented workflow and verified behavior. It intentionally does not publish API tokens, SMTP secrets, full source files, or credential-bearing configuration.
Posting photography sets manually across several platforms creates repeated work and repeated risk: captions can drift, platform selections can be missed, schedules depend on the computer being on, and partial failures are hard to track cleanly.
Objective: keep the creative review step manual, but automate the repetitive operational work around scheduling, publishing, logging, email reporting, and cleanup.
The workflow is deliberately staged. The tool does not immediately post from a folder scan. It first builds a reviewed Post 1 queue, then saves a scheduled record with captions, selected platforms, image references, and status fields.
The local workflow keeps the full desktop experience available through the Social Media Picker and a Windows scheduled task.
social_media_picker.py, a Tkinter desktop application.autopost_runner.py, used by the local AutoPost task.social_media_history.db, used for saved sessions, scheduled records, posted records, and restore flows.Social Media Picker.vbs, used to open the app without the extra PowerShell window.mail_secrets.php outside the public case-study content.Confirmed local behavior includes session save/restore, history view, caption generation, ChatGPT polish, scheduled posting, and HTML email summaries after post runs.
The online scheduler removes the requirement that the local computer stays on at the posting time. The desktop app exports a queue package, uploads it by FTP, and a Hostinger PHP cron processes due items.
cron.php under the online social_autopost folder.data/queue.Europe/Amsterdam.contact@amir2000.nl.data/archive/posted and temporary media/post_ID folders are removed..htaccess rules.The online queue carries only the operational data needed for the run: schedule time, timezone, selected platforms, captions, media references, source references, and platform results.
{
"id": "post_ID",
"local_post_id": 0,
"status": "scheduled",
"scheduled_for": "YYYY-MM-DD HH:MM",
"timezone": "Europe/Amsterdam",
"platforms": ["FB Page", "Instagram", "Threads", "Tumblr", "Mastodon"],
"media": [
{
"filename": "image.jpg",
"relative_path": "media/post_ID/image.jpg",
"public_url": "https://www.amir2000.nl/..."
}
],
"platform_results": {}
}
The confirmed auto-post targets are FB Page, Instagram, Threads, Tumblr, and Mastodon. X remains visible in the UI but intentionally unchecked and disabled for auto-posting because automated posting requires paid API access.
Split rules currently implemented:
The scheduler treats every platform result separately instead of assuming that a post is all-or-nothing. This matters because real platform APIs can return transient failures or token/authentication errors.
needs_attention so the scheduler does not retry forever.partial first, then completed successfully on the next cron pass.A confirmed 18:00 online run posted successfully to all selected targets after a second cron pass for Tumblr. The final cron state archived the posted JSON and removed the matching online media folder.
The interface screenshots below show the main operating surface, the date/time picker, and the online scheduling path.
This public case study should not include the full code. The full implementation contains configuration paths, platform integration details, and operational wiring that should stay private or be shared only in a cleaned repository.
Best public approach:
Known boundary: caption quality tuning remains an improvement area, and X auto-posting is intentionally disabled because of paid API access requirements.