def unstar(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response trackId = kwargs.get('id') if trackId: track = request.env['oomusic.track'].browse([int(trackId)]) if track.exists(): track.write({'star': '0'}) else: folder = request.env['oomusic.folder'].browse([int(trackId)]) if folder.exists(): folder.write({'star': '1'}) albumId = kwargs.get('albumId') if albumId: album = request.env['oomusic.album'].browse([int(albumId)]) if album.exists(): album.write({'star': '0'}) artistId = kwargs.get('artistId') if artistId: artist = request.env['oomusic.artist'].browse([int(artistId)]) if artist.exists(): artist.write({'star': '0'}) root = etree.Element('subsonic-response', status='ok', version=rest.version_server) return rest.make_response(root)
def getCoverArt(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response folderId = kwargs.get('id') if folderId: try: if 'al-' in folderId: folder = request.env['oomusic.album'].browse( [int(folderId.split('-')[-1])]) else: folder = request.env['oomusic.folder'].browse( [int(folderId.split('-')[-1])]) if not folder.exists(): return rest.make_error(code='70', message='Folder not found') except: folder = request.env['oomusic.folder'] else: return rest.make_error( code='10', message='Required int parameter "id" is not present') image = folder.image_medium or 'R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' image_stream = StringIO.StringIO(image.decode('base64')) image_ext = '.' + (imghdr.what(image_stream) or 'png') return http.send_file(image_stream, filename=folderId + image_ext)
def jukeboxControl(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response return rest.make_error(code='30', message='Feature not supported by server.')
def getVideoInfo(self, **kwargs): # TODO: support video infos rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response return request.make_error(code='30', message='Videos are not supported yet')
def addChatMessage(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) return rest.make_response(root)
def scrobble(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response # TODO support lastfm scrobble return rest.make_error(code='30', message='Feature not supported by server.')
def getMusicDirectory(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response folderId = kwargs.get('id') if folderId: folder = request.env['oomusic.folder'].browse([int(folderId)]) if not folder.exists(): return rest.make_error(code='70', message='Folder not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_directory = rest.make_Directory(folder) root.append(xml_directory) # List of folders for child in folder.child_ids: xml_data = rest.make_Child_folder(child) xml_directory.append(xml_data) # List of tracks for track in folder.track_ids: xml_data = rest.make_Child_track(track) xml_directory.append(xml_data) return rest.make_response(root)
def getChatMessages(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_messages = rest.make_ChatMessages() root.append(xml_messages) return rest.make_response(root)
def getNewestPodcasts(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_podcasts = rest.make_Podcasts(tag_name='newestPodcasts') root.append(xml_podcasts) return rest.make_response(root)
def actionUsers(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response # Do not support these actions on purpose, for security reason root = etree.Element('subsonic-response', status='ok', version=rest.version_server) return rest.make_response(root)
def getInternetRadioStations(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_radios = rest.make_InternetRadioStations() root.append(xml_radios) return rest.make_response(root)
def stream(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response trackId = kwargs.get('id') if trackId: track = request.env['oomusic.track'].browse([int(trackId)]) if not track.exists(): return rest.make_error(code='70', message='Song not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') maxBitRate = int(kwargs.get('maxBitRate', 0)) output_format = kwargs.get('format', 'mp3') estimateContentLength = kwargs.get('estimateContentLength', False) # Only for video # timeOffset = kwargs.get('timeOffset') # size = kwargs.get('size') # converted = kwargs.get('size', False) fn_ext = os.path.splitext(track.path)[1] # As specified in Subsonic API: if maxBitRate is set to zero, no limit is imposed. We also # avoid any upsampling. if fn_ext[1:] == output_format and (not maxBitRate or maxBitRate >= track.bitrate): return http.send_file(track.path) Transcoder = request.env['oomusic.transcoder'].search( [('input_formats.name', '=', fn_ext[1:]), ('output_format.name', '=', output_format)], limit=1, ) if Transcoder: generator = Transcoder.transcode(int(trackId), bitrate=maxBitRate).stdout mimetype = Transcoder.output_format.mimetype else: _logger.warning('Could not find converter from "%s" to "%s"', fn_ext[1:], output_format) return http.send_file(track.path) data = wrap_file(request.httprequest.environ, generator, buffer_size=Transcoder.buffer_size * 1024) return Response(data, mimetype=mimetype, direct_passthrough=True)
def getPlaylist(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response playlistId = kwargs.get('id') if playlistId: playlist = request.env['oomusic.playlist'].browse( [int(playlistId)]) if not playlist.exists(): return rest.make_error(code='70', message='Playlist not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_playlist = rest.make_Playlist(playlist) root.append(xml_playlist) for playlist_line in playlist.playlist_line_ids: xml_playlist_line = rest.make_Child_track(playlist_line.track_id, tag_name='entry') xml_playlist.append(xml_playlist_line) return rest.make_response(root)
def getAlbum(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response albumId = kwargs.get('id') if albumId: album = request.env['oomusic.album'].browse([int(albumId)]) if not album.exists(): return rest.make_error(code='70', message='Album not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_album = rest.make_AlbumID3(album) root.append(xml_album) for track in album.track_ids: xml_song = rest.make_Child_track(track, tag_name='song') xml_album.append(xml_song) return rest.make_response(root)
def getArtist(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response artistId = kwargs.get('id') if artistId: artist = request.env['oomusic.artist'].browse([int(artistId)]) if not artist.exists(): return rest.make_error(code='70', message='Artist not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_artist = rest.make_ArtistID3(artist) root.append(xml_artist) for album in artist.album_ids: xml_album = rest.make_AlbumID3(album) xml_artist.append(xml_album) return rest.make_response(root)
def getArtists(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_artists = rest.make_ArtistsID3() root.append(xml_artists) musicFolderId = kwargs.get('musicFolderId') if musicFolderId: artists = request.env['oomusic.track'].search([ ('folder_id', 'child_of', int(musicFolderId)) ]).mapped('artist_id') else: artists = request.env['oomusic.artist'].search([]) # Build indexes indexes_dict = rest.build_dict_indexes_artists(artists) # List of artists for k, v in sorted(indexes_dict.iteritems()): xml_index = rest.make_IndexID3(k) xml_artists.append(xml_index) for artist in v: xml_artist = rest.make_ArtistID3(artist) xml_index.append(xml_artist) return rest.make_response(root)
def getLicense(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) etree.SubElement(root, 'license', valid='true', email='*****@*****.**', licenseExpires='2099-12-31T23:59:59') return rest.make_response(root)
def getShares(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_shares = rest.make_Shares() root.append(xml_shares) # TODO support shares return rest.make_response(root)
def getNowPlaying(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_song_list = rest.make_listSongs('nowPlaying') root.append(xml_song_list) # TODO support NowPlayingEntry return rest.make_response(root)
def getLyrics(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response artist = kwargs.get('artist') title = kwargs.get('title') root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_lyrics = rest.make_Lyrics(artist, title) root.append(xml_lyrics) return rest.make_response(root)
def download(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response trackId = kwargs.get('id') if trackId: track = request.env['oomusic.track'].browse([int(trackId)]) if not track.exists(): return rest.make_error(code='70', message='Song not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') return http.send_file(track.path, as_attachment=True)
def getSimilarSongs2(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response songId = kwargs.get('id') if songId: track = request.env['oomusic.track'].browse([int(songId)]) if not track.exists(): return rest.make_error(code='70', message='Song not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') count = int(kwargs.get('count', 50)) tag_name = kwargs.get('tag_name', 'similarSongs2') root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_song_info = rest.make_SimilarSongs2(track, count=count, tag_name=tag_name) root.append(xml_song_info) return rest.make_response(root)
def getArtistInfo2(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response artistId = kwargs.get('id') if artistId: artist = request.env['oomusic.artist'].browse([int(artistId)]) if not artist.exists(): return rest.make_error(code='70', message='Artist not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') count = int(kwargs.get('count', 20)) if kwargs.get('includeNotPresent'): includeNotPresent = True if kwargs.get( 'includeNotPresent') == 'true' else False else: includeNotPresent = False root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_artist_info = rest.make_ArtistInfo2( artist, count=count, includeNotPresent=includeNotPresent) root.append(xml_artist_info) return rest.make_response(root)
def getAvatar(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response username = kwargs.get('username') if not username: return rest.make_error( code='10', message='Required str parameter "username" is not present') user = request.env['res.users'].search([('login', '=', username)]) image = user.partner_id.image_medium or 'R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' image_stream = StringIO.StringIO(image.decode('base64')) image_ext = '.' + (imghdr.what(image_stream) or 'png') return http.send_file(image_stream, filename=str(user.id) + image_ext)
def getGenres(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_genres = rest.make_Genres() root.append(xml_genres) # For some mysterious reason, in this particular route, the xml declaration should be made # with double quotes instead of simple quotes. response =\ '<?xml version="1.0" encoding="UTF-8"?>\n'\ + etree.tostring(root, encoding='UTF-8', pretty_print=True) return request.make_response(response)
def deletePlaylist(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response PlaylistObj = request.env['oomusic.playlist'] playlistId = kwargs.get('id') if playlistId: playlist = PlaylistObj.browse([int(playlistId)]) if not playlist.exists(): return rest.make_error(code='70', message='Playlist not found') else: return rest.make_error( code='10', message='Required int parameter "id" is not present') playlist.unlink() root = etree.Element('subsonic-response', status='ok', version=rest.version_server) return rest.make_response(root)
def createPlaylist(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response PlaylistObj = request.env['oomusic.playlist'] mode = 'create' playlistId = kwargs.get('id') if playlistId: playlist = PlaylistObj.browse([int(playlistId)]) if playlist.exists(): mode = 'update' name = kwargs.get('name') if mode == 'mode' and not name: return rest.make_error( code='10', message='Required str parameter "name" is not present') songId = kwargs.get('songId') if songId: track = request.env['oomusic.track'].browse([int(songId)]) if not track.exists(): return rest.make_error(code='70', message='Song not found') if mode == 'create': playlist = PlaylistObj.create({'name': name}) if playlist: playlist._add_tracks(track) root = etree.Element('subsonic-response', status='ok', version=rest.version_server) if API_VERSION_LIST[rest.version_client] >= API_VERSION_LIST['1.14.0']: xml_playlist = rest.make_Playlist(playlist) root.append(xml_playlist) for playlist_line in playlist.playlist_line_ids: xml_playlist_line = rest.make_Child_track( playlist_line.track_id, tag_name='entry') xml_playlist.append(xml_playlist_line) return rest.make_response(root)
def getStarred2(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response ArtistObj = request.env['oomusic.artist'] AlbumObj = request.env['oomusic.album'] TrackObj = request.env['oomusic.track'] folderId = kwargs.get('musicFolderId') if folderId: folder = request.env['oomusic.folder'].browse([int(folderId)]) if not folder.exists(): return rest.make_error(code='70', message='Folder not found') domain = [('id', 'child_of', int(folderId))] if folderId else [] root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_starred_list = rest.make_listSongs('starred2') root.append(xml_starred_list) artists = ArtistObj.search(domain + [('star', '=', '1')]) albums = AlbumObj.search(domain + [('star', '=', '1')]) tracks = TrackObj.search(domain + [('star', '=', '1')]) for artist in artists: xml_artist = rest.make_ArtistID3(artist) xml_starred_list.append(xml_artist) for album in albums: xml_album = rest.make_AlbumID3(album) xml_starred_list.append(xml_album) for track in tracks: xml_song = rest.make_Child_track(track, tag_name='song') xml_starred_list.append(xml_song) return rest.make_response(root)
def getSongsByGenre(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response TrackObj = request.env['oomusic.track'] genre = kwargs.get('genre') if not genre: return rest.make_error( code='10', message='Required str parameter "genre" is not present') folderId = kwargs.get('musicFolderId') if folderId: folder = request.env['oomusic.folder'].browse([int(folderId)]) if not folder.exists(): return rest.make_error(code='70', message='Folder not found') size = min(int(kwargs.get('size', 10)), 500) offset = int(kwargs.get('offset', 0)) # Build domain domain = [('id', 'child_of', int(folderId))] if folderId else [] domain += [('genre_id.name', '=', genre)] root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_song_list = rest.make_listSongs('songsByGenre') root.append(xml_song_list) tracks = TrackObj.search(domain) if tracks: min_val = min(offset, len(tracks)) max_val = min_val + size for track in tracks[min_val:max_val]: xml_song = rest.make_Child_track(track, tag_name='song') xml_song_list.append(xml_song) return rest.make_response(root)
def getStarred(self, **kwargs): rest = SubsonicREST(kwargs) success, response = rest.check_login() if not success: return response FolderObj = request.env['oomusic.folder'] TrackObj = request.env['oomusic.track'] folderId = kwargs.get('musicFolderId') if folderId: folder = request.env['oomusic.folder'].browse([int(folderId)]) if not folder.exists(): return rest.make_error(code='70', message='Folder not found') domain = [('id', 'child_of', int(folderId))] if folderId else [] root = etree.Element('subsonic-response', status='ok', version=rest.version_server) xml_starred_list = rest.make_listSongs('starred') root.append(xml_starred_list) folders = FolderObj.search(domain + [('star', '=', '1')]) tracks = TrackObj.search(domain + [('star', '=', '1')]) for folder in folders.sorted(lambda r: len(r.track_ids)): if not folder.track_ids: xml_folder = rest.make_Artist(folder) else: xml_folder = rest.make_Child_folder(folder, tag_name='album') xml_starred_list.append(xml_folder) for track in tracks: xml_song = rest.make_Child_track(track, tag_name='song') xml_starred_list.append(xml_song) return rest.make_response(root)