diff --git a/pysonic/api.py b/pysonic/api.py index 050240c..211c694 100644 --- a/pysonic/api.py +++ b/pysonic/api.py @@ -190,10 +190,13 @@ class PysonicApi(object): def getIndexes_view(self, **kwargs): # Get listing of top-level dir response = ApiResponse() + # TODO real lastmodified date + # TODO deal with ignoredArticles response.add_child("indexes", lastModified="1502310831000", ignoredArticles="The El La Los Las Le Les") + artists = self.library.get_artists(sortby="name", order="asc") for letter in LETTER_GROUPS: index = response.add_child("index", _parent="indexes", name=letter.upper()) - for artist in self.library.get_artists(): + for artist in artists: if artist["name"][0].lower() in letter: response.add_child("artist", _real_parent=index, id=artist["id"], name=artist["name"]) return response @@ -242,25 +245,33 @@ class PysonicApi(object): """ List an artist dir """ - dir_id = int(id) + artist_id = int(id) cherrypy.response.headers['Content-Type'] = 'text/xml; charset=utf-8' response = ApiResponse() response.add_child("directory") - directory = self.library.get_dir(dir_id) - dir_meta = directory["metadata"] - children = self.library.get_dir_children(dir_id) - response.set_attrs(_path="directory", name=directory['name'], id=directory['id'], - parent=directory['parent'], playCount=10) + artist = self.library.get_artists(id=artist_id)[0] + children = self.library.get_albums(artist=artist_id) + response.set_attrs(_path="directory", name=artist['name'], id=artist['id'], + parent=artist['libraryid'], playCount=10) for item in children: # omit not dirs and media in browser - if not item["isdir"] and item["type"] not in MUSIC_TYPES: - continue - item_meta = item['metadata'] - response.add_child("child", _parent="directory", **self.render_node(item, item_meta, directory, dir_meta)) + # if not item["isdir"] and item["type"] not in MUSIC_TYPES: + # continue + # item_meta = item['metadata'] + response.add_child("child", _parent="directory", + album=item["name"], + title=item["name"], # TODO dupe? + artist=artist["name"], + coverArt=item["coverid"], + id=item["id"], + isDir="false", # TODO song files in artist dir + parent=artist["id"], + size="4096", + type="music") return response @@ -273,9 +284,14 @@ class PysonicApi(object): :param directory: :param dir_meta: """ + print("\n\n\n") + print(item) + print(item_meta) + print(directory) + print(dir_meta) child = dict(id=item["id"], parent=item["id"], - isDir="true" if item['isdir'] else "false", + isDir="true" if "file" not in item else "false", title=item_meta.get("id3_title", item["name"]), album=item_meta.get("id3_album", item["album"]), artist=item_meta.get("id3_artist", item["artist"]), diff --git a/pysonic/database.py b/pysonic/database.py index ba9d8f7..cbb401b 100644 --- a/pysonic/database.py +++ b/pysonic/database.py @@ -140,6 +140,48 @@ class PysonicDatabase(object): libs.append(row) return libs + @readcursor + def get_artists(self, cursor, id=None, sortby=None, order=None): + assert order in ["asc", "desc", None] + artists = [] + q = "SELECT * FROM artists" + params = [] + if id: + q += " WHERE id = ?" + params.append(id) + if sortby: + q += " ORDER BY {} {}".format(sortby, order.upper() if order else "ASC") + cursor.execute(q, params) + for row in cursor: + artists.append(row) + return artists + + @readcursor + def get_albums(self, cursor, id=None, artist=None, sortby=None, order=None): + assert order in ["asc", "desc", None] + albums = [] + + q = "SELECT * FROM albums" + params = [] + + conditions = [] + if id: + conditions.append("id = ?") + params.append(id) + if artist: + conditions.append("artistid = ?") + params.append(artist) + if conditions: + q += " WHERE " + " AND ".join(conditions) + + if sortby: + q += " ORDER BY {} {}".format(sortby, order.upper() if order else "ASC") + cursor.execute(q, params) + for row in cursor: + albums.append(row) + return albums + + diff --git a/pysonic/library.py b/pysonic/library.py index 0c61b41..090c70a 100644 --- a/pysonic/library.py +++ b/pysonic/library.py @@ -31,12 +31,17 @@ class NoDataException(Exception): class PysonicLibrary(object): def __init__(self, database): self.db = database + + self.get_libraries = self.db.get_libraries + self.get_artists = self.db.get_artists + self.get_albums = self.db.get_albums + self.scanner = PysonicFilesystemScanner(self) logging.info("library ready") def update(self): """ - Start the library media scanner and + Start the library media scanner ands """ self.scanner.init_scan() @@ -47,7 +52,98 @@ class PysonicLibrary(object): path = os.path.abspath(os.path.normpath(path)) self.db.add_root(path) + # def get_artists(self, *args, **kwargs): + # artists = self.db.get_artists(*args, **kwargs) + # for item in artists: + # item["parent"] = item["libraryid"] + # return artists + + # def get_albums(self, *args, **kwargs): + # albums = self.db.get_albums(*args, **kwargs) + # for item in albums: + # item["parent"] = item["artistid"] + # return albums + + def get_artist_info(self, item_id): + #TODO + return {"biography": "placeholder biography", + "musicBrainzId": "playerholder", + "lastFmUrl": "https://www.last.fm/music/Placeholder", + "smallImageUrl": "", + "mediumImageUrl": "", + "largeImageUrl": "", + "similarArtists": []} + + # #@memoize + # def get_libraries(self): + # """ + # Libraries are top-level nodes + # """ + # return self.db.getnodes(-1) + + # #@memoize + # def get_artists(self): + # # Assume artists are second level dirs + # return self.db.getnodes(*[item["id"] for item in self.get_libraries()]) + + # def get_dir(self, dirid): + # return self.db.getnode(dirid) + + # def get_dir_children(self, dirid): + # return self.db.getnodes(dirid) + + # #@memoize + # def get_albums(self): + # return self.db.getnodes(*[item["id"] for item in self.get_artists()]) + + # #@memoize + # def get_filepath(self, nodeid): + # parents = [self.db.getnode(nodeid)] + # while parents[-1]['parent'] != -1: + # parents.append(self.db.getnode(parents[-1]['parent'])) + # root = parents.pop() + # parents.reverse() + # return os.path.join(root['metadata']['fspath'], *[i['name'] for i in parents]) + + # def get_file_metadata(self, nodeid): + # return self.db.get_metadata(nodeid) + + # def get_artist_info(self, item_id): + # # artist = self.db.getnode(item_id) + # return {"biography": "placeholder biography", + # "musicBrainzId": "playerholder", + # "lastFmUrl": "https://www.last.fm/music/Placeholder", + # "smallImageUrl": "", + # "mediumImageUrl": "", + # "largeImageUrl": "", + # "similarArtists": []} + + # def set_starred(self, username, node_id, starred): + # self.db.set_starred(self.db.get_user(username)["id"], node_id, starred) + + # def get_stars(self, user, user_id): + # self.db.get_stars() + + # def get_user(self, user): + # return self.db.get_user(user) + + # def get_starred(self, username): + # return self.db.get_starred_items(self.db.get_user(username)["id"]) + + # def get_songs(self, limit=50, shuffle=True): + # return self.db.getnodes(types=MUSIC_TYPES, limit=limit, order="rand") + + # def get_song(self, id=None): + # if id: + # return self.db.getnode(id) + # else: + # return self.db.getnodes(types=MUSIC_TYPES, limit=1, order="rand") + + # def report_transcode(self, item_id, bitrate, num_bytes): + # assert type(bitrate) is int and bitrate > 0 and bitrate <= 320 + # logging.info("Got transcode report of {} for item {} @ {}".format(num_bytes, item_id, bitrate)) + # self.db.update_metadata(item_id, {"transcoded_{}_size".format(bitrate):int(num_bytes)})