static gboolean xmms_playlist_advance_do (xmms_playlist_t *playlist) { gint size, currpos; gboolean ret = TRUE; xmmsv_coll_t *plcoll; const gchar *jumplist; xmms_error_t err; xmms_playlist_t *buffer = playlist; guint newpos; xmms_error_reset (&err); plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, NULL); if (plcoll == NULL) { ret = FALSE; } else if ((size = xmms_playlist_coll_get_size (plcoll)) == 0) { if (xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) { xmms_playlist_client_load (buffer, jumplist, &err); if (xmms_error_isok (&err)) { ret = xmms_playlist_advance_do (playlist); } else { ret = FALSE; } } else { ret = FALSE; } } else if (!playlist->repeat_one) { currpos = xmms_playlist_coll_get_currpos (plcoll); currpos++; if (currpos == size && !playlist->repeat_all && xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) { xmms_collection_set_int_attr (plcoll, "position", -1); XMMS_PLAYLIST_CURRPOS_MSG (-1, XMMS_ACTIVE_PLAYLIST); xmms_playlist_client_load (buffer, jumplist, &err); if (xmms_error_isok (&err)) { ret = xmms_playlist_advance_do (playlist); } else { ret = FALSE; } } else { newpos = currpos%size; xmms_collection_set_int_attr (plcoll, "position", newpos); XMMS_PLAYLIST_CURRPOS_MSG (newpos, XMMS_ACTIVE_PLAYLIST); ret = (currpos != size) || playlist->repeat_all; } } return ret; }
static gboolean xmms_playlist_remove_unlocked (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *plcoll, guint pos, xmms_error_t *err) { gint currpos; xmmsv_t *dict; g_return_val_if_fail (playlist, FALSE); currpos = xmms_playlist_coll_get_currpos (plcoll); if (!xmmsv_coll_idlist_remove (plcoll, pos)) { if (err) xmms_error_set (err, XMMS_ERROR_NOENT, "Entry was not in list!"); return FALSE; } dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_REMOVE, 0, plname); xmmsv_dict_set_int (dict, "position", pos); xmms_playlist_changed_msg_send (playlist, dict); /* decrease current position if removed entry was before or if it's * the current entry, but only if current position is a valid entry. */ if (currpos != -1 && pos <= currpos) { currpos = MAX (0, currpos - 1); xmms_collection_set_int_attr (plcoll, "position", currpos); XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname); } return TRUE; }
static gint xmms_playlist_set_current_position_do (xmms_playlist_t *playlist, guint32 pos, xmms_error_t *err) { gint size; xmms_medialib_entry_t mid; xmmsv_coll_t *plcoll; const gchar *jumplist; g_return_val_if_fail (playlist, FALSE); plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err); if (plcoll == NULL) { return 0; } size = xmms_playlist_coll_get_size (plcoll); if (pos == size && xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) { xmms_collection_set_int_attr (plcoll, "position", 0); XMMS_PLAYLIST_CURRPOS_MSG (0, XMMS_ACTIVE_PLAYLIST); xmms_playlist_client_load (playlist, jumplist, err); if (xmms_error_iserror (err)) { return 0; } plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err); if (plcoll == NULL) { return 0; } } else if (pos < size) { XMMS_DBG ("newpos! %d", pos); xmms_collection_set_int_attr (plcoll, "position", pos); XMMS_PLAYLIST_CURRPOS_MSG (pos, XMMS_ACTIVE_PLAYLIST); } else { xmms_error_set (err, XMMS_ERROR_INVAL, "Can't set pos outside the current playlist!"); return 0; } xmmsv_coll_idlist_get_index (plcoll, pos, &mid); return mid; }
/** * Insert an entry at a given position in the playlist without * validating it. * * @internal */ void xmms_playlist_insert_entry (xmms_playlist_t *playlist, const gchar *plname, guint32 pos, xmms_medialib_entry_t file, xmms_error_t *err) { xmms_medialib_session_t *session; xmmsv_t *dict; gint currpos; gint len; xmmsv_coll_t *plcoll; gboolean valid; g_mutex_lock (playlist->mutex); do { session = xmms_medialib_session_begin_ro (playlist->medialib); valid = xmms_medialib_check_id (session, file); } while (!xmms_medialib_session_commit (session)); if (!valid) { g_mutex_unlock (playlist->mutex); xmms_error_set (err, XMMS_ERROR_NOENT, "That is not a valid medialib id!"); return; } plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { /* FIXME: happens ? */ g_mutex_unlock (playlist->mutex); return; } len = xmms_playlist_coll_get_size (plcoll); if (pos > len) { xmms_error_set (err, XMMS_ERROR_GENERIC, "Could not insert entry outside of playlist!"); g_mutex_unlock (playlist->mutex); return; } xmmsv_coll_idlist_insert (plcoll, pos, file); /** propagate the MID ! */ dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_INSERT, file, plname); xmmsv_dict_set_int (dict, "position", pos); xmms_playlist_changed_msg_send (playlist, dict); /** update position once client is familiar with the new item. */ currpos = xmms_playlist_coll_get_currpos (plcoll); if (pos <= currpos) { currpos++; xmms_collection_set_int_attr (plcoll, "position", currpos); XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname); } g_mutex_unlock (playlist->mutex); }
/** * Shuffle the playlist. * */ static void xmms_playlist_client_shuffle (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err) { guint j,i; gint len, currpos; xmmsv_coll_t *plcoll; g_return_if_fail (playlist); g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist"); g_mutex_unlock (playlist->mutex); return; } currpos = xmms_playlist_coll_get_currpos (plcoll); len = xmms_playlist_coll_get_size (plcoll); if (len > 1) { /* put current at top and exclude from shuffling */ if (currpos != -1) { swap_entries (plcoll, 0, currpos); currpos = 0; xmms_collection_set_int_attr (plcoll, "position", currpos); } /* knuth <3 */ for (i = currpos + 1; i < len; i++) { j = g_random_int_range (i, len); if (i != j) { swap_entries (plcoll, i, j); } } } XMMS_PLAYLIST_CHANGED_MSG (XMMS_PLAYLIST_CHANGED_SHUFFLE, 0, plname); XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname); g_mutex_unlock (playlist->mutex); }
/** * Retrieve the currently active xmms_medialib_entry_t. * */ xmms_medialib_entry_t xmms_playlist_current_entry (xmms_playlist_t *playlist) { gint size, currpos; xmmsv_coll_t *plcoll; xmms_medialib_entry_t ent = 0; g_return_val_if_fail (playlist, 0); g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, NULL); if (plcoll == NULL) { /* FIXME: What happens? */ g_mutex_unlock (playlist->mutex); return 0; } currpos = xmms_playlist_coll_get_currpos (plcoll); size = xmms_playlist_coll_get_size (plcoll); if (currpos == -1 && (size > 0)) { currpos = 0; xmms_collection_set_int_attr (plcoll, "position", currpos); XMMS_PLAYLIST_CURRPOS_MSG (0, XMMS_ACTIVE_PLAYLIST); } if (currpos < size) { xmmsv_coll_idlist_get_index (plcoll, currpos, &ent); } else { ent = 0; } g_mutex_unlock (playlist->mutex); return ent; }
/** * Move an entry in playlist * */ static void xmms_playlist_client_move_entry (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, gint32 newpos, xmms_error_t *err) { xmmsv_t *dict; xmms_medialib_entry_t id; gint currpos, size; gint64 ipos, inewpos; xmmsv_coll_t *plcoll; g_return_if_fail (playlist); XMMS_DBG ("Moving %d, to %d", pos, newpos); g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { /* FIXME: happens ? */ g_mutex_unlock (playlist->mutex); return; } currpos = xmms_playlist_coll_get_currpos (plcoll); size = xmms_playlist_coll_get_size (plcoll); if (size == 0 || newpos > (size - 1)) { xmms_error_set (err, XMMS_ERROR_NOENT, "Cannot move entry outside playlist"); g_mutex_unlock (playlist->mutex); return; } if (!xmmsv_coll_idlist_move (plcoll, pos, newpos)) { xmms_error_set (err, XMMS_ERROR_NOENT, "Entry was not in list!"); g_mutex_unlock (playlist->mutex); return; } /* Update the current position pointer */ ipos = pos; inewpos = newpos; if (inewpos <= currpos && ipos > currpos) currpos++; else if (inewpos >= currpos && ipos < currpos) currpos--; else if (ipos == currpos) currpos = inewpos; xmms_collection_set_int_attr (plcoll, "position", currpos); xmmsv_coll_idlist_get_index (plcoll, newpos, &id); dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_MOVE, id, plname); xmmsv_dict_set_int (dict, "position", pos); xmmsv_dict_set_int (dict, "newposition", newpos); xmms_playlist_changed_msg_send (playlist, dict); XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname); g_mutex_unlock (playlist->mutex); return; }
/** Sorts the playlist by properties. * * This will sort the list. * @param playlist The playlist to sort. * @param properties Tells xmms_playlist_sort which properties it * should use when sorting. * @param err An #xmms_error_t - needed since xmms_playlist_sort is an ipc * method handler. */ static void xmms_playlist_client_sort (xmms_playlist_t *playlist, const gchar *plname, xmmsv_t *properties, xmms_error_t *err) { xmmsv_t *tmp, *idlist, *val, *spec, *metadata, *get; xmmsv_coll_t *plcoll, *ordered; gint currpos, pos; xmms_medialib_entry_t currid; g_return_if_fail (playlist); g_return_if_fail (properties); if (xmmsv_list_get_size (properties) < 1) { xmms_error_set (err, XMMS_ERROR_NOENT, "need at least one property to sort"); return; } g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist!"); g_mutex_unlock (playlist->mutex); return; } currpos = xmms_playlist_coll_get_currpos (plcoll); xmmsv_coll_idlist_get_index (plcoll, currpos, &currid); get = xmmsv_new_list (); xmmsv_list_append_string (get, "id"); metadata = xmmsv_new_dict (); xmmsv_dict_set_string (metadata, "type", "metadata"); xmmsv_dict_set_string (metadata, "aggregate", "first"); xmmsv_dict_set (metadata, "get", get); xmmsv_unref (get); spec = xmmsv_new_dict (); xmmsv_dict_set_string (spec, "type", "cluster-list"); xmmsv_dict_set_string (spec, "cluster-by", "position"); xmmsv_dict_set (spec, "data", metadata); xmmsv_unref (metadata); ordered = xmmsv_coll_add_order_operators (plcoll, properties); MEDIALIB_BEGIN (playlist->medialib); tmp = xmms_medialib_query (session, ordered, spec, err); MEDIALIB_COMMIT (); xmmsv_coll_unref (ordered); xmmsv_unref (spec); if (tmp == NULL) { g_mutex_unlock (playlist->mutex); return; } idlist = xmmsv_coll_idlist_get (plcoll); xmmsv_list_clear (idlist); for (pos = 0; xmmsv_list_get (tmp, pos, &val); pos++) { xmms_medialib_entry_t id; xmmsv_get_int (val, &id); xmmsv_list_append (idlist, val); if (id == currid) { xmms_collection_set_int_attr (plcoll, "position", pos); currpos = pos; } } xmmsv_unref (tmp); XMMS_PLAYLIST_CHANGED_MSG (XMMS_PLAYLIST_CHANGED_SORT, 0, plname); XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname); g_mutex_unlock (playlist->mutex); }
/** Sorts the playlist by properties. * * This will sort the list. * @param playlist The playlist to sort. * @param properties Tells xmms_playlist_sort which properties it * should use when sorting. * @param err An #xmms_error_t - needed since xmms_playlist_sort is an ipc * method handler. */ static void xmms_playlist_client_replace (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll, xmms_playlist_position_action_t action, xmms_error_t *err) { xmms_medialib_entry_t id, current_id; xmmsv_coll_t *plcoll; xmmsv_t *result; gint current_position, i; g_return_if_fail (playlist); g_return_if_fail (coll); g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist!"); g_mutex_unlock (playlist->mutex); return; } current_position = xmms_playlist_coll_get_currpos (plcoll); xmmsv_coll_idlist_get_index (plcoll, current_position, ¤t_id); result = xmms_collection_query_ids (playlist->colldag, coll, err); if (result == NULL) { g_mutex_unlock (playlist->mutex); return; } xmmsv_coll_idlist_clear (plcoll); current_position = -1; for (i = 0; xmmsv_list_get_int (result, i, &id); i++) { if (id == current_id) current_position = i; xmmsv_coll_idlist_append (plcoll, id); } switch (action) { case XMMS_PLAYLIST_CURRENT_ID_FORGET: current_position = -1; break; case XMMS_PLAYLIST_CURRENT_ID_MOVE_TO_FRONT: if (current_position > 0) { xmmsv_coll_idlist_move (plcoll, current_position, 0); current_position = 0; } break; default: break; } xmmsv_unref (result); xmms_collection_set_int_attr (plcoll, "position", current_position); XMMS_PLAYLIST_CHANGED_MSG (XMMS_PLAYLIST_CHANGED_REPLACE, (current_position < 0) ? 0 : current_id, plname); XMMS_PLAYLIST_CURRPOS_MSG (current_position, plname); g_mutex_unlock (playlist->mutex); }