2013-01-19 14:24:53 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Extension script to stream podcasts to Sonos speakers
|
2014-11-26 18:37:37 +01:00
|
|
|
# Requirements: gPodder 3.x and the soco module (https://pypi.python.org/pypi/soco)
|
2013-01-19 14:24:53 +01:00
|
|
|
# (c) 2013-01-19 Stefan Kögl <stefan@skoegl.net>
|
|
|
|
# Released under the same license terms as gPodder itself.
|
|
|
|
|
|
|
|
from functools import partial
|
|
|
|
|
|
|
|
import gpodder
|
|
|
|
_ = gpodder.gettext
|
|
|
|
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
import soco
|
|
|
|
import requests
|
|
|
|
|
|
|
|
|
|
|
|
__title__ = _('Stream to Sonos')
|
|
|
|
__description__ = _('Stream podcasts to Sonos speakers')
|
2013-03-24 21:13:27 +01:00
|
|
|
__authors__ = 'Stefan Kögl <stefan@skoegl.net>'
|
2013-01-19 14:24:53 +01:00
|
|
|
__category__ = 'interface'
|
|
|
|
__only_for__ = 'gtk'
|
|
|
|
|
|
|
|
|
|
|
|
SONOS_CAN_PLAY = lambda e: 'audio' in e.file_type()
|
|
|
|
|
|
|
|
class gPodderExtension:
|
|
|
|
def __init__(self, container):
|
|
|
|
sd = soco.SonosDiscovery()
|
|
|
|
speaker_ips = sd.get_speaker_ips()
|
|
|
|
|
|
|
|
logger.info('Found Sonos speakers: %s' % ', '.join(speaker_ips))
|
|
|
|
|
|
|
|
self.speakers = {}
|
|
|
|
for speaker_ip in speaker_ips:
|
|
|
|
controller = soco.SoCo(speaker_ip)
|
|
|
|
|
|
|
|
try:
|
|
|
|
info = controller.get_speaker_info()
|
|
|
|
|
|
|
|
except requests.ConnectionError as ce:
|
|
|
|
# ignore speakers we can't connect to
|
|
|
|
continue
|
|
|
|
|
|
|
|
name = info.get('zone_name', None)
|
|
|
|
|
|
|
|
# devices that do not have a name are probably bridges
|
|
|
|
if name:
|
|
|
|
self.speakers[speaker_ip] = name
|
|
|
|
|
|
|
|
def _stream_to_speaker(self, speaker_ip, episodes):
|
|
|
|
""" Play or enqueue selected episodes """
|
|
|
|
|
2013-02-08 11:20:05 +01:00
|
|
|
urls = [episode.url for episode in episodes if SONOS_CAN_PLAY(episode)]
|
2013-01-19 14:24:53 +01:00
|
|
|
logger.info('Streaming to Sonos %s: %s'%(speaker_ip, ', '.join(urls)))
|
|
|
|
|
|
|
|
controller = soco.SoCo(speaker_ip)
|
|
|
|
|
|
|
|
# enqueue and play
|
|
|
|
for episode in episodes:
|
2014-11-26 18:37:37 +01:00
|
|
|
controller.play_uri(episode.url)
|
2013-01-19 14:24:53 +01:00
|
|
|
episode.playback_mark()
|
|
|
|
|
|
|
|
controller.play()
|
|
|
|
|
|
|
|
def on_episodes_context_menu(self, episodes):
|
|
|
|
""" Adds a context menu for each Sonos speaker group """
|
|
|
|
|
2013-02-08 11:20:05 +01:00
|
|
|
# Only show context menu if we can play at least one file
|
|
|
|
if not any(SONOS_CAN_PLAY(e) for e in episodes):
|
|
|
|
return []
|
2013-01-19 14:24:53 +01:00
|
|
|
|
|
|
|
menu_entries = []
|
|
|
|
for speaker_ip, name in self.speakers.items():
|
|
|
|
callback = partial(self._stream_to_speaker, speaker_ip)
|
2013-02-08 11:20:05 +01:00
|
|
|
|
2014-11-26 18:37:37 +01:00
|
|
|
item = ('/'.join((_('Stream to Sonos'), name)), callback)
|
|
|
|
menu_entries.append(item)
|
2013-01-19 14:24:53 +01:00
|
|
|
|
|
|
|
return menu_entries
|