udiskie
udiskie copied to clipboard
[Feature Request] MTP support
Automounting mtp-enabed devices using libmtp or any other mtp backend
Sounds promising. Do you have any experience with this? I'm afraid, I don't know anything about libmtp. Is there a dbus interface or a python binding or will it require writing a C(ython) binding manually? If you want to speed things up, you (or someone else) could start development. Otherwise, I will postpone this for possibly quite a long time, since I don't even have any mtp device.
I opened an issue on storaged repo, hope it can be implemented there.
Edit: See here: https://github.com/storaged-project/udisks/issues/187
Hello @coldfix, do you support MTP already? Or have same tips and pointers on it? Any status on issue?
Nope, sorry. I'd rather have it implemented on the udisks side and continue to use udiskie only as udisks-client (unless you can propose a somewhat clean patch for udiskie that works on the user level). However, I currently don't have the time to read into libmtp or propose a udisks interface+patch, so don't hold back if anyone wants to step in.
For anyone interested: android-file-transfer-linux works very well for mounting MTP over FUSE, way better than libmtp
-based programs I tried (gvfs, mtpfs).
There is an open ticket to introduce python bindings to android-file-transfer-linux, if it ever happens I can work on udiskie
patches.
That would be great!
For the record, the udisks team seems to be unwilling to add mtp to the udisks featureset itself.
Hi!
udiskie is really nice @coldfix thanks! I'm also missing MTP support, I know nothing about D-Bus, but if I start dbus-monitor and plug my cellphone I see:
signal time=1591045012.179222 sender=:1.26 -> destination=(null destination) serial=2858 path=/org/gtk/Private/RemoteVolumeMonitor; interface=org.gtk.Private.RemoteVolumeMonitor; member=VolumeAdded
string "org.gtk.vfs.MTPVolumeMonitor"
string "0x7fd91c010800"
struct {
string "0x7fd91c010800"
string "SAMSUNG Android"
string "multimedia-player"
string ". GThemedIcon multimedia-player-symbolic multimedia-symbolic multimedia-player multimedia"
string ""
string "mtp://SAMSUNG_SAMSUNG_Android_420329bed4df5200/"
boolean true
boolean true
string ""
string ""
array [
dict entry(
string "unix-device"
string "/dev/bus/usb/002/043"
)
]
string ""
array [
]
}
And it contains all the needed data:
- It says a volume was added (member=VolumeAdded)
- It says this is an MTP device (mtp://...)
- It provides a name to identify it ("SAMSUNG Android")
- It says the bus and device (/dev/bus/usb/002/043)
So you just need to:
- Create a mount point
- Invoke jmtpfs tool:
jmtpfs -device=BUS,DEVICE MOUNT_POINT
- When finished just:
fusermount -u MOUNT_POINT
It works really well for me, and you could make it configurable allowing the user to replace jmtpfs by another tool.
I don't know who is sending this message, but I'm not using Gnome nor KDE. Seems to be some very basic functionality. And doesn't look too complex to implement. What do you think?
Oh, BTW, here is an example using dbus-python:
from gi.repository import GLib
import dbus
import dbus.mainloop.glib
import re
def mountDetected(sender, mount_id, data):
name=data[1]
uri=data[5]
device=data[10]['unix-device']
if uri[:6] == 'mtp://':
m = re.search(r'\/dev\/bus\/usb\/(\d+)/(\d+)', device)
if m:
bus = m.group(1)
dev = m.group(2)
print "To mount "+name+" use:"
print "jmtpfs -device={},{} MOUNT_POINT".format(bus, dev)
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
sessionbus = dbus.SessionBus()
sessionbus.add_signal_receiver(signal_name="VolumeAdded",
dbus_interface="org.gtk.Private.RemoteVolumeMonitor",
path="/org/gtk/Private/RemoteVolumeMonitor",
bus_name=None,
handler_function=mountDetected)
loop = GLib.MainLoop()
loop.run()
Hi!
udiskie is really nice @coldfix thanks! I'm also missing MTP support, I know nothing about D-Bus, but if I start dbus-monitor and plug my cellphone I see:
signal time=1591045012.179222 sender=:1.26 -> destination=(null destination) serial=2858 path=/org/gtk/Private/RemoteVolumeMonitor; interface=org.gtk.Private.RemoteVolumeMonitor; member=VolumeAdded string "org.gtk.vfs.MTPVolumeMonitor" string "0x7fd91c010800" struct { string "0x7fd91c010800" string "SAMSUNG Android" string "multimedia-player" string ". GThemedIcon multimedia-player-symbolic multimedia-symbolic multimedia-player multimedia" string "" string "mtp://SAMSUNG_SAMSUNG_Android_420329bed4df5200/" boolean true boolean true string "" string "" array [ dict entry( string "unix-device" string "/dev/bus/usb/002/043" ) ] string "" array [ ] }
And it contains all the needed data:
1. It says a volume was added (member=VolumeAdded) 2. It says this is an MTP device (mtp://...) 3. It provides a name to identify it ("SAMSUNG Android") 4. It says the bus and device (/dev/bus/usb/002/043)
Hi,
many thanks, I didn't know about this dbus interface. With such a binding it should be relatively easy to add support in udiskie. I guess this depends on gvfs(?)
So you just need to:
1. Create a mount point 2. Invoke jmtpfs tool:
I would hope this dbus interface also has methods for mounting, but I haven't checked yet.
jmtpfs -device=BUS,DEVICE MOUNT_POINT
1. When finished just:
fusermount -u MOUNT_POINT
It works really well for me, and you could make it configurable allowing the user to replace jmtpfs by another tool.
I don't know who is sending this message, but I'm not using Gnome nor KDE. Seems to be some very basic functionality. And doesn't look too complex to implement. What do you think?
Looks like it's gvfs. It's not that basic, but one could give it a try as optional dependency. (Actually I think udiskie probably better fits the niche of users who are willing to install udisks but don't necessarily want gvfs).
Looks like it's gvfs. It's not that basic, but one could give it a try as optional dependency. (Actually I think udiskie probably better fits the niche of users who are willing to install udisks but don't necessarily want gvfs).
I can confirm gvfs is running on my system:
$ systemctl | grep gvfs
run-user-1000-gvfs.mount loaded active mounted /run/user/1000/gvfs
The good thing is that this is all optional, no extra Python packages are needed.
At low level libmtp seems to be hooking udev. GIO MTP backend uses libmtp. Various Python bindings for libmtp seems to be available. Not sure if any of them can inform about a new device plugged without needing to poll.
So I took a quick look. It seems this is an undocumented private interface of gvfs-mtp (org.gtk.Private.RemoteVolumeMonitor
) for use by other gvfs tools. So this will probably take some reading the source gvfs source code. It has a method VolumeMount
that could be useful, but I'm actually not even sure whether this will mount an actual fuse filesystem or make the device just visible within some gvfs scope.
In any case, it doesn't seem to know about mount points created by jmtpfs (execute its List
method and observe that the mountpoint isn't listed). So its only use for us seems to be listing available devices.
You mention
GIO MTP backend uses libmtp. Various Python bindings for libmtp seems to be available.
What gio mtp backend and python bindings? Can you paste some links?
but I'm actually not even sure whether this will mount an actual fuse filesystem or make the device just visible within some gvfs scope.
When I used gnome-shell something that annoyed me was that in order to do anything with an MTP device I was forced to use nautilus (well, at least worked, KDE+dolphin didn't). So I think this is only visible inside gvfs, not really mounted.
So its only use for us seems to be listing available devices.
Yes, list and report the connection.
What gio mtp backend
gvfs: "GIO - GLib Input, Output and Streaming Library MTP Backend" https://github.com/gicmo/gvfs/blob/master/daemon/gvfsbackendmtp.c
and python bindings?
Just search for "python libmtp" on Google (PyMTP, mtpy, python-mtp, etc.)
Ok, this is really low level, at least for Python ;-)
import pyudev
mounted = {}
def log_event(action, device):
if action == 'add' and device.get('ID_MTP_DEVICE'): # remove, bind, unbind
path = str(device)
print('\nAdding: '+path)
bus = device.get('BUSNUM')
dev = device.get('DEVNUM')
# for a in device.properties:
# print(a+' -> '+device.get(a))
name = device.get('ID_SERIAL')
print("To mount "+name+" use:")
print("jmtpfs -device={},{} MOUNT_POINT".format(bus, dev))
mounted[path] = 1
elif action == 'remove': # remove, bind, unbind
name = str(device)
try:
if mounted[name]:
print('\nRemoving: '+name)
mounted[name] = 0
except KeyError:
pass
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('usb')
observer = pyudev.MonitorObserver(monitor, log_event)
observer.start()
input("Press Enter to stop ...\n")
observer.stop()
This is even lower level than what gvfs-mtp-volume-monitor does (uses gudev on top of udev).
Nice! You seem to know more about this than me :) A pyudev based solution might also be a good option.
By the way: mounting via gvfs should also provide a fuse filesystem in /run/user/UID/gvfs
, see here.
Nice! You seem to know more about this than me :) A pyudev based solution might also be a good option.
:-) (Google "knows" more than us ;-)
By the way: mounting via gvfs should also provide a fuse filesystem in
/run/user/UID/gvfs
, see here.
Thanks for the tip!