mopidy/mopidy/mpd/translator.py
Thomas Adamcik 6adeea6009 core: Correctly handle missing duration in seek.
Seeks will now fail when the duration is None, this is an approximation to if
the track is seekable or not. This check is need as otherwise seeking a radio
stream will trigger the next track.

If the track truly isn't seekable despite having a duration we should still
fail as GStreamer will reject the seek.
2015-03-15 11:29:07 +01:00

139 lines
4.5 KiB
Python

from __future__ import absolute_import, unicode_literals
import re
from mopidy.models import TlTrack
# TODO: special handling of local:// uri scheme
normalize_path_re = re.compile(r'[^/]+')
def normalize_path(path, relative=False):
parts = normalize_path_re.findall(path or '')
if not relative:
parts.insert(0, '')
return '/'.join(parts)
def track_to_mpd_format(track, position=None, stream_title=None):
"""
Format track for output to MPD client.
:param track: the track
:type track: :class:`mopidy.models.Track` or :class:`mopidy.models.TlTrack`
:param position: track's position in playlist
:type position: integer
:param stream_title: the current streams title
:type position: string
:rtype: list of two-tuples
"""
if isinstance(track, TlTrack):
(tlid, track) = track
else:
(tlid, track) = (None, track)
result = [
('file', track.uri or ''),
# TODO: only show length if not none, see:
# https://github.com/mopidy/mopidy/issues/923#issuecomment-79584110
('Time', track.length and (track.length // 1000) or 0),
('Artist', artists_to_mpd_format(track.artists)),
('Title', track.name or ''),
('Album', track.album and track.album.name or ''),
]
if stream_title:
result.append(('Name', stream_title))
if track.date:
result.append(('Date', track.date))
if track.album is not None and track.album.num_tracks is not None:
result.append(('Track', '%d/%d' % (
track.track_no or 0, track.album.num_tracks)))
else:
result.append(('Track', track.track_no or 0))
if position is not None and tlid is not None:
result.append(('Pos', position))
result.append(('Id', tlid))
if track.album is not None and track.album.musicbrainz_id is not None:
result.append(('MUSICBRAINZ_ALBUMID', track.album.musicbrainz_id))
# FIXME don't use first and best artist?
# FIXME don't duplicate following code?
if track.album is not None and track.album.artists:
artists = artists_to_mpd_format(track.album.artists)
result.append(('AlbumArtist', artists))
artists = [
a for a in track.album.artists if a.musicbrainz_id is not None]
if artists:
result.append(
('MUSICBRAINZ_ALBUMARTISTID', artists[0].musicbrainz_id))
if track.artists:
artists = [a for a in track.artists if a.musicbrainz_id is not None]
if artists:
result.append(('MUSICBRAINZ_ARTISTID', artists[0].musicbrainz_id))
if track.composers:
result.append(('Composer', artists_to_mpd_format(track.composers)))
if track.performers:
result.append(('Performer', artists_to_mpd_format(track.performers)))
if track.genre:
result.append(('Genre', track.genre))
if track.disc_no:
result.append(('Disc', track.disc_no))
if track.musicbrainz_id is not None:
result.append(('MUSICBRAINZ_TRACKID', track.musicbrainz_id))
return result
def artists_to_mpd_format(artists):
"""
Format track artists for output to MPD client.
:param artists: the artists
:type track: array of :class:`mopidy.models.Artist`
:rtype: string
"""
artists = list(artists)
artists.sort(key=lambda a: a.name)
return ', '.join([a.name for a in artists if a.name])
def tracks_to_mpd_format(tracks, start=0, end=None):
"""
Format list of tracks for output to MPD client.
Optionally limit output to the slice ``[start:end]`` of the list.
:param tracks: the tracks
:type tracks: list of :class:`mopidy.models.Track` or
:class:`mopidy.models.TlTrack`
:param start: position of first track to include in output
:type start: int (positive or negative)
:param end: position after last track to include in output
:type end: int (positive or negative) or :class:`None` for end of list
:rtype: list of lists of two-tuples
"""
if end is None:
end = len(tracks)
tracks = tracks[start:end]
positions = range(start, end)
assert len(tracks) == len(positions)
result = []
for track, position in zip(tracks, positions):
result.append(track_to_mpd_format(track, position))
return result
def playlist_to_mpd_format(playlist, *args, **kwargs):
"""
Format playlist for output to MPD client.
Arguments as for :func:`tracks_to_mpd_format`, except the first one.
"""
return tracks_to_mpd_format(playlist.tracks, *args, **kwargs)