Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🧲 OrphanPull — Content-Aware Android Backup Deduplicator

Find the photos and videos on your phone that exist in none of your backup drives — compared by content, not by filename — copy only those, then safely free up your phone.

Türkçe dokümantasyon için aşağıya bakınız.

OrphanPull main window

The interface follows your Windows accent color and light/dark theme. Shown here with the default blue accent.


🎯 The Problem

You have a phone with 80 GB of photos and videos. You also have years of scattered backups: D:\Phone Backup, D:\Photo Archive, E:\Old Drive. Some files were renamed along the way — wedding.mp4 on the drive is the exact same video as 20250607_203217.mp4 on the phone.

Now answer this: which files on your phone exist nowhere on your drives?

Every existing adb sync tool answers the wrong question. They all inherit rsync semantics — compare by path + timestamp + size against one destination folder. Rename a file and it gets copied again. Keep backups in three folders and they can only look at one.

OrphanPull answers the right question. It compares by content, across every backup folder you point it at.

✨ Features

  • 🧬 Rename-proof comparison. Filenames are ignored entirely. wedding.mp4 and VID_0012.mp4 are recognized as the same video.
  • 🗂️ Multiple backup roots. Point it at as many existing archives as you like. A file is "missing" only if it's absent from all of them.
  • 🖱️ Native Windows GUI. Reads your Windows accent color and light/dark theme from the registry, including the dark title bar. No config files, no command line required.
  • 🌍 English and Turkish. Follows your Windows UI language automatically and defaults to English. One click in the header switches language at any time, without losing your selections.
  • 🛡️ Two-tier verification. Fast heuristic while scanning, full cryptographic verification before anything is deleted. See Safety Model.
  • 🚀 On-device hashing. Full-file SHA-256 is computed by the phone — only the 64-character digest crosses the USB cable, not the file. A 2.9 GB video verifies in ~7 seconds.
  • 💾 Persistent hash cache. Drive-side hashes are stored in SQLite next to your target folder. The first run is the slow one; every run after is fast.
  • ⚡ Parallel transfers with resumable .part staging — pull the cable mid-copy and a half-written file is never mistaken for a backup.
  • 🎬 Video-first priority. Largest videos are processed first, so the biggest space wins land early.
  • 🔍 Dry run mode. See exactly what would be copied before anything moves.

🆚 How It Compares

Compares by Multiple backup roots GUI Verified deletion
OrphanPull Content hash ✅ Windows ✅ Full SHA-256
google/adb-sync (archived) path + mtime
riyad/android-backup path + mtime (rsync)
BojanStipic/adbackup path + mtime (rsync)
adbsyncer size + mtime (JSON) never deletes

🛡️ Safety Model

Deleting files is irreversible, so OrphanPull deliberately uses two different standards of proof depending on what's at stake.

Tier 1 — Scanning: size + first 4 MB SHA-256

Runs against thousands of files, so it has to be fast. Two files are treated as identical if their byte size matches and the SHA-256 of their first 4 MB matches.

If this is ever wrong, the cost is that one file gets copied unnecessarily. You lose some disk space. Nothing is destroyed.

Tier 2 — Before deletion: full-file SHA-256

Runs only on the files you have explicitly chosen to delete. The entire file is hashed on both sides and the digests must match exactly.

If this were ever wrong, a file with no backup anywhere would be destroyed permanently. So there is no shortcut here.

Additionally, before a single file is removed:

  1. The local copy must exist and its size must match the phone's, and
  2. the full-file SHA-256 of both copies must be identical, and
  3. if the hash cannot be computed for any reason, the file is left on the phone
  4. any file that fails verification is left on the phone — the rest still proceed
  5. you must confirm twice, and the GUI defaults to "No" on both dialogs

Honest disclosure: the scan is a heuristic, not a proof. It is extremely reliable for real photos and videos (two different files would need a byte-identical size and a byte-identical first 4 MB), but it is not a cryptographic guarantee. The deletion check is.

📋 Requirements

  • Windows 10/11
  • Python 3.9+ (only if running from source — the release .exe is standalone)
  • Android platform-tools (adb)
  • An Android phone with USB debugging enabled

Installing adb

adb.exe ships with the Android SDK. OrphanPull finds it automatically in any of these locations — you usually don't need to touch PATH:

  • Next to OrphanPull.exe
  • Anywhere on your PATH
  • %LOCALAPPDATA%\Android\Sdk\platform-tools
  • %PROGRAMFILES%\Android\android-sdk\platform-tools
  • $ANDROID_SDK_ROOT / $ANDROID_HOME

If you have none of these, download Android SDK Platform-Tools and unzip it next to the executable.

adb.exe is not bundled in the release. It is distributed under Google's Android SDK Terms of Service, which restricts redistribution.

Preparing the phone

  1. Settings → About phone → tap Build number 7 times to unlock Developer options
  2. Settings → Developer options → enable USB debugging
  3. Connect the cable and set the USB mode to File transfer (MTP)
  4. Approve the "Allow USB debugging?" prompt on the phone

Verify with adb devices — your device should be listed as device, not unauthorized.

🚀 Usage

GUI (recommended)

python orphanpull_gui.py

The window is laid out as four numbered cards:

Card Location Purpose
1 · Backup folders Your PC Where OrphanPull searches. Read-only, never written to.
2 · Target folder Your PC Where missing files are copied.
3 · Phone folders Your phone Which phone folders to scan. Press Scan phone first.
4 · File types Video / photo / document.

Then press Analyze (copies nothing, just reports) before Start transfer.

⚠️ Add every archive that might already contain your files to card 1. If you leave one out, everything in it is reported as missing and gets copied a second time.

⚠️ Don't use a folder from card 1 as your target in card 2.

Command line

python orphanpull.py --surucu "D:\Phone Backup" "D:\Photo Archive" --hedef "D:\Phone Backup\New" --tur video
Flag Meaning
--surucu Backup folders to search (space-separated, multiple allowed)
--hedef Target folder for missing files
--kaynak Phone folders (default: DCIM, Movies, Pictures, Download, Documents)
--tur video / foto / belge (multiple allowed)
--dry-run Report only, copy nothing

Any flag you omit is asked interactively, so you can mix and match.

Always start with a dry run:

python orphanpull.py --dry-run

🌍 Language

The interface is available in English and Turkish. The language is chosen automatically:

  • If your Windows UI language is Turkish, OrphanPull starts in Turkish.
  • Otherwise it starts in English.

You can override this in three ways:

  • Click the language chip in the top-right corner of the window — it switches immediately and keeps everything you have already selected.
  • Pass --dil en or --lang tr on the command line.
  • Set the ORPHANPULL_LANG environment variable to en or tr.

Adding another language means adding one column to i18n.py. Every string in both the engine and the GUI goes through t("key"); there are no hard-coded user-facing strings left. Pull requests welcome.

⚙️ How It Works

[1] Index drives      →  Walk every backup folder. Build a size → paths map.
                         No hashing yet.

[2] List phone        →  One adb shell call:  find … -exec stat -c '%s|%Y|%n'
                         Gets every file's size and mtime in a single round trip.

[3] Compare           →  Phone file size absent from the map?  → missing, done.
                         Size collides?  → hash first 4 MB on both sides.
                         Drive-side hashes are cached in SQLite.

[4] Transfer          →  Parallel adb pull into .part files, renamed on success.

[5] Verify & delete   →  (Optional) Full SHA-256 both sides, two confirmations.

The key optimization is step 3: hashing is only ever performed on files whose size already collides. For a typical library that's a small fraction of the total, so most files are resolved with zero I/O.

Tuning

WORKERS in orphanpull.py controls parallel adb pull operations. Default is 4. Use 6–8 for an SSD target, 2–3 for a spinning disk.

USB 3.0 (blue port) matters — USB 2.0 caps out around 35 MB/s.

🔨 Building the executable

pip install pyinstaller
pyinstaller --onefile --windowed --name OrphanPull orphanpull_gui.py

Output lands in dist\OrphanPull.exe.

🧪 Technical Notes

A few things discovered while building this, in case they save you time:

  • /sdcard is a symlink (→ /storage/self/primary) on modern Android. find /sdcard -maxdepth 1 -type d returns nothing, because find doesn't descend into symlinks. You need the trailing slash — find /sdcard/ … — or find -L. This silently breaks a lot of backup scripts.
  • Hash on the device, not the host. adb shell sha256sum runs on the phone's hardware-accelerated crypto (~400 MB/s on a Snapdragon 8 Gen 2) and returns 64 bytes. Streaming the file over USB to hash it locally is an order of magnitude slower.
  • Quote your paths properly. A filename containing an apostrophe (Ali'nin düğünü.mp4) breaks naive '…' shell quoting. In a command that runs rm, that's not a cosmetic bug.
  • Android filenames are not Windows filenames. : ? * | < > are all legal on Android and illegal on Windows, as are trailing spaces and dots.

🧰 My Other Projects

💖 Sponsor & Support

If this tool saved your photos or freed up your phone, please consider fueling our open-source journey. Your sponsorships directly support my open-source sessions and my daughter's international engineering and architecture higher education:

  • 🧡 Become a Patron: Patreon (opensource2)
  • 🪙 Bitcoin (BTC) Address: bc1q7kpfdc9stpnexvwgpzxl8nzaua8wfyp2ht8xxa

📄 License

MIT — free to use, modify and redistribute.



🇹🇷 OrphanPull Türkçe Dokümantasyon

Telefonundaki hiçbir yedeğinde bulunmayan fotoğraf ve videoları — dosya adına göre değil, içeriğe göre — bulur, sadece onları kopyalar, sonra telefonunda güvenle yer açar.

OrphanPull ana pencere

Arayüz, Windows'un vurgu rengini ve açık/koyu temasını izler. Burada varsayılan mavi vurgu ile gösteriliyor.


🎯 Çözdüğü Problem

Telefonunda 80 GB fotoğraf ve video var. Yıllara yayılmış dağınık yedeklerin de var: D:\Yedek, D:\Fotoğraf Arşivi, E:\Eski disk. Bazı dosyaların adı yol boyunca değişmiş — sürücüdeki dugun.mp4 ile telefondaki 20250607_203217.mp4 tıpatıp aynı video.

Şimdi şu soruya cevap ver: telefonundaki hangi dosyaların sürücülerinde hiç kopyası yok?

Mevcut adb senkronizasyon araçlarının hepsi yanlış soruyu cevaplıyor. Hepsi rsync mantığını miras almış — tek bir hedef klasöre karşı yol + tarih + boyut karşılaştırıyorlar. Dosyanın adını değiştirdiysen tekrar kopyalanır. Yedeklerin üç ayrı klasördeyse sadece birine bakabilirler.

OrphanPull doğru soruyu cevaplıyor. İçeriğe göre ve gösterdiğin bütün yedek klasörlerine karşı karşılaştırıyor.

✨ Özellikler

  • 🧬 Ada bakmayan karşılaştırma. Dosya adları tamamen yok sayılır. dugun.mp4 ile VID_0012.mp4 aynı video olarak tanınır.
  • 🗂️ Birden fazla yedek klasörü. İstediğin kadar mevcut arşiv gösterebilirsin. Bir dosya ancak hepsinde birden yoksa "eksik" sayılır.
  • 🖱️ Yerel Windows arayüzü. Windows'un vurgu rengini ve açık/koyu temasını registry'den okur, koyu başlık çubuğu dahil. Ayar dosyası yok, komut satırı zorunlu değil.
  • 🌍 Türkçe ve İngilizce. Windows arayüz dilini otomatik izler, varsayılanı İngilizce'dir. Başlıktaki tek tıkla, seçimlerini kaybetmeden istediğin an dil değiştirilir.
  • 🛡️ İki kademeli doğrulama. Tararken hızlı sezgisel yöntem, silmeden önce tam kriptografik doğrulama. Bkz. Güvenlik Modeli.
  • 🚀 Hash'i telefon hesaplar. Tam dosya SHA-256'sını telefon hesaplar — kablodan dosya değil, 64 karakterlik özet geçer. 2.9 GB'lık bir video ~7 saniyede doğrulanır.
  • 💾 Kalıcı hash önbelleği. Sürücü tarafındaki hash'ler hedef klasörün yanında SQLite'ta saklanır. Yavaş olan ilk turdur, sonrakiler hızlıdır.
  • ⚡ Paralel aktarım ve .part uzantılı geçici dosyalar — kopyalama sırasında kablo çıkarsa yarım kalmış dosya asla "yedeklendi" sayılmaz.
  • 🎬 Video önceliği. En büyük videolar önce işlenir, en çok yer kazandıran dosyalar erken biter.
  • 🔍 Kuru çalıştırma. Hiçbir şey kopyalanmadan önce neyin kopyalanacağını tam olarak gösterir.

🛡️ Güvenlik Modeli

Silme geri alınamaz. Bu yüzden OrphanPull, riskin büyüklüğüne göre iki farklı kanıt standardı kullanır.

1. Kademe — Tarama: boyut + ilk 4 MB SHA-256

Binlerce dosya üzerinde çalışır, o yüzden hızlı olmak zorunda. İki dosya, bayt cinsinden boyutları ve ilk 4 MB'larının SHA-256'sı aynıysa aynı kabul edilir.

Bu yöntem yanılırsa bedeli, bir dosyanın boşuna kopyalanmasıdır. Biraz disk alanı gider. Hiçbir şey yok olmaz.

2. Kademe — Silmeden önce: tam dosya SHA-256

Sadece silmeyi açıkça onayladığın dosyalar üzerinde çalışır. Dosyanın tamamı iki tarafta da hashlenir ve özetlerin birebir tutması gerekir.

Bu yöntem yanılsaydı, hiçbir yerde yedeği olmayan bir dosya kalıcı olarak yok olurdu. O yüzden burada kısayol yok.

Ayrıca tek bir dosya bile silinmeden önce:

  1. Yerel kopya var olmalı ve boyutu telefondakiyle aynı olmalı, ve
  2. iki kopyanın tam dosya SHA-256'sı birebir aynı olmalı, ve
  3. hash herhangi bir sebeple hesaplanamazsa dosya telefonda bırakılır
  4. doğrulamayı geçemeyen dosya telefonda bırakılır — diğerleri yine de devam eder
  5. iki kez onay vermen istenir ve arayüzde iki pencerede de varsayılan "Hayır"dır

Dürüst uyarı: tarama aşaması bir sezgisel yöntemdir, matematiksel kanıt değildir. Gerçek fotoğraf ve videolarda son derece güvenilirdir (iki farklı dosyanın hem boyutunun hem ilk 4 MB'ının bayt bayt aynı olması gerekirdi) ama kriptografik bir garanti değildir. Silme kontrolü ise garantidir.

📋 Gereksinimler

  • Windows 10/11
  • Python 3.9+ (yalnızca kaynaktan çalıştıracaksan — release'teki .exe kendi başına çalışır)
  • Android platform-tools (adb)
  • USB hata ayıklama açık bir Android telefon

adb kurulumu

adb.exe Android SDK ile birlikte gelir. OrphanPull şu konumların hepsine otomatik bakar, genelde PATH ile uğraşman gerekmez:

  • OrphanPull.exe'nin yanı
  • PATH üzerindeki herhangi bir yer
  • %LOCALAPPDATA%\Android\Sdk\platform-tools
  • %PROGRAMFILES%\Android\android-sdk\platform-tools
  • $ANDROID_SDK_ROOT / $ANDROID_HOME

Hiçbiri yoksa Android SDK Platform-Tools paketini indirip exe'nin yanına çıkar.

adb.exe release'e gömülmemiştir. Google'ın Android SDK Kullanım Şartları'na tabidir ve yeniden dağıtımı kısıtlıdır.

Telefonu hazırlama

  1. Ayarlar → Telefon hakkında → Yapı numarasına 7 kez dokun, Geliştirici seçenekleri açılsın
  2. Ayarlar → Geliştirici seçenekleri → USB hata ayıklamayı aç
  3. Kabloyu tak ve USB modunu Dosya aktarımı (MTP) yap
  4. Telefonda çıkan "USB hata ayıklamaya izin verilsin mi?" kutusunu onayla

adb devices ile kontrol et — cihazın unauthorized değil device olarak görünmeli.

🚀 Kullanım

Arayüz (önerilen)

python orphanpull_gui.py

Pencere dört numaralı karttan oluşur:

Kart Neresi Ne işe yarar
1 · Yedek klasörleri Bilgisayarın OrphanPull'un aradığı yer. Sadece okunur, asla yazılmaz.
2 · Hedef klasör Bilgisayarın Eksik dosyaların kopyalanacağı yer.
3 · Telefon klasörleri Telefonun Hangi telefon klasörlerinin taranacağı. Önce Telefonu taraya bas.
4 · Dosya türleri Video / fotoğraf / belge.

Sonra Aktarımı başlattan önce Analiz ete bas — hiçbir şey kopyalamaz, sadece raporlar.

⚠️ Dosyalarının zaten bulunabileceği bütün arşivleri 1. karta ekle. Birini dışarıda bırakırsan içindeki her şey "eksik" olarak raporlanır ve ikinci kez kopyalanır.

⚠️ 1. kartta seçtiğin bir klasörü 2. kartta hedef olarak kullanma.

Komut satırı

python orphanpull.py --surucu "D:\Yedek" "D:\Fotoğraf Arşivi" --hedef "D:\Yedek\Yeni" --tur video
Parametre Anlamı
--surucu Aranacak yedek klasörleri (boşlukla ayrılır, birden fazla olabilir)
--hedef Eksik dosyaların kopyalanacağı klasör
--kaynak Telefon klasörleri (varsayılan: DCIM, Movies, Pictures, Download, Documents)
--tur video / foto / belge (birden fazla olabilir)
--dry-run Sadece raporlar, hiçbir şey kopyalamaz

Vermediğin parametre ekrandan sorulur, karışık kullanabilirsin.

Her zaman kuru çalıştırmayla başla:

python orphanpull.py --dry-run

🌍 Dil

Arayüz Türkçe ve İngilizce kullanılabilir. Dil otomatik seçilir:

  • Windows arayüz dilin Türkçe ise OrphanPull Türkçe açılır.
  • Değilse İngilizce açılır.

Üç şekilde değiştirebilirsin:

  • Pencerenin sağ üst köşesindeki dil etiketine tıkla — anında değişir ve o ana kadar yaptığın tüm seçimler korunur.
  • Komut satırında --dil tr ya da --lang en ver.
  • ORPHANPULL_LANG ortam değişkenini tr veya en yap.

Yeni bir dil eklemek, i18n.py dosyasına bir sütun eklemek demek. Hem motorda hem arayüzde her metin t("anahtar") üzerinden geçiyor; kodda gömülü tek bir kullanıcı metni kalmadı. Katkılara açık.

⚙️ Nasıl Çalışıyor

[1] Sürücüleri indeksle  →  Her yedek klasörünü gez. boyut → yollar haritası çıkar.
                            Henüz hash yok.

[2] Telefonu listele     →  Tek bir adb shell çağrısı:
                            find … -exec stat -c '%s|%Y|%n'
                            Tüm dosyaların boyut ve tarihi tek turda gelir.

[3] Karşılaştır          →  Telefon dosyasının boyutu haritada yok mu? → eksik, bitti.
                            Boyut çakışıyor mu? → iki tarafta da ilk 4 MB hashlenir.
                            Sürücü tarafındaki hash'ler SQLite'a önbelleklenir.

[4] Aktar                →  Paralel adb pull, .part dosyasına; başarılıysa adı değişir.

[5] Doğrula ve sil       →  (İsteğe bağlı) İki tarafta tam SHA-256, iki kez onay.

Asıl optimizasyon 3. adımda: hash yalnızca boyutu zaten çakışan dosyalar için hesaplanır. Tipik bir kütüphanede bu, toplamın küçük bir kısmıdır; yani dosyaların çoğu hiç okuma yapılmadan karara bağlanır.

Ayar

orphanpull.py içindeki WORKERS sabiti paralel adb pull sayısını belirler. Varsayılan 4. SSD hedefte 6-8, klasik diskte 2-3 kullan.

USB 3.0 (mavi port) fark eder — USB 2.0'da tavan yaklaşık 35 MB/s.

🔨 Exe derleme

pip install pyinstaller
pyinstaller --onefile --windowed --name OrphanPull orphanpull_gui.py

Çıktı: dist\OrphanPull.exe

🧪 Teknik Notlar

Bunu yazarken keşfedilen, başkasının vaktini kurtarabilecek birkaç şey:

  • /sdcard bir symlink (→ /storage/self/primary). find /sdcard -maxdepth 1 -type d hiçbir şey döndürmez, çünkü find symlink'in içine inmez. Sondaki eğik çizgi gerekir — find /sdcard/ … — ya da find -L. Bu, birçok yedekleme script'ini sessizce bozar.
  • Hash'i telefonda hesapla, bilgisayarda değil. adb shell sha256sum telefonun donanım hızlandırmalı kripto biriminde çalışır (Snapdragon 8 Gen 2'de ~400 MB/s) ve 64 bayt döndürür. Dosyayı USB'den akıtıp yerelde hashlemek kat kat yavaştır.
  • Yolları düzgün tırnakla. İçinde kesme işareti olan bir dosya adı (Ali'nin düğünü.mp4) naif '…' tırnaklamasını bozar. rm çalıştıran bir komutta bu kozmetik bir hata değildir.
  • Android dosya adları Windows dosya adları değildir. : ? * | < > karakterleri Android'de geçerli, Windows'ta geçersizdir; sondaki boşluk ve noktalar da öyle.

🧰 Diğer Projelerim

💖 Destek & Bağış (Support)

Eğer bu araç fotoğraflarını kurtardıysa veya telefonunda yer açtıysa ve geliştiriciye destek olmak isterseniz Patreon üzerinden destekçi olabilir veya Bitcoin (BTC) ile bağışta bulunabilirsiniz. Desteğiniz açık kaynaklı projelerin devamlılığına katkı sağlamakta ve kızımın mühendislik & mimarlık alanındaki uluslararası yükseköğrenimini finanse etmeye yardımcı olmaktadır:

  • 🧡 Patreon Destekçisi Ol: Patreon (opensource2)
  • 🪙 Bitcoin (BTC) Cüzdan Adresi: bc1q7kpfdc9stpnexvwgpzxl8nzaua8wfyp2ht8xxa

📄 Lisans (License)

Bu proje MIT Lisansı ile lisanslanmıştır. Tamamen ücretsiz olup, kodlarını istediğiniz gibi değiştirebilir, dağıtabilir veya kendi projelerinizde kullanabilirsiniz.

About

Content-aware Android backup deduplicator - finds the files on your phone that exist in none of your backup drives, compared by content hash rather than filename, and copies only those.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages