Skip to content

About

Plug your Android phone into Linux and a window opens showing every photo and video, grouped by album, with save-to-folder buttons. adb-based, no MTP, never writes to the phone.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

Repository files navigation

Phone Bridge

Plug your Android phone into a Linux machine and a window opens showing every photo and video on it, grouped by album, with a button to save what you want into a folder you choose.

It never writes to or deletes anything on the phone. Copy only, by design.

Phone Bridge


Why this exists

Getting photos off an Android phone on Linux is worse than it should be. MTP mounts are flaky or missing entirely, cloud sync means uploading everything to somebody else, and adb pull from a terminal means knowing the paths by heart.

Phone Bridge is the boring middle ground: plug in, look at your stuff, click what you want, choose where it goes.

It also finds media the Gallery scatters around — smart-glasses imports, for instance, land in Download/Meta AI/ rather than anywhere you'd think to look. Phone Bridge enumerates through Android's MediaStore, so it sees every album the Gallery sees.

Install

git clone https://github.com/mrmoe28/phonebridge.git
cd phonebridge
./install.sh

Then plug your phone in. It's also in your applications menu as Phone Bridge.

Requirements

sudo apt install adb ffmpeg python3-gi python3-pil python3-pyudev gir1.2-webkit2-4.1

install.sh checks for all of these and tells you what's missing.

Your phone needs USB debugging enabled (Settings → Developer options), and the first time you connect you'll get a prompt on the phone asking you to authorize the computer.

Tested on Linux Mint 22 / Ubuntu 24.04 with a Galaxy S25 on Android 16. It should work on any Android device and any GTK3 desktop; if it doesn't, please open an issue with the output of adb devices -l.

Try it without a phone

PHONEBRIDGE_DEMO=1 python3 -m phonebridge

Runs the whole app against a generated sample library — no device, no adb, no setup. The sample images are drawn procedurally with Pillow on first run and cached in ~/.cache/phonebridge/demo. That's what the screenshot above shows.

What it does

  • Every album on the phone in a sidebar, with counts and sizes
  • Filter by Photos / Videos / All
  • Real thumbnails for photos and videos, cached on disk
  • Click to select; Ctrl+A selects everything shown, Esc clears
  • Per-album save folders — screenshots to one place, camera to another — each remembered between runs
  • Verifies file size after every copy, so an unplug mid-transfer can't leave a silently truncated file behind
  • "Open folder" straight from the save confirmation
  • Opens itself when you plug the phone in

Uninstall

systemctl --user disable --now phonebridge-watch.service
rm -f ~/.config/systemd/user/phonebridge-watch.service
rm -f ~/.local/share/applications/phonebridge.desktop
rm -rf ~/.cache/phonebridge ~/.config/phonebridge

How it works

File Job
phonebridge/device.py adb + Android MediaStore: find the phone, list albums, copy files
phonebridge/thumbs.py Thumbnails, cached in ~/.cache/phonebridge/thumbs
phonebridge/config.py Per-album save folders, in ~/.config/phonebridge/config.json
phonebridge/app.py GTK3 window + WebKit view + the JS↔Python bridge
phonebridge/watcher.py Watches USB, opens the window on plug-in
phonebridge/demo.py Generated sample library for PHONEBRIDGE_DEMO=1
ui/ The interface — plain HTML/CSS/JS, no build step, no framework

No build step and no node_modules. Edit ui/app.css and restart.

Design notes, and the traps behind them

Each of these cost real debugging time. They're written down so nobody has to rediscover them.

adb, not MTP. MTP support on Linux is inconsistent and frequently just absent — no gvfsd-mtp, no jmtpfs, nothing in the file manager. adb is already there for anyone with developer options on, and reads at roughly 20 MB/s.

Address the phone by serial, never by transport id. adb transport ids get reassigned whenever the connection is re-established — one was seen going 2102 → 2103 within a single session. Code holding a transport id breaks minutes later with no device with transport id.

Never match a phone by idProduct in udev. Phones report a different product id per USB mode (Samsung uses 6860 for MTP), so a product-id match silently stops working the moment the mode changes. Match the ADB interface descriptor ff4201 instead — stable, and vendor-neutral.

udev cannot launch your GUI. A RUN+= rule executes as root with no DISPLAY, and udev kills anything still running when the event completes. The auto-open is a systemd --user service running a pyudev monitor inside the desktop session, which has neither problem.

Android 16 removed the MediaStore thumbnails table. Querying content://media/external/images/thumbnails returns "No result found" on modern Android, so every thumbnail has to be generated locally.

Half of all videos open on a black frame. Extracting frame 0 gives you a perfectly valid ~780-byte solid black JPEG. thumbs.py walks a seek ladder (1s, 3s, 10% of duration) and only accepts a blank frame as a last resort.

Some MP4s put their index at the end. Where moov sits near the start, a 4 MB partial read thumbnails a 142 MB video in about 0.2s. Where it doesn't — screen recordings especially — nothing short of the whole file works. _video_thumb escalates 4 MB → 12 MB → full rather than guessing.

Don't pkill -f "python3 -m phonebridge". That pattern matches any shell whose command line merely mentions it, including the one running the pkill. It will kill your own terminal. Match on /proc/<pid>/cmdline argv instead.

Contributing

Issues and PRs welcome. This was built against one phone on one distro, so reports from other hardware are genuinely useful — especially non-Samsung devices, where album layout and USB descriptors may differ.

PHONEBRIDGE_DEMO=1 lets you work on the UI without a device attached.

License

MIT — see LICENSE.

About

Plug your Android phone into Linux and a window opens showing every photo and video, grouped by album, with save-to-folder buttons. adb-based, no MTP, never writes to the phone.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages