/** * 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); }
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 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; }
/** * 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); }
/** * Add an entry to the playlist without locking the mutex. */ void xmms_playlist_add_entry_unlocked (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *plcoll, xmms_medialib_entry_t file, xmms_error_t *err) { gint prev_size; xmmsv_t *dict; prev_size = xmms_playlist_coll_get_size (plcoll); xmmsv_coll_idlist_append (plcoll, file); /** propagate the MID ! */ dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_ADD, file, plname); xmmsv_dict_set_int (dict, "position", prev_size); xmms_playlist_changed_msg_send (playlist, dict); }
static void xmms_playlist_update_partyshuffle (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll) { gint history, upcoming, currpos, size; xmmsv_coll_t *src; xmmsv_t *tmp; XMMS_DBG ("PLAYLIST: Update partyshuffle."); if (!xmms_collection_get_int_attr (coll, "history", &history)) { history = 0; } if (!xmms_collection_get_int_attr (coll, "upcoming", &upcoming)) { upcoming = XMMS_DEFAULT_PARTYSHUFFLE_UPCOMING; } currpos = xmms_playlist_coll_get_currpos (coll); while (currpos > history) { /* Removing entries is fast enough to be processed at once. */ xmms_playlist_remove_unlocked (playlist, plname, coll, 0, NULL); currpos = xmms_playlist_coll_get_currpos (coll); } g_return_if_fail(xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp)); g_return_if_fail(xmmsv_get_coll (tmp, &src)); /* Since getting random media can be slow on huge medialibs, we refill only * one entry at a time. This let other threads a chance to get the lock on * the playlist object as soon as possible. */ size = xmms_playlist_coll_get_size (coll); if (size < currpos + 1 + upcoming) { xmms_medialib_entry_t randentry; randentry = xmms_collection_get_random_media (playlist->colldag, src); if (randentry > 0) { xmms_playlist_add_entry_unlocked (playlist, plname, coll, randentry, NULL); } } }
/** * 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; }