- Python 95.6%
- HTML 3%
- CSS 0.8%
- Shell 0.4%
- Batchfile 0.1%
- Other 0.1%
| app | ||
| installer | ||
| scripts | ||
| tests | ||
| tools | ||
| .gitattributes | ||
| .gitignore | ||
| .woodpecker.yml | ||
| build.bat | ||
| build.sh | ||
| CHANGELOG.md | ||
| FAQ.md | ||
| install.sh | ||
| launch-ui.bat | ||
| launch-ui.sh | ||
| pytest.ini | ||
| README.md | ||
| RELEASING.md | ||
| requirements.txt | ||
| requirements_dev.txt | ||
| runtime_hook_encoding.py | ||
| test_installation.py | ||
| tumblockr.ico | ||
| tumblockr.py | ||
| tumblockr.spec | ||
tumblockr
Automatically block every Tumblr account that has liked posts you specify. Useful for moderating large fandom posts, organizing pre-emptive blocks of accounts that engage with content you want to avoid, or just keeping your dashboard clean.
Get it
Windows: download tumblockr-<version>-setup.exe from the releases page and run it. It installs for your user only (no admin prompt), adds a Start-menu entry, and can register itself to start when you sign in. If you would rather not install anything, tumblockr-windows.zip holds the same program as a folder: unpack it and run tumblockr-windows\tumblockr.exe. Either way the program lives in the system tray: double-click the icon to open the UI, and quit from its menu. Launching it while it is already running just opens the running UI. For commands from a terminal, use tumblockr-cli.exe next to it.
Linux: download tumblockr-linux.zip, unpack it, and run tumblockr-linux/tumblockr; or run install.sh from this repository, which does that and puts tumblockr on your PATH. The build needs glibc 2.28 or newer, which any mainstream distribution released since 2019 has.
macOS: no prebuilt download; run from source as below.
If you're running from source instead (Python 3.11 or newer):
pip install -r requirements.txt
python tumblockr.py
(or use the included launch-ui.bat / launch-ui.sh helpers.)
The first launch opens a browser-based setup wizard that walks you through registering a Tumblr OAuth app, pasting in your credentials, authorizing your blog, and adding your first post to monitor.
Two ways to use it
- Web UI —
tumblockr ui. Single-user, runs locally on127.0.0.1:5000(no auth, no network exposure unless you opt in with--bind 0.0.0.0). This is the everyday interface, and the only place for scheduler intervals, the rate-limit meter, automatic backups, update checks and starting with Windows. - CLI —
tumblockr <command>. Runtumblockr --helpfor the full list. A few things are CLI-only: importing a whitelist from a file,export file --include-metadata, and the finer-grainedbackup createswitches.
Both interfaces share the same database and run the same backend code, so you can mix and match freely.
Features
Monitoring & blocking
- Monitor one or more posts per blog; every user who likes a monitored post gets queued for blocking.
- Or monitor a whole blog or a tag: its new original posts are added as they appear (checked at most hourly), and its newest 50 stay monitored. Reblogs are skipped (they carry the original post's notes), and so are your own blogs. CLI:
tumblockr monitor blog <name>ortumblockr monitor tag <tag>. - With more posts than one check can afford, each check picks up where the previous one stopped and wraps around, so every post gets its turn.
- Posts that have gone quiet are checked less often: after a quarter of the time since their newest note, and at least once a day, or every three days once a post has been quiet for two weeks. A new note puts a post back on every check. A post whose note count has not moved since its notes were read is not read again, but every post is read at least daily. On by default; switch it off in Settings.
- Background scheduler runs at user-configurable intervals (defaults: fetch likers every 60 min, drain queue every 15 min).
- Rate-limit handling with persistent state, scoped to what Tumblr actually limited: a per-endpoint cooldown pauses only the blog that hit it, while a limit on the OAuth app as a whole pauses every blog, since they all share it.
- Idempotency guard: users already blocked on a blog never re-hit the API.
- Likers are tracked by Tumblr's stable blog id as well as their name, so a rename between the like and the block cannot send the block to the wrong blog.
- A name Tumblr refuses to block is tracked down and set aside after a second try, instead of holding up everyone queued behind it; the Queue page shows it. A blog deleted since it was queued, or a typo in an imported file, is not refused: Tumblr blocks the rest of the batch and skips it without a word, and the next sync, not finding it on the list, drops its record.
- Your own blogs are never queued or blocked, even if they like a monitored post. That covers every blog on the accounts you've signed in with, sideblogs and group blogs included, and the list is checked weekly, and again at once when a block batch fails the way a batch naming one of them does. Tumblr answers a block batch that includes any blog on the blocking account with an error, which the app used to retry forever.
- Blocks go out 100 names per call.
- Unblock someone from the Blocked page, on Tumblr and here. "Unblock and whitelist" also keeps their next like from queuing them again.
- Post identifiers accept any of:
blog|post_id,blog.tumblr.com/post/id,tumblr.com/blog/id, or justblog/id— paste straight from your address bar.
Rename resilience
- Renaming a blog on Tumblr does not break anything. Blogs are addressed by
Tumblr's stable
uuid, which a rename cannot change, and the stored name is healed automatically off the 404 a rename would otherwise cause - no polling, no extra API calls in normal operation. - Never guesses: a rename is only applied when it can be proved (matching uuid, or exactly one unaccounted-for blog on both sides). Anything ambiguous is flagged for you instead of relinking one blog's block history to another.
- A blog Tumblr no longer lists is paused rather than retried forever, and said so on the dashboard.
Multi-blog support
- Manage multiple blogs you own from one install. Each blog has its own queue, blocked list, and monitored posts.
- Authorize once per Tumblr account: authorizing a blog also authorizes its sideblogs here, and a sideblog added later is already authorized. A group blog keeps its own authorization.
- Blogs on the same Tumblr account that monitor the same post share one read of its notes.
Whitelist
- Per-blog do-not-block list. Optional auto-populate from blogs you follow: a followed blog that likes a monitored post is whitelisted on sight, a blog you unfollow comes off again, and switching the option off takes back everything it added. Entries you added yourself always stay. Blogs on the same Tumblr account share one read of its follow list.
- A whitelisted blog that renames stays protected: entries are matched by Tumblr's stable blog id once one of its likes has shown it, and take the new name.
- Bulk import via paste or file.
Importing
- Queue usernames in bulk from a text file (one per line, or comma/space separated).
- CSV and detailed block list exports carry each blog's stable id beside its name, so a list you share still finds blogs that have renamed since; imports and subscriptions read it back.
- Subscribe a blog to a block list someone shares at a web address (a text or CSV file: a raw GitHub file, a spreadsheet's CSV export). Its users are queued at once, and anyone it adds when it is checked again each week. Each user is queued once, so one you unblock stays unblocked; unsubscribing removes its users from the queue. CLI:
tumblockr import subscribe <url>. - Copy a block list from another blog you own (experimental - it needs a second Tumblr account to exercise, so it has seen much less testing; imports only ever fill the queue, which you can clear). It reads the list at the same pace, and within the same API budget, as a sync.
Sync
- Pull your existing Tumblr block list into the local DB (so the UI's "blocked" view matches what Tumblr actually has).
- Resumable: a sync interrupted by rate-limiting picks up where it left off.
- Paced to Tumblr's documented 60 requests/minute cap on the blocks endpoints, measured request-to-request so response time cannot erode it.
- The API budget held back for fetching and blocking is computed rather than fixed: how many cycles will run before the hourly window resets, times what those cycles have actually been costing. Both Tumblr limits are respected - 1,000/hour and 5,000/day.
- Detects external unblocks: if you unblock someone via Tumblr's web UI, the next full sync prunes the local record.
- Once a full sync has shown that Tumblr lists the newest blocks first (by when Tumblr says each was made, or where the app's own blocks turn up), the daily sync reads only the blocks added since the last one - usually a call or two - and the full read runs weekly. A block the app made since the last sync and you unblocked on Tumblr is not among them, and leaves the record then.
- For a list of 1,000 blocks or more, where Tumblr says when each was made, the daily sync also reads the page where the list should end. As long as expected, nothing was unblocked on Tumblr, and the full read waits a month; shorter, and the full read finds what, the next day, or at the weekly read if the list was read in full that week.
- A blocked blog renamed on Tumblr keeps its record: it is matched by its stable blog id, not its name.
Backup & restore
- Export settings, blogs, monitored posts, whitelists, queues, and blocked users to a single JSON file.
- Leaving tokens out leaves the OAuth app secret out too, so an unencrypted backup carries no credentials at all — restoring it on a new machine means entering the app keys again and re-authorizing.
- OAuth tokens, when included, are encrypted with a passphrase you supply (PBKDF2 + Fernet) so the backup file is portable between machines.
- Restore on a fresh install with the same passphrase.
- Uploading a backup shows you what is inside it (blogs, blocked/queued counts, export date, whether tokens are included) before anything is written, so a wrong pick out of a folder of timestamped files is a cancel rather than a merge.
Security
- OAuth tokens encrypted at rest. Encryption key is stored in your OS credential store (Windows Credential Manager / macOS Keychain / Linux Secret Service) when available, with an automatic fallback for headless setups.
- 401 responses trigger a token refresh transparently; concurrent refreshes are serialized so you don't burn your refresh-token quota.
Observability
- One line at the top of the dashboard says whether it is working, needs you, or is stopped; the browser tab shows a warning mark when it needs you.
- Activity feed on the dashboard saying what each run did, in plain sentences; the raw logs stay one click away.
- Light and dark themes: follows your system setting, or pick one from the header.
- Dashboard counts (queue, blocked, monitored posts, scheduler timings) refresh themselves — no manual reload.
- Rate-limit meter tracking both kinds of Tumblr limit: the hourly/daily budget per consumer key (read from Tumblr's own
X-Ratelimit-*headers when it sends them), and per-endpoint usage, which Tumblr caps but never reports — so that half is counted locally and annotated with wherever a 429 actually landed. - Manual triggers for fetch / block / sync from the dashboard, with status pills that auto-poll until the job completes.
- On Windows it runs from the system tray and can start when you sign in (Settings, or the installer's checkbox).
- Optionally blocks users who reblog a monitored post as well as those who like it, or only those whose reblog carries a tag you list (Settings).
- Weekly automatic backup of blogs, posts, blocks and queue — without tokens or the app secret — in
backups/under the data directory, keeping the last 4. - Weekly check for a new release, dismissible and switchable off in Settings; it sends nothing identifying. What changed in each version is in CHANGELOG.md.
- A bookmarklet (Posts page) adds the post you are looking at on Tumblr in one click.
Help
- CLI help:
tumblockr --help, ortumblockr <command> --helpfor any specific command. - Logs live in your data directory (
~/.tumblockr/on a fresh install, ordata/if running from a source checkout that already has one).