From 82a9aa1232a28e8206b3eab8301e1fa1f9f6ea0e Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Sat, 23 May 2020 23:11:42 +0200 Subject: [PATCH] Added clipboard backend --- docs/source/backends.rst | 1 + docs/source/events.rst | 1 + docs/source/platypush/backend/clipboard.rst | 5 +++ docs/source/platypush/events/clipboard.rst | 5 +++ platypush/backend/clipboard.py | 34 +++++++++++++++ platypush/message/event/clipboard.py | 9 ++++ platypush/plugins/pushbullet.py | 46 ++++++++++++++++----- requirements.txt | 3 ++ setup.py | 2 + 9 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 docs/source/platypush/backend/clipboard.rst create mode 100644 docs/source/platypush/events/clipboard.rst create mode 100644 platypush/backend/clipboard.py create mode 100644 platypush/message/event/clipboard.py diff --git a/docs/source/backends.rst b/docs/source/backends.rst index eedc39cd89..49cdeac9da 100644 --- a/docs/source/backends.rst +++ b/docs/source/backends.rst @@ -19,6 +19,7 @@ Backends platypush/backend/button.flic.rst platypush/backend/camera.pi.rst platypush/backend/chat.telegram.rst + platypush/backend/clipboard.rst platypush/backend/covid19.rst platypush/backend/foursquare.rst platypush/backend/google.fit.rst diff --git a/docs/source/events.rst b/docs/source/events.rst index e1edcb4ba0..9196bacec5 100644 --- a/docs/source/events.rst +++ b/docs/source/events.rst @@ -15,6 +15,7 @@ Events platypush/events/button.flic.rst platypush/events/camera.rst platypush/events/chat.telegram.rst + platypush/events/clipboard.rst platypush/events/covid19.rst platypush/events/distance.rst platypush/events/foursquare.rst diff --git a/docs/source/platypush/backend/clipboard.rst b/docs/source/platypush/backend/clipboard.rst new file mode 100644 index 0000000000..8d6ea0a390 --- /dev/null +++ b/docs/source/platypush/backend/clipboard.rst @@ -0,0 +1,5 @@ +``platypush.backend.clipboard`` +=============================== + +.. automodule:: platypush.backend.clipboard + :members: diff --git a/docs/source/platypush/events/clipboard.rst b/docs/source/platypush/events/clipboard.rst new file mode 100644 index 0000000000..34ba60b6b1 --- /dev/null +++ b/docs/source/platypush/events/clipboard.rst @@ -0,0 +1,5 @@ +``platypush.message.event.clipboard`` +===================================== + +.. automodule:: platypush.message.event.clipboard + :members: diff --git a/platypush/backend/clipboard.py b/platypush/backend/clipboard.py new file mode 100644 index 0000000000..ece09b5d90 --- /dev/null +++ b/platypush/backend/clipboard.py @@ -0,0 +1,34 @@ +import time +from typing import Optional + +import pyperclip + +from platypush.backend import Backend +from platypush.message.event.clipboard import ClipboardEvent + + +class ClipboardBackend(Backend): + """ + This backend monitors for changes in the clipboard and generates even when the user copies a new text. + + Requires: + + - **pyperclip** (``pip install pyperclip``) + + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._last_text: Optional[str] = None + + def run(self): + while not self.should_stop(): + text = pyperclip.paste() + if text and text != self._last_text: + self.bus.post(ClipboardEvent(text=text)) + + self._last_text = text + time.sleep(0.1) + + +# vim:sw=4:ts=4:et: diff --git a/platypush/message/event/clipboard.py b/platypush/message/event/clipboard.py new file mode 100644 index 0000000000..4fc4fa748b --- /dev/null +++ b/platypush/message/event/clipboard.py @@ -0,0 +1,9 @@ +from platypush.message.event import Event + + +class ClipboardEvent(Event): + def __init__(self, text: str, *args, **kwargs): + super().__init__(*args, text=text, **kwargs) + + +# vim:sw=4:ts=4:et: diff --git a/platypush/plugins/pushbullet.py b/platypush/plugins/pushbullet.py index 9763e76c91..3e7ccf2a9e 100644 --- a/platypush/plugins/pushbullet.py +++ b/platypush/plugins/pushbullet.py @@ -1,5 +1,7 @@ import json import os +from typing import Optional + import requests from platypush.context import get_backend @@ -18,12 +20,12 @@ class PushbulletPlugin(Plugin): * The :class:`platypush.backend.pushbullet.Pushbullet` backend enabled """ - def __init__(self, token: str = None, *args, **kwargs): + def __init__(self, token: str = None, **kwargs): """ :param token: Pushbullet API token. If not set the plugin will try to retrieve it from the Pushbullet backend configuration, if available """ - super().__init__(*args, **kwargs) + super().__init__(**kwargs) if not token: backend = get_backend('pushbullet') @@ -44,18 +46,18 @@ class PushbulletPlugin(Plugin): Get the list of available devices """ resp = requests.get('https://api.pushbullet.com/v2/devices', - headers={'Authorization': 'Bearer ' + self.token, - 'Content-Type': 'application/json'}) + headers={'Authorization': 'Bearer ' + self.token, + 'Content-Type': 'application/json'}) self._devices = resp.json().get('devices', []) self._devices_by_id = { - dev['iden']: dev - for dev in self._devices + dev['iden']: dev + for dev in self._devices } self._devices_by_name = { - dev['nickname']: dev - for dev in self._devices if 'nickname' in dev + dev['nickname']: dev + for dev in self._devices if 'nickname' in dev } @action @@ -124,7 +126,6 @@ class PushbulletPlugin(Plugin): if not device: raise RuntimeError('No such device') - pushbullet = get_backend('pushbullet') resp = requests.post('https://api.pushbullet.com/v2/upload-request', data=json.dumps({'file_name': os.path.basename(filename)}), headers={'Authorization': 'Bearer ' + self.token, @@ -151,7 +152,7 @@ class PushbulletPlugin(Plugin): 'device_iden': device['iden'] if device else None, 'file_name': r['file_name'], 'file_type': r['file_type'], - 'file_url': r['file_url'] })) + 'file_url': r['file_url']})) if resp.status_code >= 400: raise Exception('Pushbullet file push failed with status {}'. @@ -163,6 +164,29 @@ class PushbulletPlugin(Plugin): 'url': r['file_url'] } + @action + def send_clipboard(self, text: str): + """ + Copy text to the clipboard of a device. + + :param text: Text to be copied. + """ + backend = get_backend('pushbullet') + device_id = backend.get_device_id() if backend else None + + resp = requests.post('https://api.pushbullet.com/v2/ephemerals', + data=json.dumps({ + 'type': 'push', + 'push': { + 'body': text, + 'type': 'clip', + 'source_device_iden': device_id, + }, + }), + headers={'Authorization': 'Bearer ' + self.token, + 'Content-Type': 'application/json'}) + + resp.raise_for_status() + # vim:sw=4:ts=4:et: - diff --git a/requirements.txt b/requirements.txt index 8c7a8fe6c7..26bf934620 100644 --- a/requirements.txt +++ b/requirements.txt @@ -264,3 +264,6 @@ croniter # Support for SSH integration # paramiko + +# Support for clipboard integration +# pyperclip diff --git a/setup.py b/setup.py index d874c2de53..93a526e1c5 100755 --- a/setup.py +++ b/setup.py @@ -301,5 +301,7 @@ setup( 'samsungtv': ['samsungtvws'], # Support for SSH integration 'ssh': ['paramiko'], + # Support for clipboard integration + 'clipboard': ['pyperclip'], }, )