diff options
Diffstat (limited to '')
48 files changed, 838 insertions, 331 deletions
diff --git a/src/playlist.c b/src/playlist.c index 4a1e54814..0c9eea92d 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -75,7 +75,8 @@ playlist_finish(struct playlist *playlist) * Queue a song, addressed by its order number. */ static void -playlist_queue_song_order(struct playlist *playlist, unsigned order) +playlist_queue_song_order(struct playlist *playlist, struct player_control *pc, + unsigned order) { struct song *song; char *uri; @@ -89,16 +90,16 @@ playlist_queue_song_order(struct playlist *playlist, unsigned order) g_debug("queue song %i:\"%s\"", playlist->queued, uri); g_free(uri); - pc_enqueue_song(song); + pc_enqueue_song(pc, song); } /** * Called if the player thread has started playing the "queued" song. */ static void -playlist_song_started(struct playlist *playlist) +playlist_song_started(struct playlist *playlist, struct player_control *pc) { - assert(pc.next_song == NULL); + assert(pc->next_song == NULL); assert(playlist->queued >= -1); /* queued song has started: copy queued to current, @@ -110,11 +111,13 @@ playlist_song_started(struct playlist *playlist) /* Pause if we are in single mode. */ if(playlist->queue.single && !playlist->queue.repeat) { - pc_set_pause(true); + pc_set_pause(pc, true); } if(playlist->queue.consume) - playlist_delete(playlist, queue_order_to_position(&playlist->queue, current)); + playlist_delete(playlist, pc, + queue_order_to_position(&playlist->queue, + current)); idle_add(IDLE_PLAYER); } @@ -129,7 +132,9 @@ playlist_get_queued_song(struct playlist *playlist) } void -playlist_update_queued_song(struct playlist *playlist, const struct song *prev) +playlist_update_queued_song(struct playlist *playlist, + struct player_control *pc, + const struct song *prev) { int next_order; const struct song *next_song; @@ -170,20 +175,21 @@ playlist_update_queued_song(struct playlist *playlist, const struct song *prev) if (prev != NULL && next_song != prev) { /* clear the currently queued song */ - pc_cancel(); + pc_cancel(pc); playlist->queued = -1; } if (next_order >= 0) { if (next_song != prev) - playlist_queue_song_order(playlist, next_order); + playlist_queue_song_order(playlist, pc, next_order); else playlist->queued = next_order; } } void -playlist_play_order(struct playlist *playlist, int orderNum) +playlist_play_order(struct playlist *playlist, struct player_control *pc, + int orderNum) { struct song *song; char *uri; @@ -197,46 +203,46 @@ playlist_play_order(struct playlist *playlist, int orderNum) g_debug("play %i:\"%s\"", orderNum, uri); g_free(uri); - pc_play(song); + pc_play(pc, song); playlist->current = orderNum; } static void -playlist_resume_playback(struct playlist *playlist); +playlist_resume_playback(struct playlist *playlist, struct player_control *pc); /** * This is the "PLAYLIST" event handler. It is invoked by the player * thread whenever it requests a new queued song, or when it exits. */ void -playlist_sync(struct playlist *playlist) +playlist_sync(struct playlist *playlist, struct player_control *pc) { if (!playlist->playing) /* this event has reached us out of sync: we aren't playing anymore; ignore the event */ return; - player_lock(); - enum player_state pc_state = pc_get_state(); - const struct song *pc_next_song = pc.next_song; - player_unlock(); + player_lock(pc); + enum player_state pc_state = pc_get_state(pc); + const struct song *pc_next_song = pc->next_song; + player_unlock(pc); if (pc_state == PLAYER_STATE_STOP) /* the player thread has stopped: check if playback should be restarted with the next song. That can happen if the playlist isn't filling the queue fast enough */ - playlist_resume_playback(playlist); + playlist_resume_playback(playlist, pc); else { /* check if the player thread has already started playing the queued song */ if (pc_next_song == NULL && playlist->queued != -1) - playlist_song_started(playlist); + playlist_song_started(playlist, pc); /* make sure the queued song is always set (if possible) */ - if (pc.next_song == NULL && playlist->queued < 0) - playlist_update_queued_song(playlist, NULL); + if (pc->next_song == NULL && playlist->queued < 0) + playlist_update_queued_song(playlist, pc, NULL); } } @@ -245,14 +251,14 @@ playlist_sync(struct playlist *playlist) * decide whether to re-start playback */ static void -playlist_resume_playback(struct playlist *playlist) +playlist_resume_playback(struct playlist *playlist, struct player_control *pc) { enum player_error error; assert(playlist->playing); - assert(pc_get_state() == PLAYER_STATE_STOP); + assert(pc_get_state(pc) == PLAYER_STATE_STOP); - error = pc_get_error(); + error = pc_get_error(pc); if (error == PLAYER_ERROR_NOERROR) playlist->error_count = 0; else @@ -263,10 +269,10 @@ playlist_resume_playback(struct playlist *playlist) playlist->error_count >= queue_length(&playlist->queue)) /* too many errors, or critical error: stop playback */ - playlist_stop(playlist); + playlist_stop(playlist, pc); else /* continue playback at the next song */ - playlist_next(playlist); + playlist_next(playlist, pc); } bool @@ -294,7 +300,8 @@ playlist_get_consume(const struct playlist *playlist) } void -playlist_set_repeat(struct playlist *playlist, bool status) +playlist_set_repeat(struct playlist *playlist, struct player_control *pc, + bool status) { if (status == playlist->queue.repeat) return; @@ -303,7 +310,7 @@ playlist_set_repeat(struct playlist *playlist, bool status) /* if the last song is currently being played, the "next song" might change when repeat mode is toggled */ - playlist_update_queued_song(playlist, + playlist_update_queued_song(playlist, pc, playlist_get_queued_song(playlist)); idle_add(IDLE_OPTIONS); @@ -321,7 +328,8 @@ playlist_order(struct playlist *playlist) } void -playlist_set_single(struct playlist *playlist, bool status) +playlist_set_single(struct playlist *playlist, struct player_control *pc, + bool status) { if (status == playlist->queue.single) return; @@ -330,7 +338,7 @@ playlist_set_single(struct playlist *playlist, bool status) /* if the last song is currently being played, the "next song" might change when single mode is toggled */ - playlist_update_queued_song(playlist, + playlist_update_queued_song(playlist, pc, playlist_get_queued_song(playlist)); idle_add(IDLE_OPTIONS); @@ -347,7 +355,8 @@ playlist_set_consume(struct playlist *playlist, bool status) } void -playlist_set_random(struct playlist *playlist, bool status) +playlist_set_random(struct playlist *playlist, struct player_control *pc, + bool status) { const struct song *queued; @@ -384,7 +393,7 @@ playlist_set_random(struct playlist *playlist, bool status) } else playlist_order(playlist); - playlist_update_queued_song(playlist, queued); + playlist_update_queued_song(playlist, pc, queued); idle_add(IDLE_OPTIONS); } diff --git a/src/playlist.h b/src/playlist.h index 3ba90ff91..caed0a220 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -21,24 +21,11 @@ #define MPD_PLAYLIST_H #include "queue.h" +#include "playlist_error.h" #include <stdbool.h> -#define PLAYLIST_COMMENT '#' - -enum playlist_result { - PLAYLIST_RESULT_SUCCESS, - PLAYLIST_RESULT_ERRNO, - PLAYLIST_RESULT_DENIED, - PLAYLIST_RESULT_NO_SUCH_SONG, - PLAYLIST_RESULT_NO_SUCH_LIST, - PLAYLIST_RESULT_LIST_EXISTS, - PLAYLIST_RESULT_BAD_NAME, - PLAYLIST_RESULT_BAD_RANGE, - PLAYLIST_RESULT_NOT_PLAYING, - PLAYLIST_RESULT_TOO_LARGE, - PLAYLIST_RESULT_DISABLED, -}; +struct player_control; struct playlist { /** @@ -111,7 +98,7 @@ playlist_get_queue(const struct playlist *playlist) } void -playlist_clear(struct playlist *playlist); +playlist_clear(struct playlist *playlist, struct player_control *pc); #ifndef WIN32 /** @@ -119,20 +106,21 @@ playlist_clear(struct playlist *playlist); * but only if the file's owner is equal to the specified uid. */ enum playlist_result -playlist_append_file(struct playlist *playlist, const char *path, int uid, - unsigned *added_id); +playlist_append_file(struct playlist *playlist, struct player_control *pc, + const char *path, int uid, unsigned *added_id); #endif enum playlist_result -playlist_append_uri(struct playlist *playlist, const char *file, - unsigned *added_id); +playlist_append_uri(struct playlist *playlist, struct player_control *pc, + const char *file, unsigned *added_id); enum playlist_result -playlist_append_song(struct playlist *playlist, +playlist_append_song(struct playlist *playlist, struct player_control *pc, struct song *song, unsigned *added_id); enum playlist_result -playlist_delete(struct playlist *playlist, unsigned song); +playlist_delete(struct playlist *playlist, struct player_control *pc, + unsigned song); /** * Deletes a range of songs from the playlist. @@ -141,64 +129,86 @@ playlist_delete(struct playlist *playlist, unsigned song); * @param end the position after the last song to delete */ enum playlist_result -playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end); +playlist_delete_range(struct playlist *playlist, struct player_control *pc, + unsigned start, unsigned end); enum playlist_result -playlist_delete_id(struct playlist *playlist, unsigned song); +playlist_delete_id(struct playlist *playlist, struct player_control *pc, + unsigned song); void -playlist_stop(struct playlist *playlist); +playlist_stop(struct playlist *playlist, struct player_control *pc); enum playlist_result -playlist_play(struct playlist *playlist, int song); +playlist_play(struct playlist *playlist, struct player_control *pc, + int song); enum playlist_result -playlist_play_id(struct playlist *playlist, int song); +playlist_play_id(struct playlist *playlist, struct player_control *pc, + int song); void -playlist_next(struct playlist *playlist); +playlist_next(struct playlist *playlist, struct player_control *pc); void -playlist_sync(struct playlist *playlist); +playlist_sync(struct playlist *playlist, struct player_control *pc); void -playlist_previous(struct playlist *playlist); +playlist_previous(struct playlist *playlist, struct player_control *pc); void -playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end); +playlist_shuffle(struct playlist *playlist, struct player_control *pc, + unsigned start, unsigned end); void -playlist_delete_song(struct playlist *playlist, const struct song *song); +playlist_delete_song(struct playlist *playlist, struct player_control *pc, + const struct song *song); + +enum playlist_result +playlist_move_range(struct playlist *playlist, struct player_control *pc, + unsigned start, unsigned end, int to); + +enum playlist_result +playlist_move_id(struct playlist *playlist, struct player_control *pc, + unsigned id, int to); enum playlist_result -playlist_move_range(struct playlist *playlist, unsigned start, unsigned end, int to); +playlist_swap_songs(struct playlist *playlist, struct player_control *pc, + unsigned song1, unsigned song2); enum playlist_result -playlist_move_id(struct playlist *playlist, unsigned id, int to); +playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc, + unsigned id1, unsigned id2); enum playlist_result -playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2); +playlist_set_priority(struct playlist *playlist, struct player_control *pc, + unsigned start_position, unsigned end_position, + uint8_t priority); enum playlist_result -playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2); +playlist_set_priority_id(struct playlist *playlist, struct player_control *pc, + unsigned song_id, uint8_t priority); bool playlist_get_repeat(const struct playlist *playlist); void -playlist_set_repeat(struct playlist *playlist, bool status); +playlist_set_repeat(struct playlist *playlist, struct player_control *pc, + bool status); bool playlist_get_random(const struct playlist *playlist); void -playlist_set_random(struct playlist *playlist, bool status); +playlist_set_random(struct playlist *playlist, struct player_control *pc, + bool status); bool playlist_get_single(const struct playlist *playlist); void -playlist_set_single(struct playlist *playlist, bool status); +playlist_set_single(struct playlist *playlist, struct player_control *pc, + bool status); bool playlist_get_consume(const struct playlist *playlist); @@ -222,12 +232,25 @@ unsigned long playlist_get_version(const struct playlist *playlist); enum playlist_result -playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time); +playlist_seek_song(struct playlist *playlist, struct player_control *pc, + unsigned song, float seek_time); enum playlist_result -playlist_seek_song_id(struct playlist *playlist, +playlist_seek_song_id(struct playlist *playlist, struct player_control *pc, unsigned id, float seek_time); +/** + * Seek within the current song. Fails if MPD is not currently + * playing. + * + * @param time the time in seconds + * @param relative if true, then the specified time is relative to the + * current position + */ +enum playlist_result +playlist_seek_current(struct playlist *playlist, struct player_control *pc, + float seek_time, bool relative); + void playlist_increment_version_all(struct playlist *playlist); diff --git a/src/playlist/asx_playlist_plugin.c b/src/playlist/asx_playlist_plugin.c index 39513e710..298687859 100644 --- a/src/playlist/asx_playlist_plugin.c +++ b/src/playlist/asx_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -233,7 +233,8 @@ asx_open_stream(struct input_stream *is) &parser, asx_parser_destroy); while (true) { - nbytes = input_stream_read(is, buffer, sizeof(buffer), &error); + nbytes = input_stream_lock_read(is, buffer, sizeof(buffer), + &error); if (nbytes == 0) { if (error != NULL) { g_markup_parse_context_free(context); diff --git a/src/playlist/asx_playlist_plugin.h b/src/playlist/asx_playlist_plugin.h index 7ce91aa41..6c01c1209 100644 --- a/src/playlist/asx_playlist_plugin.h +++ b/src/playlist/asx_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/cue_playlist_plugin.c b/src/playlist/cue_playlist_plugin.c index b22712bc7..3f2d5b34c 100644 --- a/src/playlist/cue_playlist_plugin.c +++ b/src/playlist/cue_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -41,7 +41,8 @@ struct cue_playlist { }; static struct playlist_provider * -cue_playlist_open_uri(const char *uri) +cue_playlist_open_uri(const char *uri, + G_GNUC_UNUSED GMutex *mutex, G_GNUC_UNUSED GCond *cond) { struct cue_playlist *playlist; FILE *file; diff --git a/src/playlist/cue_playlist_plugin.h b/src/playlist/cue_playlist_plugin.h index c89ec55c5..c02e2235a 100644 --- a/src/playlist/cue_playlist_plugin.h +++ b/src/playlist/cue_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/despotify_playlist_plugin.c b/src/playlist/despotify_playlist_plugin.c new file mode 100644 index 000000000..08a32d79d --- /dev/null +++ b/src/playlist/despotify_playlist_plugin.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "config.h" +#include "playlist/despotify_playlist_plugin.h" +#include "playlist_plugin.h" +#include "playlist_list.h" +#include "conf.h" +#include "uri.h" +#include "tag.h" +#include "song.h" +#include "input_stream.h" +#include "glib_compat.h" +#include "despotify_utils.h" + +#include <glib.h> + +#include <assert.h> +#include <string.h> +#include <stdlib.h> +#include <despotify.h> + +struct despotify_playlist { + struct playlist_provider base; + + struct despotify_session *session; + GSList *list; +}; + +static void +add_song(struct despotify_playlist *ctx, struct ds_track *track) +{ + const char *dsp_scheme = despotify_playlist_plugin.schemes[0]; + struct song *song; + char uri[128]; + char *ds_uri; + + /* Create a spt://... URI for MPD */ + g_snprintf(uri, sizeof(uri), "%s://", dsp_scheme); + ds_uri = uri + strlen(dsp_scheme) + 3; + + if (despotify_track_to_uri(track, ds_uri) != ds_uri) { + /* Should never really fail, but let's be sure */ + g_debug("Can't add track %s\n", track->title); + return; + } + + song = song_remote_new(uri); + song->tag = mpd_despotify_tag_from_track(track); + + ctx->list = g_slist_prepend(ctx->list, song); +} + +static bool +parse_track(struct despotify_playlist *ctx, + struct ds_link *link) +{ + struct ds_track *track; + + track = despotify_link_get_track(ctx->session, link); + if (!track) + return false; + add_song(ctx, track); + + return true; +} + +static bool +parse_playlist(struct despotify_playlist *ctx, + struct ds_link *link) +{ + struct ds_playlist *playlist; + struct ds_track *track; + + playlist = despotify_link_get_playlist(ctx->session, link); + if (!playlist) + return false; + + for (track = playlist->tracks; track; track = track->next) + add_song(ctx, track); + + return true; +} + +static bool +despotify_playlist_init(G_GNUC_UNUSED const struct config_param *param) +{ + return true; +} + +static void +despotify_playlist_finish(void) +{ +} + + +static struct playlist_provider * +despotify_playlist_open_uri(const char *url, G_GNUC_UNUSED GMutex *mutex, + G_GNUC_UNUSED GCond *cond) +{ + struct despotify_playlist *ctx; + struct despotify_session *session; + struct ds_link *link; + bool parse_result; + + session = mpd_despotify_get_session(); + if (!session) + goto clean_none; + + /* Get link without spt:// */ + link = despotify_link_from_uri(url + strlen(despotify_playlist_plugin.schemes[0]) + 3); + if (!link) { + g_debug("Can't find %s\n", url); + goto clean_none; + } + + ctx = g_new(struct despotify_playlist, 1); + + ctx->list = NULL; + ctx->session = session; + playlist_provider_init(&ctx->base, &despotify_playlist_plugin); + + switch (link->type) + { + case LINK_TYPE_TRACK: + parse_result = parse_track(ctx, link); + break; + case LINK_TYPE_PLAYLIST: + parse_result = parse_playlist(ctx, link); + break; + default: + parse_result = false; + break; + } + despotify_free_link(link); + if (!parse_result) + goto clean_playlist; + + ctx->list = g_slist_reverse(ctx->list); + + return &ctx->base; + +clean_playlist: + g_slist_free(ctx->list); +clean_none: + + return NULL; +} + +static void +track_free_callback(gpointer data, G_GNUC_UNUSED gpointer user_data) +{ + struct song *song = (struct song *)data; + + song_free(song); +} + +static void +despotify_playlist_close(struct playlist_provider *_playlist) +{ + struct despotify_playlist *ctx = (struct despotify_playlist *)_playlist; + + g_slist_foreach(ctx->list, track_free_callback, NULL); + g_slist_free(ctx->list); + + g_free(ctx); +} + + +static struct song * +despotify_playlist_read(struct playlist_provider *_playlist) +{ + struct despotify_playlist *ctx = (struct despotify_playlist *)_playlist; + struct song *out; + + if (!ctx->list) + return NULL; + + /* Remove the current track */ + out = ctx->list->data; + ctx->list = g_slist_remove(ctx->list, out); + + return out; +} + + +static const char *const despotify_schemes[] = { + "spt", + NULL +}; + +const struct playlist_plugin despotify_playlist_plugin = { + .name = "despotify", + + .init = despotify_playlist_init, + .finish = despotify_playlist_finish, + .open_uri = despotify_playlist_open_uri, + .read = despotify_playlist_read, + .close = despotify_playlist_close, + + .schemes = despotify_schemes, +}; diff --git a/src/playlist/despotify_playlist_plugin.h b/src/playlist/despotify_playlist_plugin.h new file mode 100644 index 000000000..f8ee20de0 --- /dev/null +++ b/src/playlist/despotify_playlist_plugin.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_H +#define MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_H + +extern const struct playlist_plugin despotify_playlist_plugin; + +#endif diff --git a/src/playlist/extm3u_playlist_plugin.c b/src/playlist/extm3u_playlist_plugin.c index 9a04aa066..19be8d1c4 100644 --- a/src/playlist/extm3u_playlist_plugin.c +++ b/src/playlist/extm3u_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include "uri.h" #include "song.h" #include "tag.h" +#include "string_util.h" #include <glib.h> @@ -89,7 +90,7 @@ extm3u_parse_tag(const char *line) /* 0 means unknown duration */ duration = 0; - name = g_strchug(endptr + 1); + name = strchug_fast_c(endptr + 1); if (*name == 0 && duration == 0) /* no information available; don't allocate a tag object */ diff --git a/src/playlist/extm3u_playlist_plugin.h b/src/playlist/extm3u_playlist_plugin.h index fa726c5f6..5f611ac9c 100644 --- a/src/playlist/extm3u_playlist_plugin.h +++ b/src/playlist/extm3u_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/flac_playlist_plugin.c b/src/playlist/flac_playlist_plugin.c index 9d66fb331..e20519435 100644 --- a/src/playlist/flac_playlist_plugin.c +++ b/src/playlist/flac_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -45,7 +45,8 @@ struct flac_playlist { }; static struct playlist_provider * -flac_playlist_open_uri(const char *uri) +flac_playlist_open_uri(const char *uri, + G_GNUC_UNUSED GMutex *mutex, G_GNUC_UNUSED GCond *cond) { if (!g_path_is_absolute(uri)) /* only local files supported */ diff --git a/src/playlist/flac_playlist_plugin.h b/src/playlist/flac_playlist_plugin.h index 7b141264f..231d90e4a 100644 --- a/src/playlist/flac_playlist_plugin.h +++ b/src/playlist/flac_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/lastfm_playlist_plugin.c b/src/playlist/lastfm_playlist_plugin.c index afb3979d9..86113643c 100644 --- a/src/playlist/lastfm_playlist_plugin.c +++ b/src/playlist/lastfm_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -83,15 +83,14 @@ lastfm_finish(void) * @return data fetched, or NULL on error. Must be freed with g_free. */ static char * -lastfm_get(const char *url) +lastfm_get(const char *url, GMutex *mutex, GCond *cond) { struct input_stream *input_stream; GError *error = NULL; - int ret; char buffer[4096]; size_t length = 0, nbytes; - input_stream = input_stream_open(url, &error); + input_stream = input_stream_open(url, mutex, cond, &error); if (input_stream == NULL) { if (error != NULL) { g_warning("%s", error->message); @@ -101,15 +100,9 @@ lastfm_get(const char *url) return NULL; } - while (!input_stream->ready) { - ret = input_stream_buffer(input_stream, &error); - if (ret < 0) { - input_stream_close(input_stream); - g_warning("%s", error->message); - g_error_free(error); - return NULL; - } - } + g_mutex_lock(mutex); + + input_stream_wait_ready(input_stream); do { nbytes = input_stream_read(input_stream, buffer + length, @@ -124,6 +117,7 @@ lastfm_get(const char *url) break; /* I/O error */ + g_mutex_unlock(mutex); input_stream_close(input_stream); return NULL; } @@ -131,6 +125,8 @@ lastfm_get(const char *url) length += nbytes; } while (length < sizeof(buffer)); + g_mutex_unlock(mutex); + input_stream_close(input_stream); return g_strndup(buffer, length); } @@ -139,7 +135,7 @@ lastfm_get(const char *url) * Ini-style value fetcher. * @param response data through which to search. * @param name name of value to search for. - * @return value for param name in param reponse or NULL on error. Free with g_free. + * @return value for param name in param response or NULL on error. Free with g_free. */ static char * lastfm_find(const char *response, const char *name) @@ -162,7 +158,7 @@ lastfm_find(const char *response, const char *name) } static struct playlist_provider * -lastfm_open_uri(const char *uri) +lastfm_open_uri(const char *uri, GMutex *mutex, GCond *cond) { struct lastfm_playlist *playlist; GError *error = NULL; @@ -175,7 +171,7 @@ lastfm_open_uri(const char *uri) "username=", lastfm_config.user, "&" "passwordmd5=", lastfm_config.md5, "&" "debug=0&partner=", NULL); - response = lastfm_get(p); + response = lastfm_get(p, mutex, cond); g_free(p); if (response == NULL) return NULL; @@ -207,7 +203,7 @@ lastfm_open_uri(const char *uri) NULL); g_free(escaped_uri); - response = lastfm_get(p); + response = lastfm_get(p, mutex, cond); g_free(response); g_free(p); @@ -229,7 +225,7 @@ lastfm_open_uri(const char *uri) NULL); g_free(session); - playlist->is = input_stream_open(p, &error); + playlist->is = input_stream_open(p, mutex, cond, &error); g_free(p); if (playlist->is == NULL) { @@ -243,26 +239,17 @@ lastfm_open_uri(const char *uri) return NULL; } - while (!playlist->is->ready) { - int ret = input_stream_buffer(playlist->is, &error); - if (ret < 0) { - input_stream_close(playlist->is); - g_free(playlist); - g_warning("%s", error->message); - g_error_free(error); - return NULL; - } + g_mutex_lock(mutex); - if (ret == 0) - /* nothing was buffered - wait */ - g_usleep(10000); - } + input_stream_wait_ready(playlist->is); /* last.fm does not send a MIME type, we have to fake it here :-( */ g_free(playlist->is->mime); playlist->is->mime = g_strdup("application/xspf+xml"); + g_mutex_unlock(mutex); + /* parse the XSPF playlist */ playlist->xspf = playlist_list_open_stream(playlist->is, NULL); diff --git a/src/playlist/lastfm_playlist_plugin.h b/src/playlist/lastfm_playlist_plugin.h index 363377c21..46a8b0caf 100644 --- a/src/playlist/lastfm_playlist_plugin.h +++ b/src/playlist/lastfm_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/m3u_playlist_plugin.c b/src/playlist/m3u_playlist_plugin.c index 221c27277..45b70d2b1 100644 --- a/src/playlist/m3u_playlist_plugin.c +++ b/src/playlist/m3u_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/m3u_playlist_plugin.h b/src/playlist/m3u_playlist_plugin.h index 98dcc4729..3890a5fc2 100644 --- a/src/playlist/m3u_playlist_plugin.h +++ b/src/playlist/m3u_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/pls_playlist_plugin.c b/src/playlist/pls_playlist_plugin.c index 2a36f12f5..c4e5492af 100644 --- a/src/playlist/pls_playlist_plugin.c +++ b/src/playlist/pls_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -115,7 +115,8 @@ pls_open_stream(struct input_stream *is) GString *kf_data = g_string_new(""); do { - nbytes = input_stream_read(is, buffer, sizeof(buffer), &error); + nbytes = input_stream_lock_read(is, buffer, sizeof(buffer), + &error); if (nbytes == 0) { if (error != NULL) { g_string_free(kf_data, TRUE); diff --git a/src/playlist/pls_playlist_plugin.h b/src/playlist/pls_playlist_plugin.h index c3bcf3f05..d03435f6d 100644 --- a/src/playlist/pls_playlist_plugin.h +++ b/src/playlist/pls_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/rss_playlist_plugin.c b/src/playlist/rss_playlist_plugin.c index b5787bb68..6740cba7e 100644 --- a/src/playlist/rss_playlist_plugin.c +++ b/src/playlist/rss_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -231,7 +231,8 @@ rss_open_stream(struct input_stream *is) &parser, rss_parser_destroy); while (true) { - nbytes = input_stream_read(is, buffer, sizeof(buffer), &error); + nbytes = input_stream_lock_read(is, buffer, sizeof(buffer), + &error); if (nbytes == 0) { if (error != NULL) { g_markup_parse_context_free(context); diff --git a/src/playlist/rss_playlist_plugin.h b/src/playlist/rss_playlist_plugin.h index d8992f2e5..3b376de79 100644 --- a/src/playlist/rss_playlist_plugin.h +++ b/src/playlist/rss_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist/xspf_playlist_plugin.c b/src/playlist/xspf_playlist_plugin.c index 50f6bd1e7..17d9040e2 100644 --- a/src/playlist/xspf_playlist_plugin.c +++ b/src/playlist/xspf_playlist_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -253,7 +253,8 @@ xspf_open_stream(struct input_stream *is) &parser, xspf_parser_destroy); while (true) { - nbytes = input_stream_read(is, buffer, sizeof(buffer), &error); + nbytes = input_stream_lock_read(is, buffer, sizeof(buffer), + &error); if (nbytes == 0) { if (error != NULL) { g_markup_parse_context_free(context); diff --git a/src/playlist/xspf_playlist_plugin.h b/src/playlist/xspf_playlist_plugin.h index ea832207d..4636d7e83 100644 --- a/src/playlist/xspf_playlist_plugin.h +++ b/src/playlist/xspf_playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist_any.c b/src/playlist_any.c index 39e21b178..450ca5932 100644 --- a/src/playlist_any.c +++ b/src/playlist_any.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -27,18 +27,20 @@ #include <assert.h> static struct playlist_provider * -playlist_open_remote(const char *uri, struct input_stream **is_r) +playlist_open_remote(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r) { assert(uri_has_scheme(uri)); - struct playlist_provider *playlist = playlist_list_open_uri(uri); + struct playlist_provider *playlist = + playlist_list_open_uri(uri, mutex, cond); if (playlist != NULL) { *is_r = NULL; return playlist; } GError *error = NULL; - struct input_stream *is = input_stream_open(uri, &error); + struct input_stream *is = input_stream_open(uri, mutex, cond, &error); if (is == NULL) { if (error != NULL) { g_warning("Failed to open %s: %s", @@ -60,9 +62,10 @@ playlist_open_remote(const char *uri, struct input_stream **is_r) } struct playlist_provider * -playlist_open_any(const char *uri, struct input_stream **is_r) +playlist_open_any(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r) { return uri_has_scheme(uri) - ? playlist_open_remote(uri, is_r) - : playlist_mapper_open(uri, is_r); + ? playlist_open_remote(uri, mutex, cond, is_r) + : playlist_mapper_open(uri, mutex, cond, is_r); } diff --git a/src/playlist_any.h b/src/playlist_any.h index 6fed97d15..310913de9 100644 --- a/src/playlist_any.h +++ b/src/playlist_any.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ #ifndef MPD_PLAYLIST_ANY_H #define MPD_PLAYLIST_ANY_H -#include <stdbool.h> +#include <glib.h> struct playlist_provider; struct input_stream; @@ -35,6 +35,7 @@ struct input_stream; * freed */ struct playlist_provider * -playlist_open_any(const char *uri, struct input_stream **is_r); +playlist_open_any(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r); #endif diff --git a/src/playlist_control.c b/src/playlist_control.c index 76066d274..0dea7676a 100644 --- a/src/playlist_control.c +++ b/src/playlist_control.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -32,7 +32,8 @@ #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "playlist" -void playlist_stop(struct playlist *playlist) +void +playlist_stop(struct playlist *playlist, struct player_control *pc) { if (!playlist->playing) return; @@ -40,7 +41,7 @@ void playlist_stop(struct playlist *playlist) assert(playlist->current >= 0); g_debug("stop"); - pc_stop(); + pc_stop(pc); playlist->queued = -1; playlist->playing = false; @@ -62,11 +63,13 @@ void playlist_stop(struct playlist *playlist) } } -enum playlist_result playlist_play(struct playlist *playlist, int song) +enum playlist_result +playlist_play(struct playlist *playlist, struct player_control *pc, + int song) { unsigned i = song; - pc_clear_error(); + pc_clear_error(pc); if (song == -1) { /* play any song ("current" song, or the first song */ @@ -77,7 +80,7 @@ enum playlist_result playlist_play(struct playlist *playlist, int song) if (playlist->playing) { /* already playing: unpause playback, just in case it was paused, and return */ - pc_set_pause(false); + pc_set_pause(pc, false); return PLAYLIST_RESULT_SUCCESS; } @@ -109,28 +112,29 @@ enum playlist_result playlist_play(struct playlist *playlist, int song) playlist->stop_on_error = false; playlist->error_count = 0; - playlist_play_order(playlist, i); + playlist_play_order(playlist, pc, i); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_play_id(struct playlist *playlist, int id) +playlist_play_id(struct playlist *playlist, struct player_control *pc, + int id) { int song; if (id == -1) { - return playlist_play(playlist, id); + return playlist_play(playlist, pc, id); } song = queue_id_to_position(&playlist->queue, id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_play(playlist, song); + return playlist_play(playlist, pc, song); } void -playlist_next(struct playlist *playlist) +playlist_next(struct playlist *playlist, struct player_control *pc) { int next_order; int current; @@ -149,7 +153,7 @@ playlist_next(struct playlist *playlist) next_order = queue_next_order(&playlist->queue, playlist->current); if (next_order < 0) { /* no song after this one: stop playback */ - playlist_stop(playlist); + playlist_stop(playlist, pc); /* reset "current song" */ playlist->current = -1; @@ -170,15 +174,18 @@ playlist_next(struct playlist *playlist) discard them anyway */ } - playlist_play_order(playlist, next_order); + playlist_play_order(playlist, pc, next_order); } /* Consume mode removes each played songs. */ if(playlist->queue.consume) - playlist_delete(playlist, queue_order_to_position(&playlist->queue, current)); + playlist_delete(playlist, pc, + queue_order_to_position(&playlist->queue, + current)); } -void playlist_previous(struct playlist *playlist) +void +playlist_previous(struct playlist *playlist, struct player_control *pc) { if (!playlist->playing) return; @@ -187,21 +194,22 @@ void playlist_previous(struct playlist *playlist) if (playlist->current > 0) { /* play the preceding song */ - playlist_play_order(playlist, + playlist_play_order(playlist, pc, playlist->current - 1); } else if (playlist->queue.repeat) { /* play the last song in "repeat" mode */ - playlist_play_order(playlist, + playlist_play_order(playlist, pc, queue_length(&playlist->queue) - 1); } else { /* re-start playing the current song if it's the first one */ - playlist_play_order(playlist, playlist->current); + playlist_play_order(playlist, pc, playlist->current); } } enum playlist_result -playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time) +playlist_seek_song(struct playlist *playlist, struct player_control *pc, + unsigned song, float seek_time) { const struct song *queued; unsigned i; @@ -217,7 +225,7 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time) else i = song; - pc_clear_error(); + pc_clear_error(pc); playlist->stop_on_error = true; playlist->error_count = 0; @@ -231,25 +239,50 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time) queued = NULL; } - success = pc_seek(queue_get_order(&playlist->queue, i), seek_time); + success = pc_seek(pc, queue_get_order(&playlist->queue, i), seek_time); if (!success) { - playlist_update_queued_song(playlist, queued); + playlist_update_queued_song(playlist, pc, queued); return PLAYLIST_RESULT_NOT_PLAYING; } playlist->queued = -1; - playlist_update_queued_song(playlist, NULL); + playlist_update_queued_song(playlist, pc, NULL); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_seek_song_id(struct playlist *playlist, unsigned id, float seek_time) +playlist_seek_song_id(struct playlist *playlist, struct player_control *pc, + unsigned id, float seek_time) { int song = queue_id_to_position(&playlist->queue, id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_seek_song(playlist, song, seek_time); + return playlist_seek_song(playlist, pc, song, seek_time); +} + +enum playlist_result +playlist_seek_current(struct playlist *playlist, struct player_control *pc, + float seek_time, bool relative) +{ + if (!playlist->playing) + return PLAYLIST_RESULT_NOT_PLAYING; + + if (relative) { + struct player_status status; + pc_get_status(pc, &status); + + if (status.state != PLAYER_STATE_PLAY && + status.state != PLAYER_STATE_PAUSE) + return PLAYLIST_RESULT_NOT_PLAYING; + + seek_time += (int)status.elapsed_time; + } + + if (seek_time < 0) + seek_time = 0; + + return playlist_seek_song(playlist, pc, playlist->current, seek_time); } diff --git a/src/playlist_database.c b/src/playlist_database.c index 0a8a6f139..2ad913d00 100644 --- a/src/playlist_database.c +++ b/src/playlist_database.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,7 @@ #include "playlist_database.h" #include "playlist_vector.h" #include "text_file.h" +#include "string_util.h" #include <string.h> #include <stdlib.h> @@ -62,7 +63,7 @@ playlist_metadata_load(FILE *fp, struct playlist_vector *pv, const char *name, } *colon++ = 0; - value = g_strchug(colon); + value = strchug_fast_c(colon); if (strcmp(line, "mtime") == 0) pm.mtime = strtol(value, NULL, 10); diff --git a/src/playlist_database.h b/src/playlist_database.h index 7e114abdd..f80ebdaff 100644 --- a/src/playlist_database.h +++ b/src/playlist_database.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist_edit.c b/src/playlist_edit.c index 3bcb2ce14..dbd205a06 100644 --- a/src/playlist_edit.c +++ b/src/playlist_edit.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -43,16 +43,17 @@ static void playlist_increment_version(struct playlist *playlist) idle_add(IDLE_PLAYLIST); } -void playlist_clear(struct playlist *playlist) +void +playlist_clear(struct playlist *playlist, struct player_control *pc) { - playlist_stop(playlist); + playlist_stop(playlist, pc); /* make sure there are no references to allocated songs anymore */ for (unsigned i = 0; i < queue_length(&playlist->queue); i++) { const struct song *song = queue_get(&playlist->queue, i); if (!song_in_database(song)) - pc_song_deleted(song); + pc_song_deleted(pc, song); } queue_clear(&playlist->queue); @@ -64,8 +65,8 @@ void playlist_clear(struct playlist *playlist) #ifndef WIN32 enum playlist_result -playlist_append_file(struct playlist *playlist, const char *path, int uid, - unsigned *added_id) +playlist_append_file(struct playlist *playlist, struct player_control *pc, + const char *path, int uid, unsigned *added_id) { int ret; struct stat st; @@ -87,12 +88,12 @@ playlist_append_file(struct playlist *playlist, const char *path, int uid, if (song == NULL) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_append_song(playlist, song, added_id); + return playlist_append_song(playlist, pc, song, added_id); } #endif enum playlist_result -playlist_append_song(struct playlist *playlist, +playlist_append_song(struct playlist *playlist, struct player_control *pc, struct song *song, unsigned *added_id) { const struct song *queued; @@ -121,7 +122,7 @@ playlist_append_song(struct playlist *playlist, playlist_increment_version(playlist); - playlist_update_queued_song(playlist, queued); + playlist_update_queued_song(playlist, pc, queued); if (added_id) *added_id = id; @@ -145,8 +146,8 @@ song_by_uri(const char *uri) } enum playlist_result -playlist_append_uri(struct playlist *playlist, const char *uri, - unsigned *added_id) +playlist_append_uri(struct playlist *playlist, struct player_control *pc, + const char *uri, unsigned *added_id) { struct song *song; @@ -156,11 +157,12 @@ playlist_append_uri(struct playlist *playlist, const char *uri, if (song == NULL) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_append_song(playlist, song, added_id); + return playlist_append_song(playlist, pc, song, added_id); } enum playlist_result -playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2) +playlist_swap_songs(struct playlist *playlist, struct player_control *pc, + unsigned song1, unsigned song2) { const struct song *queued; @@ -192,13 +194,14 @@ playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2) playlist_increment_version(playlist); - playlist_update_queued_song(playlist, queued); + playlist_update_queued_song(playlist, pc, queued); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2) +playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc, + unsigned id1, unsigned id2) { int song1 = queue_id_to_position(&playlist->queue, id1); int song2 = queue_id_to_position(&playlist->queue, id2); @@ -206,12 +209,67 @@ playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2) if (song1 < 0 || song2 < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_swap_songs(playlist, song1, song2); + return playlist_swap_songs(playlist, pc, song1, song2); +} + +enum playlist_result +playlist_set_priority(struct playlist *playlist, struct player_control *pc, + unsigned start, unsigned end, + uint8_t priority) +{ + if (start >= queue_length(&playlist->queue)) + return PLAYLIST_RESULT_BAD_RANGE; + + if (end > queue_length(&playlist->queue)) + end = queue_length(&playlist->queue); + + if (start >= end) + return PLAYLIST_RESULT_SUCCESS; + + /* remember "current" and "queued" */ + + int current_position = playlist->current >= 0 + ? (int)queue_order_to_position(&playlist->queue, + playlist->current) + : -1; + + const struct song *queued = playlist_get_queued_song(playlist); + + /* apply the priority changes */ + + queue_set_priority_range(&playlist->queue, start, end, priority, + playlist->current); + + playlist_increment_version(playlist); + + /* restore "current" and choose a new "queued" */ + + if (current_position >= 0) + playlist->current = queue_position_to_order(&playlist->queue, + current_position); + + playlist_update_queued_song(playlist, pc, queued); + + return PLAYLIST_RESULT_SUCCESS; +} + +enum playlist_result +playlist_set_priority_id(struct playlist *playlist, struct player_control *pc, + unsigned song_id, uint8_t priority) +{ + int song_position = queue_id_to_position(&playlist->queue, song_id); + if (song_position < 0) + return PLAYLIST_RESULT_NO_SUCH_SONG; + + return playlist_set_priority(playlist, pc, + song_position, song_position + 1, + priority); + } static void -playlist_delete_internal(struct playlist *playlist, unsigned song, - const struct song **queued_p) +playlist_delete_internal(struct playlist *playlist, struct player_control *pc, + unsigned song, const struct song **queued_p) { unsigned songOrder; @@ -220,11 +278,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song, songOrder = queue_position_to_order(&playlist->queue, song); if (playlist->playing && playlist->current == (int)songOrder) { - bool paused = pc_get_state() == PLAYER_STATE_PAUSE; + bool paused = pc_get_state(pc) == PLAYER_STATE_PAUSE; /* the current song is going to be deleted: stop the player */ - pc_stop(); + pc_stop(pc); playlist->playing = false; /* see which song is going to be played instead */ @@ -236,11 +294,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song, if (playlist->current >= 0 && !paused) /* play the song after the deleted one */ - playlist_play_order(playlist, playlist->current); + playlist_play_order(playlist, pc, playlist->current); else /* no songs left to play, stop playback completely */ - playlist_stop(playlist); + playlist_stop(playlist, pc); *queued_p = NULL; } else if (playlist->current == (int)songOrder) @@ -251,7 +309,7 @@ playlist_delete_internal(struct playlist *playlist, unsigned song, /* now do it: remove the song */ if (!song_in_database(queue_get(&playlist->queue, song))) - pc_song_deleted(queue_get(&playlist->queue, song)); + pc_song_deleted(pc, queue_get(&playlist->queue, song)); queue_delete(&playlist->queue, song); @@ -263,7 +321,8 @@ playlist_delete_internal(struct playlist *playlist, unsigned song, } enum playlist_result -playlist_delete(struct playlist *playlist, unsigned song) +playlist_delete(struct playlist *playlist, struct player_control *pc, + unsigned song) { const struct song *queued; @@ -272,16 +331,17 @@ playlist_delete(struct playlist *playlist, unsigned song) queued = playlist_get_queued_song(playlist); - playlist_delete_internal(playlist, song, &queued); + playlist_delete_internal(playlist, pc, song, &queued); playlist_increment_version(playlist); - playlist_update_queued_song(playlist, queued); + playlist_update_queued_song(playlist, pc, queued); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end) +playlist_delete_range(struct playlist *playlist, struct player_control *pc, + unsigned start, unsigned end) { const struct song *queued; @@ -297,37 +357,39 @@ playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end) queued = playlist_get_queued_song(playlist); do { - playlist_delete_internal(playlist, --end, &queued); + playlist_delete_internal(playlist, pc, --end, &queued); } while (end != start); playlist_increment_version(playlist); - playlist_update_queued_song(playlist, queued); + playlist_update_queued_song(playlist, pc, queued); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_delete_id(struct playlist *playlist, unsigned id) +playlist_delete_id(struct playlist *playlist, struct player_control *pc, + unsigned id) { int song = queue_id_to_position(&playlist->queue, id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_delete(playlist, song); + return playlist_delete(playlist, pc, song); } void -playlist_delete_song(struct playlist *playlist, const struct song *song) +playlist_delete_song(struct playlist *playlist, struct player_control *pc, + const struct song *song) { for (int i = queue_length(&playlist->queue) - 1; i >= 0; --i) if (song == queue_get(&playlist->queue, i)) - playlist_delete(playlist, i); + playlist_delete(playlist, pc, i); - pc_song_deleted(song); + pc_song_deleted(pc, song); } enum playlist_result -playlist_move_range(struct playlist *playlist, +playlist_move_range(struct playlist *playlist, struct player_control *pc, unsigned start, unsigned end, int to) { const struct song *queued; @@ -382,23 +444,25 @@ playlist_move_range(struct playlist *playlist, playlist_increment_version(playlist); - playlist_update_queued_song(playlist, queued); + playlist_update_queued_song(playlist, pc, queued); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_move_id(struct playlist *playlist, unsigned id1, int to) +playlist_move_id(struct playlist *playlist, struct player_control *pc, + unsigned id1, int to) { int song = queue_id_to_position(&playlist->queue, id1); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_move_range(playlist, song, song+1, to); + return playlist_move_range(playlist, pc, song, song+1, to); } void -playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end) +playlist_shuffle(struct playlist *playlist, struct player_control *pc, + unsigned start, unsigned end) { const struct song *queued; @@ -440,5 +504,5 @@ playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end) playlist_increment_version(playlist); - playlist_update_queued_song(playlist, queued); + playlist_update_queued_song(playlist, pc, queued); } diff --git a/src/playlist_error.h b/src/playlist_error.h new file mode 100644 index 000000000..ad9c62cf1 --- /dev/null +++ b/src/playlist_error.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_PLAYLIST_ERROR_H +#define MPD_PLAYLIST_ERROR_H + +#include <glib.h> + +enum playlist_result { + PLAYLIST_RESULT_SUCCESS, + PLAYLIST_RESULT_ERRNO, + PLAYLIST_RESULT_DENIED, + PLAYLIST_RESULT_NO_SUCH_SONG, + PLAYLIST_RESULT_NO_SUCH_LIST, + PLAYLIST_RESULT_LIST_EXISTS, + PLAYLIST_RESULT_BAD_NAME, + PLAYLIST_RESULT_BAD_RANGE, + PLAYLIST_RESULT_NOT_PLAYING, + PLAYLIST_RESULT_TOO_LARGE, + PLAYLIST_RESULT_DISABLED, +}; + +/** + * Quark for GError.domain; the code is an enum #playlist_result. + */ +G_GNUC_CONST +static inline GQuark +playlist_quark(void) +{ + return g_quark_from_static_string("playlist"); +} + +#endif diff --git a/src/playlist_global.c b/src/playlist_global.c index 2833b62ed..650b88bb8 100644 --- a/src/playlist_global.c +++ b/src/playlist_global.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include "playlist.h" #include "playlist_state.h" #include "event_pipe.h" +#include "main.h" struct playlist g_playlist; @@ -38,7 +39,7 @@ playlist_tag_event(void) static void playlist_event(void) { - playlist_sync(&g_playlist); + playlist_sync(&g_playlist, global_player_control); } void diff --git a/src/playlist_internal.h b/src/playlist_internal.h index 9d205188f..81b175176 100644 --- a/src/playlist_internal.h +++ b/src/playlist_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -27,6 +27,8 @@ #include "playlist.h" +struct player_control; + /** * Returns the song object which is currently queued. Returns none if * there is none (yet?) or if MPD isn't playing. @@ -44,9 +46,11 @@ playlist_get_queued_song(struct playlist *playlist); */ void playlist_update_queued_song(struct playlist *playlist, + struct player_control *pc, const struct song *prev); void -playlist_play_order(struct playlist *playlist, int orderNum); +playlist_play_order(struct playlist *playlist, struct player_control *pc, + int orderNum); #endif diff --git a/src/playlist_list.c b/src/playlist_list.c index 019654bfc..1f220eee8 100644 --- a/src/playlist_list.c +++ b/src/playlist_list.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include "playlist/m3u_playlist_plugin.h" #include "playlist/xspf_playlist_plugin.h" #include "playlist/lastfm_playlist_plugin.h" +#include "playlist/despotify_playlist_plugin.h" #include "playlist/pls_playlist_plugin.h" #include "playlist/asx_playlist_plugin.h" #include "playlist/rss_playlist_plugin.h" @@ -31,7 +32,7 @@ #include "playlist/flac_playlist_plugin.h" #include "input_stream.h" #include "uri.h" -#include "utils.h" +#include "string_util.h" #include "conf.h" #include "glib_compat.h" #include "mpd_error.h" @@ -47,6 +48,9 @@ static const struct playlist_plugin *const playlist_plugins[] = { &pls_playlist_plugin, &asx_playlist_plugin, &rss_playlist_plugin, +#ifdef ENABLE_DESPOTIFY + &despotify_playlist_plugin, +#endif #ifdef ENABLE_LASTFM &lastfm_playlist_plugin, #endif @@ -115,7 +119,8 @@ playlist_list_global_finish(void) } static struct playlist_provider * -playlist_list_open_uri_scheme(const char *uri, bool *tried) +playlist_list_open_uri_scheme(const char *uri, GMutex *mutex, GCond *cond, + bool *tried) { char *scheme; struct playlist_provider *playlist = NULL; @@ -134,7 +139,8 @@ playlist_list_open_uri_scheme(const char *uri, bool *tried) if (playlist_plugins_enabled[i] && plugin->open_uri != NULL && plugin->schemes != NULL && string_array_contains(plugin->schemes, scheme)) { - playlist = playlist_plugin_open_uri(plugin, uri); + playlist = playlist_plugin_open_uri(plugin, uri, + mutex, cond); if (playlist != NULL) break; @@ -147,7 +153,8 @@ playlist_list_open_uri_scheme(const char *uri, bool *tried) } static struct playlist_provider * -playlist_list_open_uri_suffix(const char *uri, const bool *tried) +playlist_list_open_uri_suffix(const char *uri, GMutex *mutex, GCond *cond, + const bool *tried) { const char *suffix; struct playlist_provider *playlist = NULL; @@ -164,7 +171,8 @@ playlist_list_open_uri_suffix(const char *uri, const bool *tried) if (playlist_plugins_enabled[i] && !tried[i] && plugin->open_uri != NULL && plugin->suffixes != NULL && string_array_contains(plugin->suffixes, suffix)) { - playlist = playlist_plugin_open_uri(plugin, uri); + playlist = playlist_plugin_open_uri(plugin, uri, + mutex, cond); if (playlist != NULL) break; } @@ -174,7 +182,7 @@ playlist_list_open_uri_suffix(const char *uri, const bool *tried) } struct playlist_provider * -playlist_list_open_uri(const char *uri) +playlist_list_open_uri(const char *uri, GMutex *mutex, GCond *cond) { struct playlist_provider *playlist; /** this array tracks which plugins have already been tried by @@ -185,9 +193,10 @@ playlist_list_open_uri(const char *uri) memset(tried, false, sizeof(tried)); - playlist = playlist_list_open_uri_scheme(uri, tried); + playlist = playlist_list_open_uri_scheme(uri, mutex, cond, tried); if (playlist == NULL) - playlist = playlist_list_open_uri_suffix(uri, tried); + playlist = playlist_list_open_uri_suffix(uri, mutex, cond, + tried); return playlist; } @@ -274,16 +283,7 @@ playlist_list_open_stream(struct input_stream *is, const char *uri) const char *suffix; struct playlist_provider *playlist; - GError *error = NULL; - while (!is->ready) { - int ret = input_stream_buffer(is, &error); - if (ret < 0) { - input_stream_close(is); - g_warning("%s", error->message); - g_error_free(error); - return NULL; - } - } + input_stream_lock_wait_ready(is); if (is->mime != NULL) { playlist = playlist_list_open_stream_mime(is); @@ -318,7 +318,8 @@ playlist_suffix_supported(const char *suffix) } struct playlist_provider * -playlist_list_open_path(const char *path_fs, struct input_stream **is_r) +playlist_list_open_path(const char *path_fs, GMutex *mutex, GCond *cond, + struct input_stream **is_r) { GError *error = NULL; const char *suffix; @@ -331,7 +332,7 @@ playlist_list_open_path(const char *path_fs, struct input_stream **is_r) if (suffix == NULL || !playlist_suffix_supported(suffix)) return NULL; - is = input_stream_open(path_fs, &error); + is = input_stream_open(path_fs, mutex, cond, &error); if (is == NULL) { if (error != NULL) { g_warning("%s", error->message); @@ -341,15 +342,7 @@ playlist_list_open_path(const char *path_fs, struct input_stream **is_r) return NULL; } - while (!is->ready) { - int ret = input_stream_buffer(is, &error); - if (ret < 0) { - input_stream_close(is); - g_warning("%s", error->message); - g_error_free(error); - return NULL; - } - } + input_stream_lock_wait_ready(is); playlist = playlist_list_open_stream_suffix(is, suffix); if (playlist != NULL) diff --git a/src/playlist_list.h b/src/playlist_list.h index 3710589a2..4a2485303 100644 --- a/src/playlist_list.h +++ b/src/playlist_list.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,8 @@ #ifndef MPD_PLAYLIST_LIST_H #define MPD_PLAYLIST_LIST_H +#include <glib.h> + #include <stdbool.h> struct playlist_provider; @@ -41,7 +43,7 @@ playlist_list_global_finish(void); * Opens a playlist by its URI. */ struct playlist_provider * -playlist_list_open_uri(const char *uri); +playlist_list_open_uri(const char *uri, GMutex *mutex, GCond *cond); /** * Opens a playlist from an input stream. @@ -69,6 +71,7 @@ playlist_suffix_supported(const char *suffix); * @return a playlist, or NULL on error */ struct playlist_provider * -playlist_list_open_path(const char *path_fs, struct input_stream **is_r); +playlist_list_open_path(const char *path_fs, GMutex *mutex, GCond *cond, + struct input_stream **is_r); #endif diff --git a/src/playlist_mapper.c b/src/playlist_mapper.c index 99b322073..13adb80d0 100644 --- a/src/playlist_mapper.c +++ b/src/playlist_mapper.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -27,15 +27,16 @@ #include <assert.h> static struct playlist_provider * -playlist_open_path(const char *path_fs, struct input_stream **is_r) +playlist_open_path(const char *path_fs, GMutex *mutex, GCond *cond, + struct input_stream **is_r) { struct playlist_provider *playlist; - playlist = playlist_list_open_uri(path_fs); + playlist = playlist_list_open_uri(path_fs, mutex, cond); if (playlist != NULL) *is_r = NULL; else - playlist = playlist_list_open_path(path_fs, is_r); + playlist = playlist_list_open_path(path_fs, mutex, cond, is_r); return playlist; } @@ -44,7 +45,8 @@ playlist_open_path(const char *path_fs, struct input_stream **is_r) * Load a playlist from the configured playlist directory. */ static struct playlist_provider * -playlist_open_in_playlist_dir(const char *uri, struct input_stream **is_r) +playlist_open_in_playlist_dir(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r) { char *path_fs; @@ -56,7 +58,8 @@ playlist_open_in_playlist_dir(const char *uri, struct input_stream **is_r) path_fs = g_build_filename(playlist_directory_fs, uri, NULL); - struct playlist_provider *playlist = playlist_open_path(path_fs, is_r); + struct playlist_provider *playlist = + playlist_open_path(path_fs, mutex, cond, is_r); g_free(path_fs); return playlist; @@ -66,7 +69,8 @@ playlist_open_in_playlist_dir(const char *uri, struct input_stream **is_r) * Load a playlist from the configured music directory. */ static struct playlist_provider * -playlist_open_in_music_dir(const char *uri, struct input_stream **is_r) +playlist_open_in_music_dir(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r) { char *path_fs; @@ -76,25 +80,28 @@ playlist_open_in_music_dir(const char *uri, struct input_stream **is_r) if (path_fs == NULL) return NULL; - struct playlist_provider *playlist = playlist_open_path(path_fs, is_r); + struct playlist_provider *playlist = + playlist_open_path(path_fs, mutex, cond, is_r); g_free(path_fs); return playlist; } struct playlist_provider * -playlist_mapper_open(const char *uri, struct input_stream **is_r) +playlist_mapper_open(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r) { struct playlist_provider *playlist; if (spl_valid_name(uri)) { - playlist = playlist_open_in_playlist_dir(uri, is_r); + playlist = playlist_open_in_playlist_dir(uri, mutex, cond, + is_r); if (playlist != NULL) return playlist; } if (uri_safe_local(uri)) { - playlist = playlist_open_in_music_dir(uri, is_r); + playlist = playlist_open_in_music_dir(uri, mutex, cond, is_r); if (playlist != NULL) return playlist; } diff --git a/src/playlist_mapper.h b/src/playlist_mapper.h index b98af1b13..9a7187d93 100644 --- a/src/playlist_mapper.h +++ b/src/playlist_mapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,8 @@ #ifndef MPD_PLAYLIST_MAPPER_H #define MPD_PLAYLIST_MAPPER_H +#include <glib.h> + struct input_stream; /** @@ -31,6 +33,7 @@ struct input_stream; * freed */ struct playlist_provider * -playlist_mapper_open(const char *uri, struct input_stream **is_r); +playlist_mapper_open(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r); #endif diff --git a/src/playlist_plugin.h b/src/playlist_plugin.h index 3d840573e..a27f651c0 100644 --- a/src/playlist_plugin.h +++ b/src/playlist_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,8 @@ #ifndef MPD_PLAYLIST_PLUGIN_H #define MPD_PLAYLIST_PLUGIN_H +#include <glib.h> + #include <stdbool.h> #include <stddef.h> @@ -64,7 +66,8 @@ struct playlist_plugin { * Opens the playlist on the specified URI. This URI has * either matched one of the schemes or one of the suffixes. */ - struct playlist_provider *(*open_uri)(const char *uri); + struct playlist_provider *(*open_uri)(const char *uri, + GMutex *mutex, GCond *cond); /** * Opens the playlist in the specified input stream. It has @@ -110,9 +113,10 @@ playlist_plugin_finish(const struct playlist_plugin *plugin) } static inline struct playlist_provider * -playlist_plugin_open_uri(const struct playlist_plugin *plugin, const char *uri) +playlist_plugin_open_uri(const struct playlist_plugin *plugin, const char *uri, + GMutex *mutex, GCond *cond) { - return plugin->open_uri(uri); + return plugin->open_uri(uri, mutex, cond); } static inline struct playlist_provider * diff --git a/src/playlist_print.c b/src/playlist_print.c index 89ab2e5ab..a6bf84ccd 100644 --- a/src/playlist_print.c +++ b/src/playlist_print.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,6 +23,7 @@ #include "playlist_plugin.h" #include "playlist_any.h" #include "playlist_song.h" +#include "playlist.h" #include "queue_print.h" #include "stored_playlist.h" #include "song_print.h" @@ -116,11 +117,12 @@ playlist_print_changes_position(struct client *client, } bool -spl_print(struct client *client, const char *name_utf8, bool detail) +spl_print(struct client *client, const char *name_utf8, bool detail, + GError **error_r) { GPtrArray *list; - list = spl_load(name_utf8); + list = spl_load(name_utf8, error_r); if (list == NULL) return false; @@ -153,7 +155,7 @@ playlist_provider_print(struct client *client, const char *uri, char *base_uri = uri != NULL ? g_path_get_dirname(uri) : NULL; while ((song = playlist_plugin_read(playlist)) != NULL) { - song = playlist_check_translate_song(song, base_uri); + song = playlist_check_translate_song(song, base_uri, false); if (song == NULL) continue; @@ -169,10 +171,17 @@ playlist_provider_print(struct client *client, const char *uri, bool playlist_file_print(struct client *client, const char *uri, bool detail) { + GMutex *mutex = g_mutex_new(); + GCond *cond = g_cond_new(); + struct input_stream *is; - struct playlist_provider *playlist = playlist_open_any(uri, &is); - if (playlist == NULL) + struct playlist_provider *playlist = + playlist_open_any(uri, mutex, cond, &is); + if (playlist == NULL) { + g_cond_free(cond); + g_mutex_free(mutex); return false; + } playlist_provider_print(client, uri, playlist, detail); playlist_plugin_close(playlist); @@ -180,5 +189,8 @@ playlist_file_print(struct client *client, const char *uri, bool detail) if (is != NULL) input_stream_close(is); + g_cond_free(cond); + g_mutex_free(mutex); + return true; } diff --git a/src/playlist_print.h b/src/playlist_print.h index b3a0446ed..d4f1911d2 100644 --- a/src/playlist_print.h +++ b/src/playlist_print.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,7 @@ #ifndef PLAYLIST_PRINT_H #define PLAYLIST_PRINT_H +#include <glib.h> #include <stdbool.h> #include <stdint.h> @@ -99,7 +100,8 @@ playlist_print_changes_position(struct client *client, * @return true on success, false if the playlist does not exist */ bool -spl_print(struct client *client, const char *name_utf8, bool detail); +spl_print(struct client *client, const char *name_utf8, bool detail, + GError **error_r); /** * Send the playlist file to the client. diff --git a/src/playlist_queue.c b/src/playlist_queue.c index 635e23a28..33885ae21 100644 --- a/src/playlist_queue.c +++ b/src/playlist_queue.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -22,23 +22,25 @@ #include "playlist_plugin.h" #include "playlist_any.h" #include "playlist_song.h" +#include "playlist.h" #include "song.h" #include "input_stream.h" enum playlist_result playlist_load_into_queue(const char *uri, struct playlist_provider *source, - struct playlist *dest) + struct playlist *dest, struct player_control *pc, + bool secure) { enum playlist_result result; struct song *song; char *base_uri = uri != NULL ? g_path_get_dirname(uri) : NULL; while ((song = playlist_plugin_read(source)) != NULL) { - song = playlist_check_translate_song(song, base_uri); + song = playlist_check_translate_song(song, base_uri, secure); if (song == NULL) continue; - result = playlist_append_song(dest, song, NULL); + result = playlist_append_song(dest, pc, song, NULL); if (result != PLAYLIST_RESULT_SUCCESS) { if (!song_in_database(song)) song_free(song); @@ -53,19 +55,31 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source, } enum playlist_result -playlist_open_into_queue(const char *uri, struct playlist *dest) +playlist_open_into_queue(const char *uri, + struct playlist *dest, struct player_control *pc, + bool secure) { + GMutex *mutex = g_mutex_new(); + GCond *cond = g_cond_new(); + struct input_stream *is; - struct playlist_provider *playlist = playlist_open_any(uri, &is); - if (playlist == NULL) + struct playlist_provider *playlist = + playlist_open_any(uri, mutex, cond, &is); + if (playlist == NULL) { + g_cond_free(cond); + g_mutex_free(mutex); return PLAYLIST_RESULT_NO_SUCH_LIST; + } enum playlist_result result = - playlist_load_into_queue(uri, playlist, dest); + playlist_load_into_queue(uri, playlist, dest, pc, secure); playlist_plugin_close(playlist); if (is != NULL) input_stream_close(is); + g_cond_free(cond); + g_mutex_free(mutex); + return result; } diff --git a/src/playlist_queue.h b/src/playlist_queue.h index 530d4b4be..3ae63bc16 100644 --- a/src/playlist_queue.h +++ b/src/playlist_queue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -24,10 +24,13 @@ #ifndef MPD_PLAYLIST_QUEUE_H #define MPD_PLAYLIST_QUEUE_H -#include "playlist.h" +#include "playlist_error.h" + +#include <stdbool.h> struct playlist_provider; struct playlist; +struct player_control; /** * Loads the contents of a playlist and append it to the specified @@ -38,14 +41,17 @@ struct playlist; */ enum playlist_result playlist_load_into_queue(const char *uri, struct playlist_provider *source, - struct playlist *dest); + struct playlist *dest, struct player_control *pc, + bool secure); /** * Opens a playlist with a playlist plugin and append to the specified * play queue. */ enum playlist_result -playlist_open_into_queue(const char *uri, struct playlist *dest); +playlist_open_into_queue(const char *uri, + struct playlist *dest, struct player_control *pc, + bool secure); #endif diff --git a/src/playlist_save.c b/src/playlist_save.c index 8ddc93ec9..b8e03ea85 100644 --- a/src/playlist_save.c +++ b/src/playlist_save.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,7 +19,9 @@ #include "config.h" #include "playlist_save.h" +#include "playlist.h" #include "stored_playlist.h" +#include "queue.h" #include "song.h" #include "mapper.h" #include "path.h" @@ -108,18 +110,19 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist) return spl_save_queue(name_utf8, &playlist->queue); } -enum playlist_result -playlist_load_spl(struct playlist *playlist, const char *name_utf8) +bool +playlist_load_spl(struct playlist *playlist, struct player_control *pc, + const char *name_utf8, GError **error_r) { GPtrArray *list; - list = spl_load(name_utf8); + list = spl_load(name_utf8, error_r); if (list == NULL) - return PLAYLIST_RESULT_NO_SUCH_LIST; + return false; for (unsigned i = 0; i < list->len; ++i) { const char *temp = g_ptr_array_index(list, i); - if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { + if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { /* for windows compatibility, convert slashes */ char *temp2 = g_strdup(temp); char *p = temp2; @@ -128,7 +131,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8) *p = '/'; p++; } - if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { + if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { g_warning("can't add file \"%s\"", temp2); } g_free(temp2); @@ -136,5 +139,5 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8) } spl_free(list); - return PLAYLIST_RESULT_SUCCESS; + return true; } diff --git a/src/playlist_save.h b/src/playlist_save.h index a0131cf7f..f8bfb8355 100644 --- a/src/playlist_save.h +++ b/src/playlist_save.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,11 +20,15 @@ #ifndef MPD_PLAYLIST_SAVE_H #define MPD_PLAYLIST_SAVE_H -#include "playlist.h" +#include "playlist_error.h" +#include <stdbool.h> #include <stdio.h> struct song; +struct queue; +struct playlist; +struct player_control; void playlist_print_song(FILE *fp, const struct song *song); @@ -48,7 +52,8 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist); * Loads a stored playlist file, and append all songs to the global * playlist. */ -enum playlist_result -playlist_load_spl(struct playlist *playlist, const char *name_utf8); +bool +playlist_load_spl(struct playlist *playlist, struct player_control *pc, + const char *name_utf8, GError **error_r); #endif diff --git a/src/playlist_song.c b/src/playlist_song.c index 827098655..d40ef63cf 100644 --- a/src/playlist_song.c +++ b/src/playlist_song.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -84,7 +84,8 @@ apply_song_metadata(struct song *dest, const struct song *src) } struct song * -playlist_check_translate_song(struct song *song, const char *base_uri) +playlist_check_translate_song(struct song *song, const char *base_uri, + bool secure) { struct song *dest; @@ -116,17 +117,18 @@ playlist_check_translate_song(struct song *song, const char *base_uri) /* XXX fs_charset vs utf8? */ char *prefix = map_directory_fs(db_get_root()); - if (prefix == NULL || !g_str_has_prefix(uri, prefix) || - uri[strlen(prefix)] != '/') { + if (prefix != NULL && g_str_has_prefix(uri, prefix) && + uri[strlen(prefix)] == '/') + uri += strlen(prefix) + 1; + else if (!secure) { /* local files must be relative to the music - directory */ + directory when "secure" is enabled */ g_free(prefix); song_free(song); return NULL; } base_uri = NULL; - uri += strlen(prefix) + 1; g_free(prefix); } @@ -138,6 +140,12 @@ playlist_check_translate_song(struct song *song, const char *base_uri) if (uri_has_scheme(uri)) { dest = song_remote_new(uri); g_free(uri); + } else if (g_path_is_absolute(uri) && secure) { + dest = song_file_load(uri, NULL); + if (dest == NULL) { + song_free(song); + return NULL; + } } else { dest = db_get_song(uri); g_free(uri); diff --git a/src/playlist_song.h b/src/playlist_song.h index 5a2e4c2b0..ea8786912 100644 --- a/src/playlist_song.h +++ b/src/playlist_song.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,12 +20,18 @@ #ifndef MPD_PLAYLIST_SONG_H #define MPD_PLAYLIST_SONG_H +#include <stdbool.h> + /** * Verifies the song, returns NULL if it is unsafe. Translate the * song to a new song object within the database, if it is a local * file. The old song object is freed. + * + * @param secure if true, then local files are only allowed if they + * are relative to base_uri */ struct song * -playlist_check_translate_song(struct song *song, const char *base_uri); +playlist_check_translate_song(struct song *song, const char *base_uri, + bool secure); #endif diff --git a/src/playlist_state.c b/src/playlist_state.c index bb9897e01..4aa2c2c92 100644 --- a/src/playlist_state.c +++ b/src/playlist_state.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -29,6 +29,7 @@ #include "queue_save.h" #include "path.h" #include "text_file.h" +#include "conf.h" #include <string.h> #include <stdlib.h> @@ -53,11 +54,12 @@ #define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX void -playlist_state_save(FILE *fp, const struct playlist *playlist) +playlist_state_save(FILE *fp, const struct playlist *playlist, + struct player_control *pc) { struct player_status player_status; - pc_get_status(&player_status); + pc_get_status(pc, &player_status); fputs(PLAYLIST_STATE_FILE_STATE, fp); @@ -89,10 +91,11 @@ playlist_state_save(FILE *fp, const struct playlist *playlist) fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n", playlist->queue.consume); fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n", - (int)(pc_get_cross_fade())); - fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", pc_get_mixramp_db()); + (int)(pc_get_cross_fade(pc))); + fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", + pc_get_mixramp_db(pc)); fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n", - pc_get_mixramp_delay()); + pc_get_mixramp_delay(pc)); fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp); queue_save(fp, &playlist->queue); fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp); @@ -123,11 +126,11 @@ playlist_state_load(FILE *fp, GString *buffer, struct playlist *playlist) bool playlist_state_restore(const char *line, FILE *fp, GString *buffer, - struct playlist *playlist) + struct playlist *playlist, struct player_control *pc) { int current = -1; int seek_time = 0; - int state = PLAYER_STATE_STOP; + enum player_state state = PLAYER_STATE_STOP; bool random_mode = false; if (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_STATE)) @@ -148,16 +151,16 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, if (strcmp (&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]), "1") == 0) { - playlist_set_repeat(playlist, true); + playlist_set_repeat(playlist, pc, true); } else - playlist_set_repeat(playlist, false); + playlist_set_repeat(playlist, pc, false); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) { if (strcmp (&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]), "1") == 0) { - playlist_set_single(playlist, true); + playlist_set_single(playlist, pc, true); } else - playlist_set_single(playlist, false); + playlist_set_single(playlist, pc, false); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) { if (strcmp (&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]), @@ -166,11 +169,14 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, } else playlist_set_consume(playlist, false); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) { - pc_set_cross_fade(atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE))); + pc_set_cross_fade(pc, + atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE))); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB)) { - pc_set_mixramp_db(atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB))); + pc_set_mixramp_db(pc, + atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB))); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) { - pc_set_mixramp_delay(atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY))); + pc_set_mixramp_delay(pc, + atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY))); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_RANDOM)) { random_mode = strcmp(line + strlen(PLAYLIST_STATE_FILE_RANDOM), @@ -185,38 +191,46 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, } } - playlist_set_random(playlist, random_mode); + playlist_set_random(playlist, pc, random_mode); if (!queue_is_empty(&playlist->queue)) { if (!queue_valid_position(&playlist->queue, current)) current = 0; + if (state == PLAYER_STATE_PLAY && + config_get_bool("restore_paused", false)) + /* the user doesn't want MPD to auto-start + playback after startup; fall back to + "pause" */ + state = PLAYER_STATE_PAUSE; + /* enable all devices for the first time; this must be called here, after the audio output states were restored, before playback begins */ if (state != PLAYER_STATE_STOP) - pc_update_audio(); + pc_update_audio(pc); if (state == PLAYER_STATE_STOP /* && config_option */) playlist->current = current; else if (seek_time == 0) - playlist_play(playlist, current); + playlist_play(playlist, pc, current); else - playlist_seek_song(playlist, current, seek_time); + playlist_seek_song(playlist, pc, current, seek_time); if (state == PLAYER_STATE_PAUSE) - pc_pause(); + pc_pause(pc); } return true; } unsigned -playlist_state_get_hash(const struct playlist *playlist) +playlist_state_get_hash(const struct playlist *playlist, + struct player_control *pc) { struct player_status player_status; - pc_get_status(&player_status); + pc_get_status(pc, &player_status); return playlist->queue.version ^ (player_status.state != PLAYER_STATE_STOP @@ -226,7 +240,7 @@ playlist_state_get_hash(const struct playlist *playlist) ? (queue_order_to_position(&playlist->queue, playlist->current) << 16) : 0) ^ - ((int)pc_get_cross_fade() << 20) ^ + ((int)pc_get_cross_fade(pc) << 20) ^ (player_status.state << 24) ^ (playlist->queue.random << 27) ^ (playlist->queue.repeat << 28) ^ diff --git a/src/playlist_state.h b/src/playlist_state.h index 8ca3657f2..f67d01d2c 100644 --- a/src/playlist_state.h +++ b/src/playlist_state.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -30,13 +30,15 @@ #include <stdio.h> struct playlist; +struct player_control; void -playlist_state_save(FILE *fp, const struct playlist *playlist); +playlist_state_save(FILE *fp, const struct playlist *playlist, + struct player_control *pc); bool playlist_state_restore(const char *line, FILE *fp, GString *buffer, - struct playlist *playlist); + struct playlist *playlist, struct player_control *pc); /** * Generates a hash number for the current state of the playlist and @@ -45,6 +47,7 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, * be saved. */ unsigned -playlist_state_get_hash(const struct playlist *playlist); +playlist_state_get_hash(const struct playlist *playlist, + struct player_control *pc); #endif diff --git a/src/playlist_vector.c b/src/playlist_vector.c index 7c1765a98..cfbe8939e 100644 --- a/src/playlist_vector.c +++ b/src/playlist_vector.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/playlist_vector.h b/src/playlist_vector.h index 62861ae49..8aa19a4e0 100644 --- a/src/playlist_vector.h +++ b/src/playlist_vector.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify |