static void xmms_playlist_client_load (xmms_playlist_t *playlist, const gchar *name, xmms_error_t *err) { xmmsv_coll_t *plcoll, *active_coll; if (strcmp (name, XMMS_ACTIVE_PLAYLIST) == 0) { xmms_error_set (err, XMMS_ERROR_INVAL, "invalid playlist to load"); return; } active_coll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err); if (active_coll == NULL) { xmms_error_set (err, XMMS_ERROR_GENERIC, "no active playlist"); return; } plcoll = xmms_playlist_get_coll (playlist, name, err); if (plcoll == NULL) { xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist"); return; } if (active_coll == plcoll) { XMMS_DBG ("Not loading %s playlist, already active!", name); return; } XMMS_DBG ("Loading new playlist! %s", name); xmms_collection_update_pointer (playlist->colldag, XMMS_ACTIVE_PLAYLIST, XMMS_COLLECTION_NSID_PLAYLISTS, plcoll); xmms_object_emit (XMMS_OBJECT (playlist), XMMS_IPC_SIGNAL_PLAYLIST_LOADED, xmmsv_new_string (name)); }
/** * Retrieve the position of the currently active xmms_medialib_entry_t * */ xmmsv_t * xmms_playlist_client_current_pos (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err) { guint32 pos; xmmsv_coll_t *plcoll; xmmsv_t *dict; g_return_val_if_fail (playlist, 0); g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { g_mutex_unlock (playlist->mutex); xmms_error_set (err, XMMS_ERROR_INVAL, "no such playlist"); return 0; } pos = xmms_playlist_coll_get_currpos (plcoll); if (pos == -1) { xmms_error_set (err, XMMS_ERROR_GENERIC, "no current entry"); } g_mutex_unlock (playlist->mutex); dict = xmms_playlist_current_pos_msg_new (playlist, pos, plname); return dict; }
/** * Retrieve a copy of the name of the currently active playlist. * */ static gchar * xmms_playlist_client_current_active (xmms_playlist_t *playlist, xmms_error_t *err) { gchar *alias = NULL; xmmsv_coll_t *active_coll; g_return_val_if_fail (playlist, 0); g_mutex_lock (playlist->mutex); active_coll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err); if (active_coll != NULL) { alias = xmms_collection_find_alias (playlist->colldag, XMMS_COLLECTION_NSID_PLAYLISTS, active_coll, XMMS_ACTIVE_PLAYLIST); if (alias == NULL) { xmms_error_set (err, XMMS_ERROR_GENERIC, "active playlist not referenced!"); } } else { xmms_error_set (err, XMMS_ERROR_GENERIC, "no active playlist"); } g_mutex_unlock (playlist->mutex); return alias; }
/** List a playlist */ static GList * xmms_playlist_client_list_entries (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err) { GList *entries = NULL; xmmsv_coll_t *plcoll; xmms_medialib_entry_t entry; xmmsv_list_iter_t *it; g_return_val_if_fail (playlist, NULL); g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { g_mutex_unlock (playlist->mutex); return NULL; } xmmsv_get_list_iter (xmmsv_coll_idlist_get (plcoll), &it); for (xmmsv_list_iter_first (it); xmmsv_list_iter_valid (it); xmmsv_list_iter_next (it)) { xmmsv_list_iter_entry_int (it, &entry); entries = g_list_prepend (entries, xmmsv_new_int (entry)); } xmmsv_list_iter_explicit_destroy (it); g_mutex_unlock (playlist->mutex); entries = g_list_reverse (entries); return entries; }
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); }
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; }
/** * Add an entry to the playlist without validating it. * * @internal */ void xmms_playlist_add_entry (xmms_playlist_t *playlist, const gchar *plname, xmms_medialib_entry_t file, xmms_error_t *err) { xmmsv_coll_t *plcoll; g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll != NULL) { xmms_playlist_add_entry_unlocked (playlist, plname, plcoll, file, err); } g_mutex_unlock (playlist->mutex); }
/** * Remove an entry from playlist. * */ void xmms_playlist_client_remove_entry (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, xmms_error_t *err) { 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_playlist_remove_unlocked (playlist, plname, plcoll, pos, err); } g_mutex_unlock (playlist->mutex); }
static void xmms_playlist_update_unlocked (xmms_playlist_t *playlist, const gchar *plname) { xmmsv_coll_t *plcoll; const gchar *type = NULL; plcoll = xmms_playlist_get_coll (playlist, plname, NULL); if (plcoll) { xmmsv_coll_attribute_get (plcoll, "type", &type); if (g_strcmp0 (type, "queue") == 0) { xmms_playlist_update_queue (playlist, plname, plcoll); } else if (g_strcmp0 (type, "pshuffle") == 0) { xmms_playlist_update_partyshuffle (playlist, plname, plcoll); } } }
/** * 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); }
static gint xmms_playlist_client_set_next_rel (xmms_playlist_t *playlist, gint32 pos, xmms_error_t *err) { gint currpos, newpos, size; xmms_medialib_entry_t mid = 0; xmmsv_coll_t *plcoll; g_return_val_if_fail (playlist, FALSE); g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err); if (plcoll != NULL) { currpos = xmms_playlist_coll_get_currpos (plcoll); if (playlist->repeat_all) { newpos = pos + currpos; size = (gint) xmmsv_coll_idlist_get_size (plcoll); if (size > 0) { newpos %= size; if (newpos < 0) { newpos += size; } } mid = xmms_playlist_set_current_position_do (playlist, newpos, err); } else { if (currpos + pos >= 0) { mid = xmms_playlist_set_current_position_do (playlist, currpos + pos, err); } else { xmms_error_set (err, XMMS_ERROR_INVAL, "Can't set pos outside the current playlist!"); } } } g_mutex_unlock (playlist->mutex); return mid; }
/** Clear the playlist */ static void xmms_playlist_client_clear (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err) { 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) { g_mutex_unlock (playlist->mutex); return; } xmmsv_coll_idlist_clear (plcoll); xmms_collection_set_int_attr (plcoll, "position", -1); XMMS_PLAYLIST_CHANGED_MSG (XMMS_PLAYLIST_CHANGED_CLEAR, 0, 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; }
/** 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); }
/** * 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_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); }