00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <unistd.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <glib.h>
00027 #include <math.h>
00028 #include <ctype.h>
00029
00030 #include "xmmspriv/xmms_playlist.h"
00031 #include "xmms/xmms_ipc.h"
00032 #include "xmms/xmms_config.h"
00033 #include "xmmspriv/xmms_medialib.h"
00034 #include "xmmspriv/xmms_collection.h"
00035 #include "xmms/xmms_log.h"
00036
00037
00038
00039
00040
00041
00042
00043
00044 static void xmms_playlist_destroy (xmms_object_t *object);
00045 static void xmms_playlist_client_shuffle (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err);
00046 static void xmms_playlist_client_clear (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err);
00047 static void xmms_playlist_client_sort (xmms_playlist_t *playlist, const gchar *plname, xmmsv_t *property, xmms_error_t *err);
00048 static GList * xmms_playlist_client_list_entries (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err);
00049 static gchar *xmms_playlist_client_current_active (xmms_playlist_t *playlist, xmms_error_t *err);
00050 static void xmms_playlist_destroy (xmms_object_t *object);
00051
00052 static void xmms_playlist_client_add_id (xmms_playlist_t *playlist, const gchar *plname, xmms_medialib_entry_t file, xmms_error_t *error);
00053 static void xmms_playlist_client_add_url (xmms_playlist_t *playlist, const gchar *plname, const gchar *nurl, xmms_error_t *err);
00054 static void xmms_playlist_client_add_idlist (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll, xmms_error_t *err);
00055 static void xmms_playlist_client_add_collection (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll, xmmsv_t *order, xmms_error_t *err);
00056 static GTree * xmms_playlist_client_current_pos (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err);
00057 static gint xmms_playlist_client_set_next (xmms_playlist_t *playlist, gint32 pos, xmms_error_t *error);
00058 static void xmms_playlist_client_remove_entry (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, xmms_error_t *err);
00059 static gboolean xmms_playlist_remove_unlocked (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *plcoll, guint pos, xmms_error_t *err);
00060 static void xmms_playlist_client_move_entry (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, gint32 newpos, xmms_error_t *err);
00061 static gint xmms_playlist_client_set_next_rel (xmms_playlist_t *playlist, gint32 pos, xmms_error_t *error);
00062 static gint xmms_playlist_set_current_position_do (xmms_playlist_t *playlist, guint32 pos, xmms_error_t *err);
00063
00064 static void xmms_playlist_client_insert_url (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, const gchar *url, xmms_error_t *error);
00065 static void xmms_playlist_client_insert_id (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, xmms_medialib_entry_t file, xmms_error_t *error);
00066 static void xmms_playlist_client_insert_collection (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, xmmsv_coll_t *coll, xmmsv_t *order, xmms_error_t *error);
00067 static void xmms_playlist_client_radd (xmms_playlist_t *playlist, const gchar *plname, const gchar *path, xmms_error_t *error);
00068 static void xmms_playlist_client_rinsert (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, const gchar *path, xmms_error_t *error);
00069
00070 static void xmms_playlist_client_load (xmms_playlist_t *, const gchar *, xmms_error_t *);
00071
00072 static xmmsv_coll_t *xmms_playlist_get_coll (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *error);
00073 static const gchar *xmms_playlist_canonical_name (xmms_playlist_t *playlist, const gchar *plname);
00074 static gint xmms_playlist_coll_get_currpos (xmmsv_coll_t *plcoll);
00075 static gint xmms_playlist_coll_get_size (xmmsv_coll_t *plcoll);
00076
00077 static void xmms_playlist_update_queue (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll);
00078 static void xmms_playlist_update_partyshuffle (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll);
00079 static void xmms_playlist_register_ipc_commands (xmms_object_t *playlist_object);
00080
00081 static void xmms_playlist_current_pos_msg_send (xmms_playlist_t *playlist, GTree *dict);
00082 static GTree * xmms_playlist_current_pos_msg_new (xmms_playlist_t *playlist, guint32 pos, const gchar *plname);
00083
00084 #define XMMS_PLAYLIST_CHANGED_MSG(type, id, name) xmms_playlist_changed_msg_send (playlist, xmms_playlist_changed_msg_new (playlist, type, id, name))
00085 #define XMMS_PLAYLIST_CURRPOS_MSG(pos, name) xmms_playlist_current_pos_msg_send (playlist, xmms_playlist_current_pos_msg_new (playlist, pos, name))
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 struct xmms_playlist_St {
00099 xmms_object_t object;
00100
00101
00102 xmms_coll_dag_t *colldag;
00103
00104 gboolean repeat_one;
00105 gboolean repeat_all;
00106
00107 GMutex *mutex;
00108
00109 xmms_mediainfo_reader_t *mediainfordr;
00110
00111 gboolean update_flag;
00112 xmms_medialib_t *medialib;
00113 };
00114
00115 #include "playlist_ipc.c"
00116
00117 static void
00118 on_playlist_r_all_changed (xmms_object_t *object, xmmsv_t *_data,
00119 gpointer udata)
00120 {
00121 xmms_playlist_t *playlist = udata;
00122 gint value;
00123
00124 value = xmms_config_property_get_int ((xmms_config_property_t *) object);
00125
00126 g_mutex_lock (playlist->mutex);
00127 playlist->repeat_all = !!value;
00128 g_mutex_unlock (playlist->mutex);
00129 }
00130
00131 static void
00132 on_playlist_r_one_changed (xmms_object_t *object, xmmsv_t *_data,
00133 gpointer udata)
00134 {
00135 xmms_playlist_t *playlist = udata;
00136 gint value;
00137
00138 value = xmms_config_property_get_int ((xmms_config_property_t *) object);
00139
00140 g_mutex_lock (playlist->mutex);
00141 playlist->repeat_one = !!value;
00142 g_mutex_unlock (playlist->mutex);
00143 }
00144
00145
00146 static void
00147 on_playlist_updated (xmms_object_t *object, const gchar *plname)
00148 {
00149 xmmsv_coll_t *plcoll;
00150 xmms_playlist_t *playlist = (xmms_playlist_t*)object;
00151
00152
00153 if (playlist->update_flag) {
00154 return;
00155 }
00156
00157 plcoll = xmms_playlist_get_coll (playlist, plname, NULL);
00158 if (plcoll == NULL) {
00159 return;
00160 } else {
00161
00162 switch (xmmsv_coll_get_type (plcoll)) {
00163 case XMMS_COLLECTION_TYPE_QUEUE:
00164 xmms_playlist_update_queue (playlist, plname, plcoll);
00165 break;
00166
00167 case XMMS_COLLECTION_TYPE_PARTYSHUFFLE:
00168 xmms_playlist_update_partyshuffle (playlist, plname, plcoll);
00169 break;
00170
00171 default:
00172 break;
00173 }
00174 }
00175 }
00176
00177 static void
00178 on_playlist_updated_pos (xmms_object_t *object, xmmsv_t *val, gpointer udata)
00179 {
00180 XMMS_DBG ("PLAYLIST: updated pos!");
00181 on_playlist_updated (object, XMMS_ACTIVE_PLAYLIST);
00182 }
00183
00184 static void
00185 on_playlist_updated_chg (xmms_object_t *object, xmmsv_t *val, gpointer udata)
00186 {
00187 const gchar *plname = NULL;
00188 xmmsv_t *pl_val;
00189
00190 XMMS_DBG ("PLAYLIST: updated chg!");
00191
00192 xmmsv_dict_get (val, "name", &pl_val);
00193 if (pl_val != NULL) {
00194 xmmsv_get_string (pl_val, &plname);
00195 } else {
00196
00197 XMMS_DBG ("PLAYLIST: updated_chg, NULL playlist!");
00198 g_assert_not_reached ();
00199 }
00200
00201 on_playlist_updated (object, plname);
00202 }
00203
00204 static void
00205 xmms_playlist_update_queue (xmms_playlist_t *playlist, const gchar *plname,
00206 xmmsv_coll_t *coll)
00207 {
00208 gint history, currpos;
00209
00210 XMMS_DBG ("PLAYLIST: update-queue!");
00211
00212 if (!xmms_collection_get_int_attr (coll, "history", &history)) {
00213 history = 0;
00214 }
00215
00216 playlist->update_flag = TRUE;
00217 currpos = xmms_playlist_coll_get_currpos (coll);
00218 while (currpos > history) {
00219 xmms_playlist_remove_unlocked (playlist, plname, coll, 0, NULL);
00220 currpos = xmms_playlist_coll_get_currpos (coll);
00221 }
00222 playlist->update_flag = FALSE;
00223 }
00224
00225 static void
00226 xmms_playlist_update_partyshuffle (xmms_playlist_t *playlist,
00227 const gchar *plname, xmmsv_coll_t *coll)
00228 {
00229 gint history, upcoming, currpos, size;
00230 xmmsv_coll_t *src;
00231 xmmsv_t *tmp;
00232
00233 XMMS_DBG ("PLAYLIST: update-partyshuffle!");
00234
00235 if (!xmms_collection_get_int_attr (coll, "history", &history)) {
00236 history = 0;
00237 }
00238
00239 if (!xmms_collection_get_int_attr (coll, "upcoming", &upcoming)) {
00240 upcoming = XMMS_DEFAULT_PARTYSHUFFLE_UPCOMING;
00241 }
00242
00243 playlist->update_flag = TRUE;
00244 currpos = xmms_playlist_coll_get_currpos (coll);
00245 while (currpos > history) {
00246 xmms_playlist_remove_unlocked (playlist, plname, coll, 0, NULL);
00247 currpos = xmms_playlist_coll_get_currpos (coll);
00248 }
00249
00250 if (!xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp)) {
00251 XMMS_DBG ("Cannot find party shuffle operand!");
00252 return;
00253 }
00254 xmmsv_get_coll (tmp, &src);
00255
00256 currpos = xmms_playlist_coll_get_currpos (coll);
00257 size = xmms_playlist_coll_get_size (coll);
00258 while (size < currpos + 1 + upcoming) {
00259 xmms_medialib_entry_t randentry;
00260 randentry = xmms_collection_get_random_media (playlist->colldag, src);
00261 if (randentry == 0) {
00262 break;
00263 }
00264
00265 xmms_playlist_add_entry_unlocked (playlist, plname, coll, randentry, NULL);
00266
00267 currpos = xmms_playlist_coll_get_currpos (coll);
00268 size = xmms_playlist_coll_get_size (coll);
00269 }
00270 playlist->update_flag = FALSE;
00271 }
00272
00273
00274
00275
00276 xmms_playlist_t *
00277 xmms_playlist_init (void)
00278 {
00279 xmms_playlist_t *ret;
00280 xmms_config_property_t *val;
00281
00282 ret = xmms_object_new (xmms_playlist_t, xmms_playlist_destroy);
00283 ret->mutex = g_mutex_new ();
00284
00285 xmms_playlist_register_ipc_commands (XMMS_OBJECT (ret));
00286
00287 val = xmms_config_property_register ("playlist.repeat_one", "0",
00288 on_playlist_r_one_changed, ret);
00289 ret->repeat_one = xmms_config_property_get_int (val);
00290
00291 val = xmms_config_property_register ("playlist.repeat_all", "0",
00292 on_playlist_r_all_changed, ret);
00293 ret->repeat_all = xmms_config_property_get_int (val);
00294
00295 ret->update_flag = FALSE;
00296
00297 xmms_object_connect (XMMS_OBJECT (ret),
00298 XMMS_IPC_SIGNAL_PLAYLIST_CHANGED,
00299 on_playlist_updated_chg, ret);
00300
00301 xmms_object_connect (XMMS_OBJECT (ret),
00302 XMMS_IPC_SIGNAL_PLAYLIST_CURRENT_POS,
00303 on_playlist_updated_pos, ret);
00304
00305
00306 ret->medialib = xmms_medialib_init (ret);
00307 ret->colldag = xmms_collection_init (ret);
00308 ret->mediainfordr = xmms_mediainfo_reader_start ();
00309
00310 return ret;
00311 }
00312
00313 static gboolean
00314 xmms_playlist_advance_do (xmms_playlist_t *playlist)
00315 {
00316 gint size, currpos;
00317 gboolean ret = TRUE;
00318 xmmsv_coll_t *plcoll;
00319 char *jumplist;
00320 xmms_error_t err;
00321 xmms_playlist_t *buffer = playlist;
00322 guint newpos;
00323
00324 xmms_error_reset (&err);
00325
00326 plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, NULL);
00327 if (plcoll == NULL) {
00328 ret = FALSE;
00329 } else if ((size = xmms_playlist_coll_get_size (plcoll)) == 0) {
00330 if (xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) {
00331 xmms_playlist_client_load (buffer, jumplist, &err);
00332 if (xmms_error_isok (&err)) {
00333 ret = xmms_playlist_advance_do (playlist);
00334 } else {
00335 ret = FALSE;
00336 }
00337 } else {
00338 ret = FALSE;
00339 }
00340 } else if (!playlist->repeat_one) {
00341 currpos = xmms_playlist_coll_get_currpos (plcoll);
00342 currpos++;
00343
00344 if (currpos == size && !playlist->repeat_all &&
00345 xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) {
00346
00347 xmms_collection_set_int_attr (plcoll, "position", -1);
00348 XMMS_PLAYLIST_CURRPOS_MSG (-1, XMMS_ACTIVE_PLAYLIST);
00349
00350 xmms_playlist_client_load (buffer, jumplist, &err);
00351 if (xmms_error_isok (&err)) {
00352 ret = xmms_playlist_advance_do (playlist);
00353 } else {
00354 ret = FALSE;
00355 }
00356 } else {
00357 newpos = currpos%size;
00358 xmms_collection_set_int_attr (plcoll, "position", newpos);
00359 XMMS_PLAYLIST_CURRPOS_MSG (newpos, XMMS_ACTIVE_PLAYLIST);
00360 ret = (currpos != size) || playlist->repeat_all;
00361 }
00362 }
00363
00364 return ret;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 gboolean
00376 xmms_playlist_advance (xmms_playlist_t *playlist)
00377 {
00378 gboolean ret;
00379
00380 g_return_val_if_fail (playlist, FALSE);
00381
00382 g_mutex_lock (playlist->mutex);
00383 ret = xmms_playlist_advance_do (playlist);
00384 g_mutex_unlock (playlist->mutex);
00385
00386 return ret;
00387 }
00388
00389
00390
00391
00392
00393 xmms_medialib_entry_t
00394 xmms_playlist_current_entry (xmms_playlist_t *playlist)
00395 {
00396 gint size, currpos;
00397 xmmsv_coll_t *plcoll;
00398 xmms_medialib_entry_t ent = 0;
00399
00400 g_return_val_if_fail (playlist, 0);
00401
00402 g_mutex_lock (playlist->mutex);
00403
00404 plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, NULL);
00405 if (plcoll == NULL) {
00406
00407 g_mutex_unlock (playlist->mutex);
00408 return 0;
00409 }
00410
00411 currpos = xmms_playlist_coll_get_currpos (plcoll);
00412 size = xmms_playlist_coll_get_size (plcoll);
00413
00414 if (currpos == -1 && (size > 0)) {
00415 currpos = 0;
00416 xmms_collection_set_int_attr (plcoll, "position", currpos);
00417 XMMS_PLAYLIST_CURRPOS_MSG (0, XMMS_ACTIVE_PLAYLIST);
00418 }
00419
00420 if (currpos < size) {
00421 xmmsv_coll_idlist_get_index (plcoll, currpos, &ent);
00422 } else {
00423 ent = 0;
00424 }
00425
00426 g_mutex_unlock (playlist->mutex);
00427
00428 return ent;
00429 }
00430
00431
00432
00433
00434
00435
00436 GTree *
00437 xmms_playlist_client_current_pos (xmms_playlist_t *playlist, const gchar *plname,
00438 xmms_error_t *err)
00439 {
00440 guint32 pos;
00441 xmmsv_coll_t *plcoll;
00442 GTree *dict;
00443
00444 g_return_val_if_fail (playlist, 0);
00445
00446 g_mutex_lock (playlist->mutex);
00447
00448 plcoll = xmms_playlist_get_coll (playlist, plname, err);
00449 if (plcoll == NULL) {
00450 g_mutex_unlock (playlist->mutex);
00451 xmms_error_set (err, XMMS_ERROR_INVAL, "no such playlist");
00452 return 0;
00453 }
00454
00455 pos = xmms_playlist_coll_get_currpos (plcoll);
00456 if (pos == -1) {
00457 xmms_error_set (err, XMMS_ERROR_GENERIC, "no current entry");
00458 }
00459
00460 g_mutex_unlock (playlist->mutex);
00461
00462 dict = xmms_playlist_current_pos_msg_new (playlist, pos, plname);
00463
00464 return dict;
00465 }
00466
00467
00468
00469
00470
00471 static gchar *
00472 xmms_playlist_client_current_active (xmms_playlist_t *playlist, xmms_error_t *err)
00473 {
00474 gchar *name = NULL;
00475 xmmsv_coll_t *active_coll;
00476
00477 g_return_val_if_fail (playlist, 0);
00478
00479 g_mutex_lock (playlist->mutex);
00480
00481 active_coll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
00482 if (active_coll != NULL) {
00483 const gchar *alias;
00484
00485 alias = xmms_collection_find_alias (playlist->colldag,
00486 XMMS_COLLECTION_NSID_PLAYLISTS,
00487 active_coll, XMMS_ACTIVE_PLAYLIST);
00488 if (alias == NULL) {
00489 xmms_error_set (err, XMMS_ERROR_GENERIC, "active playlist not referenced!");
00490 } else {
00491 name = g_strdup (alias);
00492 }
00493 } else {
00494 xmms_error_set (err, XMMS_ERROR_GENERIC, "no active playlist");
00495 }
00496
00497 g_mutex_unlock (playlist->mutex);
00498
00499 return name;
00500 }
00501
00502
00503 static void
00504 xmms_playlist_client_load (xmms_playlist_t *playlist, const gchar *name, xmms_error_t *err)
00505 {
00506 xmmsv_coll_t *plcoll, *active_coll;
00507
00508 if (strcmp (name, XMMS_ACTIVE_PLAYLIST) == 0) {
00509 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid playlist to load");
00510 return;
00511 }
00512
00513 active_coll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
00514 if (active_coll == NULL) {
00515 xmms_error_set (err, XMMS_ERROR_GENERIC, "no active playlist");
00516 return;
00517 }
00518
00519 plcoll = xmms_playlist_get_coll (playlist, name, err);
00520 if (plcoll == NULL) {
00521 xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist");
00522 return;
00523 }
00524
00525 if (active_coll == plcoll) {
00526 XMMS_DBG ("Not loading %s playlist, already active!", name);
00527 return;
00528 }
00529
00530 XMMS_DBG ("Loading new playlist! %s", name);
00531 xmms_collection_update_pointer (playlist->colldag, XMMS_ACTIVE_PLAYLIST,
00532 XMMS_COLLECTION_NSID_PLAYLISTS, plcoll);
00533
00534 xmms_object_emit_f (XMMS_OBJECT (playlist),
00535 XMMS_IPC_SIGNAL_PLAYLIST_LOADED,
00536 XMMSV_TYPE_STRING,
00537 name);
00538 }
00539
00540 static inline void
00541 swap_entries (xmmsv_coll_t *coll, gint i, gint j)
00542 {
00543 xmms_medialib_entry_t tmp, tmp2;
00544
00545 xmmsv_coll_idlist_get_index (coll, i, &tmp);
00546 xmmsv_coll_idlist_get_index (coll, j, &tmp2);
00547
00548 xmmsv_coll_idlist_set_index (coll, i, tmp2);
00549 xmmsv_coll_idlist_set_index (coll, j, tmp);
00550 }
00551
00552
00553
00554
00555
00556
00557 static void
00558 xmms_playlist_client_shuffle (xmms_playlist_t *playlist, const gchar *plname,
00559 xmms_error_t *err)
00560 {
00561 guint j,i;
00562 gint len, currpos;
00563 xmmsv_coll_t *plcoll;
00564
00565 g_return_if_fail (playlist);
00566
00567 g_mutex_lock (playlist->mutex);
00568
00569 plcoll = xmms_playlist_get_coll (playlist, plname, err);
00570 if (plcoll == NULL) {
00571 xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist");
00572 g_mutex_unlock (playlist->mutex);
00573 return;
00574 }
00575
00576 currpos = xmms_playlist_coll_get_currpos (plcoll);
00577 len = xmms_playlist_coll_get_size (plcoll);
00578 if (len > 1) {
00579
00580 if (currpos != -1) {
00581 swap_entries (plcoll, 0, currpos);
00582 currpos = 0;
00583 xmms_collection_set_int_attr (plcoll, "position", currpos);
00584 }
00585
00586
00587 for (i = currpos + 1; i < len; i++) {
00588 j = g_random_int_range (i, len);
00589
00590 if (i != j) {
00591 swap_entries (plcoll, i, j);
00592 }
00593 }
00594
00595 }
00596
00597 XMMS_PLAYLIST_CHANGED_MSG (XMMS_PLAYLIST_CHANGED_SHUFFLE, 0, plname);
00598 XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
00599
00600 g_mutex_unlock (playlist->mutex);
00601 }
00602
00603 static gboolean
00604 xmms_playlist_remove_unlocked (xmms_playlist_t *playlist, const gchar *plname,
00605 xmmsv_coll_t *plcoll, guint pos, xmms_error_t *err)
00606 {
00607 gint currpos;
00608 GTree *dict;
00609
00610 g_return_val_if_fail (playlist, FALSE);
00611
00612 currpos = xmms_playlist_coll_get_currpos (plcoll);
00613
00614 if (!xmmsv_coll_idlist_remove (plcoll, pos)) {
00615 if (err) xmms_error_set (err, XMMS_ERROR_NOENT, "Entry was not in list!");
00616 return FALSE;
00617 }
00618
00619 dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_REMOVE, 0, plname);
00620 g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (pos));
00621 xmms_playlist_changed_msg_send (playlist, dict);
00622
00623
00624
00625
00626 if (currpos != -1 && pos <= currpos) {
00627 currpos--;
00628 xmms_collection_set_int_attr (plcoll, "position", currpos);
00629 XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
00630 }
00631
00632 return TRUE;
00633 }
00634
00635 typedef struct {
00636 xmms_playlist_t *pls;
00637 xmms_medialib_entry_t entry;
00638 } playlist_remove_info_t;
00639
00640 static void
00641 remove_from_playlist (gpointer key, gpointer value, gpointer udata)
00642 {
00643 playlist_remove_info_t *rminfo = (playlist_remove_info_t *) udata;
00644 guint32 i;
00645 xmms_medialib_entry_t val;
00646 gint size;
00647 xmmsv_coll_t *plcoll = (xmmsv_coll_t *) value;
00648
00649 size = xmms_playlist_coll_get_size (plcoll);
00650 for (i = 0; i < size; i++) {
00651 if (xmmsv_coll_idlist_get_index (plcoll, i, &val) && val == rminfo->entry) {
00652 XMMS_DBG ("removing entry on pos %d in %s", i, (gchar *)key);
00653 xmms_playlist_remove_unlocked (rminfo->pls, (gchar *)key, plcoll, i, NULL);
00654 i--;
00655 }
00656 }
00657 }
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669 gboolean
00670 xmms_playlist_remove_by_entry (xmms_playlist_t *playlist,
00671 xmms_medialib_entry_t entry)
00672 {
00673 playlist_remove_info_t rminfo;
00674 g_return_val_if_fail (playlist, FALSE);
00675
00676 g_mutex_lock (playlist->mutex);
00677
00678 rminfo.pls = playlist;
00679 rminfo.entry = entry;
00680
00681 xmms_collection_foreach_in_namespace (playlist->colldag,
00682 XMMS_COLLECTION_NSID_PLAYLISTS,
00683 remove_from_playlist, &rminfo);
00684
00685 g_mutex_unlock (playlist->mutex);
00686
00687 return TRUE;
00688 }
00689
00690
00691
00692
00693
00694 void
00695 xmms_playlist_client_remove_entry (xmms_playlist_t *playlist,
00696 const gchar *plname,
00697 gint32 pos, xmms_error_t *err)
00698 {
00699 gboolean ret = FALSE;
00700 xmmsv_coll_t *plcoll;
00701
00702 g_return_if_fail (playlist);
00703
00704 g_mutex_lock (playlist->mutex);
00705 plcoll = xmms_playlist_get_coll (playlist, plname, err);
00706 if (plcoll != NULL) {
00707 ret = xmms_playlist_remove_unlocked (playlist, plname, plcoll, pos, err);
00708 }
00709 g_mutex_unlock (playlist->mutex);
00710 }
00711
00712
00713
00714
00715
00716
00717 static void
00718 xmms_playlist_client_move_entry (xmms_playlist_t *playlist,
00719 const gchar *plname, gint32 pos,
00720 gint32 newpos, xmms_error_t *err)
00721 {
00722 GTree *dict;
00723 xmms_medialib_entry_t id;
00724 gint currpos, size;
00725 gint64 ipos, inewpos;
00726 xmmsv_coll_t *plcoll;
00727
00728 g_return_if_fail (playlist);
00729
00730 XMMS_DBG ("Moving %d, to %d", pos, newpos);
00731
00732 g_mutex_lock (playlist->mutex);
00733
00734 plcoll = xmms_playlist_get_coll (playlist, plname, err);
00735 if (plcoll == NULL) {
00736
00737 g_mutex_unlock (playlist->mutex);
00738 return;
00739 }
00740
00741 currpos = xmms_playlist_coll_get_currpos (plcoll);
00742 size = xmms_playlist_coll_get_size (plcoll);
00743
00744 if (size == 0 || newpos > (size - 1)) {
00745 xmms_error_set (err, XMMS_ERROR_NOENT,
00746 "Cannot move entry outside playlist");
00747 g_mutex_unlock (playlist->mutex);
00748 return;
00749 }
00750
00751 if (!xmmsv_coll_idlist_move (plcoll, pos, newpos)) {
00752 xmms_error_set (err, XMMS_ERROR_NOENT, "Entry was not in list!");
00753 g_mutex_unlock (playlist->mutex);
00754 return;
00755 }
00756
00757
00758 ipos = pos;
00759 inewpos = newpos;
00760 if (inewpos <= currpos && ipos > currpos)
00761 currpos++;
00762 else if (inewpos >= currpos && ipos < currpos)
00763 currpos--;
00764 else if (ipos == currpos)
00765 currpos = inewpos;
00766
00767 xmms_collection_set_int_attr (plcoll, "position", currpos);
00768
00769 xmmsv_coll_idlist_get_index (plcoll, newpos, &id);
00770
00771 dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_MOVE, id, plname);
00772 g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (pos));
00773 g_tree_insert (dict, (gpointer) "newposition", xmmsv_new_int (newpos));
00774 xmms_playlist_changed_msg_send (playlist, dict);
00775
00776 XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
00777
00778 g_mutex_unlock (playlist->mutex);
00779
00780 return;
00781
00782 }
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796 static void
00797 xmms_playlist_client_insert_url (xmms_playlist_t *playlist, const gchar *plname,
00798 gint32 pos, const gchar *url, xmms_error_t *err)
00799 {
00800 xmms_medialib_entry_t entry = 0;
00801 xmms_medialib_session_t *session = xmms_medialib_begin_write ();
00802
00803 entry = xmms_medialib_entry_new_encoded (session, url, err);
00804 xmms_medialib_end (session);
00805
00806 if (!entry) {
00807 return;
00808 }
00809
00810 xmms_playlist_client_insert_id (playlist, plname, pos, entry, err);
00811 }
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 static void
00825 xmms_playlist_client_rinsert (xmms_playlist_t *playlist, const gchar *plname, gint32 pos,
00826 const gchar *path, xmms_error_t *err)
00827 {
00828
00829
00830
00831 xmms_medialib_insert_recursive (playlist->medialib, plname, pos, path, err);
00832 }
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843 static void
00844 xmms_playlist_client_insert_id (xmms_playlist_t *playlist, const gchar *plname,
00845 gint32 pos, xmms_medialib_entry_t file,
00846 xmms_error_t *err)
00847 {
00848 if (!xmms_medialib_check_id (file)) {
00849 xmms_error_set (err, XMMS_ERROR_NOENT,
00850 "That is not a valid medialib id!");
00851 return;
00852 }
00853
00854 xmms_playlist_insert_entry (playlist, plname, pos, file, err);
00855 }
00856
00857 static void
00858 xmms_playlist_client_insert_collection (xmms_playlist_t *playlist, const gchar *plname,
00859 gint32 pos, xmmsv_coll_t *coll,
00860 xmmsv_t *order, xmms_error_t *err)
00861 {
00862 GList *res;
00863
00864 res = xmms_collection_query_ids (playlist->colldag, coll, 0, 0, order, err);
00865
00866 while (res) {
00867 xmmsv_t *val = (xmmsv_t*) res->data;
00868 gint id;
00869 xmmsv_get_int (val, &id);
00870 xmms_playlist_client_insert_id (playlist, plname, pos, id, err);
00871 xmmsv_unref (val);
00872
00873 res = g_list_delete_link (res, res);
00874 pos++;
00875 }
00876
00877 }
00878
00879
00880
00881
00882
00883
00884
00885 void
00886 xmms_playlist_insert_entry (xmms_playlist_t *playlist, const gchar *plname,
00887 guint32 pos, xmms_medialib_entry_t file,
00888 xmms_error_t *err)
00889 {
00890 GTree *dict;
00891 gint currpos;
00892 gint len;
00893 xmmsv_coll_t *plcoll;
00894
00895 g_mutex_lock (playlist->mutex);
00896
00897 plcoll = xmms_playlist_get_coll (playlist, plname, err);
00898 if (plcoll == NULL) {
00899
00900 g_mutex_unlock (playlist->mutex);
00901 return;
00902 }
00903
00904 len = xmms_playlist_coll_get_size (plcoll);
00905 if (pos > len) {
00906 xmms_error_set (err, XMMS_ERROR_GENERIC,
00907 "Could not insert entry outside of playlist!");
00908 g_mutex_unlock (playlist->mutex);
00909 return;
00910 }
00911 xmmsv_coll_idlist_insert (plcoll, pos, file);
00912
00913
00914 dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_INSERT, file, plname);
00915 g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (pos));
00916 xmms_playlist_changed_msg_send (playlist, dict);
00917
00918
00919 currpos = xmms_playlist_coll_get_currpos (plcoll);
00920 if (pos <= currpos) {
00921 currpos++;
00922 xmms_collection_set_int_attr (plcoll, "position", currpos);
00923 XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
00924 }
00925
00926 g_mutex_unlock (playlist->mutex);
00927 }
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940 void
00941 xmms_playlist_client_add_url (xmms_playlist_t *playlist, const gchar *plname,
00942 const gchar *nurl, xmms_error_t *err)
00943 {
00944 xmms_medialib_entry_t entry = 0;
00945 xmms_medialib_session_t *session = xmms_medialib_begin_write ();
00946
00947 entry = xmms_medialib_entry_new_encoded (session, nurl, err);
00948 xmms_medialib_end (session);
00949
00950 if (entry) {
00951 xmms_playlist_add_entry (playlist, plname, entry, err);
00952 }
00953
00954 }
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966 static void
00967 xmms_playlist_client_radd (xmms_playlist_t *playlist, const gchar *plname,
00968 const gchar *path, xmms_error_t *err)
00969 {
00970
00971
00972
00973 xmms_medialib_add_recursive (playlist->medialib, plname, path, err);
00974 }
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989 void
00990 xmms_playlist_client_add_id (xmms_playlist_t *playlist, const gchar *plname,
00991 xmms_medialib_entry_t file, xmms_error_t *err)
00992 {
00993 if (!xmms_medialib_check_id (file)) {
00994 xmms_error_set (err, XMMS_ERROR_NOENT,
00995 "That is not a valid medialib id!");
00996 return;
00997 }
00998
00999 xmms_playlist_add_entry (playlist, plname, file, err);
01000 }
01001
01002 void
01003 xmms_playlist_client_add_idlist (xmms_playlist_t *playlist,
01004 const gchar *plname,
01005 xmmsv_coll_t *coll, xmms_error_t *err)
01006 {
01007 xmms_medialib_entry_t entry;
01008 xmmsv_list_iter_t *it;
01009
01010 xmmsv_get_list_iter (xmmsv_coll_idlist_get (coll), &it);
01011 for (xmmsv_list_iter_first (it);
01012 xmmsv_list_iter_valid (it);
01013 xmmsv_list_iter_next (it)) {
01014
01015 xmmsv_list_iter_entry_int (it, &entry);
01016 if (!xmms_medialib_check_id (entry)) {
01017 xmms_error_set (err, XMMS_ERROR_NOENT,
01018 "Idlist contains invalid medialib id!");
01019 xmmsv_list_iter_explicit_destroy (it);
01020 return;
01021 }
01022 }
01023
01024 for (xmmsv_list_iter_first (it);
01025 xmmsv_list_iter_valid (it);
01026 xmmsv_list_iter_next (it)) {
01027
01028 xmmsv_list_iter_entry_int (it, &entry);
01029 xmms_playlist_add_entry (playlist, plname, entry, err);
01030 }
01031 xmmsv_list_iter_explicit_destroy (it);
01032
01033 }
01034
01035 void
01036 xmms_playlist_client_add_collection (xmms_playlist_t *playlist, const gchar *plname,
01037 xmmsv_coll_t *coll, xmmsv_t *order,
01038 xmms_error_t *err)
01039 {
01040 GList *res;
01041
01042 res = xmms_collection_query_ids (playlist->colldag, coll, 0, 0, order, err);
01043
01044 while (res) {
01045 xmmsv_t *val = (xmmsv_t*) res->data;
01046 gint id;
01047 xmmsv_get_int (val, &id);
01048 xmms_playlist_add_entry (playlist, plname, id, err);
01049 xmmsv_unref (val);
01050
01051 res = g_list_delete_link (res, res);
01052 }
01053
01054 }
01055
01056
01057
01058
01059
01060
01061 void
01062 xmms_playlist_add_entry (xmms_playlist_t *playlist, const gchar *plname,
01063 xmms_medialib_entry_t file, xmms_error_t *err)
01064 {
01065 xmmsv_coll_t *plcoll;
01066
01067 g_mutex_lock (playlist->mutex);
01068
01069 plcoll = xmms_playlist_get_coll (playlist, plname, err);
01070 if (plcoll != NULL) {
01071 xmms_playlist_add_entry_unlocked (playlist, plname, plcoll, file, err);
01072 }
01073
01074 g_mutex_unlock (playlist->mutex);
01075
01076 }
01077
01078
01079
01080
01081 void
01082 xmms_playlist_add_entry_unlocked (xmms_playlist_t *playlist,
01083 const gchar *plname,
01084 xmmsv_coll_t *plcoll,
01085 xmms_medialib_entry_t file,
01086 xmms_error_t *err)
01087 {
01088 gint prev_size;
01089 GTree *dict;
01090
01091 prev_size = xmms_playlist_coll_get_size (plcoll);
01092 xmmsv_coll_idlist_append (plcoll, file);
01093
01094
01095 dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_ADD, file, plname);
01096 g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (prev_size));
01097 xmms_playlist_changed_msg_send (playlist, dict);
01098 }
01099
01100
01101 static void
01102 xmms_playlist_client_clear (xmms_playlist_t *playlist, const gchar *plname,
01103 xmms_error_t *err)
01104 {
01105 xmmsv_coll_t *plcoll;
01106
01107 g_return_if_fail (playlist);
01108
01109 g_mutex_lock (playlist->mutex);
01110
01111 plcoll = xmms_playlist_get_coll (playlist, plname, err);
01112 if (plcoll == NULL) {
01113 g_mutex_unlock (playlist->mutex);
01114 return;
01115 }
01116
01117 xmmsv_coll_idlist_clear (plcoll);
01118 xmms_collection_set_int_attr (plcoll, "position", -1);
01119
01120 XMMS_PLAYLIST_CHANGED_MSG (XMMS_PLAYLIST_CHANGED_CLEAR, 0, plname);
01121 g_mutex_unlock (playlist->mutex);
01122
01123 }
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 static gint
01134 xmms_playlist_set_current_position_do (xmms_playlist_t *playlist, guint32 pos,
01135 xmms_error_t *err)
01136 {
01137 gint size;
01138 xmms_medialib_entry_t mid;
01139 xmmsv_coll_t *plcoll;
01140 char *jumplist;
01141
01142 g_return_val_if_fail (playlist, FALSE);
01143
01144 plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
01145 if (plcoll == NULL) {
01146 return 0;
01147 }
01148
01149 size = xmms_playlist_coll_get_size (plcoll);
01150
01151 if (pos == size &&
01152 xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) {
01153
01154 xmms_collection_set_int_attr (plcoll, "position", 0);
01155 XMMS_PLAYLIST_CURRPOS_MSG (0, XMMS_ACTIVE_PLAYLIST);
01156
01157 xmms_playlist_client_load (playlist, jumplist, err);
01158 if (xmms_error_iserror (err)) {
01159 return 0;
01160 }
01161
01162 plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
01163 if (plcoll == NULL) {
01164 return 0;
01165 }
01166 } else if (pos < size) {
01167 XMMS_DBG ("newpos! %d", pos);
01168 xmms_collection_set_int_attr (plcoll, "position", pos);
01169 XMMS_PLAYLIST_CURRPOS_MSG (pos, XMMS_ACTIVE_PLAYLIST);
01170 } else {
01171 xmms_error_set (err, XMMS_ERROR_INVAL,
01172 "Can't set pos outside the current playlist!");
01173 return 0;
01174 }
01175
01176 xmmsv_coll_idlist_get_index (plcoll, pos, &mid);
01177
01178 return mid;
01179 }
01180
01181 gint
01182 xmms_playlist_client_set_next (xmms_playlist_t *playlist, gint32 pos,
01183 xmms_error_t *err)
01184 {
01185 xmms_medialib_entry_t mid;
01186 g_return_val_if_fail (playlist, FALSE);
01187
01188 g_mutex_lock (playlist->mutex);
01189 mid = xmms_playlist_set_current_position_do (playlist, pos, err);
01190 g_mutex_unlock (playlist->mutex);
01191
01192 return mid;
01193 }
01194
01195 static gint
01196 xmms_playlist_client_set_next_rel (xmms_playlist_t *playlist, gint32 pos,
01197 xmms_error_t *err)
01198 {
01199 gint currpos, newpos, size;
01200 xmms_medialib_entry_t mid = 0;
01201 xmmsv_coll_t *plcoll;
01202
01203 g_return_val_if_fail (playlist, FALSE);
01204
01205 g_mutex_lock (playlist->mutex);
01206
01207 plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
01208 if (plcoll != NULL) {
01209 currpos = xmms_playlist_coll_get_currpos (plcoll);
01210
01211 if (playlist->repeat_all) {
01212 newpos = pos + currpos;
01213 size = (gint) xmmsv_coll_idlist_get_size (plcoll);
01214
01215 if (size > 0) {
01216 newpos %= size;
01217 if (newpos < 0) {
01218 newpos += size;
01219 }
01220 }
01221
01222 mid = xmms_playlist_set_current_position_do (playlist, newpos, err);
01223 } else {
01224 if (currpos + pos >= 0) {
01225 mid = xmms_playlist_set_current_position_do (playlist,
01226 currpos + pos,
01227 err);
01228 } else {
01229 xmms_error_set (err, XMMS_ERROR_INVAL,
01230 "Can't set pos outside the current playlist!");
01231 }
01232 }
01233 }
01234
01235 g_mutex_unlock (playlist->mutex);
01236
01237 return mid;
01238 }
01239
01240 typedef struct {
01241 xmms_medialib_entry_t id;
01242 guint position;
01243 GList *val;
01244 gboolean current;
01245 } sortdata_t;
01246
01247
01248
01249
01250
01251
01252
01253 static gint
01254 xmms_playlist_entry_compare (gconstpointer a, gconstpointer b, gpointer user_data)
01255 {
01256 GList *n1, *n2;
01257 xmmsv_t *val1, *val2, *properties, *propval;
01258 xmmsv_list_iter_t *propit;
01259 sortdata_t *data1 = (sortdata_t *) a;
01260 sortdata_t *data2 = (sortdata_t *) b;
01261 int s1, s2, res;
01262 const gchar *propstr, *str1, *str2;
01263
01264 properties = (xmmsv_t *) user_data;
01265 for (n1 = data1->val, n2 = data2->val, xmmsv_get_list_iter (properties, &propit);
01266 n1 && n2 && xmmsv_list_iter_valid (propit);
01267 n1 = n1->next, n2 = n2->next, xmmsv_list_iter_next (propit)) {
01268
01269 xmmsv_list_iter_entry (propit, &propval);
01270 xmmsv_get_string (propval, &propstr);
01271 if (propstr[0] == '-') {
01272 val2 = n1->data;
01273 val1 = n2->data;
01274 } else {
01275 val1 = n1->data;
01276 val2 = n2->data;
01277 }
01278
01279 if (!val1) {
01280 if (!val2)
01281 continue;
01282 else
01283 return -1;
01284 }
01285
01286 if (!val2) {
01287 return 1;
01288 }
01289
01290 if (xmmsv_get_type (val1) == XMMSV_TYPE_STRING &&
01291 xmmsv_get_type (val2) == XMMSV_TYPE_STRING) {
01292 xmmsv_get_string (val1, &str1);
01293 xmmsv_get_string (val2, &str2);
01294 res = g_utf8_collate (str1, str2);
01295
01296 if (res == 0)
01297 continue;
01298 else
01299 return res;
01300 }
01301
01302 if (xmmsv_get_type (val1) == XMMSV_TYPE_INT32 &&
01303 xmmsv_get_type (val2) == XMMSV_TYPE_INT32)
01304 {
01305 xmmsv_get_int (val1, &s1);
01306 xmmsv_get_int (val2, &s2);
01307
01308 if (s1 < s2)
01309 return -1;
01310 else if (s1 > s2)
01311 return 1;
01312 else
01313 continue;
01314 }
01315
01316 XMMS_DBG ("Types in compare function differ to much");
01317
01318 return 0;
01319 }
01320
01321
01322 return 0;
01323 }
01324
01325
01326
01327
01328
01329 static void
01330 xmms_playlist_sorted_free (gpointer data, gpointer userdata)
01331 {
01332 GList *n;
01333 sortdata_t *sorted = (sortdata_t *) data;
01334
01335 for (n = sorted->val; n; n = n->next) {
01336 if (n->data) {
01337 xmmsv_unref (n->data);
01338 }
01339 }
01340 g_list_free (sorted->val);
01341 g_free (sorted);
01342 }
01343
01344
01345
01346
01347
01348 static void
01349 xmms_playlist_sorted_unwind (gpointer data, gpointer userdata)
01350 {
01351 gint size;
01352 sortdata_t *sorted = (sortdata_t *) data;
01353 xmmsv_coll_t *playlist = (xmmsv_coll_t *)userdata;
01354
01355 xmmsv_coll_idlist_append (playlist, sorted->id);
01356
01357 if (sorted->current) {
01358 size = xmmsv_coll_idlist_get_size (playlist);
01359 xmms_collection_set_int_attr (playlist, "position", size - 1);
01360 }
01361
01362 xmms_playlist_sorted_free (sorted, NULL);
01363 }
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375 static void
01376 xmms_playlist_client_sort (xmms_playlist_t *playlist, const gchar *plname,
01377 xmmsv_t *properties, xmms_error_t *err)
01378 {
01379 guint32 i;
01380 GList *tmp = NULL, *n;
01381 sortdata_t *data;
01382 const gchar *str;
01383 xmmsv_t *val;
01384 xmms_medialib_session_t *session;
01385 gboolean list_changed = FALSE;
01386 xmmsv_coll_t *plcoll;
01387 gint currpos, size;
01388 xmmsv_t *valstr;
01389 xmmsv_list_iter_t *propit;
01390
01391 g_return_if_fail (playlist);
01392 g_return_if_fail (properties);
01393
01394 g_mutex_lock (playlist->mutex);
01395
01396 plcoll = xmms_playlist_get_coll (playlist, plname, err);
01397 if (plcoll == NULL) {
01398 xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist!");
01399 g_mutex_unlock (playlist->mutex);
01400 return;
01401 }
01402
01403
01404 if (!check_string_list (properties)) {
01405 xmms_error_set (err, XMMS_ERROR_NOENT,
01406 "invalid list of properties to sort by!");
01407 g_mutex_unlock (playlist->mutex);
01408 return;
01409 }
01410
01411 if (xmmsv_list_get_size (properties) < 1) {
01412 xmms_error_set (err, XMMS_ERROR_NOENT,
01413 "empty list of properties to sort by!");
01414 g_mutex_unlock (playlist->mutex);
01415 return;
01416 }
01417
01418
01419 xmmsv_list_get (properties, 0, &valstr);
01420 xmmsv_get_string (valstr, &str);
01421 XMMS_DBG ("Sorting on %s (and maybe more)", str);
01422
01423 currpos = xmms_playlist_coll_get_currpos (plcoll);
01424 size = xmms_playlist_coll_get_size (plcoll);
01425
01426
01427 if (size < 2) {
01428 g_mutex_unlock (playlist->mutex);
01429 return;
01430 }
01431
01432 session = xmms_medialib_begin ();
01433
01434 xmmsv_get_list_iter (properties, &propit);
01435 for (i = 0; i < size; i++) {
01436 data = g_new (sortdata_t, 1);
01437
01438 xmmsv_coll_idlist_get_index (plcoll, i, &data->id);
01439 data->position = i;
01440
01441
01442 data->val = NULL;
01443 for (xmmsv_list_iter_first (propit);
01444 xmmsv_list_iter_valid (propit);
01445 xmmsv_list_iter_next (propit)) {
01446
01447 xmmsv_list_iter_entry (propit, &valstr);
01448 xmmsv_get_string (valstr, &str);
01449 if (str[0] == '-')
01450 str++;
01451
01452 val = xmms_medialib_entry_property_get_value (session,
01453 data->id,
01454 str);
01455
01456 if (val && xmmsv_get_type (val) == XMMSV_TYPE_STRING) {
01457 gchar *casefold;
01458
01459 xmmsv_get_string (val, &str);
01460 casefold = g_utf8_casefold (str, strlen (str));
01461 xmmsv_unref (val);
01462
01463 val = xmmsv_new_string (casefold);
01464 g_free (casefold);
01465 }
01466
01467 data->val = g_list_prepend (data->val, val);
01468 }
01469 data->val = g_list_reverse (data->val);
01470
01471 data->current = (currpos == i);
01472
01473 tmp = g_list_prepend (tmp, data);
01474 }
01475
01476 xmms_medialib_end (session);
01477
01478 tmp = g_list_reverse (tmp);
01479 tmp = g_list_sort_with_data (tmp, xmms_playlist_entry_compare, properties);
01480
01481
01482 for (i = 0, n = tmp; n; i++, n = g_list_next (n)) {
01483 if (((sortdata_t*)n->data)->position != i) {
01484 list_changed = TRUE;
01485 break;
01486 }
01487 }
01488
01489 if (!list_changed) {
01490 g_list_foreach (tmp, xmms_playlist_sorted_free, NULL);
01491 g_list_free (tmp);
01492 g_mutex_unlock (playlist->mutex);
01493 return;
01494 }
01495
01496 xmmsv_coll_idlist_clear (plcoll);
01497 g_list_foreach (tmp, xmms_playlist_sorted_unwind, plcoll);
01498
01499 g_list_free (tmp);
01500
01501 XMMS_PLAYLIST_CHANGED_MSG (XMMS_PLAYLIST_CHANGED_SORT, 0, plname);
01502 XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
01503
01504 g_mutex_unlock (playlist->mutex);
01505 }
01506
01507
01508
01509 static GList *
01510 xmms_playlist_client_list_entries (xmms_playlist_t *playlist, const gchar *plname,
01511 xmms_error_t *err)
01512 {
01513 GList *entries = NULL;
01514 xmmsv_coll_t *plcoll;
01515 xmms_medialib_entry_t entry;
01516 xmmsv_list_iter_t *it;
01517
01518 g_return_val_if_fail (playlist, NULL);
01519
01520 g_mutex_lock (playlist->mutex);
01521
01522 plcoll = xmms_playlist_get_coll (playlist, plname, err);
01523 if (plcoll == NULL) {
01524 g_mutex_unlock (playlist->mutex);
01525 return NULL;
01526 }
01527
01528 xmmsv_get_list_iter (xmmsv_coll_idlist_get (plcoll), &it);
01529 for (xmmsv_list_iter_first (it);
01530 xmmsv_list_iter_valid (it);
01531 xmmsv_list_iter_next (it)) {
01532
01533 xmmsv_list_iter_entry_int (it, &entry);
01534 entries = g_list_prepend (entries, xmmsv_new_int (entry));
01535 }
01536 xmmsv_list_iter_explicit_destroy (it);
01537
01538 g_mutex_unlock (playlist->mutex);
01539
01540 entries = g_list_reverse (entries);
01541
01542 return entries;
01543 }
01544
01545
01546 xmms_mediainfo_reader_t *
01547 xmms_playlist_mediainfo_reader_get (xmms_playlist_t *playlist)
01548 {
01549 g_return_val_if_fail (playlist, NULL);
01550
01551 return playlist->mediainfordr;
01552 }
01553
01554
01555
01556
01557
01558
01559
01560
01561 static void
01562 xmms_playlist_destroy (xmms_object_t *object)
01563 {
01564 xmms_config_property_t *val;
01565 xmms_playlist_t *playlist = (xmms_playlist_t *)object;
01566
01567 g_return_if_fail (playlist);
01568
01569 g_mutex_free (playlist->mutex);
01570
01571 val = xmms_config_lookup ("playlist.repeat_one");
01572 xmms_config_property_callback_remove (val, on_playlist_r_one_changed, playlist);
01573 val = xmms_config_lookup ("playlist.repeat_all");
01574 xmms_config_property_callback_remove (val, on_playlist_r_all_changed, playlist);
01575
01576 xmms_object_unref (playlist->colldag);
01577 xmms_object_unref (playlist->mediainfordr);
01578
01579 xmms_playlist_unregister_ipc_commands ();
01580 }
01581
01582
01583 static xmmsv_coll_t *
01584 xmms_playlist_get_coll (xmms_playlist_t *playlist, const gchar *plname,
01585 xmms_error_t *error)
01586 {
01587 xmmsv_coll_t *coll;
01588 coll = xmms_collection_get_pointer (playlist->colldag, plname,
01589 XMMS_COLLECTION_NSID_PLAYLISTS);
01590
01591 if (coll == NULL && error != NULL) {
01592 xmms_error_set (error, XMMS_ERROR_INVAL, "invalid playlist name");
01593 }
01594
01595 return coll;
01596 }
01597
01598
01599
01600
01601
01602 static const gchar *
01603 xmms_playlist_canonical_name (xmms_playlist_t *playlist, const gchar *plname)
01604 {
01605 const gchar *fullname;
01606
01607 if (strcmp (plname, XMMS_ACTIVE_PLAYLIST) == 0) {
01608 xmmsv_coll_t *coll;
01609 coll = xmms_collection_get_pointer (playlist->colldag, plname,
01610 XMMS_COLLECTION_NSID_PLAYLISTS);
01611 fullname = xmms_collection_find_alias (playlist->colldag,
01612 XMMS_COLLECTION_NSID_PLAYLISTS,
01613 coll, plname);
01614 } else {
01615 fullname = plname;
01616 }
01617
01618 return fullname;
01619 }
01620
01621
01622 static gint
01623 xmms_playlist_coll_get_currpos (xmmsv_coll_t *plcoll)
01624 {
01625 gint currpos;
01626
01627
01628 if (!xmms_collection_get_int_attr (plcoll, "position", &currpos)) {
01629 currpos = -1;
01630 xmms_collection_set_int_attr (plcoll, "position", currpos);
01631 }
01632
01633 return currpos;
01634 }
01635
01636
01637 static gint
01638 xmms_playlist_coll_get_size (xmmsv_coll_t *plcoll)
01639 {
01640 return xmmsv_coll_idlist_get_size (plcoll);
01641 }
01642
01643
01644 GTree *
01645 xmms_playlist_changed_msg_new (xmms_playlist_t *playlist,
01646 xmms_playlist_changed_actions_t type,
01647 xmms_medialib_entry_t id, const gchar *plname)
01648 {
01649 GTree *dict;
01650 const gchar *tmp;
01651
01652 dict = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
01653 NULL, (GDestroyNotify) xmmsv_unref);
01654
01655 g_tree_insert (dict, (gpointer) "type", xmmsv_new_int (type));
01656
01657 if (id) {
01658 g_tree_insert (dict, (gpointer) "id", xmmsv_new_int (id));
01659 }
01660
01661 tmp = xmms_playlist_canonical_name (playlist, plname);
01662 g_tree_insert (dict, (gpointer) "name", xmmsv_new_string (tmp));
01663
01664 return dict;
01665 }
01666
01667 GTree *
01668 xmms_playlist_current_pos_msg_new (xmms_playlist_t *playlist,
01669 guint32 pos, const gchar *plname)
01670 {
01671 GTree *dict;
01672 const gchar *tmp;
01673
01674 dict = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
01675 NULL, (GDestroyNotify) xmmsv_unref);
01676
01677 g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (pos));
01678
01679 tmp = xmms_playlist_canonical_name (playlist, plname);
01680 g_tree_insert (dict, (gpointer) "name", xmmsv_new_string (tmp));
01681
01682 return dict;
01683 }
01684
01685 void
01686 xmms_playlist_changed_msg_send (xmms_playlist_t *playlist, GTree *dict)
01687 {
01688 xmmsv_t *type_val;
01689 xmmsv_t *pl_val;
01690 gint type;
01691 const gchar *plname;
01692
01693 g_return_if_fail (playlist);
01694 g_return_if_fail (dict);
01695
01696
01697 type_val = g_tree_lookup (dict, "type");
01698 pl_val = g_tree_lookup (dict, "name");
01699 if (type_val != NULL && xmmsv_get_int (type_val, &type) &&
01700 type != XMMS_PLAYLIST_CHANGED_UPDATE &&
01701 pl_val != NULL && xmmsv_get_string (pl_val, &plname)) {
01702 XMMS_COLLECTION_PLAYLIST_CHANGED_MSG (playlist->colldag, plname);
01703 }
01704
01705 xmms_object_emit_f (XMMS_OBJECT (playlist),
01706 XMMS_IPC_SIGNAL_PLAYLIST_CHANGED,
01707 XMMSV_TYPE_DICT,
01708 dict);
01709
01710 g_tree_destroy (dict);
01711 }
01712
01713 static void
01714 xmms_playlist_current_pos_msg_send (xmms_playlist_t *playlist,
01715 GTree *dict)
01716 {
01717 g_return_if_fail (playlist);
01718
01719 g_return_if_fail (dict);
01720
01721 xmms_object_emit_f (XMMS_OBJECT (playlist),
01722 XMMS_IPC_SIGNAL_PLAYLIST_CURRENT_POS,
01723 XMMSV_TYPE_DICT,
01724 dict);
01725
01726 g_tree_destroy (dict);
01727 }