Skip to content

Pixel Backup v0.1.0

Latest

Choose a tag to compare

@github-actions github-actions released this 20 Mar 09:00
· 26 commits to main since this release

Download

File Description
PixelBackup-0.1.0.dmg macOS app — drag to Applications and run
pixel_backup.sh Shell script — works standalone with adb in PATH

System requirements: macOS 13 Ventura or later · Apple Silicon and Intel


Install

  1. Download PixelBackup-0.1.0.dmg
  2. Open the DMG and drag PixelBackup to your Applications folder
  3. Launch from Applications (or Spotlight)

"App can't be opened" warning?
Right-click (Control-click) the app icon → Open. You only need to do this once.
This prompt does not appear on notarized releases.


Shell script (no installer)

brew install android-platform-tools
chmod +x pixel_backup.sh
./pixel_backup.sh --help

No DMG, no trust decisions, works on any macOS with bash and adb.


What's new


Changes in this release

Added

  • Wireless ADB support — connect to any Android device over Wi-Fi without a USB cable:
    • "Connect wirelessly" expandable section in the device panel: enter an IP address and tap Connect
    • Saved addresses persist across app restarts and auto-reconnect every poll cycle
    • Android Wireless Debugging pairing flow (Settings → Developer options → Wireless debugging → Pair device with pairing code) via a dedicated WirelessPairingSheet
    • Connected wireless devices show a Wi-Fi icon; USB devices show a cable icon
    • Disconnect button per wireless device; offline saved addresses shown as "reconnecting…" with a remove button
  • Documents added as a default copy folder
  • App icon — custom 1024×1024 design with all required macOS sizes bundled as AppIcon.icns
  • build.sh now auto-installs the built .app to /Applications after every build (removes the old copy first to prevent nesting)
  • Real-time transfer speed (MB/s) and ETA displayed in the progress view
  • Elapsed time counter (Xm Ys elapsed) during active backups
  • Current filename shown live under the progress bar while copying
  • Free disk space indicator on the destination picker (colour-coded: red <5 GB, orange <20 GB)
  • Last backup summary strip on config panel (date, file count, GB — read from manifest, not filesystem scan)
  • "Try Again" / "New Backup" button on failed and cancelled states
  • ⌘Return keyboard shortcut to start a backup from the config panel
  • + toolbar button to open a new independent window when only one window is open
  • USB debugging step-by-step inline guide shown when no device is detected
  • Music and Backups added as default copy folders
  • Custom folder paths: add any Android path via the UI (shown as purple pills)
  • Drag-and-drop destination folder onto the window or destination picker row
  • History view shows "Folder moved or deleted" warning for stale entries
  • English, German, Spanish, and French localization
  • --help flag on pixel_backup.sh prints all environment variable parameters

Changed

  • Backup history now reads .transfer_meta/manifest.tsv instead of walking every file — critical performance fix for large backups (18k stat() calls → 1 file read)
  • Multiple independent windows (⌘N) — each window owns its own BackupManager so two devices can be backed up simultaneously
  • Menu bar replaced SwiftUI MenuBarExtra with NSApplicationDelegate-managed NSStatusItem — fixes context menu appearing on the wrong display in multi-monitor setups
  • Backup folder names are now dated: YYYY-MM-DD_DeviceName_Serial/
  • sanitize_name() now strips Unicode, emoji, and multi-byte characters; TCP/IP serials (containing colons) are sanitised for use in macOS paths

Fixed

  • App crash near backup summary caused by @MainActor isolation: DispatchQueue.main.async replaced with Task { @MainActor in } in termination handler
  • Thread-safety warning in readabilityHandler — buffer access confined to a dedicated serial DispatchQueue
  • NotificationManager crash when running via swift run without a bundle identifier
  • Off-screen windows (e.g. from a disconnected external monitor) are relocated to the main display on launch and focus
  • Cancel crash: if the user started a new backup while a previously-cancelled process was still winding down, handleTermination would call process?.standardOutput = nil on the new (running) process — Foundation raises an exception for this. The pipe is now disconnected inside the terminationHandler closure (where proc is the already-terminated instance), and a backupID UUID guards against stale terminations ever touching a newer backup's state
  • Cancelled summary not shown: clicking Cancel while the script was in progress showed only the raw log tail; handleTermination(exit 130) now parses the partial summary that on_interrupt() prints and transitions to .done(summary:) with wasCancelled = true — so the structured SummaryCard appears with a "Backup Cancelled" header and a "Back" button
  • State race after completion: log-line tasks still queued on the main actor when handleTermination fires could overwrite .done(summary:) with .failed; isTerminating flag prevents this
  • readabilityHandler resource leak: the pipe's file handle handler was never set to nil after process exit; it is now cleared at the start of handleTermination