media-device-copier

📱 A Windows command-line utility for copying files from phones and other media devices connected as MTP devices.


Project maintained by drittich Hosted on GitHub Pages — Theme by mattgraham

Media Device Copier

CI Lint Latest release License: MIT .NET Platform

Media Device Copier is a Windows command-line utility for copying files to and from phones and other devices connected via MTP (Media Transfer Protocol).

Use it to:

Table of contents


Features


Requirements


Quick start

1) Show help

MediaDeviceCopier.exe -h

2) List devices

MediaDeviceCopier.exe list-devices
# alias
MediaDeviceCopier.exe l

3) List files in a device folder

MediaDeviceCopier.exe list-files -n "Apple iPhone" -s "Internal Storage\DCIM\100APPLE"

# alias + filter to only jpeg files + print full device paths
MediaDeviceCopier.exe lf -n "Apple iPhone" -s "Internal Storage\DCIM\100APPLE" -f "\.(jpg|jpeg)$" --full-path

4) Download from device to PC

MediaDeviceCopier.exe download-files -n "Apple iPhone" -s "Internal Storage\DCIM\100APPLE" -t "D:\Photos" -r

5) Upload from PC to device

MediaDeviceCopier.exe upload-files -n "Android Device" -s "C:\Documents" -t "Internal Storage\Documents" -r -f "\.pdf$"

Commands

list-devices

Lists all available MTP devices.

Example:

MediaDeviceCopier.exe list-devices

list-files

Lists files in a device folder.

Options:

Usage:

MediaDeviceCopier.exe list-files -n "<Device>" -s "<DeviceFolder>" [-f "<regex>"] [--full-path]

Examples:

# List all files in a device folder
MediaDeviceCopier.exe list-files -n "Apple iPhone" -s "Internal Storage\DCIM\100APPLE"

# List only JPEG files and print full device paths
MediaDeviceCopier.exe lf -n "Apple iPhone" -s "Internal Storage\DCIM\100APPLE" -f "\.(jpg|jpeg)$" --full-path

download-files

Downloads files from an MTP device folder to a Windows folder.

Required options:

Common optional options:

Examples:

# Copy pictures recursively and skip already-copied images
MediaDeviceCopier.exe download-files -n "Apple iPhone" -s "Internal Storage" -t "D:\MyPictureFolder" -r

# Move (download then delete from device) all videos after archiving
MediaDeviceCopier.exe download-files -n "Apple iPhone" -s "Internal Storage\DCIM\100APPLE" -t "D:\Archive" -r --move

# Copy only MP4 files from a flat folder (non-recursive)
MediaDeviceCopier.exe download-files -n "Apple iPhone" -s "Internal Storage\DCIM\100APPLE" -t "D:\Videos" -f "\.mp4$"

# Recursive copy: only subfolders starting with 2025, only JPG/PNG files
MediaDeviceCopier.exe download-files -n "Apple iPhone" -s "Internal Storage" -t "D:\MyPictureFolder" -r -sf "^2025.*" -f "\.(jpg|png)$"

# Force overwrite existing files (disable skip-existing)
MediaDeviceCopier.exe download-files -n "Apple iPhone" -s "Internal Storage\DCIM" -t "D:\Photos" --skip-existing false

upload-files

Uploads files from a Windows folder to an MTP device folder.

Required options:

Common optional options:

Examples:

# Upload only PDFs
MediaDeviceCopier.exe upload-files -n "Android Device" -s "C:\Documents" -t "Internal Storage\Documents" -r -f "\.pdf$"

Filtering

The filtering system uses two independent regex patterns:

  1. Subfolder filters (-sf, --filter-subfolders) are applied during folder recursion before descending into subfolders.
  2. File filters (-f, --filter-files) are applied to the file list within each processed folder.

Notes:


Common behaviors and defaults

MediaDeviceCopier.exe --version

Troubleshooting

Device not found

If you see “Device not found”, run:

MediaDeviceCopier.exe list-devices

Then copy/paste the device name exactly into -n.

Folder not found

Invalid regex

If a filter regex is invalid, the CLI will reject it. Start simple and escape backslashes correctly in your shell.

Unsupported file types

Some device files may not be transferable via MTP; those are reported as skipped.

Failed files and exit code

If a file cannot be downloaded (for example, the device reports an object with no name, or every download strategy fails), it is reported as FAILED (<reason>), the run continues with the remaining files, and a summary of failed files and folders is printed at the end. The exit code is 0 when everything succeeded and 1 if any file or folder failed, so scripts can detect an incomplete transfer.

Empty folders and transient device errors


Architecture (resilient downloads)

MTP transfers can fail for certain files due to device firmware quirks, timing issues, or protocol limitations. MediaDeviceCopier uses a multi-strategy download pipeline and detailed diagnostics to make downloads more resilient.

Implementation details are documented in ARCHITECTURE_MTP_STRATEGIES.md.


Building from source

Requires the .NET 10 SDK on Windows (the app targets net10.0-windows).

# Build
dotnet build -c Release

# Run the mocked test suite
dotnet test MediaDeviceCopier.Tests.Mocked/MediaDeviceCopier.Tests.Mocked.csproj

# Produce the single-file executable (framework-dependent, win-x64)
dotnet publish MediaDeviceCopier/MediaDeviceCopier.csproj -c Release -r win-x64 --self-contained false -p:PublishSingleFile=true -o publish
# -> publish/MediaDeviceCopier.exe

Note: MediaDeviceCopier.Tests.RealDevice is a separate suite that requires a physical MTP device connected to the machine, so it is not run by dotnet test above or in CI. Run it manually when validating against real hardware.

The application version comes from a single source: the <Version> element in MediaDeviceCopier/MediaDeviceCopier.csproj. AssemblyVersion, FileVersion, and the version shown by --version / --help are all derived from it, so a release only requires changing that one value.


Continuous integration

Two GitHub Actions workflows run automatically on every pull request and on pushes to main:

Dependabot opens weekly PRs for NuGet and GitHub Actions updates.


Releasing

Releases are produced by the Release workflow (.github/workflows/release.yml), which triggers on any pushed tag matching v*. To cut a release:

  1. Bump the version. Edit <Version> in MediaDeviceCopier/MediaDeviceCopier.csproj (this is the only place to change it), commit, and merge to main.
  2. Tag and push. The tag version must match <Version> exactly (with a v prefix) — the workflow verifies this and fails the build on a mismatch:

    git checkout main
    git pull
    git tag v0.8.0
    git push origin v0.8.0
    
  3. The workflow then publishes MediaDeviceCopier.exe, generates release notes (categorized via .github/release.yml), and creates a draft GitHub Release with the exe attached.
  4. Review and publish. Open the draft release on GitHub, review the auto-generated notes (add any behavior-change callouts), confirm “Set as the latest release”, and click Publish release.

Tip: When a PR closes multiple issues, give each one its own closing keyword — Closes #20, closes #21, closes #22. Writing Closes #20, #21, #22 only closes the first.


License

MIT License. See LICENSE for details.


Contributing

Contributions, issues, and feature requests are welcome!