forked from platypush/platypush
[#61] Plugins actions refactoring
- Using `@action` annotation to indicate methods that are allowed to be executed as actions - The output and errors of an action are automatically wrapped into a `Response` object without any response build required on the plugin side
This commit is contained in:
parent
81a81312e3
commit
66d78c8615
42 changed files with 386 additions and 216 deletions
|
@ -60,6 +60,7 @@ class Config(object):
|
|||
self._config = self._read_config_file(self._cfgfile)
|
||||
|
||||
if 'token' in self._config:
|
||||
self._config['token'] = self._config['token']
|
||||
self._config['token_hash'] = get_hash(self._config['token'])
|
||||
|
||||
if 'workdir' not in self._config:
|
||||
|
|
|
@ -86,6 +86,11 @@ class EventAction(Request):
|
|||
|
||||
if 'target' not in action:
|
||||
action['target'] = action['origin']
|
||||
|
||||
token = Config.get('token')
|
||||
if token:
|
||||
action['token'] = token
|
||||
|
||||
return super().build(action)
|
||||
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ class Request(Message):
|
|||
raise RuntimeError('Response processed with errors: {}'.format(response))
|
||||
|
||||
logger.info('Processed response from plugin {}: {}'.
|
||||
format(plugin, response))
|
||||
format(plugin, str(response)))
|
||||
except Exception as e:
|
||||
# Retry mechanism
|
||||
response = Response(output=None, errors=[str(e), traceback.format_exc()])
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
import sys
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
from platypush.config import Config
|
||||
from platypush.message.response import Response
|
||||
from platypush.utils import get_decorators
|
||||
|
||||
|
||||
def action(f):
|
||||
def _execute_action(*args, **kwargs):
|
||||
return f(*args, **kwargs)
|
||||
output = None
|
||||
errors = []
|
||||
|
||||
try:
|
||||
output = f(*args, **kwargs)
|
||||
except Exception as e:
|
||||
if isinstance(args[0], Plugin):
|
||||
args[0].logger.exception(e)
|
||||
errors.append(str(e) + '\n' + traceback.format_exc())
|
||||
|
||||
return Response(output=output, errors=errors)
|
||||
|
||||
return _execute_action
|
||||
|
||||
|
||||
|
@ -19,7 +32,13 @@ class Plugin(object):
|
|||
if 'logging' in kwargs:
|
||||
self.logger.setLevel(getattr(logging, kwargs['logging'].upper()))
|
||||
|
||||
self.registered_actions = set(get_decorators(self.__class__).get('action', []))
|
||||
|
||||
def run(self, method, *args, **kwargs):
|
||||
if method not in self.registered_actions:
|
||||
raise RuntimeError('{} is not a registered action on {}'.format(
|
||||
method, self.__class__.__name__))
|
||||
|
||||
return getattr(self, method)(*args, **kwargs)
|
||||
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
"""
|
||||
|
||||
from platypush.context import get_backend
|
||||
from platypush.message.response import Response
|
||||
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class AssistantGooglePlugin(Plugin):
|
||||
"""
|
||||
|
@ -14,21 +12,25 @@ class AssistantGooglePlugin(Plugin):
|
|||
backend to programmatically control the conversation status.
|
||||
"""
|
||||
|
||||
def __init__(*args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@action
|
||||
def start_conversation(self):
|
||||
"""
|
||||
Programmatically start a conversation with the assistant
|
||||
"""
|
||||
assistant = get_backend('assistant.google')
|
||||
assistant.start_conversation()
|
||||
return Response(output='', errors=[])
|
||||
|
||||
@action
|
||||
def stop_conversation(self):
|
||||
"""
|
||||
Programmatically stop a running conversation with the assistant
|
||||
"""
|
||||
assistant = get_backend('assistant.google')
|
||||
assistant.stop_conversation()
|
||||
return Response(output='', errors=[])
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
"""
|
||||
|
||||
from platypush.context import get_backend
|
||||
from platypush.message.response import Response
|
||||
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class AssistantGooglePushtotalkPlugin(Plugin):
|
||||
"""
|
||||
|
@ -14,21 +12,24 @@ class AssistantGooglePushtotalkPlugin(Plugin):
|
|||
:mod:`platypush.backend.assistant.google.pushtotalk` backend.
|
||||
"""
|
||||
|
||||
def __init__(*args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@action
|
||||
def start_conversation(self):
|
||||
"""
|
||||
Programmatically start a conversation with the assistant
|
||||
"""
|
||||
assistant = get_backend('assistant.google.pushtotalk')
|
||||
assistant.start_conversation()
|
||||
return Response(output='', errors=[])
|
||||
|
||||
@action
|
||||
def stop_conversation(self):
|
||||
"""
|
||||
Programmatically stop a running conversation with the assistant
|
||||
"""
|
||||
assistant = get_backend('assistant.google.pushtotalk')
|
||||
assistant.stop_conversation()
|
||||
return Response(output='', errors=[])
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -7,8 +7,7 @@ import importlib
|
|||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class CalendarInterface:
|
||||
|
@ -64,6 +63,7 @@ class CalendarPlugin(Plugin, CalendarInterface):
|
|||
self.calendars.append(getattr(module, class_name)(**calendar))
|
||||
|
||||
|
||||
@action
|
||||
def get_upcoming_events(self, max_results=10):
|
||||
"""
|
||||
Get a list of upcoming events merging all the available calendars.
|
||||
|
@ -116,7 +116,7 @@ class CalendarPlugin(Plugin, CalendarInterface):
|
|||
else event['start']['date'] + 'T00:00:00+00:00'
|
||||
))[:max_results]
|
||||
|
||||
return Response(output=events)
|
||||
return events
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -9,8 +9,7 @@ import pytz
|
|||
|
||||
from icalendar import Calendar, Event
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
from platypush.plugins.calendar import CalendarInterface
|
||||
|
||||
|
||||
|
@ -61,6 +60,7 @@ class IcalCalendarPlugin(Plugin, CalendarInterface):
|
|||
}
|
||||
|
||||
|
||||
@action
|
||||
def get_upcoming_events(self, max_results=10, only_participating=True):
|
||||
"""
|
||||
Get the upcoming events. See
|
||||
|
@ -90,7 +90,7 @@ class IcalCalendarPlugin(Plugin, CalendarInterface):
|
|||
else:
|
||||
self.logger.error("HTTP error while getting {}: {}".format(self.url, response))
|
||||
|
||||
return Response(output=events)
|
||||
return events
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
"""
|
||||
|
||||
from platypush.context import get_backend
|
||||
from platypush.message.response import Response
|
||||
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class CameraPiPlugin(Plugin):
|
||||
|
@ -15,22 +13,26 @@ class CameraPiPlugin(Plugin):
|
|||
to programmatically control the status.
|
||||
"""
|
||||
|
||||
def __init__(*args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@action
|
||||
def start_recording(self):
|
||||
"""
|
||||
Start recording
|
||||
"""
|
||||
camera = get_backend('camera.pi')
|
||||
camera.send_camera_action(camera.CameraAction.START_RECORDING)
|
||||
return Response(output={'status':'ok'})
|
||||
|
||||
@action
|
||||
def stop_recording(self):
|
||||
"""
|
||||
Stop recording
|
||||
"""
|
||||
camera = get_backend('camera.pi')
|
||||
camera.send_camera_action(camera.CameraAction.STOP_RECORDING)
|
||||
return Response(output={'status':'ok'})
|
||||
|
||||
@action
|
||||
def take_picture(self, image_file):
|
||||
"""
|
||||
Take a picture.
|
||||
|
@ -40,7 +42,7 @@ class CameraPiPlugin(Plugin):
|
|||
"""
|
||||
camera = get_backend('camera.pi')
|
||||
camera.send_camera_action(camera.CameraAction.TAKE_PICTURE, image_file=image_file)
|
||||
return Response(output={'image_file':image_file})
|
||||
return {'image_file': image_file}
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
|
||||
from sqlalchemy import create_engine, Table, MetaData
|
||||
|
||||
from platypush.message.response import Response
|
||||
|
||||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class DbPlugin(Plugin):
|
||||
"""
|
||||
|
@ -40,6 +38,7 @@ class DbPlugin(Plugin):
|
|||
else:
|
||||
return self.engine
|
||||
|
||||
@action
|
||||
def execute(self, statement, engine=None, *args, **kwargs):
|
||||
"""
|
||||
Executes a raw SQL statement.
|
||||
|
@ -65,9 +64,8 @@ class DbPlugin(Plugin):
|
|||
result = connection.execute(statement)
|
||||
connection.commit()
|
||||
|
||||
return Response()
|
||||
|
||||
|
||||
@action
|
||||
def select(self, query, engine=None, *args, **kwargs):
|
||||
"""
|
||||
Returns rows (as a list of hashes) given a query.
|
||||
|
@ -119,9 +117,10 @@ class DbPlugin(Plugin):
|
|||
for row in result.fetchall()
|
||||
]
|
||||
|
||||
return Response(output=rows)
|
||||
return rows
|
||||
|
||||
|
||||
@action
|
||||
def insert(self, table, records, engine=None, *args, **kwargs):
|
||||
"""
|
||||
Inserts records (as a list of hashes) into a table.
|
||||
|
@ -169,8 +168,6 @@ class DbPlugin(Plugin):
|
|||
insert = table.insert().values(**record)
|
||||
engine.execute(insert)
|
||||
|
||||
return Response()
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import os
|
|||
|
||||
from apiclient import discovery
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.google import GooglePlugin
|
||||
from platypush.plugins.calendar import CalendarInterface
|
||||
|
||||
|
@ -25,6 +25,7 @@ class GoogleCalendarPlugin(GooglePlugin, CalendarInterface):
|
|||
super().__init__(scopes=self.scopes, *args, **kwargs)
|
||||
|
||||
|
||||
@action
|
||||
def get_upcoming_events(self, max_results=10):
|
||||
"""
|
||||
Get the upcoming events. See
|
||||
|
|
|
@ -17,7 +17,7 @@ from email.mime.image import MIMEImage
|
|||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.google import GooglePlugin
|
||||
|
||||
|
||||
|
@ -32,6 +32,7 @@ class GoogleMailPlugin(GooglePlugin):
|
|||
super().__init__(scopes=self.scopes, *args, **kwargs)
|
||||
|
||||
|
||||
@action
|
||||
def compose(self, sender, to, subject, body, files=None):
|
||||
"""
|
||||
Compose a message.
|
||||
|
@ -91,9 +92,10 @@ class GoogleMailPlugin(GooglePlugin):
|
|||
message = (service.users().messages().send(
|
||||
userId='me', body=body).execute())
|
||||
|
||||
return Response(output=message)
|
||||
return message
|
||||
|
||||
|
||||
@action
|
||||
def get_labels(self):
|
||||
"""
|
||||
Returns the available labels on the GMail account
|
||||
|
@ -101,7 +103,7 @@ class GoogleMailPlugin(GooglePlugin):
|
|||
service = self._get_service()
|
||||
results = service.users().labels().list(userId='me').execute()
|
||||
labels = results.get('labels', [])
|
||||
return Response(output=labels)
|
||||
return labels
|
||||
|
||||
|
||||
def _get_service(self):
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import json
|
||||
import requests
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.google import GooglePlugin
|
||||
|
||||
|
||||
|
@ -26,6 +26,7 @@ class GoogleMapsPlugin(GooglePlugin):
|
|||
self.api_key = api_key
|
||||
|
||||
|
||||
@action
|
||||
def get_address_from_latlng(self, latitude, longitude):
|
||||
"""
|
||||
Get an address information given lat/long
|
||||
|
@ -65,7 +66,7 @@ class GoogleMapsPlugin(GooglePlugin):
|
|||
elif component_type == 'postal_code':
|
||||
address['postal_code'] = addr_component['long_name']
|
||||
|
||||
return Response(output=address)
|
||||
return address
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
import threading
|
||||
import time
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class GpioPlugin(Plugin):
|
||||
|
@ -17,6 +16,10 @@ class GpioPlugin(Plugin):
|
|||
* **RPi.GPIO** (`pip install RPi.GPIO`)
|
||||
"""
|
||||
|
||||
def __init__(*args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@action
|
||||
def write(self, pin, val):
|
||||
"""
|
||||
Write a byte value to a pin.
|
||||
|
@ -44,12 +47,13 @@ class GpioPlugin(Plugin):
|
|||
gpio.setup(pin, gpio.OUT)
|
||||
gpio.output(pin, val)
|
||||
|
||||
return Response(output={
|
||||
return {
|
||||
'pin': pin,
|
||||
'val': val,
|
||||
'method': 'write',
|
||||
})
|
||||
}
|
||||
|
||||
@action
|
||||
def read(self, pin):
|
||||
"""
|
||||
Reads a value from a PIN.
|
||||
|
@ -74,11 +78,11 @@ class GpioPlugin(Plugin):
|
|||
gpio.setup(pin, gpio.IN)
|
||||
val = gpio.input(pin)
|
||||
|
||||
return Response(output={
|
||||
return {
|
||||
'pin': pin,
|
||||
'val': val,
|
||||
'method': 'read',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class GpioSensorPlugin(Plugin):
|
||||
|
@ -10,6 +10,7 @@ class GpioSensorPlugin(Plugin):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@action
|
||||
def get_measurement(self, *args, **kwargs):
|
||||
"""
|
||||
Implemented by the subclasses.
|
||||
|
@ -27,6 +28,7 @@ class GpioSensorPlugin(Plugin):
|
|||
"""
|
||||
raise NotImplementedError('get_measurement should be implemented in a derived class')
|
||||
|
||||
@action
|
||||
def get_data(self, *args, **kwargs):
|
||||
"""
|
||||
Alias for ``get_measurement``
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import threading
|
||||
import time
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.gpio.sensor import GpioSensorPlugin
|
||||
|
||||
|
||||
|
@ -39,6 +39,7 @@ class GpioSensorDistancePlugin(GpioSensorPlugin):
|
|||
gpio.output(self.trigger_pin, False)
|
||||
|
||||
|
||||
@action
|
||||
def get_measurement(self):
|
||||
"""
|
||||
Extends :func:`.GpioSensorPlugin.get_measurement`
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import enum
|
||||
import time
|
||||
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.gpio.sensor import GpioSensorPlugin
|
||||
from platypush.message.response import Response
|
||||
|
||||
|
||||
class MCP3008Mode(enum.Enum):
|
||||
|
@ -125,6 +125,7 @@ class GpioSensorMcp3008Plugin(GpioSensorPlugin):
|
|||
return (value * self.Vdd) / 1023.0 if value is not None else None
|
||||
|
||||
|
||||
@action
|
||||
def get_measurement(self):
|
||||
"""
|
||||
Returns a measurement from the sensors connected to the MCP3008 device.
|
||||
|
@ -164,7 +165,7 @@ class GpioSensorMcp3008Plugin(GpioSensorPlugin):
|
|||
else:
|
||||
values[i] = value
|
||||
|
||||
return Response(output=values)
|
||||
return values
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -2,8 +2,7 @@ import enum
|
|||
import threading
|
||||
import time
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
from platypush.context import get_plugin
|
||||
from platypush.config import Config
|
||||
|
||||
|
@ -95,7 +94,7 @@ class GpioZeroborgPlugin(Plugin):
|
|||
value = None
|
||||
|
||||
while value is None:
|
||||
value = plugin.get_measurement()
|
||||
value = plugin.get_measurement().output
|
||||
if time.time() - measure_start_time > timeout:
|
||||
return None
|
||||
|
||||
|
@ -127,6 +126,7 @@ class GpioZeroborgPlugin(Plugin):
|
|||
return direction
|
||||
|
||||
|
||||
@action
|
||||
def drive(self, direction):
|
||||
"""
|
||||
Drive the motors in a certain direction.
|
||||
|
@ -184,9 +184,10 @@ class GpioZeroborgPlugin(Plugin):
|
|||
self._drive_thread = threading.Thread(target=_run)
|
||||
self._drive_thread.start()
|
||||
|
||||
return Response(output={'status': 'running', 'direction': direction})
|
||||
return {'status': 'running', 'direction': direction}
|
||||
|
||||
|
||||
@action
|
||||
def stop(self):
|
||||
"""
|
||||
Turns off the motors
|
||||
|
@ -199,7 +200,7 @@ class GpioZeroborgPlugin(Plugin):
|
|||
self.zb.MotorsOff()
|
||||
self.zb.ResetEpo()
|
||||
|
||||
return Response(output={'status':'stopped'})
|
||||
return {'status':'stopped'}
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import requests
|
||||
|
||||
from platypush.message.response import Response
|
||||
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class HttpRequestPlugin(Plugin):
|
||||
"""
|
||||
|
@ -41,6 +39,9 @@ class HttpRequestPlugin(Plugin):
|
|||
}
|
||||
"""
|
||||
|
||||
def __init__(*args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def _exec(self, method, url, output='text', **kwargs):
|
||||
""" Available output types: text (default), json, binary """
|
||||
|
||||
|
@ -51,9 +52,10 @@ class HttpRequestPlugin(Plugin):
|
|||
|
||||
if output == 'json': output = response.json()
|
||||
if output == 'binary': output = response.content
|
||||
return Response(output=output, errors=[])
|
||||
return output
|
||||
|
||||
|
||||
@action
|
||||
def get(self, url, **kwargs):
|
||||
"""
|
||||
Perform a GET request
|
||||
|
@ -68,6 +70,7 @@ class HttpRequestPlugin(Plugin):
|
|||
return self._exec(method='get', url=url, **kwargs)
|
||||
|
||||
|
||||
@action
|
||||
def post(self, url, **kwargs):
|
||||
"""
|
||||
Perform a POST request
|
||||
|
@ -82,6 +85,7 @@ class HttpRequestPlugin(Plugin):
|
|||
return self._exec(method='post', url=url, **kwargs)
|
||||
|
||||
|
||||
@action
|
||||
def head(self, url, **kwargs):
|
||||
"""
|
||||
Perform an HTTP HEAD request
|
||||
|
@ -96,6 +100,7 @@ class HttpRequestPlugin(Plugin):
|
|||
return self._exec(method='head', url=url, **kwargs)
|
||||
|
||||
|
||||
@action
|
||||
def put(self, url, **kwargs):
|
||||
"""
|
||||
Perform a PUT request
|
||||
|
@ -110,6 +115,7 @@ class HttpRequestPlugin(Plugin):
|
|||
return self._exec(method='put', url=url, **kwargs)
|
||||
|
||||
|
||||
@action
|
||||
def delete(self, url, **kwargs):
|
||||
"""
|
||||
Perform a DELETE request
|
||||
|
@ -124,6 +130,7 @@ class HttpRequestPlugin(Plugin):
|
|||
return self._exec(method='delete', url=url, **kwargs)
|
||||
|
||||
|
||||
@action
|
||||
def options(self, url, **kwargs):
|
||||
"""
|
||||
Perform an HTTP OPTIONS request
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import datetime
|
||||
import dateutil.parser
|
||||
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.http.request import HttpRequestPlugin
|
||||
|
||||
class HttpRequestOtaBookingPlugin(HttpRequestPlugin):
|
||||
|
@ -12,6 +13,7 @@ class HttpRequestOtaBookingPlugin(HttpRequestPlugin):
|
|||
self.timeout = timeout
|
||||
|
||||
|
||||
@action
|
||||
def get_reservations(self, day='today'):
|
||||
url = 'https://hub-api.booking.com/v1/hotels/{}/reservations' \
|
||||
.format(self.hotel_id)
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import pylast
|
||||
import time
|
||||
|
||||
from platypush.message.response import Response
|
||||
|
||||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class LastfmPlugin(Plugin):
|
||||
"""
|
||||
|
@ -42,6 +40,7 @@ class LastfmPlugin(Plugin):
|
|||
password_hash = pylast.md5(self.password))
|
||||
|
||||
|
||||
@action
|
||||
def scrobble(self, artist, title, album=None, **kwargs):
|
||||
"""
|
||||
Scrobble a track to Last.FM
|
||||
|
@ -61,8 +60,6 @@ class LastfmPlugin(Plugin):
|
|||
timestamp = int(time.time()),
|
||||
)
|
||||
|
||||
return Response()
|
||||
|
||||
|
||||
def update_now_playing(self, artist, title, album=None, **kwargs):
|
||||
"""
|
||||
|
@ -82,8 +79,6 @@ class LastfmPlugin(Plugin):
|
|||
album = album,
|
||||
)
|
||||
|
||||
return Response()
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class LightPlugin(Plugin):
|
||||
"""
|
||||
Abstract plugin to interface your logic with lights/bulbs.
|
||||
"""
|
||||
|
||||
@action
|
||||
def on(self):
|
||||
""" Turn the light on """
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def off(self):
|
||||
""" Turn the light off """
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def toggle(self):
|
||||
""" Toggle the light status (on/off) """
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def status(self):
|
||||
""" Get the light status """
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -8,9 +8,9 @@ from redis.exceptions import TimeoutError as QueueTimeoutError
|
|||
from phue import Bridge
|
||||
|
||||
from platypush.context import get_backend
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.light import LightPlugin
|
||||
|
||||
from .. import LightPlugin
|
||||
|
||||
class LightHuePlugin(LightPlugin):
|
||||
"""
|
||||
|
@ -75,6 +75,7 @@ class LightHuePlugin(LightPlugin):
|
|||
for g in groups:
|
||||
self.lights.extend([l.name for l in g.lights])
|
||||
|
||||
@action
|
||||
def connect(self):
|
||||
"""
|
||||
Connect to the configured Hue bridge. If the device hasn't been paired
|
||||
|
@ -100,6 +101,7 @@ class LightHuePlugin(LightPlugin):
|
|||
self.logger.info('Bridge already connected')
|
||||
|
||||
|
||||
@action
|
||||
def get_scenes(self):
|
||||
"""
|
||||
Get the available scenes on the devices.
|
||||
|
@ -129,9 +131,10 @@ class LightHuePlugin(LightPlugin):
|
|||
}
|
||||
"""
|
||||
|
||||
return Response(output=self.bridge.get_scene())
|
||||
return self.bridge.get_scene()
|
||||
|
||||
|
||||
@action
|
||||
def get_lights(self):
|
||||
"""
|
||||
Get the configured lights.
|
||||
|
@ -170,9 +173,10 @@ class LightHuePlugin(LightPlugin):
|
|||
}
|
||||
"""
|
||||
|
||||
return Response(output=self.bridge.get_light())
|
||||
return self.bridge.get_light()
|
||||
|
||||
|
||||
@action
|
||||
def get_groups(self):
|
||||
"""
|
||||
Get the list of configured light groups.
|
||||
|
@ -222,7 +226,7 @@ class LightHuePlugin(LightPlugin):
|
|||
}
|
||||
"""
|
||||
|
||||
return Response(output=self.bridge.get_group())
|
||||
return self.bridge.get_group()
|
||||
|
||||
|
||||
def _exec(self, attr, *args, **kwargs):
|
||||
|
@ -257,8 +261,8 @@ class LightHuePlugin(LightPlugin):
|
|||
self.bridge = None
|
||||
raise e
|
||||
|
||||
return Response(output='ok')
|
||||
|
||||
@action
|
||||
def set_light(self, light, **kwargs):
|
||||
"""
|
||||
Set a light (or lights) property.
|
||||
|
@ -281,8 +285,8 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
self.connect()
|
||||
self.bridge.set_light(light, **kwargs)
|
||||
return Response(output='ok')
|
||||
|
||||
@action
|
||||
def set_group(self, group, **kwargs):
|
||||
"""
|
||||
Set a group (or groups) property.
|
||||
|
@ -305,8 +309,8 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
self.connect()
|
||||
self.bridge.set_group(group, **kwargs)
|
||||
return Response(output='ok')
|
||||
|
||||
@action
|
||||
def on(self, lights=[], groups=[]):
|
||||
"""
|
||||
Turn lights/groups on.
|
||||
|
@ -317,6 +321,7 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
return self._exec('on', True, lights=lights, groups=groups)
|
||||
|
||||
@action
|
||||
def off(self, lights=[], groups=[]):
|
||||
"""
|
||||
Turn lights/groups off.
|
||||
|
@ -327,6 +332,7 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
return self._exec('on', False, lights=lights, groups=groups)
|
||||
|
||||
@action
|
||||
def bri(self, value, lights=[], groups=[]):
|
||||
"""
|
||||
Set lights/groups brightness.
|
||||
|
@ -339,6 +345,7 @@ class LightHuePlugin(LightPlugin):
|
|||
return self._exec('bri', int(value) % (self.MAX_BRI+1),
|
||||
lights=lights, groups=groups)
|
||||
|
||||
@action
|
||||
def sat(self, value, lights=[], groups=[]):
|
||||
"""
|
||||
Set lights/groups saturation.
|
||||
|
@ -351,6 +358,7 @@ class LightHuePlugin(LightPlugin):
|
|||
return self._exec('sat', int(value) % (self.MAX_SAT+1),
|
||||
lights=lights, groups=groups)
|
||||
|
||||
@action
|
||||
def hue(self, value, lights=[], groups=[]):
|
||||
"""
|
||||
Set lights/groups color hue.
|
||||
|
@ -363,6 +371,7 @@ class LightHuePlugin(LightPlugin):
|
|||
return self._exec('hue', int(value) % (self.MAX_HUE+1),
|
||||
lights=lights, groups=groups)
|
||||
|
||||
@action
|
||||
def scene(self, name, lights=[], groups=[]):
|
||||
"""
|
||||
Set a scene by name.
|
||||
|
@ -374,6 +383,7 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
return self._exec('scene', name=name, lights=lights, groups=groups)
|
||||
|
||||
@action
|
||||
def is_animation_running(self):
|
||||
"""
|
||||
:returns: True if there is an animation running, false otherwise.
|
||||
|
@ -381,6 +391,7 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
return self.animation_thread is not None
|
||||
|
||||
@action
|
||||
def stop_animation(self):
|
||||
"""
|
||||
Stop a running animation if any
|
||||
|
@ -389,6 +400,7 @@ class LightHuePlugin(LightPlugin):
|
|||
if self.animation_thread and self.animation_thread.is_alive():
|
||||
self.redis.rpush(self.ANIMATION_CTRL_QUEUE_NAME, 'STOP')
|
||||
|
||||
@action
|
||||
def animate(self, animation, duration=None,
|
||||
hue_range=[0, MAX_HUE], sat_range=[0, MAX_SAT],
|
||||
bri_range=[MAX_BRI-1, MAX_BRI], lights=None, groups=None,
|
||||
|
@ -529,7 +541,6 @@ class LightHuePlugin(LightPlugin):
|
|||
self.stop_animation()
|
||||
self.animation_thread = Thread(target=_animate_thread, args=(lights,))
|
||||
self.animation_thread.start()
|
||||
return Response(output='ok')
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -2,10 +2,9 @@ import re
|
|||
import subprocess
|
||||
|
||||
from platypush.context import get_plugin
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins.media import PlayerState
|
||||
|
||||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class MediaCtrlPlugin(Plugin):
|
||||
"""
|
||||
|
@ -76,9 +75,9 @@ class MediaCtrlPlugin(Plugin):
|
|||
return None
|
||||
|
||||
|
||||
@action
|
||||
def play(self, url):
|
||||
(type, resource) = self._get_type_and_resource_by_url(url)
|
||||
response = Response(output='', errors = [])
|
||||
plugin_name = None
|
||||
|
||||
if type == 'mpd':
|
||||
|
@ -99,11 +98,13 @@ class MediaCtrlPlugin(Plugin):
|
|||
self.url = resource
|
||||
return self.plugin.play(resource)
|
||||
|
||||
@action
|
||||
def pause(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin: return plugin.pause()
|
||||
|
||||
|
||||
@action
|
||||
def stop(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin:
|
||||
|
@ -112,36 +113,43 @@ class MediaCtrlPlugin(Plugin):
|
|||
return ret
|
||||
|
||||
|
||||
@action
|
||||
def voldown(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin: return plugin.voldown()
|
||||
|
||||
|
||||
@action
|
||||
def volup(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin: return plugin.volup()
|
||||
|
||||
|
||||
@action
|
||||
def back(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin: return plugin.back()
|
||||
|
||||
|
||||
@action
|
||||
def forward(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin: return plugin.forward()
|
||||
|
||||
|
||||
@action
|
||||
def next(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin: return plugin.next()
|
||||
|
||||
|
||||
@action
|
||||
def previous(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin: return plugin.previous()
|
||||
|
||||
|
||||
@action
|
||||
def status(self):
|
||||
plugin = self._get_playing_plugin()
|
||||
if plugin: return plugin.status()
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import rtmidi
|
||||
import time
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class MidiPlugin(Plugin):
|
||||
|
@ -39,6 +38,7 @@ class MidiPlugin(Plugin):
|
|||
format(self.device_name))
|
||||
|
||||
|
||||
@action
|
||||
def send_message(self, values, *args, **kwargs):
|
||||
"""
|
||||
:param values: Values is expected to be a list containing the MIDI command code and the command parameters - see reference at https://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html
|
||||
|
@ -70,9 +70,9 @@ class MidiPlugin(Plugin):
|
|||
"""
|
||||
|
||||
self.midiout.send_message(values, *args, **kwargs)
|
||||
return Response(output={'status':'ok'})
|
||||
|
||||
|
||||
@action
|
||||
def play_note(self, note, velocity, duration=0):
|
||||
"""
|
||||
Play a note with selected velocity and duration.
|
||||
|
@ -96,6 +96,7 @@ class MidiPlugin(Plugin):
|
|||
self._played_notes.remove(note)
|
||||
|
||||
|
||||
@action
|
||||
def release_note(self, note):
|
||||
"""
|
||||
Release a played note.
|
||||
|
@ -108,6 +109,7 @@ class MidiPlugin(Plugin):
|
|||
self._played_notes.remove(note)
|
||||
|
||||
|
||||
@action
|
||||
def release_all_notes(self):
|
||||
"""
|
||||
Release all the notes being played.
|
||||
|
|
|
@ -2,8 +2,7 @@ import json
|
|||
import paho.mqtt.publish as publisher
|
||||
|
||||
from platypush.message import Message
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class MqttPlugin(Plugin):
|
||||
|
@ -12,6 +11,7 @@ class MqttPlugin(Plugin):
|
|||
with the MQTT protocol, see http://mqtt.org/
|
||||
"""
|
||||
|
||||
@action
|
||||
def send_message(self, topic, msg, host, port=1883, *args, **kwargs):
|
||||
"""
|
||||
Sends a message to a topic/channel.
|
||||
|
@ -35,7 +35,6 @@ class MqttPlugin(Plugin):
|
|||
except: pass
|
||||
|
||||
publisher.single(topic, str(msg), hostname=host, port=port)
|
||||
return Response(output={'state': 'ok'})
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,33 +1,47 @@
|
|||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class MusicPlugin(Plugin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@action
|
||||
def play(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def pause(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def stop(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def next(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def previous(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def setvol(self, vol):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def add(self, content):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def playlistadd(self, playlist):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def clear(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def status(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import mpd
|
||||
import re
|
||||
|
||||
from platypush.message.response import Response
|
||||
|
||||
from .. import MusicPlugin
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.music import MusicPlugin
|
||||
|
||||
class MusicMpdPlugin(MusicPlugin):
|
||||
"""
|
||||
|
@ -29,6 +28,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
:type port: int
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.client = mpd.MPDClient(use_unicode=True)
|
||||
|
@ -36,8 +36,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
|
||||
def _exec(self, method, *args, **kwargs):
|
||||
getattr(self.client, method)(*args, **kwargs)
|
||||
return self.status()
|
||||
return self.status().output
|
||||
|
||||
@action
|
||||
def play(self, resource=None):
|
||||
"""
|
||||
Play a resource by path/URI
|
||||
|
@ -51,6 +52,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
self.add(resource)
|
||||
return self._exec('play')
|
||||
|
||||
@action
|
||||
def play_pos(self, pos):
|
||||
"""
|
||||
Play a track in the current playlist by position number
|
||||
|
@ -61,6 +63,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
|
||||
return self._exec('play', pos)
|
||||
|
||||
@action
|
||||
def pause(self):
|
||||
""" Pause playback """
|
||||
|
||||
|
@ -68,31 +71,38 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
if status == 'play': return self._exec('pause')
|
||||
else: return self._exec('play')
|
||||
|
||||
@action
|
||||
def pause_if_playing(self):
|
||||
""" Pause playback only if it's playing """
|
||||
|
||||
status = self.status().output['state']
|
||||
if status == 'play': return self._exec('pause')
|
||||
else: return Response(output={})
|
||||
if status == 'play':
|
||||
return self._exec('pause')
|
||||
|
||||
@action
|
||||
def play_if_paused(self):
|
||||
""" Play only if it's paused (resume) """
|
||||
|
||||
status = self.status().output['state']
|
||||
if status == 'pause': return self._exec('play')
|
||||
else: return Response(output={})
|
||||
if status == 'pause':
|
||||
return self._exec('play')
|
||||
|
||||
@action
|
||||
def stop(self):
|
||||
""" Stop playback """
|
||||
|
||||
return self._exec('stop')
|
||||
|
||||
|
||||
@action
|
||||
def play_or_stop(self):
|
||||
""" Play or stop (play state toggle) """
|
||||
status = self.status().output['state']
|
||||
if status == 'play': return self._exec('stop')
|
||||
else: return self._exec('play')
|
||||
if status == 'play':
|
||||
return self._exec('stop')
|
||||
else:
|
||||
return self._exec('play')
|
||||
|
||||
@action
|
||||
def playid(self, track_id):
|
||||
"""
|
||||
Play a track by ID
|
||||
|
@ -103,14 +113,17 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
|
||||
return self._exec('playid', track_id)
|
||||
|
||||
@action
|
||||
def next(self):
|
||||
""" Play the next track """
|
||||
return self._exec('next')
|
||||
|
||||
@action
|
||||
def previous(self):
|
||||
""" Play the previous track """
|
||||
return self._exec('previous')
|
||||
|
||||
@action
|
||||
def setvol(self, vol):
|
||||
"""
|
||||
Set the volume
|
||||
|
@ -120,6 +133,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
"""
|
||||
return self._exec('setvol', vol)
|
||||
|
||||
@action
|
||||
def volup(self, delta=10):
|
||||
"""
|
||||
Turn up the volume
|
||||
|
@ -134,6 +148,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
self.setvol(str(new_volume))
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def voldown(self, delta=10):
|
||||
"""
|
||||
Turn down the volume
|
||||
|
@ -148,6 +163,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
self.setvol(str(new_volume))
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def random(self, value=None):
|
||||
"""
|
||||
Set shuffle mode
|
||||
|
@ -161,6 +177,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
value = 1 if value == 0 else 0
|
||||
return self._exec('random', value)
|
||||
|
||||
@action
|
||||
def repeat(self, value=None):
|
||||
"""
|
||||
Set repeat mode
|
||||
|
@ -174,6 +191,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
value = 1 if value == 0 else 0
|
||||
return self._exec('repeat', value)
|
||||
|
||||
@action
|
||||
def add(self, resource):
|
||||
"""
|
||||
Add a resource (track, album, artist, folder etc.) to the current playlist
|
||||
|
@ -184,6 +202,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
|
||||
return self._exec('add', resource)
|
||||
|
||||
@action
|
||||
def load(self, playlist):
|
||||
"""
|
||||
Load and play a playlist by name
|
||||
|
@ -195,10 +214,12 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
self._exec('load', playlist)
|
||||
return self.play()
|
||||
|
||||
@action
|
||||
def clear(self):
|
||||
""" Clear the current playlist """
|
||||
return self._exec('clear')
|
||||
|
||||
@action
|
||||
def seekcur(self, value):
|
||||
"""
|
||||
Seek to the specified position
|
||||
|
@ -209,16 +230,19 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
|
||||
return self._exec('seekcur', value)
|
||||
|
||||
@action
|
||||
def forward(self):
|
||||
""" Go forward by 15 seconds """
|
||||
|
||||
return self._exec('seekcur', '+15')
|
||||
|
||||
@action
|
||||
def back(self):
|
||||
""" Go backward by 15 seconds """
|
||||
|
||||
return self._exec('seekcur', '-15')
|
||||
|
||||
@action
|
||||
def status(self):
|
||||
"""
|
||||
:returns: The current state.
|
||||
|
@ -245,8 +269,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
}
|
||||
"""
|
||||
|
||||
return Response(output=self.client.status())
|
||||
return self.client.status()
|
||||
|
||||
@action
|
||||
def currentsong(self):
|
||||
"""
|
||||
:returns: The currently played track.
|
||||
|
@ -277,8 +302,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
track['artist'] = m.group(1)
|
||||
track['title'] = m.group(2)
|
||||
|
||||
return Response(output=track)
|
||||
return track
|
||||
|
||||
@action
|
||||
def playlistinfo(self):
|
||||
"""
|
||||
:returns: The tracks in the current playlist as a list of dicts.
|
||||
|
@ -315,8 +341,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
]
|
||||
"""
|
||||
|
||||
return Response(output=self.client.playlistinfo())
|
||||
return self.client.playlistinfo()
|
||||
|
||||
@action
|
||||
def listplaylists(self):
|
||||
"""
|
||||
:returns: The playlists available on the server as a list of dicts.
|
||||
|
@ -338,17 +365,18 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
]
|
||||
"""
|
||||
|
||||
return Response(output=sorted(self.client.listplaylists(),
|
||||
key=lambda p: p['playlist']))
|
||||
return sorted(self.client.listplaylists(), key=lambda p: p['playlist'])
|
||||
|
||||
@action
|
||||
def lsinfo(self, uri=None):
|
||||
"""
|
||||
Returns the list of playlists and directories on the server
|
||||
"""
|
||||
|
||||
output = self.client.lsinfo(uri) if uri else self.client.lsinfo()
|
||||
return Response(output=output)
|
||||
return output
|
||||
|
||||
@action
|
||||
def plchanges(self, version):
|
||||
"""
|
||||
Show what has changed on the current playlist since a specified playlist
|
||||
|
@ -360,8 +388,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
:returns: A list of dicts representing the songs being added since the specified version
|
||||
"""
|
||||
|
||||
return Response(output=self.client.plchanges(version))
|
||||
return self.client.plchanges(version)
|
||||
|
||||
@action
|
||||
def searchaddplaylist(self, name):
|
||||
"""
|
||||
Search and add a playlist by (partial or full) name
|
||||
|
@ -379,10 +408,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
self.client.clear()
|
||||
self.client.load(playlists[0])
|
||||
self.client.play()
|
||||
return Response(output={'playlist': playlists[0]})
|
||||
|
||||
return Response(output={})
|
||||
return {'playlist': playlists[0]}
|
||||
|
||||
@action
|
||||
def find(self, filter, *args, **kwargs):
|
||||
"""
|
||||
Find in the database/library by filter.
|
||||
|
@ -392,9 +420,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
:returns: list[dict]
|
||||
"""
|
||||
|
||||
return Response(
|
||||
output=self.client.find(*filter, *args, **kwargs))
|
||||
return self.client.find(*filter, *args, **kwargs)
|
||||
|
||||
@action
|
||||
def findadd(self, filter, *args, **kwargs):
|
||||
"""
|
||||
Find in the database/library by filter and add to the current playlist.
|
||||
|
@ -404,9 +432,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
:returns: list[dict]
|
||||
"""
|
||||
|
||||
return Response(
|
||||
output=self.client.findadd(*filter, *args, **kwargs))
|
||||
return self.client.findadd(*filter, *args, **kwargs)
|
||||
|
||||
@action
|
||||
def search(self, filter, *args, **kwargs):
|
||||
"""
|
||||
Free search by filter.
|
||||
|
@ -422,8 +450,9 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
items = sorted(items, key=lambda item:
|
||||
0 if item['file'].startswith('spotify:') else 1)
|
||||
|
||||
return Response(output=items)
|
||||
return items
|
||||
|
||||
@action
|
||||
def searchadd(self, filter, *args, **kwargs):
|
||||
"""
|
||||
Free search by filter and add the results to the current playlist.
|
||||
|
@ -433,8 +462,7 @@ class MusicMpdPlugin(MusicPlugin):
|
|||
:returns: list[dict]
|
||||
"""
|
||||
|
||||
return Response(
|
||||
output=self.client.searchadd(*filter, *args, **kwargs))
|
||||
return self.client.searchadd(*filter, *args, **kwargs)
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ import os
|
|||
import requests
|
||||
|
||||
from platypush.context import get_backend
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class PushbulletPlugin(Plugin):
|
||||
|
@ -18,6 +17,7 @@ class PushbulletPlugin(Plugin):
|
|||
* **requests** (``pip install requests``)
|
||||
"""
|
||||
|
||||
@action
|
||||
def send_push(self, **kwargs):
|
||||
"""
|
||||
Send a push.
|
||||
|
@ -40,9 +40,8 @@ class PushbulletPlugin(Plugin):
|
|||
raise Exception('Pushbullet push failed with status {}: {}'.
|
||||
format(resp.status_code, resp.json()))
|
||||
|
||||
return Response(output={'status':'ok'})
|
||||
|
||||
|
||||
@action
|
||||
def send_file(self, filename):
|
||||
"""
|
||||
Send a file.
|
||||
|
@ -83,11 +82,11 @@ class PushbulletPlugin(Plugin):
|
|||
raise Exception('Pushbullet file push failed with status {}'.
|
||||
format(resp.status_code))
|
||||
|
||||
return Response(output={
|
||||
return {
|
||||
'filename': r['file_name'],
|
||||
'type': r['file_type'],
|
||||
'url': r['file_url']
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from redis import Redis
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class RedisPlugin(Plugin):
|
||||
|
@ -13,6 +12,7 @@ class RedisPlugin(Plugin):
|
|||
* **redis** (``pip install redis``)
|
||||
"""
|
||||
|
||||
@action
|
||||
def send_message(self, queue, msg, *args, **kwargs):
|
||||
"""
|
||||
Send a message to a Redis queu.
|
||||
|
@ -32,7 +32,6 @@ class RedisPlugin(Plugin):
|
|||
|
||||
redis = Redis(*args, **kwargs)
|
||||
redis.rpush(queue, msg)
|
||||
return Response(output={'state': 'ok'})
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import json
|
||||
import serial
|
||||
|
||||
from platypush.message.response import Response
|
||||
|
||||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class SerialPlugin(Plugin):
|
||||
|
@ -60,6 +58,7 @@ class SerialPlugin(Plugin):
|
|||
|
||||
return output.decode().strip()
|
||||
|
||||
@action
|
||||
def get_data(self):
|
||||
"""
|
||||
Reads JSON data from the serial device and returns it as a message
|
||||
|
@ -78,7 +77,7 @@ class SerialPlugin(Plugin):
|
|||
self.logger.warning('Invalid JSON message from {}: {}'.
|
||||
format(self.device, data))
|
||||
|
||||
return Response(output=data)
|
||||
return data
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import subprocess
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
from .. import Plugin
|
||||
|
||||
class ShellPlugin(Plugin):
|
||||
"""
|
||||
Plugin to run custom shell commands.
|
||||
"""
|
||||
|
||||
@action
|
||||
def exec(self, cmd):
|
||||
"""
|
||||
Execute a command.
|
||||
|
@ -19,16 +20,12 @@ class ShellPlugin(Plugin):
|
|||
:returns: A response object where the ``output`` field will contain the command output as a string, and the ``errors`` field will contain whatever was sent to stderr.
|
||||
"""
|
||||
|
||||
output = None
|
||||
errors = []
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
return subprocess.check_output(
|
||||
cmd, stderr=subprocess.STDOUT, shell=True).decode('utf-8')
|
||||
except subprocess.CalledProcessError as e:
|
||||
errors = [e.output.decode('utf-8')]
|
||||
raise RuntimeError(e.output.decode('utf-8'))
|
||||
|
||||
return Response(output=output, errors=errors)
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class SwitchPlugin(Plugin):
|
||||
"""
|
||||
Abstract class for interacting with switch devices
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@action
|
||||
def on(self, args):
|
||||
""" Turn the device on """
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def off(self, args):
|
||||
""" Turn the device off """
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def toggle(self, args):
|
||||
""" Toggle the device status (on/off) """
|
||||
raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def status(self):
|
||||
""" Get the device state """
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -4,9 +4,8 @@ import time
|
|||
|
||||
from bluetooth.ble import DiscoveryService, GATTRequester
|
||||
|
||||
from platypush.message.response import Response
|
||||
|
||||
from .. import SwitchPlugin
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.switch import SwitchPlugin
|
||||
|
||||
class Scanner(object):
|
||||
service_uuid = '1bc5d5a5-0200b89f-e6114d22-000da2cb'
|
||||
|
@ -112,6 +111,7 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
|||
:type devices: dict
|
||||
"""
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
self.bt_interface = bt_interface
|
||||
self.connect_timeout = connect_timeout if connect_timeout else 5
|
||||
self.scan_timeout = scan_timeout if scan_timeout else 2
|
||||
|
@ -119,15 +119,12 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
|||
|
||||
|
||||
def _run(self, device, command=None):
|
||||
output = None
|
||||
errors = []
|
||||
|
||||
try:
|
||||
# XXX this requires sudo and it's executed in its own process
|
||||
# because the Switchbot plugin requires root privileges to send
|
||||
# raw bluetooth messages on the interface. Make sure that the user
|
||||
# that runs platypush has the right permissions to run this with sudo
|
||||
output = subprocess.check_output((
|
||||
return subprocess.check_output((
|
||||
'sudo python3 -m platypush.plugins.switch.switchbot ' +
|
||||
'--device {} ' +
|
||||
('--interface {} '.format(self.bt_interface) if self.bt_interface else '') +
|
||||
|
@ -135,11 +132,10 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
|||
('--{} '.format(command) if command else '')).format(device),
|
||||
stderr=subprocess.STDOUT, shell=True).decode('utf-8')
|
||||
except subprocess.CalledProcessError as e:
|
||||
errors = [e.output.decode('utf-8')]
|
||||
|
||||
return Response(output=output, errors=errors)
|
||||
raise RuntimeError(e.output.decode('utf-8'))
|
||||
|
||||
|
||||
@action
|
||||
def press(self, device):
|
||||
"""
|
||||
Send a press button command to a device
|
||||
|
@ -149,6 +145,7 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
|||
"""
|
||||
return self._run(device)
|
||||
|
||||
@action
|
||||
def on(self, device):
|
||||
"""
|
||||
Send a press-on button command to a device
|
||||
|
@ -158,6 +155,7 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
|||
"""
|
||||
return self._run(device, 'on')
|
||||
|
||||
@action
|
||||
def off(self, device):
|
||||
"""
|
||||
Send a press-off button command to a device
|
||||
|
@ -167,25 +165,17 @@ class SwitchSwitchbotPlugin(SwitchPlugin):
|
|||
"""
|
||||
return self._run(device, 'off')
|
||||
|
||||
@action
|
||||
def scan(self):
|
||||
""" Scan for available Switchbot devices nearby """
|
||||
output = None
|
||||
errors = []
|
||||
|
||||
try:
|
||||
print('sudo python3 -m platypush.plugins.switch.switchbot --scan ' +
|
||||
('--interface {} '.format(self.bt_interface) if self.bt_interface else '') +
|
||||
('--scan-timeout {} '.format(self.scan_timeout) if self.scan_timeout else ''))
|
||||
|
||||
output = subprocess.check_output(
|
||||
return subprocess.check_output(
|
||||
'sudo python3 -m platypush.plugins.switch.switchbot --scan ' +
|
||||
('--interface {} '.format(self.bt_interface) if self.bt_interface else '') +
|
||||
('--scan-timeout {} '.format(self.scan_timeout) if self.scan_timeout else ''),
|
||||
stderr=subprocess.STDOUT, shell=True).decode('utf-8')
|
||||
except subprocess.CalledProcessError as e:
|
||||
errors = [e.output.decode('utf-8')]
|
||||
|
||||
return Response(output=output, errors=errors)
|
||||
raise RuntimeError(e.output.decode('utf-8'))
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from pyHS100 import Discover
|
||||
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.switch import SwitchPlugin
|
||||
|
||||
|
||||
|
@ -17,6 +17,8 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
|||
_ip_to_dev = {}
|
||||
_alias_to_dev = {}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def _scan(self):
|
||||
devices = Discover.discover()
|
||||
|
@ -46,6 +48,7 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
|||
raise RuntimeError('Device {} not found'.format(device))
|
||||
|
||||
|
||||
@action
|
||||
def status(self):
|
||||
"""
|
||||
:returns: The available device over the network as a
|
||||
|
@ -61,8 +64,9 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
|||
} for (ip, dev) in self._scan().items()
|
||||
} }
|
||||
|
||||
return Response(output=devices)
|
||||
return devices
|
||||
|
||||
@action
|
||||
def on(self, device):
|
||||
"""
|
||||
Turn on a device
|
||||
|
@ -73,9 +77,10 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
|||
|
||||
device = self._get_device(device)
|
||||
device.turn_on()
|
||||
return Response(output={'status':'on'})
|
||||
return {'status':'on'}
|
||||
|
||||
|
||||
@action
|
||||
def off(self, device):
|
||||
"""
|
||||
Turn off a device
|
||||
|
@ -86,9 +91,10 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
|||
|
||||
device = self._get_device(device)
|
||||
device.turn_off()
|
||||
return Response(output={'status':'off'})
|
||||
return {'status':'off'}
|
||||
|
||||
|
||||
@action
|
||||
def toggle(self, device):
|
||||
"""
|
||||
Toggle the state of a device (on/off)
|
||||
|
@ -104,7 +110,7 @@ class SwitchTplinkPlugin(SwitchPlugin):
|
|||
else:
|
||||
device.turn_on()
|
||||
|
||||
return Response(output={'status': 'off' if device.is_off else 'on'})
|
||||
return {'status': 'off' if device.is_off else 'on'}
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import json
|
||||
|
||||
from ouimeaux.environment import Environment, UnknownDevice
|
||||
from platypush.message.response import Response
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.switch import SwitchPlugin
|
||||
|
||||
from .. import SwitchPlugin
|
||||
|
||||
class SwitchWemoPlugin(SwitchPlugin):
|
||||
"""
|
||||
|
@ -20,8 +20,8 @@ class SwitchWemoPlugin(SwitchPlugin):
|
|||
:param discovery_seconds: Discovery time when scanning for devices (default: 3)
|
||||
:type discovery_seconds: int
|
||||
"""
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
self.discovery_seconds=discovery_seconds
|
||||
self.env = Environment()
|
||||
self.env.start()
|
||||
|
@ -33,6 +33,7 @@ class SwitchWemoPlugin(SwitchPlugin):
|
|||
self.env.discover(seconds=self.discovery_seconds)
|
||||
self.devices = self.env.devices
|
||||
|
||||
@action
|
||||
def get_devices(self):
|
||||
"""
|
||||
Get the list of available devices
|
||||
|
@ -57,8 +58,8 @@ class SwitchWemoPlugin(SwitchPlugin):
|
|||
}
|
||||
"""
|
||||
self.refresh_devices()
|
||||
return Response(
|
||||
output = { 'devices': [
|
||||
return {
|
||||
'devices': [
|
||||
{
|
||||
'host': dev.host,
|
||||
'name': dev.name,
|
||||
|
@ -67,8 +68,8 @@ class SwitchWemoPlugin(SwitchPlugin):
|
|||
'serialnumber': dev.serialnumber,
|
||||
}
|
||||
for (name, dev) in self.devices.items()
|
||||
] }
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
def _exec(self, method, device, *args, **kwargs):
|
||||
if device not in self.devices:
|
||||
|
@ -81,9 +82,9 @@ class SwitchWemoPlugin(SwitchPlugin):
|
|||
dev = self.devices[device]
|
||||
getattr(dev, method)(*args, **kwargs)
|
||||
|
||||
resp = {'device': device, 'state': dev.get_state()}
|
||||
return Response(output=json.dumps(resp))
|
||||
return {'device': device, 'state': dev.get_state()}
|
||||
|
||||
@action
|
||||
def on(self, device):
|
||||
"""
|
||||
Turn a switch on
|
||||
|
@ -93,6 +94,7 @@ class SwitchWemoPlugin(SwitchPlugin):
|
|||
"""
|
||||
return self._exec('on', device)
|
||||
|
||||
@action
|
||||
def off(self, device):
|
||||
"""
|
||||
Turn a switch off
|
||||
|
@ -102,6 +104,7 @@ class SwitchWemoPlugin(SwitchPlugin):
|
|||
"""
|
||||
return self._exec('off', device)
|
||||
|
||||
@action
|
||||
def toggle(self, device):
|
||||
"""
|
||||
Toggle the state of a switch (on/off)
|
||||
|
|
|
@ -2,8 +2,7 @@ import subprocess
|
|||
import urllib.parse
|
||||
|
||||
from platypush.message.response import Response
|
||||
|
||||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class TtsPlugin(Plugin):
|
||||
"""
|
||||
|
@ -18,6 +17,7 @@ class TtsPlugin(Plugin):
|
|||
super().__init__()
|
||||
self.lang=lang
|
||||
|
||||
@action
|
||||
def say(self, phrase, lang=None):
|
||||
"""
|
||||
Say a phrase
|
||||
|
@ -41,12 +41,10 @@ class TtsPlugin(Plugin):
|
|||
}))]
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
return subprocess.check_output(
|
||||
cmd, stderr=subprocess.STDOUT, shell=True).decode('utf-8')
|
||||
except subprocess.CalledProcessError as e:
|
||||
errors = [e.output.decode('utf-8')]
|
||||
|
||||
return Response(output=output, errors=errors)
|
||||
raise RuntimeError(e.output.decode('utf-8'))
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from platypush.message.response import Response
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class VariablePlugin(Plugin):
|
||||
|
@ -12,6 +11,7 @@ class VariablePlugin(Plugin):
|
|||
super().__init__(*args, **kwargs)
|
||||
self._variables = {}
|
||||
|
||||
@action
|
||||
def get(self, name, default_value=None):
|
||||
"""
|
||||
Get the value of a variable by name.
|
||||
|
@ -24,8 +24,9 @@ class VariablePlugin(Plugin):
|
|||
:returns: A map in the format ``{"<name>":"<value>"}``
|
||||
"""
|
||||
|
||||
return Response(output={name: self._variables.get(name, default_value)})
|
||||
return {name: self._variables.get(name, default_value)}
|
||||
|
||||
@action
|
||||
def set(self, **kwargs):
|
||||
"""
|
||||
Set a variable or a set of variables.
|
||||
|
@ -35,8 +36,9 @@ class VariablePlugin(Plugin):
|
|||
|
||||
for (name, value) in kwargs.items():
|
||||
self._variables[name] = value
|
||||
return Response(output=kwargs)
|
||||
return kwargs
|
||||
|
||||
@action
|
||||
def unset(self, name):
|
||||
"""
|
||||
Unset a variable by name if it's set
|
||||
|
@ -46,9 +48,6 @@ class VariablePlugin(Plugin):
|
|||
"""
|
||||
if name in self._variables:
|
||||
del self._variables[name]
|
||||
return Response(output={'status':'ok'})
|
||||
else:
|
||||
return Response(output={'status':'not_found'})
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -12,11 +12,11 @@ from omxplayer import OMXPlayer
|
|||
|
||||
from platypush.context import get_backend
|
||||
from platypush.plugins.media import PlayerState
|
||||
from platypush.message.response import Response
|
||||
from platypush.message.event.video import VideoPlayEvent, VideoPauseEvent, \
|
||||
VideoStopEvent, NewPlayingVideoEvent
|
||||
|
||||
from .. import Plugin
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
|
||||
class VideoOmxplayerPlugin(Plugin):
|
||||
"""
|
||||
|
@ -83,6 +83,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
self.videos_queue = []
|
||||
self.torrent_ports = torrent_ports if torrent_ports else self.default_torrent_ports
|
||||
|
||||
@action
|
||||
def play(self, resource):
|
||||
"""
|
||||
Play a resource.
|
||||
|
@ -105,9 +106,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
self.videos_queue = resources
|
||||
resource = self.videos_queue.pop(0)
|
||||
else:
|
||||
error = 'Unable to download torrent {}'.format(resource)
|
||||
self.logger.warning(error)
|
||||
return Response(errors=[error])
|
||||
raise RuntimeError('Unable to download torrent {}'.format(resource))
|
||||
|
||||
self.logger.info('Playing {}'.format(resource))
|
||||
|
||||
|
@ -130,10 +129,12 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def pause(self):
|
||||
""" Pause the playback """
|
||||
if self.player: self.player.play_pause()
|
||||
|
||||
@action
|
||||
def stop(self):
|
||||
""" Stop the playback """
|
||||
if self.player:
|
||||
|
@ -143,30 +144,35 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def voldown(self):
|
||||
""" Volume down by 10% """
|
||||
if self.player:
|
||||
self.player.set_volume(max(-6000, self.player.volume()-1000))
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def volup(self):
|
||||
""" Volume up by 10% """
|
||||
if self.player:
|
||||
self.player.set_volume(min(0, self.player.volume()+1000))
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def back(self):
|
||||
""" Back by 30 seconds """
|
||||
if self.player:
|
||||
self.player.seek(-30)
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def forward(self):
|
||||
""" Forward by 30 seconds """
|
||||
if self.player:
|
||||
self.player.seek(+30)
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def next(self):
|
||||
""" Play the next track/video """
|
||||
if self.player:
|
||||
|
@ -176,19 +182,19 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
video = self.videos_queue.pop(0)
|
||||
return self.play(video)
|
||||
|
||||
return Response(output={'status': 'no media'}, errors = [])
|
||||
|
||||
|
||||
@action
|
||||
def hide_subtitles(self):
|
||||
""" Hide the subtitles """
|
||||
if self.player: self.player.hide_subtitles()
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def hide_video(self):
|
||||
""" Hide the video """
|
||||
if self.player: self.player.hide_video()
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def is_playing(self):
|
||||
"""
|
||||
:returns: True if it's playing, False otherwise
|
||||
|
@ -197,6 +203,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
if self.player: return self.player.is_playing()
|
||||
else: return False
|
||||
|
||||
@action
|
||||
def load(self, resource, pause=False):
|
||||
"""
|
||||
Load a resource/video in the player.
|
||||
|
@ -208,21 +215,26 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
if self.player: self.player.load(resource, pause)
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def metadata(self):
|
||||
""" Get the metadata of the current video """
|
||||
if self.player: return Response(output=self.player.metadata())
|
||||
if self.player:
|
||||
return self.player.metadata()
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def mute(self):
|
||||
""" Mute the player """
|
||||
if self.player: self.player.mute()
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def unmute(self):
|
||||
""" Unmute the player """
|
||||
if self.player: self.player.unmute()
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def seek(self, relative_position):
|
||||
"""
|
||||
Seek backward/forward by the specified number of seconds
|
||||
|
@ -234,6 +246,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
if self.player: self.player.seek(relative_position)
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def set_position(self, position):
|
||||
"""
|
||||
Seek backward/forward to the specified absolute position
|
||||
|
@ -245,6 +258,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
if self.player: self.player.set_seek(position)
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def set_volume(self, volume):
|
||||
"""
|
||||
Set the volume
|
||||
|
@ -258,6 +272,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
if self.player: self.player.set_volume(volume)
|
||||
return self.status()
|
||||
|
||||
@action
|
||||
def status(self):
|
||||
"""
|
||||
Get the current player state.
|
||||
|
@ -285,7 +300,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
elif state == 'stopped': state = PlayerState.STOP.value
|
||||
elif state == 'paused': state = PlayerState.PAUSE.value
|
||||
|
||||
return Response(output=json.dumps({
|
||||
return {
|
||||
'source': self.player.get_source(),
|
||||
'state': state,
|
||||
'volume': self.player.volume(),
|
||||
|
@ -293,12 +308,13 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
'duration': self.player.duration(),
|
||||
'width': self.player.width(),
|
||||
'height': self.player.height(),
|
||||
}))
|
||||
}
|
||||
else:
|
||||
return Response(output=json.dumps({
|
||||
return {
|
||||
'state': PlayerState.STOP.value
|
||||
}))
|
||||
}
|
||||
|
||||
@action
|
||||
def send_message(self, msg):
|
||||
try:
|
||||
redis = get_backend('redis')
|
||||
|
@ -311,16 +327,19 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
|
||||
redis.send_message(msg)
|
||||
|
||||
@action
|
||||
def on_play(self):
|
||||
def _f(player):
|
||||
self.send_message(VideoPlayEvent(video=self.player.get_source()))
|
||||
return _f
|
||||
|
||||
@action
|
||||
def on_pause(self):
|
||||
def _f(player):
|
||||
self.send_message(VideoPauseEvent(video=self.player.get_source()))
|
||||
return _f
|
||||
|
||||
@action
|
||||
def on_stop(self):
|
||||
def _f(player):
|
||||
self.send_message(VideoStopEvent())
|
||||
|
@ -335,6 +354,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
self.player.pauseEvent += self.on_pause()
|
||||
self.player.stopEvent += self.on_stop()
|
||||
|
||||
@action
|
||||
def search(self, query, types=None, queue_results=False, autoplay=False):
|
||||
"""
|
||||
Perform a video search.
|
||||
|
@ -376,7 +396,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
elif autoplay:
|
||||
self.play(results[0]['url'])
|
||||
|
||||
return Response(output=results)
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def _is_video_file(cls, filename):
|
||||
|
@ -388,6 +408,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
|
||||
return is_video
|
||||
|
||||
@action
|
||||
def file_search(self, query):
|
||||
results = []
|
||||
query_tokens = [_.lower() for _ in re.split('\s+', query.strip())]
|
||||
|
@ -413,8 +434,9 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
'title': f,
|
||||
})
|
||||
|
||||
return Response(output=results)
|
||||
return results
|
||||
|
||||
@action
|
||||
def youtube_search(self, query):
|
||||
self.logger.info('Searching YouTube for "{}"'.format(query))
|
||||
|
||||
|
@ -439,7 +461,7 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
self.logger.info('{} YouTube video results for the search query "{}"'
|
||||
.format(len(results), query))
|
||||
|
||||
return Response(output=results)
|
||||
return results
|
||||
|
||||
|
||||
@classmethod
|
||||
|
@ -476,8 +498,9 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
for _ in json.loads(request.read())['MovieList']
|
||||
]
|
||||
|
||||
return Response(output=results)
|
||||
return results
|
||||
|
||||
@action
|
||||
def download_torrent(self, magnet):
|
||||
"""
|
||||
Download a torrent to ``download_dir`` by Magnet URI
|
||||
|
@ -538,9 +561,10 @@ class VideoOmxplayerPlugin(Plugin):
|
|||
|
||||
time.sleep(5)
|
||||
|
||||
return Response(output=files)
|
||||
return files
|
||||
|
||||
|
||||
@action
|
||||
def get_torrent_state(self):
|
||||
return self.torrent_state
|
||||
|
||||
|
|
|
@ -3,10 +3,8 @@ import urllib3
|
|||
import urllib.request
|
||||
import urllib.parse
|
||||
|
||||
from platypush.plugins import Plugin, action
|
||||
from platypush.plugins.media import PlayerState
|
||||
from platypush.message.response import Response
|
||||
|
||||
from .. import Plugin
|
||||
|
||||
class VideoTorrentcastPlugin(Plugin):
|
||||
def __init__(self, server='localhost', port=9090, *args, **kwargs):
|
||||
|
@ -14,6 +12,7 @@ class VideoTorrentcastPlugin(Plugin):
|
|||
self.port = port
|
||||
self.state = PlayerState.STOP.value
|
||||
|
||||
@action
|
||||
def play(self, url):
|
||||
request = urllib.request.urlopen(
|
||||
'http://{}:{}/play/'.format(self.server, self.port),
|
||||
|
@ -23,24 +22,27 @@ class VideoTorrentcastPlugin(Plugin):
|
|||
)
|
||||
|
||||
self.state = PlayerState.PLAY.value
|
||||
return Response(output=request.read())
|
||||
return request.read()
|
||||
|
||||
@action
|
||||
def pause(self):
|
||||
http = urllib3.PoolManager()
|
||||
request = http.request('POST',
|
||||
'http://{}:{}/pause/'.format(self.server, self.port))
|
||||
|
||||
self.state = PlayerState.PAUSE.value
|
||||
return Response(output=request.read())
|
||||
return request.read()
|
||||
|
||||
@action
|
||||
def stop(self):
|
||||
http = urllib3.PoolManager()
|
||||
request = http.request('POST',
|
||||
'http://{}:{}/stop/'.format(self.server, self.port))
|
||||
|
||||
self.state = PlayerState.STOP.value
|
||||
return Response(output=request.read())
|
||||
return request.read()
|
||||
|
||||
@action
|
||||
def search(self, query):
|
||||
request = urllib.request.urlopen(urllib.request.Request(
|
||||
'https://api.apidomain.info/list?' + urllib.parse.urlencode({
|
||||
|
@ -56,8 +58,9 @@ class VideoTorrentcastPlugin(Plugin):
|
|||
)
|
||||
|
||||
results = json.loads(request.read())
|
||||
return Response(output=results)
|
||||
return results
|
||||
|
||||
@action
|
||||
def search_and_play(self, query):
|
||||
response = self.search(query)
|
||||
if not response.output['MovieList']:
|
||||
|
@ -71,13 +74,20 @@ class VideoTorrentcastPlugin(Plugin):
|
|||
|
||||
return self.play(magnet)
|
||||
|
||||
def voldown(self): return Response(output='Unsupported method')
|
||||
def volup(self): return Response(output='Unsupported method')
|
||||
def back(self): return Response(output='Unsupported method')
|
||||
def forward(self): return Response(output='Unsupported method')
|
||||
@action
|
||||
def voldown(self): raise NotImplementedError()
|
||||
|
||||
def status(self):
|
||||
return Response(output={ 'state': self.state })
|
||||
@action
|
||||
def volup(self): raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def back(self): raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def forward(self): raise NotImplementedError()
|
||||
|
||||
@action
|
||||
def status(self): return { 'state': self.state }
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from platypush.message.response import Response
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.http.request import HttpRequestPlugin
|
||||
|
||||
|
||||
|
@ -46,6 +46,7 @@ class WeatherForecastPlugin(HttpRequestPlugin):
|
|||
format(self.darksky_token, (lat or self.lat), (long or self.long),
|
||||
self.units)
|
||||
|
||||
@action
|
||||
def get_current_weather(self, lat=None, long=None, **kwargs):
|
||||
"""
|
||||
Get the current weather.
|
||||
|
@ -83,8 +84,9 @@ class WeatherForecastPlugin(HttpRequestPlugin):
|
|||
"""
|
||||
|
||||
response = self.get(self._get_url(lat, long))
|
||||
return Response(output=response.output['currently'])
|
||||
return response.output['currently']
|
||||
|
||||
@action
|
||||
def get_hourly_forecast(self, lat=None, long=None, **kwargs):
|
||||
"""
|
||||
Get the hourly forecast.
|
||||
|
@ -146,8 +148,9 @@ class WeatherForecastPlugin(HttpRequestPlugin):
|
|||
"""
|
||||
|
||||
response = self.get(self._get_url(lat, long))
|
||||
return Response(output=response.output['hourly'])
|
||||
return response.output['hourly']
|
||||
|
||||
@action
|
||||
def get_daily_forecast(self, lat=None, long=None, **kwargs):
|
||||
"""
|
||||
Get the daily forecast.
|
||||
|
@ -250,7 +253,7 @@ class WeatherForecastPlugin(HttpRequestPlugin):
|
|||
"""
|
||||
|
||||
response = self.get(self._get_url(lat, long))
|
||||
return Response(output=response.output['daily'])
|
||||
return response.output['daily']
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import ast
|
||||
import errno
|
||||
import hashlib
|
||||
import importlib
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
|
@ -67,8 +69,32 @@ def clear_timeout():
|
|||
|
||||
|
||||
def get_hash(s):
|
||||
""" Get the SHA256 hash hexdigest of a string input """
|
||||
return hashlib.sha256(s.encode('utf-8')).hexdigest()
|
||||
|
||||
|
||||
def get_decorators(cls):
|
||||
target = cls
|
||||
decorators = {}
|
||||
|
||||
def visit_FunctionDef(node):
|
||||
# decorators[node.name] = []
|
||||
for n in node.decorator_list:
|
||||
name = ''
|
||||
if isinstance(n, ast.Call):
|
||||
name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id
|
||||
else:
|
||||
name = n.attr if isinstance(n, ast.Attribute) else n.id
|
||||
|
||||
decorators[name] = decorators.get(name, [])
|
||||
# decorators[node.name].append(name)
|
||||
decorators[name].append(node.name)
|
||||
|
||||
node_iter = ast.NodeVisitor()
|
||||
node_iter.visit_FunctionDef = visit_FunctionDef
|
||||
node_iter.visit(ast.parse(inspect.getsource(target)))
|
||||
return decorators
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
Loading…
Reference in a new issue