devbits
A lightweight CLI toolkit for daily development utilities — video/image processing, project file management, and more.
Installation
pip install devbits
Requires Python ≥ 3.9.
Usage
All commands are available in two ways:
# As subcommands of devbits
devbits <command> [options]
# As standalone commands
<command> [options]
Use --help on any command for detailed usage and parameter descriptions:
devbits editvideo --help
editvideo --help
Commands
Video
| Command | Description |
|---|---|
editvideo |
Trim a video by time (seconds) or frame range. Includes --gui for browser-based editing. (Formerly clipvideo, which still works but prints a rename notice.) |
video2images |
Extract frames from a video. |
video2gif |
Convert a video (or a portion) to animated GIF. |
images2video |
Assemble an image sequence into an MP4 video. |
images2gif |
Assemble an image sequence into an animated GIF. |
resizevideo |
Re-encode a video at a different resolution. |
Image
| Command | Description |
|---|---|
resizeimage |
Resize a single image (preserves aspect ratio by default). |
recolor |
Recolor a logo/icon foreground, leaving the background intact. |
image2ico |
Convert an image to a multi-size ICO file. |
batchimages |
Batch resize or convert all images in a folder. |
checkimages |
Scan for broken / corrupt image files. |
contactsheet |
Generate a thumbnail grid (contact sheet) from a folder of images. |
draw |
Windows Paint-style editor in the browser — start from a blank canvas or open a photo. See Drawing. |
Project / Files
| Command | Description |
|---|---|
clearcache |
Remove __pycache__ and other Python cache directories. |
tree |
Print a directory tree. |
size |
List the largest files / folders, sorted by size. |
renamefiles |
Batch rename files sequentially. |
samplefiles |
Copy or move the first N files to another folder. |
Network
| Command | Description |
|---|---|
netscan |
List devices connected to your local network (Wi-Fi / router) with their IP, MAC, and hostname. --lookup adds the manufacturer. |
netsurvey |
Map every network segment visible on the current link — your own interfaces, foreign subnets on the same switch, the addresses in use, and the conflicts between them. Built for shared networks (trade shows, offices). |
wifi |
Manage Wi-Fi: list, connect (arrow-key picker + hidden password prompt), on, off, forget. Linux and Windows fully; macOS without list. |
Windows
| Command | Description |
|---|---|
ime |
Stop games from triggering input-method switches. start / stop / restart / status run a background watcher; disable-hotkeys turns off Alt+Shift, Ctrl+Space and friends for good. Windows only. |
Examples
# Trim video from 5s to 20s
editvideo movie.mp4 --start 5.0 --end 20.0
# Open interactive clip editor in the browser
editvideo movie.mp4 --gui
# Convert video to GIF (3.5s–10s at 15 fps)
video2gif movie.mp4 --start 3.5 --end 10.0 --fps 15
# Extract every 5th frame as PNG
video2images movie.mp4 --every 5 --format png
# Recolor a logo's foreground to black (keeps the background)
recolor logo.png
# Recolor a logo's foreground to a custom color (hex or R,G,B)
recolor logo.png --color '#1a73e8'
recolor logo.png --color 0,178,179
# Open the Paint-style editor on a blank canvas, or on a photo
draw
draw photo.jpg
batchimages ./photos -o ./resized --size 800,600
# Clean Python caches
clearcache . --all
# List every device on your local network
netscan
# Also identify each device's manufacturer (online OUI lookup)
netscan --lookup
# Scan a specific subnet, faster, without hostname lookups
netscan --network 192.168.1.0/24 --timeout 0.5 --no-resolve
# Map every network segment and address around you (passive, ~2s)
netsurvey
# Segments and conflicts only, no address lists
netsurvey --summary
# Also ping-sweep your ranges and the discovered ones
netsurvey --sweep
# Check specific ranges before assigning them at a venue
netsurvey --include 192.168.1.0/24 --include 10.0.0.0/24
# Show the Wi-Fi networks in range (Linux / Windows)
wifi list
# Pick a Wi-Fi network with the arrow keys, then type the password
wifi connect
# Join a specific network without the picker
wifi connect MyHome-5G
# Turn the Wi-Fi radio on / off
wifi on
wifi off
# Stop a network from auto-connecting
wifi forget OldCafe
# Stop Shift / Alt / Space from switching the input method while gaming
ime disable-hotkeys # once, applies at the next sign-in
ime start # before you play
ime status
ime stop
# Only guard specific games, and leave everything else alone
ime start --apps valorant.exe,cs2.exe
# For exclusive-fullscreen games: remove the other input languages outright
ime start --strict
netscanreports IP, MAC, hostname and (with--lookup) the hardware manufacturer — a network scan can't read a device's CPU/RAM/OS. Phones and laptops that use a randomized/private MAC show up as(private)and can't be attributed to a vendor.
Drawing
draw starts a local server and opens a Paint-style editor in your browser.
With no argument you get a blank canvas (--size W,H, default 1280×720); give
it an image to edit that instead. Nothing is uploaded anywhere — the page talks
only to the devbits process on 127.0.0.1, and closing it with Ctrl+C stops it.
What it covers, following Windows Paint:
| Area | Features |
|---|---|
| Tools | Pencil, fill (with tolerance), text, eraser (right-drag swaps Color 1 → Color 2 only), color picker, magnifier |
| Brushes | Brush, calligraphy ×2, airbrush, oil, crayon, marker, natural pencil, watercolor |
| Shapes | Line, curve, oval, rectangle, rounded rectangle, polygon, triangles, diamond, pentagon, hexagon, four arrows, 4/5/6-point stars, callouts, heart, lightning — outline and fill styles, adjustable until you click away |
| Selection | Rectangular and free-form, move / resize / Ctrl+drag to duplicate, transparent selection, cut / copy / paste (system clipboard) |
| Image | Crop, resize and skew, rotate, flip, invert colors, canvas size (or drag the canvas edges) |
| Colors | Color 1 / Color 2 (left / right click), Paint palette, custom colors |
| View | Zoom (Ctrl+wheel, magnifier, slider), fit, pixel gridlines, Space+drag to pan |
| Files | New, open, Add photo (drops an image onto the canvas as a movable selection — also by drag-and-drop or paste), save / save as (PNG, JPEG, BMP, GIF, WebP, TIFF, ICO, PGM, PPM), download. Opens anything Pillow reads, including 8/16-bit PGM / PPM / PBM |
Save writes next to the opened image as <stem>_drawn.<ext> — the original is
never touched unless you pick its name in Save as — or to ./untitled.png
for a blank canvas. -o / --output sets the file directly. An existing file
is only replaced after you confirm.
Shortcuts: Ctrl+Z / Ctrl+Y undo / redo, Ctrl+S save, Ctrl+Shift+S save as,
Ctrl+O open, Ctrl+A select all, Ctrl+C / X / V clipboard, Ctrl+Shift+X crop,
Ctrl+E canvas size, Ctrl+G gridlines, Ctrl+± / Ctrl+0 / Ctrl+1 zoom, Delete,
Esc / Enter to finish, arrows to nudge, [ / ] size, X swap colors, and
P / B / E / F / I / T / S / Z / U for the tools.
Surveying a shared network
netscan answers "who is on my subnet?". netsurvey answers "what is on
this wire?" — the question that matters in an exhibition hall, an office, or
a co-working space where other people's routers hand out their own ranges:
INTERFACES
en0 192.168.0.122/24 gateway 192.168.0.1
utun6 10.2.244.44/32
SEGMENTS (3 total, 2 yours, 9 address(es) in use)
192.168.0.0/24 local (en0) swept 6 host(s)
192.168.0.1 06:f2:67:75:4d:e2 gateway,arp,ping gateway / router
192.168.0.122 4e:e5:41:93:7c:1f self,arp,mdns this device
...
10.77.0.0/24 foreign passive 2 host(s)
10.77.0.9 de:ad:be:ef:00:01 ssdp,arp
CONFLICTS (2)
! [duplicate-ip] 192.168.0.50 answers from 2 MAC addresses (…) — two devices claim the same address
- [shared-l2] 1 foreign segment(s) share this link: 10.77.0.0/24
Three independent sources are combined, so segments you have no address in still show up:
- every local interface with its real netmask (
ip/ifconfig/ipconfig); - the ARP / neighbour cache, which lists link neighbours regardless of subnet — this is what exposes somebody else's range on the same switch;
- SSDP and mDNS answers, sent out of each interface (skip with
--no-passive).
The default pass is passive and takes about two seconds. --sweep additionally
ping-sweeps your ranges and the discovered ones so each address list is complete;
--include CIDR sweeps a specific range you are about to assign. Ranges larger
than --max-sweep (4096 hosts) are narrowed to the /24 around your own address
or skipped, with a note on stderr.
Reported conflicts:
| Kind | Meaning |
|---|---|
duplicate-ip |
One address answers from two MACs — two devices claim it. |
overlap |
A foreign range, or a second local interface (VPN!), overlaps one of your subnets. |
no-dhcp |
An interface self-assigned a 169.254.x.x address; no DHCP server answered. |
router-bridge |
One MAC answers for addresses in several segments — a router joining them. |
shared-l2 |
Foreign segments are present on your link (informational). |
Survey only networks you are entitled to.
netsurveysends ordinary pings and standard discovery multicast — nothing privileged — but probing networks you don't administer may still violate policy or law.
Wi-Fi
wifi connect lists everything in range — move with ↑/↓, press Enter to join,
Esc to cancel. The password prompt is hidden, skipped for open networks, and
skipped again for networks your system already remembers. When stdout isn't a
terminal the picker degrades to a numbered prompt, so the command still works
over pipes and in scripts.
Each subcommand drives the platform's own tooling, so no extra dependency or driver access is needed:
| OS | Tooling used | Notes |
|---|---|---|
| Linux | nmcli (NetworkManager) |
The Ubuntu default. Systems without NetworkManager aren't supported. See the sudo note below. |
| Windows | netsh |
wifi on / wifi off enable and disable the adapter, which needs an Administrator terminal. |
| macOS | networksetup |
No scanning — see below. connect, on, off and forget all work; wifi forget edits the preferred-networks list and may need sudo. |
Scanning support
list |
connect <ssid> |
connect (picker) |
on / off |
forget |
|
|---|---|---|---|---|---|
| Linux | ✅ | ✅ | networks in range | ✅ | ✅ |
| Windows | ✅ | ✅ | networks in range | ✅ | ✅ |
| macOS | ❌ | ✅ | saved networks | ✅ | ✅ |
--passwordexists for automation but lands in your shell history — prefer the interactive prompt. On Linux, NetworkManager itself takes the passphrase as a command-line argument, so it is briefly visible in the process list.
Linux: polkit and sudo
NetworkManager's polkit rules usually let a local desktop session toggle Wi-Fi
without a password, but deny the same thing over SSH. When an operation is
refused, wifi says so and re-runs just that nmcli command under sudo,
which prompts for your password on the terminal:
Error: Failed to set radio: Not authorized to enable/disable WiFi.
Retrying with sudo (you may be asked for your password) ...
The escalation only happens on an interactive terminal. In a script or pipeline the command fails with the permission error instead of hanging on a prompt.
If you have a shell function or alias named
wifi(a commonnmcliwrapper), it takes precedence over this command — shell functions win overPATH. Usedevbits wifi ..., or remove the function.
macOS: no scanning
wifi list is unsupported on macOS, and wifi connect without an SSID picks
from the networks this Mac already remembers rather than what's in range:
$ devbits wifi connect
Listing nearby Wi-Fi networks is not supported on macOS. ...
Falling back to your saved networks.
Select a network to join:
❯ MyHome-5G (saved)
CoffeeShop (saved)
Joining by name — wifi connect MyHome-5G — always works, as do on, off
and forget.
The reason is that the last remaining macOS API that enumerates networks,
system_profiler SPAirPortDataType, replaces every SSID with the literal string
<redacted> unless the calling process holds Location Services authorization.
That is a TCC privacy permission, not a file permission: sudo does not bypass
it, the authorization database is SIP-protected, and a CLI cannot request it —
only a bundled app linking CoreLocation can. Rather than ship a pyobjc
dependency for one platform, devbits doesn't scan on macOS at all.
Input methods while gaming (Windows)
Games bind Shift, Alt and Space to actions, and Windows binds the same keys to input-method switches. Mid-fight you end up composing Chinese instead of shooting. Three separate mechanisms cause it, each living somewhere different:
| Trigger | What it is | Turned off by |
|---|---|---|
Alt+Shift, Ctrl+Shift |
Input language hotkey, in HKCU\Keyboard Layout\Toggle |
ime disable-hotkeys |
Ctrl+Space, Shift+Space |
IME on/off and full-width hotkeys, in HKCU\Control Panel\Input Method\Hot Keys |
ime disable-hotkeys |
A bare Shift |
The IME's own Chinese/English toggle — a conversion mode, not a hotkey | ime start only |
So the two commands are complementary: run ime disable-hotkeys once, and
ime start before you play.
disable-hotkeys backs up what it replaces (restore-hotkeys puts it back
exactly) and takes effect at your next sign-in — the settings are cached by
ctfmon.exe, which Windows protects from being restarted.
start runs a background watcher that forces the foreground window back to the
English keyboard layout. A layout with no IME attached has no Chinese/English
mode to toggle, which is what kills the bare-Shift case. It only posts window
messages — no keyboard hook, no DLL injection — so anti-cheat drivers have
nothing to object to.
Two things follow from being that well-behaved:
- Elevated games need an elevated watcher. Windows' UIPI silently drops
messages posted from a lower integrity level, so a game running as
Administrator can only be reached from an Administrator terminal. The watcher
detects windows it cannot switch, backs off instead of retrying forever, and
names them in
ime status. - Exclusive fullscreen may ignore the messages. Borderless-windowed mode avoids it.
ime start --strict covers both by removing every non-English input language
for the duration, which no keystroke can undo. ime stop puts them back; if the
watcher is killed without it, ime restore-languages recovers them.
State, backups and the watcher log live in %LOCALAPPDATA%\devbits\ime\.
Output Defaults
When -o / --output is omitted, the output filename is derived from the input:
editvideo movie.mp4 → movie_clip.mp4
video2gif movie.mp4 → movie.gif
resizeimage photo.jpg → photo_resized.jpg
recolor logo.png → logo_revised.png
contactsheet ./photos → photos_sheet.jpg
draw photo.jpg (Save) → photo_drawn.jpg
License
MIT
Metadata
Release files for devbits 1.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| devbits-1.6.1.tar.gz | 145.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| devbits-1.6.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 268.1 kB
Release files / devbits-1.6.1.tar.gz
| Download URL | devbits-1.6.1.tar.gz |
|---|---|
| Size | 145.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c5bdfbf55cafb5739acf05ec463ffd0d41527b1b4ef09f94b2488c7005c8b549
|
|
BLAKE2b-256 checksum How to use checksums |
de32f28fdaf57aebc85d1fa8a9be85d0d2842e3dd388e53ca0d53e8d955def57
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.6
|
Release files / devbits-1.6.1-py3-none-any.whl
| Download URL | devbits-1.6.1-py3-none-any.whl |
|---|---|
| Size | 122.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
241ed0524541068333904b58bc163cf6694d5735d0993e4621881dbbb6d33a80
|
|
BLAKE2b-256 checksum How to use checksums |
4c9e7d338e44b111cd6bae7668f268b075ad991f2ffad7d28c4d70764dad0fc7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.6
|