Exemplo n.º 1
0
 def handle_request(self, request, params):
   self.ensure_request_possible(request, params[0])
   logging.debug("DBClient: handling %s request params %s", request, str(params))
   if request == "metadata":
     return self.query_list(*params[:2], None, [params[2]], "metadata_request")
   elif request == "root_menu":
     return self.query_list(*params, None, [], "root_menu_request")
   elif request == "title":
     return self.query_list(*params, [], "title_request")
   elif request == "title_by_album":
     return self.query_list(*params, "title_by_album_request")
   elif request == "title_by_artist_album":
     return self.query_list(*params, "title_by_artist_album_request")
   elif request == "title_by_genre_artist_album":
     return self.query_list(*params, "title_by_genre_artist_album_request")
   elif request == "artist":
     return self.query_list(*params, None, [], "artist_request")
   elif request == "artist_by_genre":
     return self.query_list(*params[:2], None, params[2], "artist_by_genre_request")
   elif request == "album":
     return self.query_list(*params, None, [], "album_request")
   elif request == "album_by_artist":
     return self.query_list(*params[:2], None, params[2], "album_by_artist_request")
   elif request == "album_by_genre_artist":
     return self.query_list(*params[:2], None, params[2], "album_by_genre_artist_request")
   elif request == "genre":
     return self.query_list(*params, None, [], "genre_request")
   elif request == "playlist_folder":
     return self.query_list(*params[:2], None, [params[2], 0], "playlist_request")
   elif request == "playlist":
     return self.query_list(*params[:3], [0, params[3]], "playlist_request")
   elif request == "artwork":
     return self.query_blob(*params, "artwork_request")
   elif request == "waveform":
     waveform = self.query_blob(*params, "waveform_request", 1)
     return None if waveform is None else waveform[20:]
   elif request == "preview_waveform":
     return self.query_blob(*params, "preview_waveform_request")
   elif request == "color_waveform":
     blob = self.query_blob(*params, "color_waveform_request", 1)
     return None if blob is None else AnlzTag.parse(blob[4:]).content.entries
   elif request == "color_preview_waveform":
     blob = self.query_blob(*params, "color_preview_waveform_request")
     return None if blob is None else AnlzTag.parse(blob[4:]).content.entries
   elif request == "beatgrid":
     reply = self.query_blob(*params, "beatgrid_request")
     if reply is None:
       return None
     try: # pre-parse beatgrid data (like metadata) for easier access
       return packets.Beatgrid.parse(reply)["beats"]
     except (RangeError, FieldError) as e:
       raise dataprovider.FatalQueryError("DBClient: failed to parse beatgrid data: {}".format(e))
   elif request == "mount_info":
     return self.query_list(*params[:2], None, [params[2]], "mount_info_request")
   elif request == "track_info":
     return self.query_list(*params[:2], None, [params[2]], "track_info_request")
   else:
     raise dataprovider.FatalQueryError("DBClient: invalid request type {}".format(request))
Exemplo n.º 2
0
 def download_and_parse_pdb(self, player_number, slot):
     filename = self.download_pdb(player_number, slot)
     db = PDBDatabase()
     try:
         db.load_file(filename)
     except RuntimeError as e:
         raise dataprovider.FatalQueryError(
             "PDBFile: failed to parse \"{}\": {}".format(filename, e))
     return db
Exemplo n.º 3
0
 def download_pdb(self, player_number, slot):
     player = self.prodj.cl.getClient(player_number)
     if player is None:
         raise dataprovider.FatalQueryError(
             "PDBProvider: player {} not found in clientlist".format(
                 player_number))
     filename = "databases/player-{}-{}.pdb".format(player_number, slot)
     self.delete_pdb(filename)
     try:
         self.prodj.nfs.enqueue_download(player.ip_addr,
                                         slot,
                                         "/PIONEER/rekordbox/export.pdb",
                                         filename,
                                         sync=True)
     except RuntimeError as e:
         raise dataprovider.FatalQueryError(
             "PDBProvider: database download from player {} failed: {}".
             format(player_number, e))
     return filename
Exemplo n.º 4
0
 def get_artwork(self, player_number, slot, artwork_id):
     player = self.prodj.cl.getClient(player_number)
     if player is None:
         raise dataprovider.FatalQueryError(
             "PDBProvider: player {} not found in clientlist".format(
                 player_number))
     db = self.get_db(player_number, slot)
     artwork = db.get_artwork(artwork_id)
     return self.prodj.nfs.enqueue_buffer_download(player.ip_addr, slot,
                                                   artwork.path)
Exemplo n.º 5
0
 def socksnd(self, sock, data):
   try:
     sock.send(data)
   except BrokenPipeError as e:
     player_number = next((n for n, d in self.socks.items() if d[0] == sock), None)
     if player_number is None:
       raise dataprovider.FatalQueryError("socksnd failed with unknown sock")
     else:
       self.closeSocket(player_number)
       raise dataprovider.TemporaryQueryError("Connection to player {} lost".format(player_number))
Exemplo n.º 6
0
 def convert_and_sort_track_list(self, db, track_list, sort_mode):
     converted = []
     # we do not know the default sort mode from pdb, thus fall back to title
     if sort_mode in ["title", "default"]:
         col2_name = "artist"
     else:
         col2_name = sort_mode
     for track in track_list:
         if col2_name in ["title", "artist"]:
             col2_item = db.get_artist(
                 track.artist_id).name if track.artist_id > 0 else ""
         elif col2_name == "album":
             col2_item = db.get_album(
                 track.album_id).name if track.album_id > 0 else ""
         elif col2_name == "genre":
             col2_item = db.get_genre(
                 track.genre_id).name if track.genre_id > 0 else ""
         elif col2_name == "label":
             col2_item = db.get_label(
                 track.label_id).name if track.label_id > 0 else ""
         elif col2_name == "original_artist":
             col2_item = db.get_artist(
                 track.original_artist_id
             ).name if track.original_artist_id > 0 else ""
         elif col2_name == "remixer":
             col2_item = db.get_artist(
                 track.remixer_id).name if track.remixer_id > 0 else ""
         elif col2_name == "key":
             col2_item = db.get_key(
                 track.key_id).name if track.key_id > 0 else ""
         elif col2_name == "bpm":
             col2_item = track.bpm_100 / 100
         elif col2_name in [
                 "rating", "comment", "duration", "bitrate", "play_count"
         ]:  # 1:1 mappings
             col2_item = track[col2_name]
         else:
             raise dataprovider.FatalQueryError(
                 "PDBProvider: unknown sort mode {}".format(sort_mode))
         converted += [{
             "title": track.title,
             col2_name: col2_item,
             "track_id": track.id,
             "artist_id": track.artist_id,
             "album_id": track.album_id,
             "artwork_id": track.artwork_id,
             "genre_id": track.genre_id
         }]
     if sort_mode == "default":
         return converted
     else:
         return sorted(converted,
                       key=lambda key: key[sort_mode],
                       reverse=sort_mode == "rating")
Exemplo n.º 7
0
 def download_and_parse_usbanlz(self, player_number, slot, anlz_path):
     player = self.prodj.cl.getClient(player_number)
     if player is None:
         raise dataprovider.FatalQueryError(
             "PDBProvider: player {} not found in clientlist".format(
                 player_number))
     dat = self.prodj.nfs.enqueue_buffer_download(player.ip_addr, slot,
                                                  anlz_path)
     ext = self.prodj.nfs.enqueue_buffer_download(
         player.ip_addr, slot, anlz_path.replace("DAT", "EXT"))
     db = UsbAnlzDatabase()
     db.load_dat_buffer(dat)
     db.load_ext_buffer(ext)
     return db
 def handle_request(self, request, params):
     logging.debug("PDBProvider: handling %s request params %s", request,
                   str(params))
     if request == "metadata":
         return self.get_metadata(*params)
     elif request == "root_menu":
         return self.get_root_menu()
     elif request == "title":
         return self.get_titles(*params)
     elif request == "title_by_album":
         return self.get_titles(*params)
     elif request == "title_by_artist_album":
         return self.get_titles(*params)
     elif request == "title_by_genre_artist_album":
         return self.get_titles(*params)
     elif request == "artist":
         return self.get_artists(*params)
     elif request == "artist_by_genre":
         return self.get_artists(*params)
     elif request == "album":
         return self.get_albums(*params)
     elif request == "album_by_artist":
         return self.get_albums(*params)
     elif request == "album_by_genre_artist":
         return self.get_albums(*params)
     elif request == "genre":
         return self.get_genres(*params)
     elif request == "playlist_folder":
         return self.get_playlists(*params)
     elif request == "playlist":
         return self.get_playlist(*params)
     elif request == "artwork":
         return self.get_artwork(*params)
     elif request == "waveform":
         return self.get_waveform(*params)
     elif request == "preview_waveform":
         return self.get_preview_waveform(*params)
     elif request == "color_waveform":
         return self.get_color_waveform(*params)
     elif request == "color_preview_waveform":
         return self.get_color_preview_waveform(*params)
     elif request == "beatgrid":
         return self.get_beatgrid(*params)
     elif request == "mount_info":
         return self.get_mount_info(*params)
     else:
         raise dataprovider.FatalQueryError(
             "PDBProvider: invalid request type {}".format(request))
 def get_artwork(self, player_number, slot, artwork_id):
     player = self.prodj.cl.getClient(player_number)
     if player is None:
         raise dataprovider.FatalQueryError(
             "PDBProvider: player {} not found in clientlist".format(
                 player_number))
     db = self.get_db(player_number, slot)
     try:
         artwork = db.get_artwork(artwork_id)
     except KeyError as e:
         logging.warning(
             "PDBProvider: No artwork for {}, returning empty data".format(
                 (player_number, slot, artwork_id)))
         return None
     return self.prodj.nfs.enqueue_buffer_download(player.ip_addr, slot,
                                                   artwork.path)
Exemplo n.º 10
0
    def query_list(self, player_number, slot, sort_mode, id_list,
                   request_type):
        sock = self.getSocket(player_number)
        slot_id = byte2int(
            packets.PlayerSlot.build(slot)) if slot is not None else 0
        if sort_mode is None:
            sort_id = 0  # 0 for root_menu, playlist folders
        else:
            if sort_mode not in sort_types:
                logging.warning("DBClient: unknown sort mode %s", sort_mode)
                return None
            sort_id = sort_types[sort_mode]
        query = {
            "transaction_id":
            self.getTransactionId(player_number),
            "type":
            request_type,
            "args": [{
                "type":
                "int32",
                "value":
                self.own_player_number << 24 | 1 << 16 | slot_id << 8 | 1
            }]
        }
        # request-specific argument agumentations
        if request_type == "root_menu_request":
            query["args"].append({"type": "int32", "value": 0})
            query["args"].append({"type": "int32", "value": 0xffffff})
        elif request_type in [
                "metadata_request", "track_data_request", "track_info_request"
        ]:
            query["args"].append({"type": "int32", "value": id_list[0]})
        elif request_type == "playlist_request":
            query["args"].append({"type": "int32", "value": sort_id})
            query["args"].append({
                "type":
                "int32",
                "value":
                id_list[1] if id_list[1] > 0 else id_list[0]
            })
            query["args"].append({
                "type": "int32",
                "value": 0 if id_list[1] > 0 else 1
            })  # 1 -> get folder, 0 -> get playlist
        else:  # for any (non-playlist) "*_by_*_request"
            query["args"].append({"type": "int32", "value": sort_id})
            for item_id in id_list:
                if item_id == 0:  # we use id 0 for "ALL", dbserver expects all bits set
                    item_id = 0xffffffff
                query["args"].append({"type": "int32", "value": item_id})
        data = packets.DBMessage.build(query)
        logging.debug("DBClient: query_list request: {}".format(query))
        self.socksnd(sock, data)

        try:
            reply = self.receive_dbmessage(sock)
        except (RangeError, MappingError, KeyError) as e:
            logging.error(
                "DBClient: parsing %s query failed on player %d failed: %s",
                query["type"], player_number, str(e))
            return None
        if reply is None or reply["type"] != "success":
            logging.error("DBClient: %s failed on player %d (got %s)",
                          query["type"], player_number,
                          "NONE" if reply is None else reply["type"])
            return None
        entry_count = reply["args"][1]["value"]
        if entry_count == 0:
            logging.warning("DBClient: %s empty (0 entries)", request_type)
            return []
        logging.debug("DBClient: query_list %s: %d entries available",
                      request_type, entry_count)

        # i could successfully receive hundreds of entries at once on xdj 1000
        # thus i do not fragment render requests here
        query = {
            "transaction_id":
            self.getTransactionId(player_number),
            "type":
            "render",
            "args": [
                {
                    "type":
                    "int32",
                    "value":
                    self.own_player_number << 24 | 1 << 16 | slot_id << 8 | 1
                },
                {
                    "type": "int32",
                    "value": 0
                },  # entry offset
                {
                    "type": "int32",
                    "value": entry_count
                },  # entry count
                {
                    "type": "int32",
                    "value": 0
                },
                {
                    "type": "int32",
                    "value": entry_count
                },  # entry count
                {
                    "type": "int32",
                    "value": 0
                }
            ]
        }
        data = packets.DBMessage.build(query)
        logging.debug("DBClient: render query {}".format(query))
        self.socksnd(sock, data)
        parse_errors = 0
        receive_timeouts = 0
        data = b""
        while parse_errors < self.parse_error_count and receive_timeouts < self.receive_timeout_count:
            new_data = sockrcv(sock, 4096, 1)
            if len(new_data) == 0:
                receive_timeouts += 1
                continue
            data += new_data
            try:
                reply = packets.ManyDBMessages.parse(data)
            except (RangeError, FieldError, MappingError, KeyError,
                    TypeError) as e:
                logging.debug(
                    "DBClient: failed to parse %s render reply (%d bytes), trying to receive more",
                    request_type, len(data))
                parse_errors += 1
            else:
                if reply[-1]["type"] != "menu_footer":
                    logging.debug(
                        "DBClient: %s rendering without menu_footer @ %d bytes, trying to receive more",
                        request_type, len(data))
                    parse_errors += 1
                else:
                    break
        if parse_errors >= self.parse_error_count or receive_timeouts >= self.receive_timeout_count:
            raise dataprovider.FatalQueryError(
                "DBClient: Failed to receive {} render reply after {} timeouts, {} parse errors"
                .format(request_type, receive_timeouts, parse_errors))

        # basically, parse_metadata returns a single dict whereas parse_list returns a list of dicts
        if request_type in [
                "metadata_request", "mount_info_request", "track_info_request"
        ]:
            parsed = self.parse_metadata(reply)
        else:
            parsed = self.parse_list(reply)
        return parsed