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