makervox_publish
Post to TikTok, Facebook, Instagram and X from Python — with your own developer apps.
Writing the API calls is the easy part. Getting them to keep working is not — and this library's real content is the accumulated knowledge of what breaks:
TikTok's chunk count must use
floor, notceil, or files over 64MB fail withinvalid chunk count. Scopes are frozen at authorization, so adding one does nothing until the account is re-authorized — refreshing will not do it, and the error does not tell you that. A Facebook first comment posted too fast fails because the story object does not exist yet. Refresh tokens rotate on use, so two processes refreshing the same account destroys one of them, and recovery is a manual browser re-auth.
Each of those cost somebody a real outage. They are collected in docs/scar-tissue.md (why the defaults look paranoid) and docs/platform-limits.md (what no amount of code will fix).
| Platform | Post | Media | Notes |
|---|---|---|---|
| TikTok | ✅ | video | chunked upload, inbox + direct post, insights |
| ✅ | video, photo | reels, first comment retry | |
| ✅ | video, photo | reels, cover-frame selection | |
| X | ✅ | text, image | daily governor, deny-by-default allow-lists |
Missing a platform you have been approved for? That is the single most useful contribution — see CONTRIBUTING.md.
You bring your own developer apps. makervox_publish publishes to TikTok, Facebook,
Instagram and X using your TikTok app, your Meta app and your X app.
There is no shared application, no hosted OAuth broker, no account system and
no default that points at anyone else's domain or cloud project. Anything only
you can supply — an OAuth redirect URI, a media staging bucket, a cloud project
id — has no default and raises ConfigError rather than guessing.
It is a library first and a CLI second, with one runtime dependency
(requests) and optional extras for the things you may not want
(makervox-publish[gcp], makervox-publish[s3], makervox-publish[keyring], makervox-publish[toml],
makervox-publish[yaml]).
from makervox_publish import Config, Credentials
cfg = Config.load() # ./makervox-publish.toml, ~/.config/makervox-publish/…, /etc/makervox-publish/…
creds = Credentials.default() # environment variables; no file, no cloud, no network
values, missing = creds.require(["X_API_KEY", "X_API_SECRET"])
if missing:
print("not configured yet:", ", ".join(missing))
Install
GH=git+https://github.com/TheGringo-ai/makervox-publish
# library + CLI
pip install $GH
# TOML config on Python 3.9 / 3.10
pip install "makervox-publish[toml] @ $GH"
# optional credential + staging backends
pip install "makervox-publish[gcp,keyring] @ $GH"
Installed straight from the repository — this is not on PyPI. Pin a tag or a
commit if you want reproducible installs; main is what gets tested by CI.
Python 3.9 or newer. ffmpeg/ffprobe are optional: without them, cover-frame
selection, duration probing, short cuts and pre-upload transcodes are disabled
with one warning at startup instead of failing mid-publish.
Configure
Copy config.example.toml — every value in it is a fake
placeholder — to ./makervox-publish.toml, ~/.config/makervox-publish/makervox-publish.toml or
/etc/makervox-publish/makervox-publish.toml, or point MAKERVOX_PUBLISH_CONFIG at any path. Any
MAKERVOX_PUBLISH_-prefixed environment variable overlays the file:
MAKERVOX_PUBLISH_PLATFORMS__X__GOVERNOR__DAILY_CAP=2
The config file holds secret NAMES, never secret VALUES. Every
*_credential key names something the credential chain resolves — an
environment variable by default. That makes the file safe to commit; your
tokens are not, and .gitignore here refuses both by default.
What it is careful about
The defaults encode failures that have actually happened, not hypotheticals:
- A filename is not an identity. A scheduler that renders the same content
type twice in one day overwrites the first file, so two genuinely different
videos share one name. Dedupe is on
(account, date, key, slot, content hash), hashed from the source media, and it says so out loud when it cannot resolve an identity instead of silently disabling itself. - Deduplication happens inside the publish lock. A lock only serializes callers; the second caller wakes up and publishes the same reel again unless the check is re-run after acquiring it.
- Refresh tokens that rotate on use are treated as unrecoverable. The refresh is serialized, re-read inside the lock so the loser adopts the winner's token instead of spending its own, and written to local disk before anything that can time out.
- Allow-lists deny by default. An empty X account allow-list means post nothing, because a shared publish path otherwise grants posting rights to anything that passes through it.
- Nothing is swallowed silently. Every deliberate
exceptthat continues anyway logs its reason; a cover frame is never worth failing a post over, but a cover frame that vanished without a word is how a profile grid ends up a wall of black thumbnails. - Nothing is created on import. Loading a config on a fresh machine touches
no socket, no subprocess and no
$HOME. Directories appear on first write.
docs/scar-tissue.md records the incident behind each of these;
docs/platform-limits.md records the vendor realities that no amount of code
will fix (scopes are frozen at authorization, Instagram can only pull media by
URL and cannot attach a trending sound, reels report plays and not reach).
Layout
Strictly one-directional layering, with no lazy imports anywhere:
config / credentials / state / media / text / identity / http
<- platforms
<- cli
media/cover.py is the clearest example of why: both Meta publishers need a
cover offset, so cover_offset_ms() lives a layer below both of them and
neither owns it. Putting it inside one publisher is what produced the circular
import in the code this package was extracted from.
Contributing
The most valuable contributions are corrections to docs/platform-limits.md — platform tiers and error strings change constantly and that file decays without help — and setup write-ups for platforms you have personally got through review. See CONTRIBUTING.md.
License
MIT © Fred Taylor. This is a deliberate relicense of proprietary source; no account names, domains, cloud project ids or marketing copy crossed the boundary.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file makervox_publish-0.1.0.tar.gz.
File metadata
- Download URL: makervox_publish-0.1.0.tar.gz
- Upload date:
- Size: 167.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1413e0c115aaf9aa9e6db732e1c4ee4ee215bfe74640226a4593e214f9078e8f
|
|
| MD5 |
6c67c8118b9acce4b81f9b8ccb5afaed
|
|
| BLAKE2b-256 |
8e819a0ffd6baa7c651f2bf4ea667e1b5924ef1a4dd80f6321c625378701b628
|
Provenance
The following attestation bundles were made for makervox_publish-0.1.0.tar.gz:
Publisher:
release.yml on TheGringo-ai/makervox-publish
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
makervox_publish-0.1.0.tar.gz -
Subject digest:
1413e0c115aaf9aa9e6db732e1c4ee4ee215bfe74640226a4593e214f9078e8f - Sigstore transparency entry: 2742818597
- Sigstore integration time:
-
Permalink:
TheGringo-ai/makervox-publish@a27f12100b525c2d5649c31b41608ea68303cd1d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/TheGringo-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a27f12100b525c2d5649c31b41608ea68303cd1d -
Trigger Event:
release
-
Statement type:
File details
Details for the file makervox_publish-0.1.0-py3-none-any.whl.
File metadata
- Download URL: makervox_publish-0.1.0-py3-none-any.whl
- Upload date:
- Size: 180.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9356ac4e7d74c4132d110316b1ac54dd8ee84393731bf66507ab5acca3b3bc91
|
|
| MD5 |
00fe7116b1c60ee86343787f230af545
|
|
| BLAKE2b-256 |
9358721d0d4e2d9386731a72789da7fa71a34533f77abe6190a167d1597dc416
|
Provenance
The following attestation bundles were made for makervox_publish-0.1.0-py3-none-any.whl:
Publisher:
release.yml on TheGringo-ai/makervox-publish
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
makervox_publish-0.1.0-py3-none-any.whl -
Subject digest:
9356ac4e7d74c4132d110316b1ac54dd8ee84393731bf66507ab5acca3b3bc91 - Sigstore transparency entry: 2742818916
- Sigstore integration time:
-
Permalink:
TheGringo-ai/makervox-publish@a27f12100b525c2d5649c31b41608ea68303cd1d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/TheGringo-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a27f12100b525c2d5649c31b41608ea68303cd1d -
Trigger Event:
release
-
Statement type: