Merge branch 'develop' into feature/modularised-output
Conflicts: mopidy/gstreamer.py
This commit is contained in:
commit
865d62e6e1
@ -1,4 +1,4 @@
|
||||
include LICENSE pylintrc *.rst data/mopidy.desktop
|
||||
include LICENSE pylintrc *.rst *.ini data/mopidy.desktop
|
||||
include mopidy/backends/spotify/spotify_appkey.key
|
||||
recursive-include docs *
|
||||
prune docs/_build
|
||||
|
||||
@ -5,11 +5,35 @@ Changes
|
||||
This change log is used to track all major changes to Mopidy.
|
||||
|
||||
|
||||
0.4.0 (in development)
|
||||
0.5.0 (in development)
|
||||
======================
|
||||
|
||||
No description yet.
|
||||
|
||||
**Changes**
|
||||
|
||||
No changes yet.
|
||||
|
||||
|
||||
0.4.0 (2011-04-27)
|
||||
==================
|
||||
|
||||
Mopidy 0.4.0 is another release without major feature additions. In 0.4.0 we've
|
||||
fixed a bunch of issues and bugs, with the help of several new contributors
|
||||
who are credited in the changelog below. The major change of 0.4.0 is an
|
||||
internal refactoring which clears way for future features, and which also make
|
||||
Mopidy work on Python 2.7. In other words, Mopidy 0.4.0 works on Ubuntu 11.04
|
||||
and Arch Linux.
|
||||
|
||||
Please note that 0.4.0 requires some updated dependencies, as listed under
|
||||
*Important changes* below. Also, the known bug in the Spotify playlist
|
||||
loading from Mopidy 0.3.0 is still present.
|
||||
|
||||
.. warning:: Known bug in Spotify playlist loading
|
||||
|
||||
There is a known bug in the loading of Spotify playlists. To avoid the bug,
|
||||
follow the simple workaround described at :issue:`59`.
|
||||
|
||||
|
||||
**Important changes**
|
||||
|
||||
@ -30,7 +54,7 @@ No description yet.
|
||||
|
||||
- Mopidy now use Pykka actors for thread management and inter-thread
|
||||
communication. The immediate advantage of this is that Mopidy now works on
|
||||
Python 2.7. (Fixes: :issue:`66`)
|
||||
Python 2.7, which is the default on e.g. Ubuntu 11.04. (Fixes: :issue:`66`)
|
||||
|
||||
- Spotify backend:
|
||||
|
||||
@ -40,6 +64,11 @@ No description yet.
|
||||
- Better error messages on wrong login or network problems. Thanks to Antoine
|
||||
Pierlot-Garcin for patches to Mopidy and Pyspotify. (Fixes: :issue:`77`)
|
||||
|
||||
- Reduce log level for trivial log messages from warning to info. (Fixes:
|
||||
:issue:`71`)
|
||||
|
||||
- Pause playback on network connection errors. (Fixes: :issue:`65`)
|
||||
|
||||
- Local backend:
|
||||
|
||||
- Fix crash in :command:`mopidy-scan` if a track has no artist name. Thanks
|
||||
@ -61,11 +90,29 @@ No description yet.
|
||||
- Fix bug where ``status`` returned ``song: None``, which caused MPDroid to
|
||||
crash. (Fixes: :issue:`69`)
|
||||
|
||||
- Gracefully fallback to IPv4 sockets on systems that supports IPv6, but has
|
||||
turned it off. (Fixes: :issue:`75`)
|
||||
|
||||
- GStreamer output:
|
||||
|
||||
- Use ``uridecodebin`` for playing audio from both Spotify and the local
|
||||
backend. This contributes to support for multiple backends simultaneously.
|
||||
|
||||
- Settings:
|
||||
|
||||
- Fix crash on ``--list-settings`` on clean installation. Thanks to Martins
|
||||
Grunskis for the bug report and patch. (Fixes: :issue:`63`)
|
||||
|
||||
- Packaging:
|
||||
|
||||
- Replace test data symlinks with real files to avoid symlink issues when
|
||||
installing with pip. (Fixes: :issue:`68`)
|
||||
|
||||
- Debugging:
|
||||
|
||||
- Include platform, architecture, Linux distribution, and Python version in
|
||||
the debug log, to ease debugging of issues with attached debug logs.
|
||||
|
||||
|
||||
0.3.1 (2010-01-22)
|
||||
==================
|
||||
|
||||
@ -202,4 +202,4 @@ latex_documents = [
|
||||
|
||||
needs_sphinx = '1.0'
|
||||
|
||||
extlinks = {'issue': ('http://github.com/mopidy/mopidy/issues#issue/%s', 'GH-')}
|
||||
extlinks = {'issue': ('http://github.com/mopidy/mopidy/issues/%s', 'GH-')}
|
||||
|
||||
@ -5,7 +5,7 @@ if not (2, 6) <= sys.version_info < (3,):
|
||||
|
||||
from subprocess import PIPE, Popen
|
||||
|
||||
VERSION = (0, 4, 0)
|
||||
VERSION = (0, 5, 0)
|
||||
|
||||
def get_version():
|
||||
try:
|
||||
|
||||
@ -24,7 +24,7 @@ class SpotifyPlaybackProvider(BasePlaybackProvider):
|
||||
self.backend.gstreamer.set_metadata(track)
|
||||
return True
|
||||
except SpotifyError as e:
|
||||
logger.warning('Play %s failed: %s', track.uri, e)
|
||||
logger.info('Playback of %s failed: %s', track.uri, e)
|
||||
return False
|
||||
|
||||
def resume(self):
|
||||
|
||||
@ -74,7 +74,11 @@ class SpotifySessionManager(BaseThread, PyspotifySessionManager):
|
||||
|
||||
def connection_error(self, session, error):
|
||||
"""Callback used by pyspotify"""
|
||||
logger.error(u'Spotify connection error: %s', error)
|
||||
if error is None:
|
||||
logger.info(u'Spotify connection error resolved')
|
||||
else:
|
||||
logger.error(u'Spotify connection error: %s', error)
|
||||
self.backend.playback.pause()
|
||||
|
||||
def message_to_user(self, session, message):
|
||||
"""Callback used by pyspotify"""
|
||||
|
||||
@ -62,5 +62,5 @@ class SpotifyTranslator(object):
|
||||
if str(Link.from_track(t, 0))],
|
||||
)
|
||||
except SpotifyError, e:
|
||||
logger.warning(u'Failed translating Spotify playlist '
|
||||
logger.info(u'Failed translating Spotify playlist '
|
||||
'(probably a playlist folder boundary): %s', e)
|
||||
|
||||
@ -24,9 +24,11 @@ def main():
|
||||
setup_backend()
|
||||
setup_frontends()
|
||||
try:
|
||||
time.sleep(10000*24*60*60)
|
||||
while ActorRegistry.get_all():
|
||||
time.sleep(1)
|
||||
logger.info(u'No actors left. Exiting...')
|
||||
except KeyboardInterrupt:
|
||||
logger.info(u'Exiting...')
|
||||
logger.info(u'User interrupt. Exiting...')
|
||||
ActorRegistry.stop_all()
|
||||
|
||||
def parse_options():
|
||||
|
||||
@ -52,7 +52,7 @@ class MpdServer(asyncore.dispatcher):
|
||||
self._format_hostname(settings.MPD_SERVER_HOSTNAME),
|
||||
settings.MPD_SERVER_PORT)
|
||||
except IOError, e:
|
||||
logger.error('MPD server startup failed: %s' % e)
|
||||
logger.error(u'MPD server startup failed: %s' % str(e).decode('utf-8'))
|
||||
sys.exit(1)
|
||||
|
||||
def handle_accept(self):
|
||||
|
||||
@ -13,6 +13,15 @@ from mopidy.backends.base import Backend
|
||||
|
||||
logger = logging.getLogger('mopidy.gstreamer')
|
||||
|
||||
default_caps = gst.Caps("""
|
||||
audio/x-raw-int,
|
||||
endianness=(int)1234,
|
||||
channels=(int)2,
|
||||
width=(int)16,
|
||||
depth=(int)16,
|
||||
signed=(boolean)true,
|
||||
rate=(int)44100""")
|
||||
|
||||
class BaseOutput(object):
|
||||
def connect_bin(self, pipeline, element_to_link_to):
|
||||
"""
|
||||
@ -92,10 +101,11 @@ class GStreamer(ThreadingActor):
|
||||
self.gst_volume = self.gst_pipeline.get_by_name('volume')
|
||||
self.gst_taginject = self.gst_pipeline.get_by_name('tag')
|
||||
|
||||
self.gst_uridecodebin = gst.element_factory_make('uridecodebin', 'uri')
|
||||
self.gst_uridecodebin.connect('pad-added', self._process_new_pad,
|
||||
uridecodebin = gst.element_factory_make('uridecodebin', 'uri')
|
||||
uridecodebin.connect('notify::source', self._process_new_source)
|
||||
uridecodebin.connect('pad-added', self._process_new_pad,
|
||||
self.gst_convert.get_pad('sink'))
|
||||
self.gst_pipeline.add(self.gst_uridecodebin)
|
||||
self.gst_pipeline.add(uridecodebin)
|
||||
|
||||
for output in settings.OUTPUTS:
|
||||
output_cls = get_class(output)()
|
||||
@ -106,6 +116,13 @@ class GStreamer(ThreadingActor):
|
||||
gst_bus.add_signal_watch()
|
||||
gst_bus.connect('message', self._process_gstreamer_message)
|
||||
|
||||
def _process_new_source(self, element, pad):
|
||||
source = element.get_by_name('source')
|
||||
try:
|
||||
source.set_property('caps', default_caps)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
def _process_new_pad(self, source, pad, target_pad):
|
||||
pad.link(target_pad)
|
||||
|
||||
|
||||
@ -190,7 +190,7 @@ class NadTalker(ThreadingActor):
|
||||
# trailing whitespace.
|
||||
if not self._device.isOpen():
|
||||
self._device.open()
|
||||
result = self._device.readline(eol='\n').strip()
|
||||
result = self._device.readline().strip()
|
||||
if result:
|
||||
logger.debug('Read: %s', result)
|
||||
return result
|
||||
|
||||
@ -1 +0,0 @@
|
||||
../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/song1.mp3
Normal file
BIN
tests/data/scanner/advanced/song1.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/song2.mp3
Normal file
BIN
tests/data/scanner/advanced/song2.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/song3.mp3
Normal file
BIN
tests/data/scanner/advanced/song3.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/subdir1/song4.mp3
Normal file
BIN
tests/data/scanner/advanced/subdir1/song4.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/subdir1/song5.mp3
Normal file
BIN
tests/data/scanner/advanced/subdir1/song5.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../../../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/subdir1/subsubdir/song8.mp3
Normal file
BIN
tests/data/scanner/advanced/subdir1/subsubdir/song8.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../../../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/subdir1/subsubdir/song9.mp3
Normal file
BIN
tests/data/scanner/advanced/subdir1/subsubdir/song9.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/subdir2/song6.mp3
Normal file
BIN
tests/data/scanner/advanced/subdir2/song6.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../../sample.mp3
|
||||
BIN
tests/data/scanner/advanced/subdir2/song7.mp3
Normal file
BIN
tests/data/scanner/advanced/subdir2/song7.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
../sample.mp3
|
||||
BIN
tests/data/scanner/simple/song1.mp3
Normal file
BIN
tests/data/scanner/simple/song1.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.flac
|
||||
BIN
tests/data/song1.flac
Normal file
BIN
tests/data/song1.flac
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.mp3
|
||||
BIN
tests/data/song1.mp3
Normal file
BIN
tests/data/song1.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.ogg
|
||||
BIN
tests/data/song1.ogg
Normal file
BIN
tests/data/song1.ogg
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.wav
|
||||
BIN
tests/data/song1.wav
Normal file
BIN
tests/data/song1.wav
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.flac
|
||||
BIN
tests/data/song2.flac
Normal file
BIN
tests/data/song2.flac
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.mp3
|
||||
BIN
tests/data/song2.mp3
Normal file
BIN
tests/data/song2.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.ogg
|
||||
BIN
tests/data/song2.ogg
Normal file
BIN
tests/data/song2.ogg
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.wav
|
||||
BIN
tests/data/song2.wav
Normal file
BIN
tests/data/song2.wav
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.flac
|
||||
BIN
tests/data/song3.flac
Normal file
BIN
tests/data/song3.flac
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.mp3
|
||||
BIN
tests/data/song3.mp3
Normal file
BIN
tests/data/song3.mp3
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.ogg
|
||||
BIN
tests/data/song3.ogg
Normal file
BIN
tests/data/song3.ogg
Normal file
Binary file not shown.
@ -1 +0,0 @@
|
||||
blank.wav
|
||||
BIN
tests/data/song3.wav
Normal file
BIN
tests/data/song3.wav
Normal file
Binary file not shown.
@ -17,8 +17,9 @@ class VersionTest(unittest.TestCase):
|
||||
self.assert_(SV('0.1.0') < SV('1.0.0'))
|
||||
self.assert_(SV('0.2.0') < SV('0.3.0'))
|
||||
self.assert_(SV('0.3.0') < SV('0.3.1'))
|
||||
self.assert_(SV('0.3.1') < SV(get_plain_version()))
|
||||
self.assert_(SV(get_plain_version()) < SV('0.4.1'))
|
||||
self.assert_(SV('0.3.1') < SV('0.4.0'))
|
||||
self.assert_(SV('0.4.0') < SV(get_plain_version()))
|
||||
self.assert_(SV(get_plain_version()) < SV('0.5.1'))
|
||||
|
||||
def test_get_platform_contains_platform(self):
|
||||
self.assert_(platform.platform() in get_platform())
|
||||
|
||||
Loading…
Reference in New Issue
Block a user