def album_list(): ltype = request.values['type'] size, offset = map(request.values.get, [ 'size', 'offset' ]) size = int(size) if size else 10 offset = int(offset) if offset else 0 query = select(t.folder for t in Track) if ltype == 'random': return request.formatter('albumList', dict( album = [ a.as_subsonic_child(request.user) for a in query.without_distinct().random(size) ] )) elif ltype == 'newest': query = query.order_by(desc(Folder.created)) elif ltype == 'highest': query = query.order_by(lambda f: desc(avg(f.ratings.rating))) elif ltype == 'frequent': query = query.order_by(lambda f: desc(avg(f.tracks.play_count))) elif ltype == 'recent': query = select(t.folder for t in Track if max(t.folder.tracks.last_play) is not None).order_by(lambda f: desc(max(f.tracks.last_play))) elif ltype == 'starred': query = select(s.starred for s in StarredFolder if s.user.id == request.user.id and count(s.starred.tracks) > 0) elif ltype == 'alphabeticalByName': query = query.order_by(Folder.name) elif ltype == 'alphabeticalByArtist': query = query.order_by(lambda f: f.parent.name + f.name) else: raise GenericError('Unknown search type') return request.formatter('albumList', dict( album = [ f.as_subsonic_child(request.user) for f in query.limit(size, offset) ] ))
def list_indexes(): musicFolderId = request.values.get("musicFolderId") ifModifiedSince = request.values.get("ifModifiedSince") if ifModifiedSince: ifModifiedSince = int(ifModifiedSince) / 1000 if musicFolderId is None: folders = Folder.select(lambda f: f.root)[:] else: mfid = get_entity_id(Folder, musicFolderId) folder = Folder[mfid] if not folder.root: raise ObjectNotFound(Folder, mfid) folders = [folder] last_modif = max(map(lambda f: f.last_scan, folders)) if ifModifiedSince is not None and last_modif < ifModifiedSince: return request.formatter("indexes", dict(lastModified=last_modif * 1000)) # The XSD lies, we don't return artists but a directory structure artists = [] children = [] for f in folders: artists += f.children.select()[:] children += f.tracks.select()[:] indexes = dict() for artist in artists: index = artist.name[0].upper() if index in string.digits: index = "#" elif index not in string.ascii_letters: index = "?" if index not in indexes: indexes[index] = [] indexes[index].append(artist) return request.formatter( "indexes", dict( lastModified=last_modif * 1000, index=[ dict( name=k, artist=[ dict(id=str(a.id), name=a.name) for a in sorted(v, key=lambda a: a.name.lower()) ], ) for k, v in sorted(indexes.items()) ], child=[ c.as_subsonic_child(request.user, request.client) for c in sorted(children, key=lambda t: t.sort_key()) ], ), )
def album_list(): ltype = request.values["type"] size, offset = map(request.values.get, ("size", "offset")) size = int(size) if size else 10 offset = int(offset) if offset else 0 query = select(t.folder for t in Track) if ltype == "random": return request.formatter( "albumList", { "album": [ a.as_subsonic_child(request.user) for a in distinct(query.random(size)) ] }, ) elif ltype == "newest": query = query.sort_by(desc(Folder.created)).distinct() elif ltype == "highest": query = query.sort_by(lambda f: desc(avg(f.ratings.rating))) elif ltype == "frequent": query = query.sort_by(lambda f: desc(avg(f.tracks.play_count))) elif ltype == "recent": query = select(t.folder for t in Track if max(t.folder.tracks.last_play) is not None).sort_by( lambda f: desc(max(f.tracks.last_play))) elif ltype == "starred": query = select( s.starred for s in StarredFolder if s.user.id == request.user.id and count(s.starred.tracks) > 0) elif ltype == "alphabeticalByName": query = query.sort_by(Folder.name).distinct() elif ltype == "alphabeticalByArtist": query = query.sort_by(lambda f: f.parent.name + f.name) elif ltype == "byYear": startyear = int(request.values["fromYear"]) endyear = int(request.values["toYear"]) query = query.where(lambda t: between(t.year, min(startyear, endyear), max(startyear, endyear))) if endyear < startyear: query = query.sort_by(lambda f: desc(min(f.tracks.year))) else: query = query.sort_by(lambda f: min(f.tracks.year)) elif ltype == "byGenre": genre = request.values["genre"] query = query.where(lambda t: t.genre == genre) else: raise GenericError("Unknown search type") return request.formatter( "albumList", { "album": [ f.as_subsonic_child(request.user) for f in query.limit(size, offset) ] }, )
def album_list_id3(): ltype = request.values['type'] size, offset = map(request.values.get, [ 'size', 'offset' ]) size = int(size) if size else 10 offset = int(offset) if offset else 0 query = Album.select() if ltype == 'random': return request.formatter('albumList2', dict( album = [ a.as_subsonic_album(request.user) for a in query.random(size) ] )) elif ltype == 'newest': query = query.order_by(lambda a: desc(min(a.tracks.created))) elif ltype == 'frequent': query = query.order_by(lambda a: desc(avg(a.tracks.play_count))) elif ltype == 'recent': query = Album.select(lambda a: max(a.tracks.last_play) is not None).order_by(lambda a: desc(max(a.tracks.last_play))) elif ltype == 'starred': query = select(s.starred for s in StarredAlbum if s.user.id == request.user.id) elif ltype == 'alphabeticalByName': query = query.order_by(Album.name) elif ltype == 'alphabeticalByArtist': query = query.order_by(lambda a: a.artist.name + a.name) else: raise GenericError('Unknown search type') return request.formatter('albumList2', dict( album = [ f.as_subsonic_album(request.user) for f in query.limit(size, offset) ] ))
def album_list(): ltype, size, offset = map(request.args.get, ['type', 'size', 'offset']) try: size = int(size) if size else 10 offset = int(offset) if offset else 0 except: return request.error_formatter(0, 'Invalid parameter format') query = session.query(Folder).filter(Folder.tracks.any()) if ltype == 'random': albums = [] count = query.count() if not count: return request.formatter({'albumList': {}}) for _ in xrange(size): x = random.choice(xrange(count)) albums.append(query.offset(x).limit(1).one()) return request.formatter({ 'albumList': { 'album': [a.as_subsonic_child(request.user) for a in albums] } }) elif ltype == 'newest': query = query.order_by(desc(Folder.created)) elif ltype == 'highest': query = query.join(RatingFolder).group_by(Folder.id).order_by( desc(func.avg(RatingFolder.rating))) elif ltype == 'frequent': query = query.join(Track, Folder.tracks).group_by(Folder.id).order_by( desc(func.avg(Track.play_count))) elif ltype == 'recent': query = query.join(Track, Folder.tracks).group_by(Folder.id).order_by( desc(func.max(Track.last_play))) elif ltype == 'starred': query = query.join(StarredFolder).join(User).filter( User.name == request.username) elif ltype == 'alphabeticalByName': query = query.order_by(Folder.name) elif ltype == 'alphabeticalByArtist': # this is a mess because who knows how your file structure is set up # with the database changes it's more difficult to get the parent of a dir parent = aliased(Folder) query = query.join(parent, Folder.parent).order_by( parent.name).order_by(Folder.name) else: return request.error_formatter(0, 'Unknown search type') return request.formatter({ 'albumList': { 'album': [ f.as_subsonic_child(request.user) for f in query.limit(size).offset(offset) ] } })
def album_list_id3(): ltype = request.values["type"] size, offset = map(request.values.get, ("size", "offset")) size = int(size) if size else 10 offset = int(offset) if offset else 0 query = Album.select() if ltype == "random": return request.formatter( "albumList2", { "album": [ a.as_subsonic_album(request.user) for a in query.random(size) ] }, ) elif ltype == "newest": query = query.order_by(lambda a: desc(min(a.tracks.created))) elif ltype == "frequent": query = query.order_by(lambda a: desc(avg(a.tracks.play_count))) elif ltype == "recent": query = Album.select( lambda a: max(a.tracks.last_play) is not None).order_by( lambda a: desc(max(a.tracks.last_play))) elif ltype == "starred": query = select(s.starred for s in StarredAlbum if s.user.id == request.user.id) elif ltype == "alphabeticalByName": query = query.order_by(Album.name) elif ltype == "alphabeticalByArtist": query = query.order_by(lambda a: a.artist.name + a.name) elif ltype == "byYear": startyear = int(request.values["fromYear"]) endyear = int(request.values["toYear"]) query = query.where(lambda a: between(min( a.tracks.year), min(startyear, endyear), max(startyear, endyear))) if endyear < startyear: query = query.order_by(lambda a: desc(min(a.tracks.year))) else: query = query.order_by(lambda a: min(a.tracks.year)) elif ltype == "byGenre": genre = request.values["genre"] query = query.where(lambda a: genre in a.tracks.genre) else: raise GenericError("Unknown search type") return request.formatter( "albumList2", { "album": [ f.as_subsonic_album(request.user) for f in query.limit(size, offset) ] }, )
def old_search(): artist, album, title, anyf, count, offset, newer_than = map( request.values.get, ['artist', 'album', 'title', 'any', 'count', 'offset', 'newerThan']) count = int(count) if count else 20 offset = int(offset) if offset else 0 newer_than = int(newer_than) / 1000 if newer_than else 0 min_date = datetime.fromtimestamp(newer_than) if artist: query = select(t.folder.parent for t in Track if artist in t.folder.parent.name and t.folder.parent.created > min_date) elif album: query = select( t.folder for t in Track if album in t.folder.name and t.folder.created > min_date) elif title: query = Track.select( lambda t: title in t.title and t.created > min_date) elif anyf: folders = Folder.select( lambda f: anyf in f.name and f.created > min_date) tracks = Track.select( lambda t: anyf in t.title and t.created > min_date) res = folders[offset:offset + count] fcount = folders.count() if offset + count > fcount: toff = max(0, offset - fcount) tend = offset + count - fcount res = res[:] + tracks[toff:tend][:] return request.formatter( 'searchResult', dict( totalHits=folders.count() + tracks.count(), offset=offset, match=[ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.client) for r in res ])) else: raise MissingParameter('search') return request.formatter( 'searchResult', dict(totalHits=query.count(), offset=offset, match=[ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.client) for r in query[offset:offset + count] ]))
def lyrics(): artist = request.values['artist'] title = request.values['title'] query = Track.select(lambda t: title in t.title and artist in t.artist.name) for track in query: lyrics_path = os.path.splitext(track.path)[0] + '.txt' if os.path.exists(lyrics_path): logger.debug('Found lyrics file: ' + lyrics_path) try: lyrics = read_file_as_unicode(lyrics_path) except UnicodeError: # Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or # return no lyrics. Log it anyway. logger.warning('Unsupported encoding for lyrics file ' + lyrics_path) continue return request.formatter('lyrics', dict( artist = track.album.artist.name, title = track.title, value = lyrics )) # Create a stable, unique, filesystem-compatible identifier for the artist+title unique = hashlib.md5(json.dumps([x.lower() for x in (artist, title)]).encode('utf-8')).hexdigest() cache_key = "lyrics-{}".format(unique) lyrics = dict() try: lyrics = json.loads( zlib.decompress( current_app.cache.get_value(cache_key) ).decode('utf-8') ) except (CacheMiss, zlib.error, TypeError, ValueError): try: r = requests.get("http://api.chartlyrics.com/apiv1.asmx/SearchLyricDirect", params={'artist': artist, 'song': title}, timeout=5) root = ElementTree.fromstring(r.content) ns = {'cl': 'http://api.chartlyrics.com/'} lyrics = dict( artist = root.find('cl:LyricArtist', namespaces=ns).text, title = root.find('cl:LyricSong', namespaces=ns).text, value = root.find('cl:Lyric', namespaces=ns).text ) current_app.cache.set( cache_key, zlib.compress(json.dumps(lyrics).encode('utf-8'), 9) ) except requests.exceptions.RequestException as e: # pragma: nocover logger.warning('Error while requesting the ChartLyrics API: ' + str(e)) return request.formatter('lyrics', lyrics)
def album_list(): ltype, size, offset = map(request.args.get, ['type', 'size', 'offset']) try: size = int(size) if size else 10 offset = int(offset) if offset else 0 except: return request.error_formatter(0, 'Invalid parameter format') query = store.find(Folder, Track.folder_id == Folder.id) if ltype == 'random': albums = [] count = query.count() if not count: return request.formatter({'albumList': {}}) for _ in xrange(size): x = random.choice(xrange(count)) albums.append(query[x]) return request.formatter({ 'albumList': { 'album': [a.as_subsonic_child(request.user) for a in albums] } }) elif ltype == 'newest': query = query.order_by(Desc(Folder.created)).config(distinct=True) elif ltype == 'highest': query = query.find(RatingFolder.rated_id == Folder.id).group_by( Folder.id).order_by(Desc(Avg(RatingFolder.rating))) elif ltype == 'frequent': query = query.group_by(Folder.id).order_by(Desc(Avg(Track.play_count))) elif ltype == 'recent': query = query.group_by(Folder.id).order_by(Desc(Max(Track.last_play))) elif ltype == 'starred': query = query.find(StarredFolder.starred_id == Folder.id, User.id == StarredFolder.user_id, User.name == request.username) elif ltype == 'alphabeticalByName': query = query.order_by(Folder.name).config(distinct=True) elif ltype == 'alphabeticalByArtist': parent = ClassAlias(Folder) query = query.find(Folder.parent_id == parent.id).order_by( parent.name, Folder.name).config(distinct=True) else: return request.error_formatter(0, 'Unknown search type') return request.formatter({ 'albumList': { 'album': [ f.as_subsonic_child(request.user) for f in query[offset:offset + size] ] } })
def album_list_id3(): ltype, size, offset = map(request.args.get, ['type', 'size', 'offset']) try: size = int(size) if size else 10 offset = int(offset) if offset else 0 except: return request.error_formatter(0, 'Invalid parameter format') query = store.find(Album) if ltype == 'random': albums = [] count = query.count() if not count: return request.formatter({'albumList2': {}}) for _ in xrange(size): x = random.choice(xrange(count)) albums.append(query[x]) return request.formatter({ 'albumList2': { 'album': [a.as_subsonic_album(request.user) for a in albums] } }) elif ltype == 'newest': query = query.find(Track.album_id == Album.id).group_by( Album.id).order_by(Desc(Min(Track.created))) elif ltype == 'frequent': query = query.find(Track.album_id == Album.id).group_by( Album.id).order_by(Desc(Avg(Track.play_count))) elif ltype == 'recent': query = query.find(Track.album_id == Album.id).group_by( Album.id).order_by(Desc(Max(Track.last_play))) elif ltype == 'starred': query = query.find(StarredAlbum.starred_id == Album.id, User.id == StarredAlbum.user_id, User.name == request.username) elif ltype == 'alphabeticalByName': query = query.order_by(Album.name) elif ltype == 'alphabeticalByArtist': query = query.find(Artist.id == Album.artist_id).order_by( Artist.name, Album.name) else: return request.error_formatter(0, 'Unknown search type') return request.formatter({ 'albumList2': { 'album': [ f.as_subsonic_album(request.user) for f in query[offset:offset + size] ] } })
def lyrics(): artist, title = map(request.args.get, ['artist', 'title']) if not artist: return request.error_formatter(10, 'Missing artist parameter') if not title: return request.error_formatter(10, 'Missing title parameter') query = session.query(Track).join(Album, Artist).filter( func.lower(Track.title) == title.lower() and func.lower(Artist.name) == artist.lower()) for track in query: lyrics_path = os.path.splitext(track.path)[0] + '.txt' if os.path.exists(lyrics_path): app.logger.debug('Found lyrics file: ' + lyrics_path) try: lyrics = read_file_as_unicode(lyrics_path) except UnicodeError: # Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or # return no lyrics. Log it anyway. app.logger.warn('Unsupported encoding for lyrics file ' + lyrics_path) continue return request.formatter({ 'lyrics': { 'artist': track.album.artist.name, 'title': track.title, '_value_': lyrics } }) try: r = requests.get( "http://api.chartlyrics.com/apiv1.asmx/SearchLyricDirect", params={ 'artist': artist, 'song': title }) root = ElementTree.fromstring(r.content) ns = {'cl': 'http://api.chartlyrics.com/'} return request.formatter({ 'lyrics': { 'artist': root.find('cl:LyricArtist', namespaces=ns).text, 'title': root.find('cl:LyricSong', namespaces=ns).text, '_value_': root.find('cl:Lyric', namespaces=ns).text } }) except requests.exceptions.RequestException, e: app.logger.warn('Error while requesting the ChartLyrics API: ' + str(e))
def album_list_id3(): ltype, size, offset = map(request.args.get, ['type', 'size', 'offset']) try: size = int(size) if size else 10 offset = int(offset) if offset else 0 except: return request.error_formatter(0, 'Invalid parameter format') query = session.query(Album) if ltype == 'random': albums = [] count = query.count() if not count: return request.formatter({'albumList2': {}}) for _ in xrange(size): x = random.choice(xrange(count)) albums.append(query.offset(x).limit(1).one()) return request.formatter({ 'albumList2': { 'album': [a.as_subsonic_album(request.user) for a in albums] } }) elif ltype == 'newest': query = query.join(Track, Album.tracks).group_by(Album.id).order_by( desc(func.min(Track.created))) elif ltype == 'frequent': query = query.join(Track, Album.tracks).group_by(Album.id).order_by( desc(func.avg(Track.play_count))) elif ltype == 'recent': query = query.join(Track, Album.tracks).group_by(Album.id).order_by( desc(func.max(Track.last_play))) elif ltype == 'starred': query = query.join(StarredAlbum).join(User).filter( User.name == request.username) elif ltype == 'alphabeticalByName': query = query.order_by(Album.name) elif ltype == 'alphabeticalByArtist': query = query.join(Artist).order_by(Artist.name).order_by(Album.name) else: return request.error_formatter(0, 'Unknown search type') return request.formatter({ 'albumList2': { 'album': [ f.as_subsonic_album(request.user) for f in query.limit(size).offset(offset) ] } })
def list_indexes(): musicFolderId = request.values.get('musicFolderId') ifModifiedSince = request.values.get('ifModifiedSince') if ifModifiedSince: ifModifiedSince = int(ifModifiedSince) / 1000 if musicFolderId is None: folders = Folder.select(lambda f: f.root)[:] else: mfid = uuid.UUID(musicFolderId) folder = Folder[mfid] if not folder.root: raise ObjectNotFound(Folder, mfid) folders = [ folder ] last_modif = max(map(lambda f: f.last_scan, folders)) if ifModifiedSince is not None and last_modif < ifModifiedSince: return request.formatter('indexes', dict(lastModified = last_modif * 1000)) # The XSD lies, we don't return artists but a directory structure artists = [] children = [] for f in folders: artists += f.children.select()[:] children += f.tracks.select()[:] indexes = dict() for artist in artists: index = artist.name[0].upper() if index in string.digits: index = '#' elif index not in string.ascii_letters: index = '?' if index not in indexes: indexes[index] = [] indexes[index].append(artist) return request.formatter('indexes', dict( lastModified = last_modif * 1000, index = [ dict( name = k, artist = [ dict( id = str(a.id), name = a.name ) for a in sorted(v, key = lambda a: a.name.lower()) ] ) for k, v in sorted(indexes.items()) ], child = [ c.as_subsonic_child(request.user, request.client) for c in sorted(children, key = lambda t: t.sort_key()) ] ))
def album_list(): ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ]) if not ltype: return request.error_formatter(10, 'Missing type') try: size = int(size) if size else 10 offset = int(offset) if offset else 0 except: return request.error_formatter(0, 'Invalid parameter format') query = store.find(Folder, Track.folder_id == Folder.id) if ltype == 'random': albums = [] count = query.count() if not count: return request.formatter({ 'albumList': {} }) for _ in xrange(size): x = random.choice(xrange(count)) albums.append(query[x]) return request.formatter({ 'albumList': { 'album': [ a.as_subsonic_child(request.user) for a in albums ] } }) elif ltype == 'newest': query = query.order_by(Desc(Folder.created)).config(distinct = True) elif ltype == 'highest': query = query.find(RatingFolder.rated_id == Folder.id).group_by(Folder.id).order_by(Desc(Avg(RatingFolder.rating))) elif ltype == 'frequent': query = query.group_by(Folder.id).order_by(Desc(Avg(Track.play_count))) elif ltype == 'recent': query = query.group_by(Folder.id).order_by(Desc(Max(Track.last_play))) elif ltype == 'starred': query = query.find(StarredFolder.starred_id == Folder.id, User.id == StarredFolder.user_id, User.name == request.username) elif ltype == 'alphabeticalByName': query = query.order_by(Folder.name).config(distinct = True) elif ltype == 'alphabeticalByArtist': parent = ClassAlias(Folder) query = query.find(Folder.parent_id == parent.id).order_by(parent.name, Folder.name).config(distinct = True) else: return request.error_formatter(0, 'Unknown search type') return request.formatter({ 'albumList': { 'album': [ f.as_subsonic_child(request.user) for f in query[offset:offset+size] ] } })
def album_list(): ltype, size, offset = map(request.args.get, [ 'type', 'size', 'offset' ]) try: size = int(size) if size else 10 offset = int(offset) if offset else 0 except: return request.error_formatter(0, 'Invalid parameter format') query = session.query(Folder).filter(Folder.tracks.any()) if ltype == 'random': albums = [] count = query.count() if not count: return request.formatter({ 'albumList': {} }) for _ in xrange(size): x = random.choice(xrange(count)) albums.append(query.offset(x).limit(1).one()) return request.formatter({ 'albumList': { 'album': [ a.as_subsonic_child(request.user) for a in albums ] } }) elif ltype == 'newest': query = query.order_by(desc(Folder.created)) elif ltype == 'highest': query = query.join(RatingFolder).group_by(Folder.id).order_by(desc(func.avg(RatingFolder.rating))) elif ltype == 'frequent': query = query.join(Track, Folder.tracks).group_by(Folder.id).order_by(desc(func.avg(Track.play_count))) elif ltype == 'recent': query = query.join(Track, Folder.tracks).group_by(Folder.id).order_by(desc(func.max(Track.last_play))) elif ltype == 'starred': query = query.join(StarredFolder).join(User).filter(User.name == request.username) elif ltype == 'alphabeticalByName': query = query.order_by(Folder.name) elif ltype == 'alphabeticalByArtist': # this is a mess because who knows how your file structure is set up # with the database changes it's more difficult to get the parent of a dir parent = aliased(Folder) query = query.join(parent, Folder.parent).order_by(parent.name).order_by(Folder.name) else: return request.error_formatter(0, 'Unknown search type') return request.formatter({ 'albumList': { 'album': [ f.as_subsonic_child(request.user) for f in query.limit(size).offset(offset) ] } })
def scrobble_view(): """Add song to last.fm id Yes A string which uniquely identifies the file to scrobble. time No (Since 1.8.0) The time (in milliseconds since 1 Jan 1970) at which the song was listened to. submission No True Whether this is a "submission" or a "now playing" notification. """ from mediamanager.scrobble import q (u, p, v, c, f, callback) = map( request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback']) (eid, ts, submission) = map( request.args.get, ['id', 'time', 'submission']) assert eid, "Missing song id" log.info("Retrieving scrobbling credentials") lastfm_user = app.iposonic.get_users(MediaManager.uuid(u)) log.info("Scobbling credentials: %s" % lastfm_user) # get song info and append timestamp info = app.iposonic.get_entry_by_id(eid) info.update({'timestamp': int(time.time())}) q.put(({ 'username': lastfm_user.get('scrobbleUser'), 'password': lastfm_user.get('scrobblePassword')}, info)) return request.formatter({})
def search_id3(): query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) try: artist_count = int(artist_count) if artist_count else 20 artist_offset = int(artist_offset) if artist_offset else 0 album_count = int(album_count) if album_count else 20 album_offset = int(album_offset) if album_offset else 0 song_count = int(song_count) if song_count else 20 song_offset = int(song_offset) if song_offset else 0 except: return request.error_formatter(0, 'Invalid parameter') if not query: return request.error_formatter(10, 'Missing query parameter') artist_query = session.query(Artist).filter(Artist.name.contains(query)).slice(artist_offset, artist_offset + artist_count) album_query = session.query(Album).filter(Album.name.contains(query)).slice(album_offset, album_offset + album_count) song_query = session.query(Track).filter(Track.title.contains(query)).slice(song_offset, song_offset + song_count) return request.formatter({ 'searchResult2': { '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 ] }})
def random_songs(typed): ok, size = check_parameter(request, 'size', fct=lambda val: int(val) if val else 10) if not ok: return False, size size = min(size, 50) fromYear = request.args.get('fromYear') toYear = request.args.get('toYear') genre = request.args.get('genre') fltr = list(get_filter(fromYear=fromYear, toYear=toYear, genre=genre)) count = typed.counttracks(lambda query: query.filter(*fltr)) def gen(): if count > 0: for _ in range(size): x = random.choice(range(count)) yield typed.gettrackinfo(ffilter=lambda query: query.filter( *fltr).offset(x).limit(1)) return request.formatter({ 'randomSongs': { 'song': [format_track(track, child=True) for track in gen()] } })
def set_formatter(): if not request.path.startswith('/rest/'): return """Return a function to create the response.""" (f, callback) = map(request.values.get, ['f', 'callback']) if f == 'jsonp': # Some clients (MiniSub, Perisonic) set f to jsonp without callback for streamed data if not callback and request.endpoint not in [ 'stream_media', 'cover_art' ]: return ResponseHelper.responsize_json( {'error': { 'code': 10, 'message': 'Missing callback' }}, error=True), 400 request.formatter = lambda x, **kwargs: ResponseHelper.responsize_jsonp( x, callback, kwargs) elif f == "json": request.formatter = ResponseHelper.responsize_json else: request.formatter = ResponseHelper.responsize_xml request.error_formatter = lambda code, msg: request.formatter( {'error': { 'code': code, 'message': msg }}, error=True)
def search_id3(): query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) try: artist_count = int(artist_count) if artist_count else 20 artist_offset = int(artist_offset) if artist_offset else 0 album_count = int(album_count) if album_count else 20 album_offset = int(album_offset) if album_offset else 0 song_count = int(song_count) if song_count else 20 song_offset = int(song_offset) if song_offset else 0 except: return request.error_formatter(0, 'Invalid parameter') if not query: return request.error_formatter(10, 'Missing query parameter') artist_query = Artist.query.filter(Artist.name.contains(query)).slice(artist_offset, artist_offset + artist_count) album_query = Album.query.filter(Album.name.contains(query)).slice(album_offset, album_offset + album_count) song_query = Track.query.filter(Track.title.contains(query)).slice(song_offset, song_offset + song_count) return request.formatter({ 'searchResult2': { '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 ] }})
def get_now_playing_view(): """TODO: save timestamp and song duration of every stream.view request xml response: <nowPlaying> <entry username="******" minutesAgo="12" playerId="2" ... # all media properties /> <entry username="******" minutesAgo="1" playerId="4" playerName="Kitchen" ... # all media properties /> </nowPlaying> """ (u, p, v, c, f, callback) = map( request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback']) user = app.iposonic.get_users(eid=MediaManager.uuid(u)) assert user.get('nowPlaying'), "Nothing playing now..." song = app.iposonic.get_songs(eid=user.get('nowPlaying')) song.update({'username': u}) return request.formatter({'nowPlaying': {'entry': song}})
def new_search(): query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) try: artist_count = int(artist_count) if artist_count else 20 artist_offset = int(artist_offset) if artist_offset else 0 album_count = int(album_count) if album_count else 20 album_offset = int(album_offset) if album_offset else 0 song_count = int(song_count) if song_count else 20 song_offset = int(song_offset) if song_offset else 0 except: return request.error_formatter(0, 'Invalid parameter') if not query: return request.error_formatter(10, 'Missing query parameter') parent = ClassAlias(Folder) artist_query = store.find(parent, Folder.parent_id == parent.id, Track.folder_id == Folder.id, parent.name.contains_string(query)).config(distinct = True, offset = artist_offset, limit = artist_count) album_query = store.find(Folder, Track.folder_id == Folder.id, Folder.name.contains_string(query)).config(distinct = True, offset = album_offset, limit = album_count) song_query = store.find(Track, Track.title.contains_string(query))[song_offset : song_offset + song_count] 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 ] }})
def unstar(): id, albumId, artistId = map(request.values.getlist, [ 'id', 'albumId', 'artistId' ]) def try_unstar(ent, eid): try: uid = uuid.UUID(eid) except: return request.error_formatter(0, 'Invalid id') store.find(ent, ent.user_id == request.user.id, ent.starred_id == uid).remove() return None for eid in id: err = try_unstar(StarredTrack, eid) if err: return err err = try_unstar(StarredFolder, eid) if err: return err for alId in albumId: err = try_unstar(StarredAlbum, alId) if err: return err for arId in artistId: err = try_unstar(StarredArtist, arId) if err: return err store.commit() return request.formatter({})
def list_artists(): # According to the API page, there are no parameters? indexes = {} for artist in store.find(Artist): index = artist.name[0].upper() if artist.name else '?' if index in map(str, xrange(10)): index = '#' elif index not in string.letters: index = '?' if index not in indexes: indexes[index] = [] indexes[index].append(artist) return request.formatter({ 'artists': { 'index': [{ 'name': k, 'artist': [ a.as_subsonic_artist(request.user) for a in sorted(v, key=lambda a: a.name.lower()) ] } for k, v in sorted(indexes.iteritems())] } })
def get_playlists_view(): """ response xml: <playlists> <playlist id="15" name="Some random songs" comment="Just something I tossed together" owner="admin" public="false" songCount="6" duration="1391" created="2012-04-17T19:53:44"> <allowedUser>sindre</allowedUser> <allowedUser>john</allowedUser> </playlist> <playlist id="16" name="More random songs" comment="No comment" owner="admin" public="true" songCount="5" duration="1018" created="2012-04-17T19:55:49"/> </playlists> response jsonp: {playlists: { playlist : [ { id : , name: , comment: , owner: , public: , songCount:, duration: , created:, }, { id, name, comment, owner, public, allowedUser: [ 'jon', 'mary' ] } ] }} """ (u, p, v, c, f, callback) = map( request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback']) playlists = app.iposonic.get_playlists_static() playlists.extend(app.iposonic.get_playlists()) return request.formatter({'status': 'ok', 'playlists': {'playlist': playlists}})
def rate(): id, rating = map(request.args.get, [ 'id', 'rating' ]) if not id or not rating: return request.error_formatter(10, 'Missing parameter') try: uid = uuid.UUID(id) rating = int(rating) except: return request.error_formatter(0, 'Invalid parameter') if not rating in xrange(6): return request.error_formatter(0, 'rating must be between 0 and 5 (inclusive)') if rating == 0: RatingTrack.query.filter(RatingTrack.user_id == request.user.id).filter(RatingTrack.rated_id == uid).delete() RatingFolder.query.filter(RatingFolder.user_id == request.user.id).filter(RatingFolder.rated_id == uid).delete() else: rated = Track.query.get(uid) rating_ent = RatingTrack if not rated: rated = Folder.query.get(uid) rating_ent = RatingFolder if not rated: return request.error_formatter(70, 'Unknown id') rating_info = rating_ent.query.get((request.user.id, uid)) if rating_info: rating_info.rating = rating else: session.add(rating_ent(user = request.user, rated = rated, rating = rating)) session.commit() return request.formatter({})
def get_starred(): folders = store.find(StarredFolder, StarredFolder.user_id == User.id, User.name == request.username) return request.formatter({ '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) ] } })
def list_artists(): # According to the API page, there are no parameters? indexes = {} # Optimized query instead of using backrefs, is there a way to speed up the backref? c = session.query(Album.artist_id, func.count(Album.artist_id).label('c')).group_by(Album.artist_id).subquery(name='c') for artist in session.query(Artist.name, Artist.id, c.c.c.label('albums')).join(c).order_by(Artist.name).all(): index = artist.name[0].upper() if artist.name else '?' if index in map(str, xrange(10)): index = '#' elif index not in string.letters: index = '?' if index not in indexes: indexes[index] = [] indexes[index].append(artist) return request.formatter({ 'artists': { 'index': [ { 'name': k, 'artist': [ { 'id': a.id, 'name': a.name.strip(), 'albumCount': a.albums } for a in v ] } for k, v in sorted(indexes.iteritems()) ] } })
def list_folders(): return request.formatter('musicFolders', dict( musicFolder = [ dict( id = str(f.id), name = f.name ) for f in Folder.select(lambda f: f.root).order_by(Folder.name) ] ))
def create_user_view(): """Create an user getting info from GET variables. TODO get with post too """ (u, p, v, c, f, callback) = map( request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback']) (un, pw, email, scrobbleUser, scrobblePassword) = map(request.args.get, [ 'x', 'password', 'email', 'scrobbleUser', 'scrobblePassword' ]) new_user = { 'username': un, 'password': pw, 'email': email, 'scrobbleUser': scrobbleUser, 'scrobblePassword': scrobblePassword } print("user: %s " % new_user) app.iposonic.add_user(new_user) return request.formatter({})
def star_view(): (u, p, v, c, f, callback) = map( request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback']) (eid, rating) = map(request.args.get, ['id', 'rating']) if not eid: raise SubsonicMissingParameterException( 'id', sys._getframe().f_code.co_name) app.iposonic.update_entry( eid, {'starred': time.strftime("%Y-%m-%dT%H:%M:%S")}) # XXX example code to be added to Iposonic # for managing user-based media tagging # like starred. # Going this way may need to really choiche ONE db # because we'll multiply data (eg. #items x #users) #usermedia = app.iposonic.db.UserMedia('mock_user', eid) #usermedia.update( { # 'starred': time.strftime("%Y-%m-%dT%H:%M:%S"), # 'eid': "%s:%s" % ('mock',eid), # 'mid' : eid, # 'uid' : 'mock' # } ) app.iposonic.create_entry(usermedia) return request.formatter({})
def new_search(): query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) try: artist_count = int(artist_count) if artist_count else 20 artist_offset = int(artist_offset) if artist_offset else 0 album_count = int(album_count) if album_count else 20 album_offset = int(album_offset) if album_offset else 0 song_count = int(song_count) if song_count else 20 song_offset = int(song_offset) if song_offset else 0 except: return request.error_formatter(0, 'Invalid parameter') if not query: return request.error_formatter(10, 'Missing query parameter') artist_query = Folder.query.filter(~ Folder.tracks.any(), Folder.name.contains(query)).slice(artist_offset, artist_offset + artist_count) album_query = Folder.query.filter(Folder.tracks.any(), Folder.name.contains(query)).slice(album_offset, album_offset + album_count) song_query = Track.query.filter(Track.title.contains(query)).slice(song_offset, song_offset + song_count) 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 ] }})
def get_now_playing_view(): """TODO: save timestamp and song duration of every stream.view request xml response: <nowPlaying> <entry username="******" minutesAgo="12" playerId="2" ... # all media properties /> <entry username="******" minutesAgo="1" playerId="4" playerName="Kitchen" ... # all media properties /> </nowPlaying> """ (u, p, v, c, f, callback) = map(request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback']) user = app.iposonic.get_users(eid=MediaManager.uuid(u)) assert user.get('nowPlaying'), "Nothing playing now..." song = app.iposonic.get_songs(eid=user.get('nowPlaying')) song.update({'username': u}) return request.formatter({'nowPlaying': {'entry': song}})
def new_search(): query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) try: artist_count = int(artist_count) if artist_count else 20 artist_offset = int(artist_offset) if artist_offset else 0 album_count = int(album_count) if album_count else 20 album_offset = int(album_offset) if album_offset else 0 song_count = int(song_count) if song_count else 20 song_offset = int(song_offset) if song_offset else 0 except: return request.error_formatter(0, 'Invalid parameter') if not query: return request.error_formatter(10, 'Missing query parameter') artist_query = session.query(Folder).filter(~ Folder.tracks.any(), Folder.path.contains(query)).slice(artist_offset, artist_offset + artist_count) album_query = session.query(Folder).filter(Folder.tracks.any(), Folder.path.contains(query)).slice(album_offset, album_offset + album_count) song_query = sesion.query(Track).filter(Track.title.contains(query)).slice(song_offset, song_offset + song_count) return request.formatter({ 'searchResult2': { 'artist': [ { 'id': 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 ] }})
def update_playlist(): status, res = get_entity(request, Playlist, 'playlistId') if not status: return res if res.user_id != request.user.id and not request.user.admin: return request.error_formatter(50, "You're not allowed to delete a playlist that isn't yours") playlist = res name, comment, public = map(request.values.get, [ 'name', 'comment', 'public' ]) to_add, to_remove = map(request.values.getlist, [ 'songIdToAdd', 'songIndexToRemove' ]) try: to_add = map(uuid.UUID, to_add) to_remove = map(int, to_remove) except: return request.error_formatter(0, 'Invalid parameter') if name: playlist.name = name if comment: playlist.comment = comment if public: playlist.public = public in (True, 'True', 'true', 1, '1') for sid in to_add: track = store.get(Track, sid) if not track: return request.error_formatter(70, 'Unknown song') playlist.add(track) playlist.remove_at_indexes(to_remove) store.commit() return request.formatter({})
def music_directory(typed): eid = request.args.get('id') cid = clean_id(eid) if is_artist_id(eid): dirlist = typed.listalbumsbyartists( lambda query: query.filter(Artist.id == cid)) children = dirlist[0].albums format_directory_id = format_artist_id format_child = format_album elif is_album_id(eid): dirlist = typed.listtracksbyalbums( lambda query: query.filter(Album.id == cid)) children = dirlist[0].tracks format_directory_id = format_album_id format_child = format_track else: return request.error_formatter(10, 'Missing or invalid id') return request.formatter({ 'directory': { 'id': format_directory_id(dirlist[0].id), 'name': dirlist[0].name, 'child': [format_child(child, child=True) for child in children] } })
def rand_songs(): size = request.values.get("size", "10") genre, fromYear, toYear, musicFolderId = map( request.values.get, ["genre", "fromYear", "toYear", "musicFolderId"]) size = int(size) if size else 10 fromYear = int(fromYear) if fromYear else None toYear = int(toYear) if toYear else None fid = None if musicFolderId: try: fid = int(musicFolderId) except ValueError: raise ValueError("Invalid folder ID") query = Track.select() if fromYear: query = query.filter(lambda t: t.year >= fromYear) if toYear: query = query.filter(lambda t: t.year <= toYear) if genre: query = query.filter(lambda t: t.genre == genre) if fid: if not Folder.exists(id=fid, root=True): raise NotFound("Folder") query = query.filter(lambda t: t.root_folder.id == fid) return request.formatter( "randomSongs", dict(song=[ t.as_subsonic_child(request.user, request.client) for t in query.without_distinct().random(size) ]), )
def show_directory(): status, res = get_entity(request, Folder) if not status: return res res.tracks = [t for t in res.tracks if os.path.isfile(t.path)] directory = { 'id': res.id, 'name': res.name, 'child': [f.as_subsonic_child(request.user) for f in res.get_children()] + [ t.as_subsonic_child(request.user) for t in sorted(res.tracks, key=lambda t: t.sort_key()) ] } if not res.root: parent = session.query(Folder).with_entities(Folder.id) \ .filter(Folder.path.like(res.path[:len(res.path)-len(res.name)-1])) \ .order_by(func.length(Folder.path).desc()).first() if parent: directory['parent'] = parent.id return request.formatter({'directory': directory})
def list_artists(): # According to the API page, there are no parameters? indexes = dict() pattern = build_ignored_articles_pattern() for artist in Artist.select(): name = artist.name or "?" if pattern: name = re.sub(pattern, "", name, flags=re.I) index = name[0].upper() if index in string.digits: index = "#" elif index not in string.ascii_letters: index = "?" if index not in indexes: indexes[index] = [] indexes[index].append((artist, name)) return request.formatter( "artists", dict( ignoredArticles=ignored_articles_str(), index=[ dict( name=k, artist=[ a.as_subsonic_artist(request.user) for a, _ in sorted(v, key=lambda t: t[1].lower()) ], ) for k, v in sorted(indexes.items()) ], ), )
def search_id3(): query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( request.values.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) try: artist_count = int(artist_count) if artist_count else 20 artist_offset = int(artist_offset) if artist_offset else 0 album_count = int(album_count) if album_count else 20 album_offset = int(album_offset) if album_offset else 0 song_count = int(song_count) if song_count else 20 song_offset = int(song_offset) if song_offset else 0 except: return request.error_formatter(0, 'Invalid parameter') if not query: return request.error_formatter(10, 'Missing query parameter') artist_query = store.find(Artist, Artist.name.contains_string(query))[artist_offset : artist_offset + artist_count] album_query = store.find(Album, Album.name.contains_string(query))[album_offset : album_offset + album_count] song_query = store.find(Track, Track.title.contains_string(query))[song_offset : song_offset + song_count] 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, request.prefs) for t in song_query ] }})
def new_search(): query = request.values['query'] artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( request.values.get, [ 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) artist_count = int(artist_count) if artist_count else 20 artist_offset = int(artist_offset) if artist_offset else 0 album_count = int(album_count) if album_count else 20 album_offset = int(album_offset) if album_offset else 0 song_count = int(song_count) if song_count else 20 song_offset = int(song_offset) if song_offset else 0 artists = select(t.folder.parent for t in Track if query in t.folder.parent.name).limit( artist_count, artist_offset) albums = select(t.folder for t in Track if query in t.folder.name).limit(album_count, album_offset) songs = Track.select(lambda t: query in t.title).limit( song_count, song_offset) return request.formatter( 'searchResult2', OrderedDict( (('artist', [dict(id=str(a.id), name=a.name) for a in artists]), ('album', [f.as_subsonic_child(request.user) for f in albums]), ('song', [ t.as_subsonic_child(request.user, request.client) for t in songs ]))))
def rand_songs(): size = request.values.get('size', '10') genre, fromYear, toYear, musicFolderId = map( request.values.get, ['genre', 'fromYear', 'toYear', 'musicFolderId']) size = int(size) if size else 10 fromYear = int(fromYear) if fromYear else None toYear = int(toYear) if toYear else None fid = uuid.UUID(musicFolderId) if musicFolderId else None query = Track.select() if fromYear: query = query.filter(lambda t: t.year >= fromYear) if toYear: query = query.filter(lambda t: t.year <= toYear) if genre: query = query.filter(lambda t: t.genre == genre) if fid: if not Folder.exists(id=fid, root=True): raise NotFound('Folder') query = query.filter(lambda t: t.root_folder.id == fid) return request.formatter( 'randomSongs', dict(song=[ t.as_subsonic_child(request.user, request.client) for t in query.without_distinct().random(size) ]))
def search_id3(): query = request.values['query'] artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( request.values.get, [ 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) artist_count = int(artist_count) if artist_count else 20 artist_offset = int(artist_offset) if artist_offset else 0 album_count = int(album_count) if album_count else 20 album_offset = int(album_offset) if album_offset else 0 song_count = int(song_count) if song_count else 20 song_offset = int(song_offset) if song_offset else 0 artists = Artist.select(lambda a: query in a.name).limit( artist_count, artist_offset) albums = Album.select(lambda a: query in a.name).limit( album_count, album_offset) songs = Track.select(lambda t: query in t.title).limit( song_count, song_offset) return request.formatter( 'searchResult3', OrderedDict( (('artist', [a.as_subsonic_artist(request.user) for a in artists]), ('album', [a.as_subsonic_album(request.user) for a in albums]), ('song', [ t.as_subsonic_child(request.user, request.client) for t in songs ]))))
def rand_songs(): size = request.values.get('size', '10') genre, fromYear, toYear, musicFolderId = map(request.values.get, [ 'genre', 'fromYear', 'toYear', 'musicFolderId' ]) size = int(size) if size else 10 fromYear = int(fromYear) if fromYear else None toYear = int(toYear) if toYear else None fid = uuid.UUID(musicFolderId) if musicFolderId else None query = Track.select() if fromYear: query = query.filter(lambda t: t.year >= fromYear) if toYear: query = query.filter(lambda t: t.year <= toYear) if genre: query = query.filter(lambda t: t.genre == genre) if fid: if not Folder.exists(id = fid, root = True): raise NotFound('Folder') query = query.filter(lambda t: t.root_folder.id == fid) return request.formatter('randomSongs', dict( song = [ t.as_subsonic_child(request.user, request.client) for t in query.without_distinct().random(size) ] ))
def unstar(): id, albumId, artistId = map(request.args.getlist, ['id', 'albumId', 'artistId']) def try_unstar(ent, eid): try: uid = uuid.UUID(eid) except: return request.error_formatter(0, 'Invalid id') store.find(ent, ent.user_id == request.user.id, ent.starred_id == uid).remove() return None for eid in id: err = try_unstar(StarredTrack, eid) if err: return err err = try_unstar(StarredFolder, eid) if err: return err for alId in albumId: err = try_unstar(StarredAlbum, alId) if err: return err for arId in artistId: err = try_unstar(StarredArtist, arId) if err: return err store.commit() return request.formatter({})
def list_artists(): # According to the API page, there are no parameters? indexes = dict() for artist in Artist.select(): index = artist.name[0].upper() if artist.name else "?" if index in string.digits: index = "#" elif index not in string.ascii_letters: index = "?" if index not in indexes: indexes[index] = [] indexes[index].append(artist) return request.formatter( "artists", dict(index=[ dict( name=k, artist=[ a.as_subsonic_artist(request.user) for a in sorted(v, key=lambda a: a.name.lower()) ], ) for k, v in sorted(indexes.items()) ]), )
def album_list_id3(): ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ]) if not ltype: return request.error_formatter(10, 'Missing type') try: size = int(size) if size else 10 offset = int(offset) if offset else 0 except: return request.error_formatter(0, 'Invalid parameter format') query = store.find(Album) if ltype == 'random': albums = [] count = query.count() if not count: return request.formatter({ 'albumList2': {} }) for _ in xrange(size): x = random.choice(xrange(count)) albums.append(query[x]) return request.formatter({ 'albumList2': { 'album': [ a.as_subsonic_album(request.user) for a in albums ] } }) elif ltype == 'newest': query = query.find(Track.album_id == Album.id).group_by(Album.id).order_by(Desc(Min(Track.created))) elif ltype == 'frequent': query = query.find(Track.album_id == Album.id).group_by(Album.id).order_by(Desc(Avg(Track.play_count))) elif ltype == 'recent': query = query.find(Track.album_id == Album.id).group_by(Album.id).order_by(Desc(Max(Track.last_play))) elif ltype == 'starred': query = query.find(StarredAlbum.starred_id == Album.id, User.id == StarredAlbum.user_id, User.name == request.username) elif ltype == 'alphabeticalByName': query = query.order_by(Album.name) elif ltype == 'alphabeticalByArtist': query = query.find(Artist.id == Album.artist_id).order_by(Artist.name, Album.name) else: return request.error_formatter(0, 'Unknown search type') return request.formatter({ 'albumList2': { 'album': [ f.as_subsonic_album(request.user) for f in query[offset:offset+size] ] } })
def get_album_list_view(): """Get albums params: - type in random, newest, TODO highest, TODO frequent, TODO recent, TODO starred, TODO alphabeticalByName, TODO alphabeticalByArtist TODO - size items to return TODO - offset paging offset TODO xml response: <albumList> <album id="11" parent="1" title="Arrival" artist="ABBA" isDir="true" coverArt="22" userRating="4" averageRating="4.5"/> <album id="12" parent="1" title="Super Trouper" artist="ABBA" isDir="true" coverArt="23" averageRating="4.4"/> </albumList> """ (u, p, v, c, f, callback, dir_id) = map( request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback', 'id']) (size, type_a, offset) = map(request.args.get, ['size', 'type', 'offset']) if not type_a in ['random', 'newest', 'highest', 'frequent', 'recent', 'starred']: raise SubsonicProtocolException("Invalid or missing parameter: type") try: size = int(size) except: size = 20 try: offset = int(offset) except: offset = 0 if type_a == 'random': log.info("getting ", type_a) albums = app.iposonic.get_albums() albums = randomize2_list(albums, size) elif type_a == 'highest': log.info("getting ", type_a) albums = app.iposonic.get_albums( query={'userRating': 'notNull'}, order=('userRating', 1)) elif type_a == 'newest': log.info("getting ", type_a) albums = app.iposonic.get_albums( query={'created': 'notNull'}, order=('created', 1)) elif type_a == 'starred': log.info("getting ", type_a) albums = app.iposonic.get_albums(query={'starred': 'notNull'}) else: # get all albums...hey, they may be a lot! albums = [a for a in app.iposonic.get_albums()] last = min(offset + size, len(albums) - 1) log.info("paging albums: %s,%s/%s" % (offset, last, len(albums))) return request.formatter({'albumList': {'album': albums[offset:last]}})
def artist_info(): res = get_entity(Artist) info = res.as_subsonic_artist(request.user) albums = set(res.albums) albums |= { t.album for t in res.tracks } info['album'] = [ a.as_subsonic_album(request.user) for a in sorted(albums, key = lambda a: a.sort_key()) ] return request.formatter('artist', info)
def get_starred_id3(): return request.formatter({ 'starred2': { 'artist': [ sa.starred.as_subsonic_artist(request.user) for sa in StarredArtist.query.join(User).filter(User.name == request.username) ], 'album': [ sa.starred.as_subsonic_album(request.user) for sa in StarredAlbum.query.join(User).filter(User.name == request.username) ], 'song': [ st.starred.as_subsonic_child(request.user) for st in StarredTrack.query.join(User).filter(User.name == request.username) ] } })
def get_starred(): return request.formatter({ 'starred': { 'artist': [ { 'id': str(sf.starred_id), 'name': sf.starred.name } for sf in StarredFolder.query.join(User).join(Folder).filter(User.name == request.username).filter(~ Folder.tracks.any()) ], 'album': [ sf.starred.as_subsonic_child(request.user) for sf in StarredFolder.query.join(User).join(Folder).filter(User.name == request.username).filter(Folder.tracks.any()) ], 'song': [ st.starred.as_subsonic_child(request.user) for st in StarredTrack.query.join(User).filter(User.name == request.username) ] } })
def show_playlist(): status, res = get_entity(request, Playlist) if not status: return res info = res.as_subsonic_playlist(request.user) info['entry'] = [ t.as_subsonic_child(request.user) for t in res.tracks ] return request.formatter({ 'playlist': info })
def get_starred(): folders = select(s.starred for s in StarredFolder if s.user.id == request.user.id) return request.formatter('starred', dict( artist = [ dict(id = str(sf.id), name = sf.name) for sf in folders.filter(lambda f: count(f.tracks) == 0) ], album = [ sf.as_subsonic_child(request.user) for sf in folders.filter(lambda f: count(f.tracks) > 0) ], song = [ st.as_subsonic_child(request.user, request.client) for st in select(s.starred for s in StarredTrack if s.user.id == request.user.id) ] ))
def get_starred_id3(): return request.formatter({ '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) ] } })
def add_chat_message(): msg = request.args.get("message") if not msg: return request.error_formatter(10, "Missing message") session.add(ChatMessage(user=request.user, message=msg)) session.commit() return request.formatter({})