This script pulls photos and videos from an Android device using ADB and
automatically sorts them into organized year/month folders on your
computer.
It collects media from common Android folders (Camera, Instagram, WhatsApp, etc.), extracts the correct date, and moves files into a structured archive.
-
Connects to your Android device via ADB
-
Pulls media from predefined Android folders
-
Automatically detects additional subfolders inside:
/sdcard/Pictures/Gallery/owner -
Extracts the correct date using:
- 📷 EXIF
DateTimeOriginal(for real camera photos) - 📁 WhatsApp filename patterns (e.g.
IMG-20240212-WA0001.jpg) - 🕒 File modification date (fallback)
- 📷 EXIF
-
Sorts files into:
<!-- -->
DESTINATION/
├── 2023/
│ ├── 11/
│ ├── 12/
├── 2024/
├── 01/
├── 02/
- Avoids duplicate files\
- Cleans up the temporary folder when finished
- Python 3.8+
- ADB (Android Debug Bridge) installed and available in PATH
- Android device with USB debugging enabled
- Python package:
Pillow
Install dependencies from requirements.txt:
pip install -r requirements.txtIf you want to run the test suite, also install pytest (a dev-only
dependency, not required to run the script itself):
pip install pytest-
Enable Developer Options:
- Go to Settings → About Phone (or About Device)
- Tap "Build number" 7 times until you see "You are now a developer"
-
Enable USB Debugging:
- Go back to Settings → Developer Options (or Settings → Additional Settings → Developer Options on some devices)
- Toggle on "USB debugging"
- You may also need to enable "USB debugging (Security settings)" for some operations
-
Connect to Computer:
- Connect your phone via USB
- Accept the debugging authorization prompt on your phone
- Select "File Transfer" or "MTP" mode if prompted
Note: The exact menu names may vary slightly between Android manufacturers (Samsung, Xiaomi, Google Pixel, etc.), but the general process is the same.
Create a config.py file in the same directory with:
TEMP_FOLDER = "temp_media"
DESTINATION = "sorted_media"TEMP_FOLDER→ where files are temporarily pulledDESTINATION→ final sorted archive location
TEMP_FOLDER must not be the same as, or contain, DESTINATION.
TEMP_FOLDER is deleted wholesale after every run, so nesting your archive
inside it would destroy the archive. The script refuses to start if it detects
this.
The script pulls media from:
/sdcard/DCIM/Camera/sdcard/Movies/Instagram/sdcard/Pictures/Instagram/sdcard/Pictures/Whatsapp/sdcard/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp Images/sdcard/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp Video/sdcard/Pictures/Gallery/owner(including all subfolders)
You can modify BASE_ANDROID_SOURCES inside the script if needed.
- Connect your Android device via USB
- Enable USB debugging
- Verify connection:
adb devices- Run the script:
python pull_and_sort_media.py-
--dry-run— preview what the script would do (pulls, moves, cleanup) without changing anything on disk or on the device:python pull_and_sort_media.py --dry-run
-
--only-after YYYY-MM-DD— skip any file dated before this cutoff. Useful for incremental runs once you've already archived everything older:python pull_and_sort_media.py --only-after 2024-04-01
-
--resolve-review— skip the ADB pull entirely and instead sortDESTINATION/_reviewinto the main archive. Use this after you've manually gone through the review folder (see "Duplicate Protection" below):python pull_and_sort_media.py --resolve-review
These flags can be combined, e.g.
python pull_and_sort_media.py --resolve-review --dry-runto preview how the review folder would resolve first.
- Check USB cable: Use a data cable, not a charge-only cable
- Try different USB port: Some ports may not support data transfer
- Restart ADB server:
adb kill-server adb start-server adb devices
- Check device connection: Ensure the phone is unlocked and the screen is on
- Revoke USB debugging authorizations: On your phone, go to Developer Options → Revoke USB debugging authorizations, then reconnect
- Disable/reenable USB debugging: Toggle USB debugging off and on again
- Check for RSA fingerprint: Some devices show an RSA fingerprint prompt that must be accepted
- Change USB mode: Swipe down from the top of your phone screen and change from "Charging" to "File Transfer" or "MTP"
- Try PTP mode: If File Transfer doesn't work, try PTP (Picture Transfer Protocol) mode
- Install Android SDK Platform Tools: Download from developer.android.com
- Add to PATH: Ensure the ADB executable is in your system PATH
- Verify installation: Run
adb versionto confirm it's installed
The script determines the file date in this order:
- EXIF metadata (
DateTimeOriginal) - WhatsApp filename date (YYYYMMDD)
- File modification timestamp
This ensures accurate sorting even for shared media.
After sorting is complete, the temporary pull folder is automatically deleted.
Duplicate handling is a two-stage workflow:
- Byte-identical files are always skipped automatically. If the file being sorted has the exact same content (SHA-1 hash) as the file already sitting at the destination path, it's a true duplicate — nothing is written, and it's safe to discard.
- A name collision with different content is never silently
dropped or blindly overwritten/merged. If a file with the same
name already exists at the destination but the contents differ
(e.g. two different sources both produced
IMG_0001.jpg), the incoming file is moved toDESTINATION/_review/YYYY/MM/instead, so nothing is lost and nothing in the archive gets clobbered. - Look through
_reviewand delete whatever you don't want to keep. Everything left behind is what you've chosen to keep. - Run
python pull_and_sort_media.py --resolve-review. It walks_reviewand files whatever survived intoDESTINATION/YYYY/MM/, auto-appending_1,_2, etc. only if a new collision shows up at that point. Once resolved, the_reviewfolder is cleaned up.
Every run appends to a persistent log file at
DESTINATION/.logs/mediamanager.log (created automatically if it
doesn't exist). Each line includes a timestamp and severity level, so
you can go back and check exactly what was pulled, moved, skipped, or
flagged for review on any given run — including runs made with
--dry-run. The same messages are also printed to the console
in real time as the script runs.
- Only processes:
.jpg.jpeg.png.mp4.mov
- Files are moved (not copied) after sorting.
- Designed for personal media archiving and cleanup.