mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
Add 'transcoded' info to API responses if the server is set to transcode for that client
Closes #62
This commit is contained in:
parent
fb79fc3f18
commit
1e1b475fe6
@ -0,0 +1,25 @@
|
||||
# coding: utf-8
|
||||
|
||||
# This file is part of Supysonic.
|
||||
#
|
||||
# Supysonic is a Python implementation of the Subsonic server API.
|
||||
# Copyright (C) 2013-2017 Alban 'spl0k' Féron
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import mimetypes
|
||||
|
||||
def get_mime(ext):
|
||||
return mimetypes.guess_type('dummy.' + ext, False)[0] or config.get('mimetypes', ext) or 'application/octet-stream'
|
||||
|
@ -75,6 +75,22 @@ def authorize():
|
||||
request.username = username
|
||||
request.user = user
|
||||
|
||||
@app.before_request
|
||||
def get_client_prefs():
|
||||
if not request.path.startswith('/rest/'):
|
||||
return
|
||||
|
||||
client = request.values.get('c')
|
||||
prefs = store.get(ClientPrefs, (request.user.id, client))
|
||||
if not prefs:
|
||||
prefs = ClientPrefs()
|
||||
prefs.user_id = request.user.id
|
||||
prefs.client_name = client
|
||||
store.add(prefs)
|
||||
store.commit()
|
||||
|
||||
request.prefs = prefs
|
||||
|
||||
@app.after_request
|
||||
def set_headers(response):
|
||||
if not request.path.startswith('/rest/'):
|
||||
|
@ -63,7 +63,7 @@ def rand_songs():
|
||||
|
||||
return request.formatter({
|
||||
'randomSongs': {
|
||||
'song': [ t.as_subsonic_child(request.user) for t in tracks ]
|
||||
'song': [ t.as_subsonic_child(request.user, request.prefs) for t in tracks ]
|
||||
}
|
||||
})
|
||||
|
||||
@ -171,7 +171,7 @@ def now_playing():
|
||||
return request.formatter({
|
||||
'nowPlaying': {
|
||||
'entry': [ dict(
|
||||
u.last_play.as_subsonic_child(request.user).items() +
|
||||
u.last_play.as_subsonic_child(request.user, request.prefs).items() +
|
||||
{ 'username': u.name, 'minutesAgo': (now() - u.last_play_date).seconds / 60, 'playerId': 0 }.items()
|
||||
) for u in query if u.last_play_date + timedelta(seconds = u.last_play.duration * 2) > now() ]
|
||||
}
|
||||
@ -185,7 +185,7 @@ def get_starred():
|
||||
'starred': {
|
||||
'artist': [ { 'id': str(sf.starred_id), 'name': sf.starred.name } for sf in folders.find(Folder.parent_id == StarredFolder.starred_id, Track.folder_id == Folder.id).config(distinct = True) ],
|
||||
'album': [ sf.starred.as_subsonic_child(request.user) for sf in folders.find(Track.folder_id == StarredFolder.starred_id).config(distinct = True) ],
|
||||
'song': [ st.starred.as_subsonic_child(request.user) for st in store.find(StarredTrack, StarredTrack.user_id == User.id, User.name == request.username) ]
|
||||
'song': [ st.starred.as_subsonic_child(request.user, request.prefs) for st in store.find(StarredTrack, StarredTrack.user_id == User.id, User.name == request.username) ]
|
||||
}
|
||||
})
|
||||
|
||||
@ -195,7 +195,7 @@ def get_starred_id3():
|
||||
'starred2': {
|
||||
'artist': [ sa.starred.as_subsonic_artist(request.user) for sa in store.find(StarredArtist, StarredArtist.user_id == User.id, User.name == request.username) ],
|
||||
'album': [ sa.starred.as_subsonic_album(request.user) for sa in store.find(StarredAlbum, StarredAlbum.user_id == User.id, User.name == request.username) ],
|
||||
'song': [ st.starred.as_subsonic_child(request.user) for st in store.find(StarredTrack, StarredTrack.user_id == User.id, User.name == request.username) ]
|
||||
'song': [ st.starred.as_subsonic_child(request.user, request.prefs) for st in store.find(StarredTrack, StarredTrack.user_id == User.id, User.name == request.username) ]
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -97,7 +97,7 @@ def list_indexes():
|
||||
'name': a.name
|
||||
} for a in sorted(v, key = lambda a: a.name.lower()) ]
|
||||
} for k, v in sorted(indexes.iteritems()) ],
|
||||
'child': [ c.as_subsonic_child(request.user) for c in sorted(childs, key = lambda t: t.sort_key()) ]
|
||||
'child': [ c.as_subsonic_child(request.user, request.prefs) for c in sorted(childs, key = lambda t: t.sort_key()) ]
|
||||
}
|
||||
})
|
||||
|
||||
@ -110,7 +110,7 @@ def show_directory():
|
||||
directory = {
|
||||
'id': str(res.id),
|
||||
'name': res.name,
|
||||
'child': [ f.as_subsonic_child(request.user) for f in sorted(res.children, key = lambda c: c.name.lower()) ] + [ t.as_subsonic_child(request.user) for t in sorted(res.tracks, key = lambda t: t.sort_key()) ]
|
||||
'child': [ f.as_subsonic_child(request.user) for f in sorted(res.children, key = lambda c: c.name.lower()) ] + [ t.as_subsonic_child(request.user, request.prefs) for t in sorted(res.tracks, key = lambda t: t.sort_key()) ]
|
||||
}
|
||||
if not res.root:
|
||||
directory['parent'] = str(res.parent_id)
|
||||
@ -162,7 +162,7 @@ def album_info():
|
||||
return res
|
||||
|
||||
info = res.as_subsonic_album(request.user)
|
||||
info['song'] = [ t.as_subsonic_child(request.user) for t in sorted(res.tracks, key = lambda t: t.sort_key()) ]
|
||||
info['song'] = [ t.as_subsonic_child(request.user, request.prefs) for t in sorted(res.tracks, key = lambda t: t.sort_key()) ]
|
||||
|
||||
return request.formatter({ 'album': info })
|
||||
|
||||
@ -172,7 +172,7 @@ def track_info():
|
||||
if not status:
|
||||
return res
|
||||
|
||||
return request.formatter({ 'song': res.as_subsonic_child(request.user) })
|
||||
return request.formatter({ 'song': res.as_subsonic_child(request.user, request.prefs) })
|
||||
|
||||
@app.route('/rest/getVideos.view', methods = [ 'GET', 'POST' ])
|
||||
def list_videos():
|
||||
|
@ -45,7 +45,7 @@ def stream_media():
|
||||
if not status:
|
||||
return res
|
||||
|
||||
maxBitRate, format, timeOffset, size, estimateContentLength, client = map(request.values.get, [ 'maxBitRate', 'format', 'timeOffset', 'size', 'estimateContentLength', 'c' ])
|
||||
maxBitRate, format, timeOffset, size, estimateContentLength = map(request.values.get, [ 'maxBitRate', 'format', 'timeOffset', 'size', 'estimateContentLength' ])
|
||||
if format:
|
||||
format = format.lower()
|
||||
|
||||
@ -54,18 +54,10 @@ def stream_media():
|
||||
dst_bitrate = res.bitrate
|
||||
dst_mimetype = res.content_type
|
||||
|
||||
if client:
|
||||
prefs = store.get(ClientPrefs, (request.user.id, client))
|
||||
if not prefs:
|
||||
prefs = ClientPrefs()
|
||||
prefs.user_id = request.user.id
|
||||
prefs.client_name = client
|
||||
store.add(prefs)
|
||||
|
||||
if prefs.format:
|
||||
dst_suffix = prefs.format
|
||||
if prefs.bitrate and prefs.bitrate < dst_bitrate:
|
||||
dst_bitrate = prefs.bitrate
|
||||
if request.prefs.format:
|
||||
dst_suffix = request.prefs.format
|
||||
if request.prefs.bitrate and request.prefs.bitrate < dst_bitrate:
|
||||
dst_bitrate = request.prefs.bitrate
|
||||
|
||||
if maxBitRate:
|
||||
try:
|
||||
@ -87,7 +79,9 @@ def stream_media():
|
||||
if not transcoder and (not decoder or not encoder):
|
||||
transcoder = config.get('transcoding', 'transcoder')
|
||||
if not transcoder:
|
||||
return request.error_formatter(0, 'No way to transcode from {} to {}'.format(src_suffix, dst_suffix))
|
||||
message = 'No way to transcode from {} to {}'.format(src_suffix, dst_suffix)
|
||||
app.logger.info(message)
|
||||
return request.error_formatter(0, message)
|
||||
|
||||
transcoder, decoder, encoder = map(lambda x: prepare_transcoding_cmdline(x, res.path, src_suffix, dst_suffix, dst_bitrate), [ transcoder, decoder, encoder ])
|
||||
try:
|
||||
|
@ -45,7 +45,7 @@ def show_playlist():
|
||||
return res
|
||||
|
||||
info = res.as_subsonic_playlist(request.user)
|
||||
info['entry'] = [ t.as_subsonic_child(request.user) for t in res.tracks ]
|
||||
info['entry'] = [ t.as_subsonic_child(request.user, request.prefs) for t in res.tracks ]
|
||||
return request.formatter({ 'playlist': info })
|
||||
|
||||
@app.route('/rest/createPlaylist.view', methods = [ 'GET', 'POST' ])
|
||||
|
@ -52,7 +52,7 @@ def old_search():
|
||||
return request.formatter({ 'searchResult': {
|
||||
'totalHits': folders.count() + tracks.count(),
|
||||
'offset': offset,
|
||||
'match': [ r.as_subsonic_child(request.user) for r in res ]
|
||||
'match': [ r.as_subsonic_child(request.user) if r is Folder else r.as_subsonic_child(request.user, request.prefs) for r in res ]
|
||||
}})
|
||||
else:
|
||||
return request.error_formatter(10, 'Missing search parameter')
|
||||
@ -60,7 +60,7 @@ def old_search():
|
||||
return request.formatter({ 'searchResult': {
|
||||
'totalHits': query.count(),
|
||||
'offset': offset,
|
||||
'match': [ r.as_subsonic_child(request.user) for r in query[offset : offset + count] ]
|
||||
'match': [ r.as_subsonic_child(request.user) if r is Folder else r.as_subsonic_child(request.user, request.prefs) for r in query[offset : offset + count] ]
|
||||
}})
|
||||
|
||||
@app.route('/rest/search2.view', methods = [ 'GET', 'POST' ])
|
||||
@ -89,7 +89,7 @@ def new_search():
|
||||
return request.formatter({ 'searchResult2': {
|
||||
'artist': [ { 'id': str(a.id), 'name': a.name } for a in artist_query ],
|
||||
'album': [ f.as_subsonic_child(request.user) for f in album_query ],
|
||||
'song': [ t.as_subsonic_child(request.user) for t in song_query ]
|
||||
'song': [ t.as_subsonic_child(request.user, request.prefs) for t in song_query ]
|
||||
}})
|
||||
|
||||
@app.route('/rest/search3.view', methods = [ 'GET', 'POST' ])
|
||||
@ -117,6 +117,6 @@ def search_id3():
|
||||
return request.formatter({ 'searchResult3': {
|
||||
'artist': [ a.as_subsonic_artist(request.user) for a in artist_query ],
|
||||
'album': [ a.as_subsonic_album(request.user) for a in album_query ],
|
||||
'song': [ t.as_subsonic_child(request.user) for t in song_query ]
|
||||
'song': [ t.as_subsonic_child(request.user, request.prefs) for t in song_query ]
|
||||
}})
|
||||
|
||||
|
@ -27,6 +27,8 @@ from storm.variables import Variable
|
||||
import uuid, datetime, time
|
||||
import os.path
|
||||
|
||||
from supysonic import get_mime
|
||||
|
||||
def now():
|
||||
return datetime.datetime.now().replace(microsecond = 0)
|
||||
|
||||
@ -168,7 +170,7 @@ class Track(object):
|
||||
folder_id = UUID()
|
||||
folder = Reference(folder_id, Folder.id)
|
||||
|
||||
def as_subsonic_child(self, user):
|
||||
def as_subsonic_child(self, user, prefs):
|
||||
info = {
|
||||
'id': str(self.id),
|
||||
'parent': str(self.folder_id),
|
||||
@ -209,8 +211,9 @@ class Track(object):
|
||||
if avgRating:
|
||||
info['averageRating'] = avgRating
|
||||
|
||||
# transcodedContentType
|
||||
# transcodedSuffix
|
||||
if prefs and prefs.format and prefs.format != self.suffix():
|
||||
info['transcodedSuffix'] = prefs.format
|
||||
info['transcodedContentType'] = get_mime(prefs.format)
|
||||
|
||||
return info
|
||||
|
||||
|
@ -19,20 +19,17 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os, os.path
|
||||
import time, mimetypes
|
||||
import time
|
||||
import mutagen
|
||||
|
||||
from storm.expr import ComparableExpr, compile, Like
|
||||
from storm.exceptions import NotSupportedError
|
||||
|
||||
from supysonic import config
|
||||
from supysonic import config, get_mime
|
||||
from supysonic.db import Folder, Artist, Album, Track, User, PlaylistTrack
|
||||
from supysonic.db import StarredFolder, StarredArtist, StarredAlbum, StarredTrack
|
||||
from supysonic.db import RatingFolder, RatingTrack
|
||||
|
||||
def get_mime(ext):
|
||||
return mimetypes.guess_type('dummy.' + ext, False)[0] or config.get('mimetypes', ext) or 'application/octet-stream'
|
||||
|
||||
# Hacking in support for a concatenation expression
|
||||
class Concat(ComparableExpr):
|
||||
__slots__ = ("left", "right", "db")
|
||||
|
Loading…
Reference in New Issue
Block a user