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