Added YouTube plugin that leverages the YouTube API; Replaced OMXPlayer search references to the old HTML parser withe new YouTube plugin
This commit is contained in:
parent
0e7345f1ee
commit
679cad53b5
4 changed files with 110 additions and 3 deletions
6
docs/source/platypush/plugins/google.youtube.rst
Normal file
6
docs/source/platypush/plugins/google.youtube.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
``platypush.plugins.google.youtube``
|
||||||
|
====================================
|
||||||
|
|
||||||
|
.. automodule:: platypush.plugins.google.youtube
|
||||||
|
:members:
|
||||||
|
|
|
@ -19,6 +19,7 @@ Plugins
|
||||||
platypush/plugins/google.mail.rst
|
platypush/plugins/google.mail.rst
|
||||||
platypush/plugins/google.maps.rst
|
platypush/plugins/google.maps.rst
|
||||||
platypush/plugins/google.rst
|
platypush/plugins/google.rst
|
||||||
|
platypush/plugins/google.youtube.rst
|
||||||
platypush/plugins/gpio.rst
|
platypush/plugins/gpio.rst
|
||||||
platypush/plugins/gpio.sensor.accelerometer.rst
|
platypush/plugins/gpio.sensor.accelerometer.rst
|
||||||
platypush/plugins/gpio.sensor.distance.rst
|
platypush/plugins/gpio.sensor.distance.rst
|
||||||
|
|
83
platypush/plugins/google/youtube.py
Normal file
83
platypush/plugins/google/youtube.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
"""
|
||||||
|
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import datetime
|
||||||
|
import httplib2
|
||||||
|
import os
|
||||||
|
|
||||||
|
from apiclient import discovery
|
||||||
|
|
||||||
|
from platypush.plugins import action
|
||||||
|
from platypush.plugins.google import GooglePlugin
|
||||||
|
from platypush.plugins.calendar import CalendarInterface
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleYoutubePlugin(GooglePlugin, CalendarInterface):
|
||||||
|
"""
|
||||||
|
YouTube plugin
|
||||||
|
"""
|
||||||
|
|
||||||
|
scopes = ['https://www.googleapis.com/auth/youtube.readonly']
|
||||||
|
|
||||||
|
# See https://developers.google.com/youtube/v3/getting-started#part
|
||||||
|
_default_parts = ['snippet']
|
||||||
|
|
||||||
|
# See https://developers.google.com/youtube/v3/getting-started#resources
|
||||||
|
_default_types = ['video']
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(scopes=self.scopes, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@action
|
||||||
|
def search(self, parts=None, query='', types=None, max_results=25, **kwargs):
|
||||||
|
"""
|
||||||
|
Search for YouTube content.
|
||||||
|
|
||||||
|
:param parts: List of parts to get (default: snippet). See the `YouTube API documentation <https://developers.google.com/youtube/v3/getting-started#part>`_.
|
||||||
|
:type parts: list[str] or str
|
||||||
|
|
||||||
|
:param query: Query string (default: empty string)
|
||||||
|
:type query: str
|
||||||
|
|
||||||
|
:param types: List of types to retrieve (default: video). See the `YouTube API documentation <https://developers.google.com/youtube/v3/getting-started#resources>`_.
|
||||||
|
:type types: list[str] or str
|
||||||
|
|
||||||
|
:param max_results: Maximum number of items that will be returned (default: 25).
|
||||||
|
:type max_results: int
|
||||||
|
|
||||||
|
:param kwargs: Any extra arguments that will be transparently passed to the YouTube API, see the `YouTube API documentation <https://developers.google.com/youtube/v3/docs/search/list#parameters>`_.
|
||||||
|
|
||||||
|
:return: A list of YouTube resources, see the `YouTube API documentation <https://developers.google.com/youtube/v3/docs/search#resource>`_.
|
||||||
|
"""
|
||||||
|
|
||||||
|
parts = parts or self._default_parts[:]
|
||||||
|
if isinstance(parts, list):
|
||||||
|
parts = ','.join(parts)
|
||||||
|
|
||||||
|
types = types or self._default_types[:]
|
||||||
|
if isinstance(types, list):
|
||||||
|
types = ','.join(types)
|
||||||
|
|
||||||
|
service = self._get_service()
|
||||||
|
result = service.search().list(part=parts, q=query, type=types,
|
||||||
|
**kwargs).execute()
|
||||||
|
|
||||||
|
events = result.get('items', [])
|
||||||
|
return events
|
||||||
|
|
||||||
|
|
||||||
|
def _get_service(self, scope=None):
|
||||||
|
if scope is None:
|
||||||
|
scope = self.scopes[0]
|
||||||
|
|
||||||
|
credentials = self.credentials[scope]
|
||||||
|
http = credentials.authorize(httplib2.Http())
|
||||||
|
return discovery.build('youtube', 'v3', http=http, cache_discovery=False)
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
|
@ -7,9 +7,6 @@ import time
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
from dbus.exceptions import DBusException
|
|
||||||
from omxplayer import OMXPlayer
|
|
||||||
|
|
||||||
from platypush.context import get_backend, get_plugin
|
from platypush.context import get_backend, get_plugin
|
||||||
from platypush.plugins.media import PlayerState
|
from platypush.plugins.media import PlayerState
|
||||||
from platypush.message.event.video import VideoPlayEvent, VideoPauseEvent, \
|
from platypush.message.event.video import VideoPlayEvent, VideoPauseEvent, \
|
||||||
|
@ -89,6 +86,8 @@ class VideoOmxplayerPlugin(Plugin):
|
||||||
* Torrents (format: Magnet links, Torrent URLs or local Torrent files)
|
* Torrents (format: Magnet links, Torrent URLs or local Torrent files)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from dbus.exceptions import DBusException
|
||||||
|
|
||||||
if resource.startswith('youtube:') \
|
if resource.startswith('youtube:') \
|
||||||
or resource.startswith('https://www.youtube.com/watch?v='):
|
or resource.startswith('https://www.youtube.com/watch?v='):
|
||||||
resource = self._get_youtube_content(resource)
|
resource = self._get_youtube_content(resource)
|
||||||
|
@ -114,6 +113,7 @@ class VideoOmxplayerPlugin(Plugin):
|
||||||
'of OMXPlayer, trying to play anyway')
|
'of OMXPlayer, trying to play anyway')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
from omxplayer import OMXPlayer
|
||||||
self.player = OMXPlayer(resource, args=self.args)
|
self.player = OMXPlayer(resource, args=self.args)
|
||||||
self._init_player_handlers()
|
self._init_player_handlers()
|
||||||
except DBusException as e:
|
except DBusException as e:
|
||||||
|
@ -430,8 +430,25 @@ class VideoOmxplayerPlugin(Plugin):
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def youtube_search(self, query):
|
def youtube_search(self, query):
|
||||||
|
"""
|
||||||
|
Performs a YouTube search either using the YouTube API (faster and
|
||||||
|
recommended, it requires the :mod:`platypush.plugins.google.youtube`
|
||||||
|
plugin to be configured) or parsing the HTML search results (fallback
|
||||||
|
slower method)
|
||||||
|
"""
|
||||||
|
|
||||||
self.logger.info('Searching YouTube for "{}"'.format(query))
|
self.logger.info('Searching YouTube for "{}"'.format(query))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return get_plugin('google.youtube').search(query=query)
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.warning('Unable to load the YouTube plugin, falling ' +
|
||||||
|
'back to HTML parse method: {}'.format(str(e)))
|
||||||
|
|
||||||
|
return self._youtube_search_html_parse(query=query)
|
||||||
|
|
||||||
|
|
||||||
|
def _youtube_search_html_parse(self, query):
|
||||||
query = urllib.parse.quote(query)
|
query = urllib.parse.quote(query)
|
||||||
url = "https://www.youtube.com/results?search_query=" + query
|
url = "https://www.youtube.com/results?search_query=" + query
|
||||||
response = urllib.request.urlopen(url)
|
response = urllib.request.urlopen(url)
|
||||||
|
|
Loading…
Reference in a new issue