2017-12-27 10:18:51 +01:00
|
|
|
import re
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
from platypush.context import get_plugin
|
2018-04-20 12:17:27 +02:00
|
|
|
from platypush.plugins.media import PlayerState
|
2017-12-27 10:18:51 +01:00
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
from platypush.plugins import Plugin, action
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
class MediaCtrlPlugin(Plugin):
|
|
|
|
"""
|
|
|
|
Wrapper plugin to control audio and video media.
|
|
|
|
Examples of supported URL types:
|
2019-02-02 00:06:28 +01:00
|
|
|
- file:///media/movies/Movie.mp4 [requires media plugin enabled]
|
|
|
|
- youtube:video:poAk9XgK7Cs [requires media plugin+youtube-dl]
|
2017-12-27 10:18:51 +01:00
|
|
|
- magnet:?torrent_magnet [requires torrentcast]
|
|
|
|
- spotify:track:track_id [leverages plugins.music.mpd]
|
|
|
|
"""
|
|
|
|
|
2018-04-20 12:17:27 +02:00
|
|
|
_supported_plugins = {
|
2019-02-02 00:06:28 +01:00
|
|
|
'music.mpd', 'media', 'video.torrentcast'
|
2018-04-20 12:17:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, torrentcast_port=9090, *args, **kwargs):
|
2018-07-06 02:24:25 +02:00
|
|
|
super().__init__()
|
2017-12-27 10:18:51 +01:00
|
|
|
self.torrentcast_port = torrentcast_port
|
|
|
|
self.url = None
|
|
|
|
self.plugin = None
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def _get_type_and_resource_by_url(cls, url):
|
|
|
|
# MPD/Mopidy media (TODO support more mopidy types)
|
2018-06-27 08:56:21 +02:00
|
|
|
m = re.search('^https://open.spotify.com/([^?]+)', url)
|
|
|
|
if m: url = 'spotify:{}'.format(m.group(1).replace('/', ':'))
|
2017-12-27 10:18:51 +01:00
|
|
|
if url.startswith('spotify:') \
|
|
|
|
or url.startswith('tunein:') \
|
|
|
|
or url.startswith('soundcloud:'):
|
|
|
|
return ('mpd', url)
|
|
|
|
|
|
|
|
# YouTube video
|
|
|
|
m = re.match('youtube:video:(.*)', url)
|
|
|
|
if m: url = 'https://www.youtube.com/watch?v={}'.format(m.group(1))
|
|
|
|
if url.startswith('https://www.youtube.com/watch?v='):
|
|
|
|
return ('youtube:video', url)
|
|
|
|
|
|
|
|
# Local media
|
|
|
|
if url.startswith('file://'):
|
|
|
|
m = re.match('^file://(.*)', url)
|
|
|
|
return ('file', m.group(1))
|
|
|
|
|
|
|
|
# URL to a .torrent media or Magnet link
|
|
|
|
if url.startswith('magnet:') or url.endswith('.torrent'):
|
|
|
|
return ('torrent', url)
|
|
|
|
|
|
|
|
raise RuntimeError('Unknown URL type: {}'.format(url))
|
|
|
|
|
|
|
|
|
2018-04-20 12:17:27 +02:00
|
|
|
def _get_playing_plugin(self):
|
|
|
|
if self.plugin:
|
|
|
|
status = self.plugin.status()
|
|
|
|
if status['state'] == PlayerState.PLAY or state['state'] == PlayerState.PAUSE:
|
|
|
|
return self.plugin
|
|
|
|
|
|
|
|
for plugin in self._supported_plugins:
|
|
|
|
try:
|
|
|
|
player = get_plugin(plugin)
|
|
|
|
except:
|
2018-04-22 23:39:23 +02:00
|
|
|
try:
|
|
|
|
player = get_plugin(plugin, reload=True)
|
|
|
|
except:
|
|
|
|
continue
|
2018-04-20 12:17:27 +02:00
|
|
|
|
|
|
|
status = player.status().output
|
|
|
|
if status['state'] == PlayerState.PLAY.value or status['state'] == PlayerState.PAUSE.value:
|
|
|
|
return player
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2017-12-27 10:18:51 +01:00
|
|
|
def play(self, url):
|
|
|
|
(type, resource) = self._get_type_and_resource_by_url(url)
|
2018-04-22 23:39:23 +02:00
|
|
|
plugin_name = None
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
if type == 'mpd':
|
2018-04-22 23:39:23 +02:00
|
|
|
plugin_name = 'music.mpd'
|
2017-12-27 10:18:51 +01:00
|
|
|
elif type == 'youtube:video' or type == 'file':
|
2019-02-02 00:06:28 +01:00
|
|
|
plugin_name = 'media'
|
2017-12-27 10:18:51 +01:00
|
|
|
elif type == 'torrent':
|
2018-04-22 23:39:23 +02:00
|
|
|
plugin_name = 'video.torrentcast'
|
|
|
|
|
|
|
|
if not plugin_name:
|
|
|
|
raise RuntimeError("Unsupported type '{}'".format(type))
|
|
|
|
|
|
|
|
try:
|
|
|
|
self.plugin = get_plugin(plugin_name)
|
|
|
|
except:
|
|
|
|
self.plugin = get_plugin(plugin_name, reload=True)
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
self.url = resource
|
|
|
|
return self.plugin.play(resource)
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2017-12-27 10:18:51 +01:00
|
|
|
def pause(self):
|
2018-04-20 12:17:27 +02:00
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin: return plugin.pause()
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2017-12-27 10:18:51 +01:00
|
|
|
def stop(self):
|
2018-04-20 12:17:27 +02:00
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin:
|
|
|
|
ret = plugin.stop()
|
2018-04-19 00:30:39 +02:00
|
|
|
self.plugin = None
|
|
|
|
return ret
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2017-12-27 10:18:51 +01:00
|
|
|
def voldown(self):
|
2018-04-20 12:17:27 +02:00
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin: return plugin.voldown()
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2017-12-27 10:18:51 +01:00
|
|
|
def volup(self):
|
2018-04-20 12:17:27 +02:00
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin: return plugin.volup()
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2017-12-27 10:18:51 +01:00
|
|
|
def back(self):
|
2018-04-20 12:17:27 +02:00
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin: return plugin.back()
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2017-12-27 10:18:51 +01:00
|
|
|
def forward(self):
|
2018-04-20 12:17:27 +02:00
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin: return plugin.forward()
|
2017-12-27 10:18:51 +01:00
|
|
|
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2018-04-18 00:50:19 +02:00
|
|
|
def next(self):
|
2018-04-20 12:17:27 +02:00
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin: return plugin.next()
|
2018-04-19 00:30:39 +02:00
|
|
|
|
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2018-04-19 00:30:39 +02:00
|
|
|
def previous(self):
|
2018-04-20 12:17:27 +02:00
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin: return plugin.previous()
|
2018-04-19 00:30:39 +02:00
|
|
|
|
2018-04-18 00:50:19 +02:00
|
|
|
|
2018-07-06 02:08:38 +02:00
|
|
|
@action
|
2018-04-20 15:18:20 +02:00
|
|
|
def status(self):
|
|
|
|
plugin = self._get_playing_plugin()
|
|
|
|
if plugin: return plugin.status()
|
|
|
|
|
|
|
|
|
2017-12-27 10:18:51 +01:00
|
|
|
# vim:sw=4:ts=4:et:
|
|
|
|
|