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 index(): stats = { 'artists': store.find(Artist).count(), 'albums': store.find(Album).count(), 'tracks': store.find(Track).count() } return render_template('home.html', stats = stats, admin = UserManager.get(store, session.get('userid'))[1].admin)
def do_user_import(): if not request.files['file']: return render_template('importusers.html', admin = UserManager.get(store, session.get('userid'))[1].admin) users = [] reader = csv.reader(request.files['file']) for id, name, mail, password, salt, admin, lfmsess, lfmstatus in reader: mail = None if mail == 'None' else mail admin = admin == 'True' lfmsess = None if lfmsess == 'None' else lfmsess lfmstatus = lfmstatus == 'True' user = User() user.id = uuid.UUID(id) user.name = name user.password = password user.salt = salt user.admin = admin user.lastfm_session = lfmsess user.lastfm_status = lfmstatus users.append(user) store.find(User).remove() for u in users: store.add(u) store.commit() return redirect(url_for('user_index'))
def do_user_import(): if not request.files['file']: return render_template('importusers.html') users = [] reader = csv.reader(request.files['file']) for id, name, mail, password, salt, admin, lfmsess, lfmstatus in reader: mail = None if mail == 'None' else mail admin = admin == 'True' lfmsess = None if lfmsess == 'None' else lfmsess lfmstatus = lfmstatus == 'True' user = User() user.id = uuid.UUID(id) user.name = name user.password = password user.salt = salt user.admin = admin user.lastfm_session = lfmsess user.lastfm_status = lfmstatus users.append(user) store.find(User).remove() for u in users: store.add(u) store.commit() return redirect(url_for('user_index'))
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 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 = 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({ '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_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 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
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, request.prefs) for st in store.find(StarredTrack, StarredTrack.user_id == User.id, User.name == request.username) ] } })
def user_profile(uid): if uid == 'me': prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(session.get('userid'))) return render_template('profile.html', user = UserManager.get(store, session.get('userid'))[1], api_key = config.get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin) else: if not UserManager.get(store, session.get('userid'))[1].admin or not UserManager.get(store, uid)[0] is UserManager.SUCCESS: return redirect(url_for('index')) prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(uid)) return render_template('profile.html', user = UserManager.get(store, uid)[1], api_key = config.get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin)
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 index(): stats = { 'artists': store.find(Artist).count(), 'albums': store.find(Album).count(), 'tracks': store.find(Track).count() } return render_template('home.html', stats=stats, admin=UserManager.get( store, session.get('userid'))[1].admin)
def list_playlists(): query = store.find(Playlist, Or(Playlist.user_id == request.user.id, Playlist.public == True)).order_by(Playlist.name) username = request.args.get('username') if username: if not request.user.admin: return request.error_formatter(50, 'Restricted to admins') query = store.find(Playlist, Playlist.user_id == User.id, User.name == username).order_by(Playlist.name) return request.formatter({ 'playlists': { 'playlist': [ p.as_subsonic_playlist(request.user) for p in query ] } })
def list_playlists(): query = store.find(Playlist, Or(Playlist.user_id == request.user.id, Playlist.public == True)).order_by( Playlist.name ) username = request.values.get("username") if username: if not request.user.admin: return request.error_formatter(50, "Restricted to admins") query = store.find(Playlist, Playlist.user_id == User.id, User.name == username).order_by(Playlist.name) return request.formatter({"playlists": {"playlist": [p.as_subsonic_playlist(request.user) for p in query]}})
def try_unstar(starred_ent, eid): """ Unstars an entity :param starred_ent: class used for the db representation of the starring of the entity :param eid: id of the entity to unstar :return error dict, if any. None otherwise """ try: uid = uuid.UUID(eid) except: return { 'code': 0, 'message': 'Invalid id {}'.format(eid) } store.find(starred_ent, starred_ent.user_id == request.user.id, starred_ent.starred_id == uid).remove() return None
def new_search(): 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') 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, request.prefs) for t in song_query ] } })
def change_username_post(uid): code, user = UserManager.get(store, uid) if code != UserManager.SUCCESS: return redirect(url_for('index')) username = request.form.get('user') if username in ('', None): flash('The username is required') return render_template('change_username.html', user = user) if user.name != username and store.find(User, User.name == username).one(): flash('This name is already taken') return render_template('change_username.html', user = user) if request.form.get('admin') is None: admin = False else: admin = True if user.name != username or user.admin != admin: user.name = username user.admin = admin store.commit() flash("User '%s' updated." % username) else: flash("No changes for '%s'." % username) return redirect(url_for('user_profile', uid = uid))
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 add_user(): if request.method == 'GET': return render_template('adduser.html', admin = UserManager.get(store, session.get('userid'))[1].admin) error = False (name, passwd, passwd_confirm, mail, admin) = map(request.form.get, [ 'user', 'passwd', 'passwd_confirm', 'mail', 'admin' ]) if name in (None, ''): flash('The name is required.') error = True if passwd in (None, ''): flash('Please provide a password.') error = True elif passwd != passwd_confirm: flash("The passwords don't match.") error = True if admin is None: admin = True if store.find(User, User.admin == True).count() == 0 else False else: admin = True if not error: status = UserManager.add(store, name, passwd, mail, admin) if status == UserManager.SUCCESS: flash("User '%s' successfully added" % name) return redirect(url_for('user_index')) else: flash(UserManager.error_str(status)) return render_template('adduser.html', admin = UserManager.get(store, session.get('userid'))[1].admin)
def add_user_post(): error = False (name, passwd, passwd_confirm, mail, admin) = map(request.form.get, [ 'user', 'passwd', 'passwd_confirm', 'mail', 'admin' ]) if not name: flash('The name is required.') error = True if not passwd: flash('Please provide a password.') error = True elif passwd != passwd_confirm: flash("The passwords don't match.") error = True if admin is None: admin = True if store.find(User, User.admin == True).count() == 0 else False else: admin = True if not error: status = UserManager.add(store, name, passwd, mail, admin) if status == UserManager.SUCCESS: flash("User '%s' successfully added" % name) return redirect(url_for('user_index')) else: flash(UserManager.error_str(status)) return add_user_form()
def try_unstar(starred_ent, eid): """ Unstars an entity :param starred_ent: class used for the db representation of the starring of the entity :param eid: id of the entity to unstar :return error dict, if any. None otherwise """ try: uid = uuid.UUID(eid) except: return {'code': 0, 'message': 'Invalid id {}'.format(eid)} store.find(starred_ent, starred_ent.user_id == request.user.id, starred_ent.starred_id == uid).remove() return None
def users_info(): if not request.user.admin: return request.error_formatter(50, 'Admin restricted') return request.formatter( {'users': { 'user': [u.as_subsonic_user() for u in store.find(User)] }})
def list_folders(): return request.formatter({ 'musicFolders': { 'musicFolder': [ { 'id': str(f.id), 'name': f.name } for f in store.find(Folder, Folder.root == True).order_by(Folder.name) ] } })
def list_playlists(): query = store.find( Playlist, Or(Playlist.user_id == request.user.id, Playlist.public == True)).order_by(Playlist.name) username = request.args.get('username') if username: if not request.user.admin: return request.error_formatter(50, 'Restricted to admins') query = store.find(Playlist, Playlist.user_id == User.id, User.name == username).order_by(Playlist.name) return request.formatter({ 'playlists': { 'playlist': [p.as_subsonic_playlist(request.user) for p in query] } })
def list_folders(): return request.formatter({ 'musicFolders': { 'musicFolder': [{ 'id': str(f.id), 'name': f.name } for f in store.find(Folder, Folder.root == True).order_by( Folder.name)] } })
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 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 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 now_playing(): query = store.find(User, Track.id == User.last_play_id) return request.formatter({ 'nowPlaying': { 'entry': [ dict( u.last_play.as_subsonic_child(request.user).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() ] } })
def now_playing(): query = store.find(User, Track.id == User.last_play_id) return request.formatter({ 'nowPlaying': { 'entry': [ dict( 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() ] } })
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: store.find(RatingTrack, RatingTrack.user_id == request.user.id, RatingTrack.rated_id == uid).remove() store.find(RatingFolder, RatingFolder.user_id == request.user.id, RatingFolder.rated_id == uid).remove() else: rated = store.get(Track, uid) rating_ent = RatingTrack if not rated: rated = store.get(Folder, uid) rating_ent = RatingFolder if not rated: return request.error_formatter(70, 'Unknown id') rating_info = store.get(rating_ent, (request.user.id, uid)) if rating_info: rating_info.rating = rating else: rating_info = rating_ent() rating_info.user_id = request.user.id rating_info.rated_id = uid rating_info.rating = rating store.add(rating_info) store.commit() return request.formatter({})
def get_chat(): since = request.args.get('since') try: since = int(since) / 1000 if since else None except: return request.error_formatter(0, 'Invalid parameter') query = store.find(ChatMessage).order_by(ChatMessage.time) if since: query = query.find(ChatMessage.time > since) return request.formatter({ 'chatMessages': { 'chatMessage': [ msg.responsize() for msg in query ] }})
def get_chat(): since = request.values.get('since') try: since = int(since) / 1000 if since else None except: return request.error_formatter(0, 'Invalid parameter') query = store.find(ChatMessage).order_by(ChatMessage.time) if since: query = query.find(ChatMessage.time > since) return request.formatter({ 'chatMessages': { 'chatMessage': [ msg.responsize() for msg in query ] }})
def old_search(): artist, album, title, anyf, count, offset, newer_than = map(request.values.get, [ 'artist', 'album', 'title', 'any', 'count', 'offset', 'newerThan' ]) try: 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 except: return request.error_formatter(0, 'Invalid parameter') min_date = datetime.fromtimestamp(newer_than) if artist: parent = ClassAlias(Folder) query = store.find(parent, Folder.parent_id == parent.id, Track.folder_id == Folder.id, parent.name.contains_string(artist), parent.created > min_date).config(distinct = True) elif album: query = store.find(Folder, Track.folder_id == Folder.id, Folder.name.contains_string(album), Folder.created > min_date).config(distinct = True) elif title: query = store.find(Track, Track.title.contains_string(title), Track.created > min_date) elif anyf: folders = store.find(Folder, Folder.name.contains_string(anyf), Folder.created > min_date) tracks = store.find(Track, Track.title.contains_string(anyf), Track.created > min_date) res = list(folders[offset : offset + count]) if offset + count > folders.count(): toff = max(0, offset - folders.count()) tend = offset + count - folders.count() res += list(tracks[toff : tend]) return request.formatter({ 'searchResult': { '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.prefs) for r in res ] }}) else: return request.error_formatter(10, 'Missing search parameter') return request.formatter({ 'searchResult': { 'totalHits': query.count(), 'offset': offset, 'match': [ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.prefs) for r in query[offset : offset + count] ] }})
def lyrics(): artist, title = map(request.values.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 = store.find(Track, Album.id == Track.album_id, Artist.id == Album.artist_id, Track.title.like(title), Artist.name.like(artist)) 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 user_info(): username = request.args.get('username') if username is None: return request.error_formatter(10, 'Missing username') if username != request.username and not request.user.admin: return request.error_formatter(50, 'Admin restricted') user = store.find(User, User.name == username).one() if user is None: return request.error_formatter(0, 'Unknown user') return request.formatter({ 'user': user.as_subsonic_user() })
def rand_songs(): size = request.values.get('size', '10') genre, fromYear, toYear, musicFolderId = map(request.values.get, [ 'genre', 'fromYear', 'toYear', 'musicFolderId' ]) try: 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 except: return request.error_formatter(0, 'Invalid parameter format') query = store.find(Track) if fromYear: query = query.find(Track.year >= fromYear) if toYear: query = query.find(Track.year <= toYear) if genre: query = query.find(Track.genre == genre) if fid: if not store.find(Folder, Folder.id == fid, Folder.root == True).one(): return request.error_formatter(70, 'Unknown folder') query = query.find(Track.root_folder_id == fid) count = query.count() if not count: return request.formatter({ 'randomSongs': {} }) tracks = [] for _ in xrange(size): x = random.choice(xrange(count)) tracks.append(query[x]) return request.formatter({ 'randomSongs': { 'song': [ t.as_subsonic_child(request.user, request.prefs) for t in tracks ] } })
def user_info(): username = request.args.get('username') if username is None: return request.error_formatter(10, 'Missing username') if username != request.username and not request.user.admin: return request.error_formatter(50, 'Admin restricted') user = store.find(User, User.name == username).one() if user is None: return request.error_formatter(0, 'Unknown user') return request.formatter({'user': user.as_subsonic_user()})
def rate(): id, rating = map(request.values.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: store.find(RatingTrack, RatingTrack.user_id == request.user.id, RatingTrack.rated_id == uid).remove() store.find(RatingFolder, RatingFolder.user_id == request.user.id, RatingFolder.rated_id == uid).remove() else: rated = store.get(Track, uid) rating_ent = RatingTrack if not rated: rated = store.get(Folder, uid) rating_ent = RatingFolder if not rated: return request.error_formatter(70, 'Unknown id') rating_info = store.get(rating_ent, (request.user.id, uid)) if rating_info: rating_info.rating = rating else: rating_info = rating_ent() rating_info.user_id = request.user.id rating_info.rated_id = uid rating_info.rating = rating store.add(rating_info) store.commit() return request.formatter({})
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 user_del(): if not request.user.admin: return request.error_formatter(50, 'Admin restricted') username = request.args.get('username') user = store.find(User, User.name == username).one() if not user: return request.error_formatter(70, 'Unknown user') status = UserManager.delete(store, user.id) if status != UserManager.SUCCESS: return request.error_formatter(0, UserManager.error_str(status)) return request.formatter({})
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 scan_folder(id = None): s = Scanner(store) if id is None: for folder in store.find(Folder, Folder.root == True): FolderManager.scan(store, folder.id, s) else: status = FolderManager.scan(store, id, s) if status != FolderManager.SUCCESS: flash(FolderManager.error_str(status)) return redirect(url_for('folder_index')) added, deleted = s.stats() store.commit() flash('Added: %i artists, %i albums, %i tracks' % (added[0], added[1], added[2])) flash('Deleted: %i artists, %i albums, %i tracks' % (deleted[0], deleted[1], deleted[2])) return redirect(url_for('folder_index'))
def scan_folder(id = None): scanner = Scanner(store) if id is None: for folder in store.find(Folder, Folder.root == True): scanner.scan(folder) else: status, folder = FolderManager.get(store, id) if status != FolderManager.SUCCESS: flash(FolderManager.error_str(status)) return redirect(url_for('folder_index')) scanner.scan(folder) scanner.finish() added, deleted = scanner.stats() store.commit() flash('Added: %i artists, %i albums, %i tracks' % (added[0], added[1], added[2])) flash('Deleted: %i artists, %i albums, %i tracks' % (deleted[0], deleted[1], deleted[2])) return redirect(url_for('folder_index'))
def scan_folder(id=None): scanner = Scanner(store) if id is None: for folder in store.find(Folder, Folder.root == True): scanner.scan(folder) else: status, folder = FolderManager.get(store, id) if status != FolderManager.SUCCESS: flash(FolderManager.error_str(status)) return redirect(url_for("folder_index")) scanner.scan(folder) scanner.finish() added, deleted = scanner.stats() store.commit() flash("Added: %i artists, %i albums, %i tracks" % (added[0], added[1], added[2])) flash("Deleted: %i artists, %i albums, %i tracks" % (deleted[0], deleted[1], deleted[2])) return redirect(url_for("folder_index"))
def lyrics(): artist, title = map(request.values.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 = store.find(Track, Album.id == Track.album_id, Artist.id == Album.artist_id, Track.title.like(title), Artist.name.like(artist)) 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 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 upload_file(): if request.method == 'POST': file = request.files['file'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) #return redirect(url_for('uploaded_file', filename=filename)) playlist = Playlist() playlist.user_id = uuid.UUID(session.get('userid')) playlist.name = filename store.add(playlist) tracks = [] with open(os.path.join(app.config['UPLOAD_FOLDER'], filename)) as f: for line in f: if line[0] != '#': line = line.rstrip() line = line.decode('utf-8') tracks.append(line) track = store.find(Track, Track.path == line).one() if track: playlist.tracks.add(track) store.commit() return render_template('upload.html', tracks = tracks) return '''
def playlist_index(): return render_template('playlists.html', mine = store.find(Playlist, Playlist.user_id == uuid.UUID(session.get('userid'))), others = store.find(Playlist, Playlist.user_id != uuid.UUID(session.get('userid'))))
def list_indexes(): musicFolderId = request.args.get('musicFolderId') ifModifiedSince = request.args.get('ifModifiedSince') if ifModifiedSince: try: ifModifiedSince = int(ifModifiedSince) / 1000 except: return request.error_formatter(0, 'Invalid timestamp') if musicFolderId is None: folder = store.find(Folder, Folder.root == True) else: try: mfid = uuid.UUID(musicFolderId) except: return request.error_formatter(0, 'Invalid id') folder = store.get(Folder, mfid) if not folder or (type(folder) is Folder and not folder.root): return request.error_formatter(70, 'Folder not found') last_modif = max( map(lambda f: f.last_scan, folder)) if type(folder) is not Folder else folder.last_scan if (not ifModifiedSince is None) and last_modif < ifModifiedSince: return request.formatter( {'indexes': { 'lastModified': last_modif * 1000 }}) # The XSD lies, we don't return artists but a directory structure if type(folder) is not Folder: artists = [] childs = [] for f in folder: artists += f.children childs += f.tracks else: artists = folder.children childs = folder.tracks indexes = {} for artist in artists: index = artist.name[0].upper() 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({ 'indexes': { 'lastModified': last_modif * 1000, 'index': [{ 'name': k, 'artist': [{ 'id': str(a.id), '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()) ] } })
def playlist_index(): return render_template( 'playlists.html', mine=store.find(Playlist, Playlist.user_id == request.user.id), others=store.find(Playlist, Playlist.user_id != request.user.id, Playlist.public == True))
def old_search(): artist, album, title, anyf, count, offset, newer_than = map( request.values.get, ['artist', 'album', 'title', 'any', 'count', 'offset', 'newerThan']) try: 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 except: return request.error_formatter(0, 'Invalid parameter') min_date = datetime.fromtimestamp(newer_than) if artist: parent = ClassAlias(Folder) query = store.find(parent, Folder.parent_id == parent.id, Track.folder_id == Folder.id, parent.name.contains_string(artist), parent.created > min_date).config(distinct=True) elif album: query = store.find(Folder, Track.folder_id == Folder.id, Folder.name.contains_string(album), Folder.created > min_date).config(distinct=True) elif title: query = store.find(Track, Track.title.contains_string(title), Track.created > min_date) elif anyf: folders = store.find(Folder, Folder.name.contains_string(anyf), Folder.created > min_date) tracks = store.find(Track, Track.title.contains_string(anyf), Track.created > min_date) res = list(folders[offset:offset + count]) if offset + count > folders.count(): toff = max(0, offset - folders.count()) tend = offset + count - folders.count() res += list(tracks[toff:tend]) return request.formatter({ 'searchResult': { '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.prefs) for r in res ] } }) else: return request.error_formatter(10, 'Missing search parameter') return request.formatter({ 'searchResult': { 'totalHits': query.count(), 'offset': offset, 'match': [ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.prefs) for r in query[offset:offset + count] ] } })
def user_index(): return render_template('users.html', users = store.find(User))
def user_profile(uid, user): prefs = store.find(ClientPrefs, ClientPrefs.user_id == user.id) return render_template('profile.html', user = user, has_lastfm = app.config['LASTFM']['api_key'] != None, clients = prefs)