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