summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Gil Peyrot <linkmauve@linkmauve.fr>2020-07-09 20:04:50 +0200
committerEmmanuel Gil Peyrot <linkmauve@linkmauve.fr>2020-07-09 21:24:59 +0200
commit95c33c1665ea1866a46c29a7bc31e8b25a5017da (patch)
treefe0b911bc6dbe33089caa56d00a73ff496baf6df
parent6146cf6a4f8574cfac6449cf78122e5854b70710 (diff)
downloadpoezio-xdg-desktop-portal.tar.gz
poezio-xdg-desktop-portal.tar.bz2
poezio-xdg-desktop-portal.tar.xz
poezio-xdg-desktop-portal.zip
Make /upload work in Flatpakxdg-desktop-portal
When /upload isn’t given an argument, it will instead open a file chooser and block poezio until the user selected a file. This will make poezio timeout from all rooms until the user is done choosing a file, but I didn’t find a good way to integrate GLib’s main loop with asyncio for now, and this can be fixed in a latter commit.
-rw-r--r--plugins/upload.py108
1 files changed, 99 insertions, 9 deletions
diff --git a/plugins/upload.py b/plugins/upload.py
index c702dc49..94393d5f 100644
--- a/plugins/upload.py
+++ b/plugins/upload.py
@@ -9,11 +9,14 @@ This plugin adds a command to the chat tabs.
.. glossary::
/upload
- **Usage:** ``/upload <filename>``
+ **Usage:** ``/upload [filename]``
Uploads the <filename> file to the preferred HTTP File Upload
service (see XEP-0363) and fill the input with its URL.
+ If <filename> isn’t specified, use the FileChooser from
+ xdg-desktop-portal to ask the user which file to upload.
+
"""
@@ -31,6 +34,83 @@ from poezio.core.structs import Completion
from poezio.decorators import command_args_parser
from poezio import tabs
+try:
+ from gi.repository import Gio, GLib
+ from urllib.parse import urlparse, unquote
+ HAVE_GLIB = True
+except ImportError:
+ HAVE_GLIB = False
+
+def open_file_xdg_desktop_portal():
+ '''
+ Use org.freedesktop.portal.FileChooser from xdg-desktop-portal to open a
+ file chooser dialog.
+
+ This method uses GDBus from GLib, and specifically runs its mainloop which
+ will block the entirety of poezio until it is done, which might cause us to
+ drop from rooms and such if the user isn’t quick enough at choosing the
+ file…
+
+ See https://flatpak.github.io/xdg-desktop-portal/portal-docs.html
+ '''
+ if not HAVE_GLIB:
+ return None
+
+ def get_file(connection,
+ sender,
+ path,
+ interface,
+ signal,
+ params):
+ nonlocal return_path
+ # TODO: figure out how to raise an exception to the outside of the GLib
+ # loop.
+ if not isinstance(params, GLib.Variant):
+ loop.quit()
+ return
+ response_code, results = params.unpack()
+ if response_code != 0:
+ loop.quit()
+ return
+ uris = results['uris']
+ if len(uris) != 1:
+ loop.quit()
+ return
+ parsed_uri = urlparse(uris[0])
+ if parsed_uri.scheme != "file":
+ loop.quit()
+ return
+ return_path = unquote(parsed_uri.path)
+ loop.quit()
+
+ return_path = None
+ proxy = Gio.DBusProxy.new_for_bus_sync(Gio.BusType.SESSION,
+ Gio.DBusProxyFlags.NONE,
+ None,
+ 'org.freedesktop.portal.Desktop',
+ '/org/freedesktop/portal/desktop',
+ 'org.freedesktop.portal.FileChooser',
+ None)
+
+ try:
+ handle = proxy.OpenFile('(ssa{sv})', '', 'poezio', {
+ 'accept_label': GLib.Variant('s', '_Upload'),
+ })
+ except GLib.Error:
+ return None
+ conn = proxy.get_connection()
+ conn.signal_subscribe('org.freedesktop.portal.Desktop',
+ 'org.freedesktop.portal.Request',
+ 'Response',
+ handle,
+ None,
+ Gio.DBusSignalFlags.NO_MATCH_RULE,
+ get_file)
+
+ loop = GLib.MainLoop()
+ loop.run()
+ return return_path
+
class Plugin(BasePlugin):
dependencies = {'embed'}
@@ -50,7 +130,12 @@ class Plugin(BasePlugin):
short='Upload a file',
completion=self.completion_filename)
- async def upload(self, filename) -> Optional[str]:
+ async def upload(self, filename: Optional[str]) -> Optional[str]:
+ if filename is None:
+ filename = open_file_xdg_desktop_portal()
+ if filename is None:
+ self.api.information('Failed to query which file to upload.', 'Error')
+ return None
try:
url = await self.core.xmpp['xep_0363'].upload_file(filename)
except UploadServiceNotFound:
@@ -66,18 +151,18 @@ class Plugin(BasePlugin):
return None
return url
- async def send_upload(self, filename):
+ async def send_upload(self, filename: Optional[str]):
url = await self.upload(filename)
if url is not None:
self.embed.embed_image_url(url)
- @command_args_parser.quoted(1)
+ @command_args_parser.quoted(0, 1)
def command_upload(self, args):
- if args is None:
- self.core.command.help('upload')
- return
- filename, = args
- filename = expanduser(filename)
+ if args:
+ filename, = args
+ filename = expanduser(filename)
+ else:
+ filename = None
asyncio.ensure_future(self.send_upload(filename))
@staticmethod
@@ -85,3 +170,8 @@ class Plugin(BasePlugin):
txt = expanduser(the_input.get_text()[8:])
files = glob(txt + '*')
return Completion(the_input.auto_completion, files, quotify=False)
+
+
+if __name__ == '__main__':
+ path = open_file_xdg_desktop_portal()
+ print('Obtained path', path)