Skip to content

Commit

Permalink
Merge remote-tracking branch 'charles/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Lochmann committed Feb 11, 2018
2 parents 6e68d1d + 25163a7 commit e81bfa4
Show file tree
Hide file tree
Showing 14 changed files with 404 additions and 75 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ build/
dist/
.cache/
runtime/*
docs/_build
docs/_build
.mypy_cache/
.pytest_cache/
4 changes: 3 additions & 1 deletion AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ Thanks to all the wonderful folks who have contributed to Libsoundtouch:
- jeanregisser <https://github.com/jeanregisser> (Use enum-compat instead of enum34 directly)
- Tyzer34 <https://github.com/Tyzer34> (add *play_media* support)
- wanderor <https://github.com/wanderor> (add local computer media support)
- obadz <https://github.com/obadz> (add Bluetooth source)
- obadz <https://github.com/obadz> (add Bluetooth source)
- luca-angemi <https://github.com/luca-angemi> (Fix new firmware error)
- vanto <https://github.com/vanto> (Fix device names with UTF-8 characters)
91 changes: 75 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ device.play_media(Source.SPOTIFY, 'spotify:track:5J59VOgvclrhLDYUoH5OaW', spot_u
account_id = device.status().content_item.source_account
device.play_media(Source.LOCAL_MUSIC, 'album:1', account_id, Type.ALBUM)

# Snapshot current playing
device.snapshot()

# Select AUX input
device.select_source_aux()
# Select Bluetooth input
device.select_source_bluetooth()

# Restore previous snapshot
device.restore()

# Play URL
device.play_url('http://fqdn/file.mp3')

Expand Down Expand Up @@ -91,8 +102,10 @@ print(len(zone_status.slaves))
* volume setting (mute/set volume/volume up/volume down)
* repeat one/all/off
* shuffle on/off
* select AUX/Bluetooth inputs
* select preset (bookmark)
* playback selected music
* allow snapshot and restore playing content
* play HTTP URL (HTTPS not supported)
* Websockets notification

Expand Down Expand Up @@ -163,7 +176,7 @@ time.sleep(600) # Wait for events

## Full documentation

[http://libsoundtouch.readthedocs.io] (http://libsoundtouch.readthedocs.io)
[http://libsoundtouch.readthedocs.io](http://libsoundtouch.readthedocs.io)

## Incoming features

Expand All @@ -181,21 +194,65 @@ You have to sent an email and you'll received a response in a minute with 2 PDF:

## Changelog

| Version | Date | Features |
|---------|:----------:|----------------------------------------------------------------------------|
| 0.7.2 | 2017/07/05 | Add missing template |
| 0.7.1 | 2017/07/05 | Remove debugging (print) |
| 0.7.0 | 2017/07/05 | Add play_url method to play an HTTP URL (HTTPS not supported) |
| 0.6.2 | 2017/06/21 | Fix websocket source status in messages |
| 0.6.1 | 2017/06/19 | Use enum-compat instead of enum34 directly |
| 0.6.0 | 2017/06/17 | Add discovery (mDNS) support |
| 0.5.0 | 2017/05/28 | Add Websocket support |
| 0.4.0 | 2017/05/21 | Add Bluetooth source |
| 0.3.0 | 2017/04/09 | Allow playing local computer media and fix issue with non ASCII characters |
| 0.2.2 | 2017/02/07 | Fix status with non ascii characters in Python 2.7 |
| 0.2.1 | 2017/02/05 | Fix dependencies |
| 0.2.0 | 2017/02/05 | Add *play_media* support |
| 0.1.0 | 2016/11/20 | Initial release |
### 0.8.0 - 2018/02/11

* Fix: New API content with latest firmware
* Fix: Device names with UTF-8 characters
* Allow to select AUX/Bluetooth inputs
* Add snapshotting/restore feature

### 0.7.2 - 2017/07/05

* Add missing template

### 0.7.1 - 2017/07/05

* Remove debugging (print) |

### 0.7.0 - 2017/07/05

* Add play_url method to play an HTTP URL (HTTPS not supported)

### 0.6.2 - 2017/06/21

* Fix websocket source status in messages

### 0.6.1 - 2017/06/19

* Use enum-compat instead of enum34 directly

### 0.6.0 - 2017/06/17

* Add discovery (mDNS) support

### 0.5.0 - 2017/05/28

* Add Websocket support

### 0.4.0 - 2017/05/21

* Add Bluetooth source

### 0.3.0 - 2017/04/09

* Fix issue with non ASCII characters
* Allow playing local computer media

### 0.2.2 - 2017/02/07

* Fix status with non ascii characters in Python 2.7

### 0.2.1 - 2017/02/05

* Fix dependencies

### 0.2.0 - 2017/02/05

* Add *play_media* support

### 0.1.0 - 2016/11/20

* Initial release

## Contributors

Expand All @@ -205,4 +262,6 @@ Thanks to:
* [Tyzer34](https://github.com/Tyzer34) (add *play_media* support)
* [wanderor](https://github.com/wanderor) (add local computer media support)
* [obadz](https://github.com/obadz) (add Bluetooth source)
* [luca-angemi](https://github.com/luca-angemi) (Fix new firmware error)
* [vanto](https://github.com/vanto) (Fix device names with UTF-8 characters)

11 changes: 11 additions & 0 deletions RELEASES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
Version 0.8.0
~~~~~~~~~~~~~

:Date:
2018/02/11

- Fix: New API content with latest firmware
- Fix: Device names with UTF-8 characters
- Allow to select AUX/Bluetooth inputs
- Add snapshotting/restore feature

Version 0.7.2
~~~~~~~~~~~~~

Expand Down
13 changes: 13 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ Features
- volume setting (mute/set volume/volume up/volume down)
- repeat one/all/off
- shuffle on/off
- select AUX/Bluetooth inputs
- select preset (bookmark)
- playback selected music
- allow snapshot and restore playing content
- play HTTP URL (not HTTPS)
- Multi room (zones)
- Websocket notifications
Expand Down Expand Up @@ -109,6 +111,17 @@ Basic Usage
account_id,
Type.ALBUM)
# Snapshot current playing
device.snapshot()
# Select AUX input
device.select_source_aux()
# Select Bluetooth input
device.select_source_bluetooth()
# Restore previous snapshot
device.restore()
# Play an HTTP URL (not HTTPS)
device.play_url('http://fqdn/file.mp3')
Expand Down
2 changes: 1 addition & 1 deletion libsoundtouch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
from queue import Queue, Empty
except ImportError:
from Queue import Queue, Empty # type: ignore
from zeroconf import Zeroconf, ServiceBrowser
from libsoundtouch.device import SoundTouchDevice
from libsoundtouch.utils import SoundtouchDeviceListener
from zeroconf import Zeroconf, ServiceBrowser

_LOGGER = logging.getLogger(__name__)

Expand Down
98 changes: 90 additions & 8 deletions libsoundtouch/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
# pylint: disable=useless-super-delegation,too-many-lines

import logging
from threading import Thread, Event
from xml.dom import minidom
from pprint import pprint
import os
import re
import sys, traceback
import xml.etree.cElementTree as ET
from threading import Thread, Event
from xml.dom import minidom
from pprint import pprint

import requests
import websocket
Expand Down Expand Up @@ -188,11 +189,13 @@ def __init__(self, host, port=8090, ws_port=8080, dlna_port=8091):
self._zone_status_updated_listeners = []
self._device_info_updated_listeners = []
self._ws_wait = Event()
self._snapshot = None

def __init_config(self):
response = requests.get(
"http://" + self._host + ":" + str(self._port) + "/info")
dom = minidom.parseString(response.text)
response.encoding = 'UTF-8'
dom = minidom.parseString(response.text.encode('utf-8'))
self._config = Config(dom)

def start_notification(self):
Expand Down Expand Up @@ -322,7 +325,8 @@ def refresh_presets(self):
"""Refresh presets."""
response = requests.get(
"http://" + self._host + ":" + str(self._port) + "/presets")
dom = minidom.parseString(response.text)
response.encoding = 'UTF-8'
dom = minidom.parseString(response.text.encode('utf-8'))
self._presets = []
for preset in _get_dom_elements(dom, "preset"):
self._presets.append(Preset(preset))
Expand All @@ -344,7 +348,38 @@ def select_preset(self, preset):
"""
requests.post(
'http://' + self._host + ":" + str(self._port) + '/select',
preset.source_xml)
preset.source_xml.encode('utf-8'))

def select_content_item(self, source, source_account=None, location=None,
media_type=None):
"""Select specified content.
:param source The source
:param source_account The source account
:param location The location
:param media_type The media type
"""
attributes = {"source": source.value}
if source_account:
attributes["sourceAccount"] = source_account
if location:
attributes["location"] = location
if media_type:
attributes["type"] = media_type
root = ET.Element("ContentItem", attributes)

content = ET.tostring(root).decode("UTF-8")
requests.post(
'http://' + self._host + ":" + str(self._port) + '/select',
content)

def select_source_aux(self):
"""Select AUX source."""
self.select_content_item(Source.AUX, Source.AUX.value)

def select_source_bluetooth(self):
"""Select BLUETOOTH source."""
self.select_content_item(Source.BLUETOOTH)

def _create_zone(self, slaves):
if len(slaves) <= 0:
Expand Down Expand Up @@ -656,6 +691,20 @@ def power_off(self):
if self.status().source != STATE_STANDBY:
self._send_key(Key.POWER.value)

def snapshot(self):
"""Snapshot current playing media."""
status = self.status(refresh=True)
if status and status.content_item:
self._snapshot = status.content_item

def restore(self):
"""Restore last snapshot."""
if self._snapshot:
self.select_content_item(Source[self._snapshot.source],
self._snapshot.source_account,
self._snapshot.location,
self._snapshot.type)


class Config:
"""Soundtouch device configuration."""
Expand Down Expand Up @@ -824,8 +873,11 @@ def __init__(self, xml_dom):
"""
self._source = _get_dom_element_attribute(xml_dom, "nowPlaying",
"source")
self._content_item = ContentItem(
_get_dom_element(xml_dom, "ContentItem"))
self._content_item = None
content_item = xml_dom.getElementsByTagName("ContentItem")
if content_item:
self._content_item = ContentItem(
_get_dom_element(xml_dom, "ContentItem"))
self._track = _get_dom_element_value(xml_dom, "track")
self._artist = _get_dom_element_value(xml_dom, "artist")
self._album = _get_dom_element_value(xml_dom, "album")
Expand Down Expand Up @@ -931,6 +983,18 @@ def station_location(self):
"""Station location."""
return self._station_location

def __repr__(self):
"""Return a String representation."""
fields = [str(self.source.encode('utf-8')), str(self.content_item),
str(self.track), str(self.artist), str(self.album),
str(self.artist), str(self.image), str(self.duration),
str(self.position), str(self.duration),
str(self.play_status), str(self.shuffle_setting),
str(self.repeat_setting), str(self.stream_type),
str(self.track_id), str(self.station_name),
str(self.station_location)]
return 'Status(' + ",".join(fields) + ')'


class MediaItem:
"""Media item."""
Expand Down Expand Up @@ -1042,6 +1106,15 @@ def is_presetable(self):
"""Return true if presetable."""
return self._is_presetable

def __repr__(self):
"""Return a String representation."""
fields = [self.name.encode('UTF-8') if self.name else self.name,
self.source, self.location, self.source_account,
self.is_presetable]
formated_fields = [str(f) for f in fields]
return 'ContentItem(' + ",".join(formated_fields) + ')'


class SourceItem:
"""Bose Soundtouch source."""

Expand Down Expand Up @@ -1180,6 +1253,15 @@ def source_xml(self):
"""XML source."""
return self._source_xml

def __repr__(self):
"""Return a String representation."""
fields = [self.name if self.name else self.name,
self.preset_id, self.source, self.type,
self.location, self.source_account,
self.source_xml.encode('utf-8')]
formated_fields = [str(f) for f in fields]
return 'Preset(' + ",".join(formated_fields) + ')'


class ZoneStatus:
"""Zone Status."""
Expand Down
1 change: 1 addition & 0 deletions libsoundtouch/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Source(Enum):
BLUETOOTH = "BLUETOOTH"
TUNEIN = "TUNEIN"
UPNP = "UPNP"
INVALID_SOURCE = "INVALID_SOURCE"


class SourceStatus(Enum):
Expand Down
2 changes: 1 addition & 1 deletion requirements_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ coveralls>=1.1
pydocstyle>=2.0.0
pytest>=2.9.2
pytest-cov>=2.3.1
mypy-lang>=0.4
mypy>=0.560
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def gen_data_files(*dirs):

setup(
name="libsoundtouch",
version="0.7.2",
version="0.8.0",
license="Apache License 2.0",
url="http://libsoundtouch.readthedocs.io",
download_url="https://github.com/CharlesBlonde/libsoundtouch",
Expand Down
Loading

0 comments on commit e81bfa4

Please sign in to comment.