diff options
Diffstat (limited to '')
-rw-r--r-- | src/playlist.c | 76 | ||||
-rw-r--r-- | src/playlist.h | 110 | ||||
-rw-r--r-- | src/playlist/m3u_playlist_plugin.c | 91 | ||||
-rw-r--r-- | src/playlist/m3u_playlist_plugin.h | 25 | ||||
-rw-r--r-- | src/playlist_control.c | 80 | ||||
-rw-r--r-- | src/playlist_edit.c | 166 | ||||
-rw-r--r-- | src/playlist_global.c | 18 | ||||
-rw-r--r-- | src/playlist_internal.h | 2 | ||||
-rw-r--r-- | src/playlist_list.c | 184 | ||||
-rw-r--r-- | src/playlist_list.h | 54 | ||||
-rw-r--r-- | src/playlist_plugin.h | 137 | ||||
-rw-r--r-- | src/playlist_print.c | 2 | ||||
-rw-r--r-- | src/playlist_save.c | 4 | ||||
-rw-r--r-- | src/playlist_state.c | 105 | ||||
-rw-r--r-- | src/playlist_state.h | 14 |
15 files changed, 816 insertions, 252 deletions
diff --git a/src/playlist.c b/src/playlist.c index 35c09329a..6ca9d014b 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -34,7 +34,8 @@ #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "playlist" -void playlistVersionChange(struct playlist *playlist) +void +playlist_increment_version_all(struct playlist *playlist) { queue_modify_all(&playlist->queue); idle_add(IDLE_PLAYLIST); @@ -61,16 +62,12 @@ playlist_init(struct playlist *playlist) playlist->queued = -1; playlist->current = -1; - - playlist->prev_elapsed = g_timer_new(); } void playlist_finish(struct playlist *playlist) { queue_finish(&playlist->queue); - - g_timer_destroy(playlist->prev_elapsed); } /** @@ -91,14 +88,15 @@ playlist_queue_song_order(struct playlist *playlist, unsigned order) g_debug("queue song %i:\"%s\"", playlist->queued, uri); g_free(uri); - queueSong(song); + pc_enqueue_song(song); } /** * Check if the player thread has already started playing the "queued" * song. */ -static void syncPlaylistWithQueue(struct playlist *playlist) +static void +playlist_sync_with_queue(struct playlist *playlist) { if (pc.next_song == NULL && playlist->queued != -1) { /* queued song has started: copy queued to current, @@ -109,7 +107,7 @@ static void syncPlaylistWithQueue(struct playlist *playlist) playlist->queued = -1; if(playlist->queue.consume) - deleteFromPlaylist(playlist, queue_order_to_position(&playlist->queue, current)); + playlist_delete(playlist, queue_order_to_position(&playlist->queue, current)); idle_add(IDLE_PLAYER); } @@ -178,7 +176,7 @@ playlist_update_queued_song(struct playlist *playlist, const struct song *prev) } void -playPlaylistOrderNumber(struct playlist *playlist, int orderNum) +playlist_play_order(struct playlist *playlist, int orderNum) { struct song *song; char *uri; @@ -192,34 +190,35 @@ playPlaylistOrderNumber(struct playlist *playlist, int orderNum) g_debug("play %i:\"%s\"", orderNum, uri); g_free(uri); - playerPlay(song); + pc_play(song); playlist->current = orderNum; } static void -playPlaylistIfPlayerStopped(struct playlist *playlist); +playlist_resume_playback(struct playlist *playlist); /** * 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 syncPlayerAndPlaylist(struct playlist *playlist) +void +playlist_sync(struct playlist *playlist) { if (!playlist->playing) /* this event has reached us out of sync: we aren't playing anymore; ignore the event */ return; - if (getPlayerState() == PLAYER_STATE_STOP) + if (pc_get_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 */ - playPlaylistIfPlayerStopped(playlist); + playlist_resume_playback(playlist); else { /* check if the player thread has already started playing the queued song */ - syncPlaylistWithQueue(playlist); + playlist_sync_with_queue(playlist); /* make sure the queued song is always set (if possible) */ @@ -233,14 +232,14 @@ void syncPlayerAndPlaylist(struct playlist *playlist) * decide whether to re-start playback */ static void -playPlaylistIfPlayerStopped(struct playlist *playlist) +playlist_resume_playback(struct playlist *playlist) { enum player_error error; assert(playlist->playing); - assert(getPlayerState() == PLAYER_STATE_STOP); + assert(pc_get_state() == PLAYER_STATE_STOP); - error = getPlayerError(); + error = pc_get_error(); if (error == PLAYER_ERROR_NOERROR) playlist->error_count = 0; else @@ -251,37 +250,38 @@ playPlaylistIfPlayerStopped(struct playlist *playlist) playlist->error_count >= queue_length(&playlist->queue)) /* too many errors, or critical error: stop playback */ - stopPlaylist(playlist); + playlist_stop(playlist); else /* continue playback at the next song */ - nextSongInPlaylist(playlist); + playlist_next(playlist); } bool -getPlaylistRepeatStatus(const struct playlist *playlist) +playlist_get_repeat(const struct playlist *playlist) { return playlist->queue.repeat; } bool -getPlaylistRandomStatus(const struct playlist *playlist) +playlist_get_random(const struct playlist *playlist) { return playlist->queue.random; } bool -getPlaylistSingleStatus(const struct playlist *playlist) +playlist_get_single(const struct playlist *playlist) { return playlist->queue.single; } bool -getPlaylistConsumeStatus(const struct playlist *playlist) +playlist_get_consume(const struct playlist *playlist) { return playlist->queue.consume; } -void setPlaylistRepeatStatus(struct playlist *playlist, bool status) +void +playlist_set_repeat(struct playlist *playlist, bool status) { if (status == playlist->queue.repeat) return; @@ -296,7 +296,8 @@ void setPlaylistRepeatStatus(struct playlist *playlist, bool status) idle_add(IDLE_OPTIONS); } -static void orderPlaylist(struct playlist *playlist) +static void +playlist_order(struct playlist *playlist) { if (playlist->current >= 0) /* update playlist.current, order==position now */ @@ -306,7 +307,8 @@ static void orderPlaylist(struct playlist *playlist) queue_restore_order(&playlist->queue); } -void setPlaylistSingleStatus(struct playlist *playlist, bool status) +void +playlist_set_single(struct playlist *playlist, bool status) { if (status == playlist->queue.single) return; @@ -321,7 +323,8 @@ void setPlaylistSingleStatus(struct playlist *playlist, bool status) idle_add(IDLE_OPTIONS); } -void setPlaylistConsumeStatus(struct playlist *playlist, bool status) +void +playlist_set_consume(struct playlist *playlist, bool status) { if (status == playlist->queue.consume) return; @@ -330,7 +333,8 @@ void setPlaylistConsumeStatus(struct playlist *playlist, bool status) idle_add(IDLE_OPTIONS); } -void setPlaylistRandomStatus(struct playlist *playlist, bool status) +void +playlist_set_random(struct playlist *playlist, bool status) { const struct song *queued; @@ -365,14 +369,15 @@ void setPlaylistRandomStatus(struct playlist *playlist, bool status) } else playlist->current = -1; } else - orderPlaylist(playlist); + playlist_order(playlist); playlist_update_queued_song(playlist, queued); idle_add(IDLE_OPTIONS); } -int getPlaylistCurrentSong(const struct playlist *playlist) +int +playlist_get_current_song(const struct playlist *playlist) { if (playlist->current >= 0) return queue_order_to_position(&playlist->queue, @@ -381,7 +386,8 @@ int getPlaylistCurrentSong(const struct playlist *playlist) return -1; } -int getPlaylistNextSong(const struct playlist *playlist) +int +playlist_get_next_song(const struct playlist *playlist) { if (playlist->current >= 0) { @@ -404,19 +410,19 @@ int getPlaylistNextSong(const struct playlist *playlist) } unsigned long -getPlaylistVersion(const struct playlist *playlist) +playlist_get_version(const struct playlist *playlist) { return playlist->queue.version; } int -getPlaylistLength(const struct playlist *playlist) +playlist_get_length(const struct playlist *playlist) { return queue_length(&playlist->queue); } unsigned -getPlaylistSongId(const struct playlist *playlist, unsigned song) +playlist_get_song_id(const struct playlist *playlist, unsigned song) { return queue_position_to_id(&playlist->queue, song); } diff --git a/src/playlist.h b/src/playlist.h index 57b2450fa..f8f5bd942 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -23,7 +23,6 @@ #include "queue.h" #include <stdbool.h> -#include <stdio.h> #define PLAYLIST_COMMENT '#' @@ -82,21 +81,16 @@ struct playlist { * This variable is only valid if #playing is true. */ int queued; - - /** - * This timer tracks the time elapsed since the last "prev" - * command. If that is less than one second ago, "prev" jumps - * to the previous song instead of rewinding the current song. - */ - GTimer *prev_elapsed; }; /** the global playlist object */ extern struct playlist g_playlist; -void initPlaylist(void); +void +playlist_global_init(void); -void finishPlaylist(void); +void +playlist_global_finish(void); void playlist_init(struct playlist *playlist); @@ -116,11 +110,8 @@ playlist_get_queue(const struct playlist *playlist) return &playlist->queue; } -void readPlaylistState(FILE *); - -void savePlaylistState(FILE *); - -void clearPlaylist(struct playlist *playlist); +void +playlist_clear(struct playlist *playlist); #ifndef WIN32 /** @@ -133,90 +124,111 @@ playlist_append_file(struct playlist *playlist, const char *path, int uid, #endif enum playlist_result -addToPlaylist(struct playlist *playlist, const char *file, unsigned *added_id); +playlist_append_uri(struct playlist *playlist, const char *file, + unsigned *added_id); enum playlist_result -addSongToPlaylist(struct playlist *playlist, +playlist_append_song(struct playlist *playlist, struct song *song, unsigned *added_id); enum playlist_result -deleteFromPlaylist(struct playlist *playlist, unsigned song); +playlist_delete(struct playlist *playlist, unsigned song); + +/** + * Deletes a range of songs from the playlist. + * + * @param start the position of the first song to delete + * @param end the position after the last song to delete + */ +enum playlist_result +playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end); enum playlist_result -deleteFromPlaylistById(struct playlist *playlist, unsigned song); +playlist_delete_id(struct playlist *playlist, unsigned song); -void stopPlaylist(struct playlist *playlist); +void +playlist_stop(struct playlist *playlist); enum playlist_result -playPlaylist(struct playlist *playlist, int song); +playlist_play(struct playlist *playlist, int song); enum playlist_result -playPlaylistById(struct playlist *playlist, int song); +playlist_play_id(struct playlist *playlist, int song); -void nextSongInPlaylist(struct playlist *playlist); +void +playlist_next(struct playlist *playlist); -void syncPlayerAndPlaylist(struct playlist *playlist); +void +playlist_sync(struct playlist *playlist); -void previousSongInPlaylist(struct playlist *playlist); +void +playlist_previous(struct playlist *playlist); -void shufflePlaylist(struct playlist *playlist, unsigned start, unsigned end); +void +playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end); void -deleteASongFromPlaylist(struct playlist *playlist, const struct song *song); +playlist_delete_song(struct playlist *playlist, const struct song *song); enum playlist_result -moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, int to); +playlist_move_range(struct playlist *playlist, unsigned start, unsigned end, int to); enum playlist_result -moveSongInPlaylistById(struct playlist *playlist, unsigned id, int to); +playlist_move_id(struct playlist *playlist, unsigned id, int to); enum playlist_result -swapSongsInPlaylist(struct playlist *playlist, unsigned song1, unsigned song2); +playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2); enum playlist_result -swapSongsInPlaylistById(struct playlist *playlist, unsigned id1, unsigned id2); +playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2); bool -getPlaylistRepeatStatus(const struct playlist *playlist); +playlist_get_repeat(const struct playlist *playlist); -void setPlaylistRepeatStatus(struct playlist *playlist, bool status); +void +playlist_set_repeat(struct playlist *playlist, bool status); bool -getPlaylistRandomStatus(const struct playlist *playlist); +playlist_get_random(const struct playlist *playlist); -void setPlaylistRandomStatus(struct playlist *playlist, bool status); +void +playlist_set_random(struct playlist *playlist, bool status); bool -getPlaylistSingleStatus(const struct playlist *playlist); +playlist_get_single(const struct playlist *playlist); -void setPlaylistSingleStatus(struct playlist *playlist, bool status); +void +playlist_set_single(struct playlist *playlist, bool status); bool -getPlaylistConsumeStatus(const struct playlist *playlist); +playlist_get_consume(const struct playlist *playlist); -void setPlaylistConsumeStatus(struct playlist *playlist, bool status); +void +playlist_set_consume(struct playlist *playlist, bool status); -int getPlaylistCurrentSong(const struct playlist *playlist); +int +playlist_get_current_song(const struct playlist *playlist); -int getPlaylistNextSong(const struct playlist *playlist); +int +playlist_get_next_song(const struct playlist *playlist); unsigned -getPlaylistSongId(const struct playlist *playlist, unsigned song); +playlist_get_song_id(const struct playlist *playlist, unsigned song); -int getPlaylistLength(const struct playlist *playlist); +int +playlist_get_length(const struct playlist *playlist); unsigned long -getPlaylistVersion(const struct playlist *playlist); +playlist_get_version(const struct playlist *playlist); enum playlist_result -seekSongInPlaylist(struct playlist *playlist, unsigned song, float seek_time); +playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time); enum playlist_result -seekSongInPlaylistById(struct playlist *playlist, +playlist_seek_song_id(struct playlist *playlist, unsigned id, float seek_time); -void playlistVersionChange(struct playlist *playlist); - -int is_valid_playlist_name(const char *utf8path); +void +playlist_increment_version_all(struct playlist *playlist); #endif diff --git a/src/playlist/m3u_playlist_plugin.c b/src/playlist/m3u_playlist_plugin.c new file mode 100644 index 000000000..6daea41f1 --- /dev/null +++ b/src/playlist/m3u_playlist_plugin.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2003-2009 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 "playlist/m3u_playlist_plugin.h" +#include "playlist_plugin.h" +#include "text_input_stream.h" +#include "uri.h" +#include "song.h" + +#include <glib.h> + +struct m3u_playlist { + struct playlist_provider base; + + struct text_input_stream *tis; +}; + +static struct playlist_provider * +m3u_open_stream(struct input_stream *is) +{ + struct m3u_playlist *playlist = g_new(struct m3u_playlist, 1); + + playlist_provider_init(&playlist->base, &m3u_playlist_plugin); + playlist->tis = text_input_stream_new(is); + + return &playlist->base; +} + +static void +m3u_close(struct playlist_provider *_playlist) +{ + struct m3u_playlist *playlist = (struct m3u_playlist *)_playlist; + + text_input_stream_free(playlist->tis); + g_free(playlist); +} + +static struct song * +m3u_read(struct playlist_provider *_playlist) +{ + struct m3u_playlist *playlist = (struct m3u_playlist *)_playlist; + const char *line; + + do { + line = text_input_stream_read(playlist->tis); + if (line == NULL) + return NULL; + + while (*line != 0 && g_ascii_isspace(*line)) + ++line; + } while (line[0] == '#' || !uri_has_scheme(line)); + + return song_remote_new(line); +} + +static const char *const m3u_suffixes[] = { + "m3u", + NULL +}; + +static const char *const m3u_mime_types[] = { + "audio/x-mpegurl", + NULL +}; + +const struct playlist_plugin m3u_playlist_plugin = { + .name = "m3u", + + .open_stream = m3u_open_stream, + .close = m3u_close, + .read = m3u_read, + + .suffixes = m3u_suffixes, + .mime_types = m3u_mime_types, +}; diff --git a/src/playlist/m3u_playlist_plugin.h b/src/playlist/m3u_playlist_plugin.h new file mode 100644 index 000000000..3cb4b8874 --- /dev/null +++ b/src/playlist/m3u_playlist_plugin.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2003-2009 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_M3U_PLAYLIST_PLUGIN_H +#define MPD_PLAYLIST_M3U_PLAYLIST_PLUGIN_H + +extern const struct playlist_plugin m3u_playlist_plugin; + +#endif diff --git a/src/playlist_control.c b/src/playlist_control.c index 4359611fd..66e7934dc 100644 --- a/src/playlist_control.c +++ b/src/playlist_control.c @@ -30,15 +30,7 @@ #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "playlist" -enum { - /** - * When the "prev" command is received, rewind the current - * track if this number of seconds has already elapsed. - */ - PLAYLIST_PREV_UNLESS_ELAPSED = 10, -}; - -void stopPlaylist(struct playlist *playlist) +void playlist_stop(struct playlist *playlist) { if (!playlist->playing) return; @@ -46,7 +38,7 @@ void stopPlaylist(struct playlist *playlist) assert(playlist->current >= 0); g_debug("stop"); - playerWait(); + pc_stop(); playlist->queued = -1; playlist->playing = false; @@ -68,11 +60,11 @@ void stopPlaylist(struct playlist *playlist) } } -enum playlist_result playPlaylist(struct playlist *playlist, int song) +enum playlist_result playlist_play(struct playlist *playlist, int song) { unsigned i = song; - clearPlayerError(); + pc_clear_error(); if (song == -1) { /* play any song ("current" song, or the first song */ @@ -83,7 +75,7 @@ enum playlist_result playPlaylist(struct playlist *playlist, int song) if (playlist->playing) { /* already playing: unpause playback, just in case it was paused, and return */ - playerSetPause(0); + pc_set_pause(false); return PLAYLIST_RESULT_SUCCESS; } @@ -115,28 +107,28 @@ enum playlist_result playPlaylist(struct playlist *playlist, int song) playlist->stop_on_error = false; playlist->error_count = 0; - playPlaylistOrderNumber(playlist, i); + playlist_play_order(playlist, i); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playPlaylistById(struct playlist *playlist, int id) +playlist_play_id(struct playlist *playlist, int id) { int song; if (id == -1) { - return playPlaylist(playlist, id); + return playlist_play(playlist, id); } song = queue_id_to_position(&playlist->queue, id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playPlaylist(playlist, song); + return playlist_play(playlist, song); } void -nextSongInPlaylist(struct playlist *playlist) +playlist_next(struct playlist *playlist) { int next_order; int current; @@ -157,7 +149,7 @@ nextSongInPlaylist(struct playlist *playlist) /* cancel single */ playlist->queue.single = false; /* no song after this one: stop playback */ - stopPlaylist(playlist); + playlist_stop(playlist); /* reset "current song" */ playlist->current = -1; @@ -174,50 +166,42 @@ nextSongInPlaylist(struct playlist *playlist) queue_shuffle_order(&playlist->queue); /* note that playlist->current and playlist->queued are - now invalid, but playPlaylistOrderNumber() will + now invalid, but playlist_play_order() will discard them anyway */ } - playPlaylistOrderNumber(playlist, next_order); + playlist_play_order(playlist, next_order); } /* Consume mode removes each played songs. */ if(playlist->queue.consume) - deleteFromPlaylist(playlist, queue_order_to_position(&playlist->queue, current)); + playlist_delete(playlist, queue_order_to_position(&playlist->queue, current)); } -void previousSongInPlaylist(struct playlist *playlist) +void playlist_previous(struct playlist *playlist) { if (!playlist->playing) return; - if (g_timer_elapsed(playlist->prev_elapsed, NULL) >= 1.0 && - getPlayerElapsedTime() > PLAYLIST_PREV_UNLESS_ELAPSED) { - /* re-start playing the current song (just like the - "prev" button on CD players) */ + assert(queue_length(&playlist->queue) > 0); - playPlaylistOrderNumber(playlist, playlist->current); + if (playlist->current > 0) { + /* play the preceding song */ + playlist_play_order(playlist, + playlist->current - 1); + } else if (playlist->queue.repeat) { + /* play the last song in "repeat" mode */ + playlist_play_order(playlist, + queue_length(&playlist->queue) - 1); } else { - if (playlist->current > 0) { - /* play the preceding song */ - playPlaylistOrderNumber(playlist, - playlist->current - 1); - } else if (playlist->queue.repeat) { - /* play the last song in "repeat" mode */ - playPlaylistOrderNumber(playlist, - queue_length(&playlist->queue) - 1); - } else { - /* re-start playing the current song if it's - the first one */ - playPlaylistOrderNumber(playlist, playlist->current); - } + /* re-start playing the current song if it's + the first one */ + playlist_play_order(playlist, playlist->current); } - - g_timer_start(playlist->prev_elapsed); } enum playlist_result -seekSongInPlaylist(struct playlist *playlist, unsigned song, float seek_time) +playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time) { const struct song *queued; unsigned i; @@ -233,7 +217,7 @@ seekSongInPlaylist(struct playlist *playlist, unsigned song, float seek_time) else i = song; - clearPlayerError(); + pc_clear_error(); playlist->stop_on_error = true; playlist->error_count = 0; @@ -241,7 +225,7 @@ seekSongInPlaylist(struct playlist *playlist, unsigned song, float seek_time) /* seeking is not within the current song - first start playing the new song */ - playPlaylistOrderNumber(playlist, i); + playlist_play_order(playlist, i); queued = NULL; } @@ -259,11 +243,11 @@ seekSongInPlaylist(struct playlist *playlist, unsigned song, float seek_time) } enum playlist_result -seekSongInPlaylistById(struct playlist *playlist, unsigned id, float seek_time) +playlist_seek_song_id(struct playlist *playlist, unsigned id, float seek_time) { int song = queue_id_to_position(&playlist->queue, id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return seekSongInPlaylist(playlist, song, seek_time); + return playlist_seek_song(playlist, song, seek_time); } diff --git a/src/playlist_edit.c b/src/playlist_edit.c index b83dc0933..8052f8470 100644 --- a/src/playlist_edit.c +++ b/src/playlist_edit.c @@ -35,16 +35,16 @@ #include <unistd.h> #include <stdlib.h> -static void incrPlaylistVersion(struct playlist *playlist) +static void playlist_increment_version(struct playlist *playlist) { queue_increment_version(&playlist->queue); idle_add(IDLE_PLAYLIST); } -void clearPlaylist(struct playlist *playlist) +void playlist_clear(struct playlist *playlist) { - stopPlaylist(playlist); + playlist_stop(playlist); /* make sure there are no references to allocated songs anymore */ @@ -58,7 +58,7 @@ void clearPlaylist(struct playlist *playlist) playlist->current = -1; - incrPlaylistVersion(playlist); + playlist_increment_version(playlist); } #ifndef WIN32 @@ -86,41 +86,12 @@ playlist_append_file(struct playlist *playlist, const char *path, int uid, if (song == NULL) return PLAYLIST_RESULT_NO_SUCH_SONG; - return addSongToPlaylist(playlist, song, added_id); + return playlist_append_song(playlist, song, added_id); } #endif -static struct song * -song_by_url(const char *url) -{ - struct song *song; - - song = db_get_song(url); - if (song != NULL) - return song; - - if (uri_has_scheme(url)) - return song_remote_new(url); - - return NULL; -} - -enum playlist_result -addToPlaylist(struct playlist *playlist, const char *url, unsigned *added_id) -{ - struct song *song; - - g_debug("add to playlist: %s", url); - - song = song_by_url(url); - if (song == NULL) - return PLAYLIST_RESULT_NO_SUCH_SONG; - - return addSongToPlaylist(playlist, song, added_id); -} - enum playlist_result -addSongToPlaylist(struct playlist *playlist, +playlist_append_song(struct playlist *playlist, struct song *song, unsigned *added_id) { const struct song *queued; @@ -147,7 +118,7 @@ addSongToPlaylist(struct playlist *playlist, queue_length(&playlist->queue)); } - incrPlaylistVersion(playlist); + playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); @@ -157,8 +128,38 @@ addSongToPlaylist(struct playlist *playlist, return PLAYLIST_RESULT_SUCCESS; } +static struct song * +song_by_uri(const char *uri) +{ + struct song *song; + + song = db_get_song(uri); + if (song != NULL) + return song; + + if (uri_has_scheme(uri)) + return song_remote_new(uri); + + return NULL; +} + +enum playlist_result +playlist_append_uri(struct playlist *playlist, const char *uri, + unsigned *added_id) +{ + struct song *song; + + g_debug("add to playlist: %s", uri); + + song = song_by_uri(uri); + if (song == NULL) + return PLAYLIST_RESULT_NO_SUCH_SONG; + + return playlist_append_song(playlist, song, added_id); +} + enum playlist_result -swapSongsInPlaylist(struct playlist *playlist, unsigned song1, unsigned song2) +playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2) { const struct song *queued; @@ -188,7 +189,7 @@ swapSongsInPlaylist(struct playlist *playlist, unsigned song1, unsigned song2) playlist->current = song1; } - incrPlaylistVersion(playlist); + playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); @@ -196,7 +197,7 @@ swapSongsInPlaylist(struct playlist *playlist, unsigned song1, unsigned song2) } enum playlist_result -swapSongsInPlaylistById(struct playlist *playlist, unsigned id1, unsigned id2) +playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2) { int song1 = queue_id_to_position(&playlist->queue, id1); int song2 = queue_id_to_position(&playlist->queue, id2); @@ -204,28 +205,25 @@ swapSongsInPlaylistById(struct playlist *playlist, unsigned id1, unsigned id2) if (song1 < 0 || song2 < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return swapSongsInPlaylist(playlist, song1, song2); + return playlist_swap_songs(playlist, song1, song2); } -enum playlist_result -deleteFromPlaylist(struct playlist *playlist, unsigned song) +static void +playlist_delete_internal(struct playlist *playlist, unsigned song, + const struct song **queued_p) { - const struct song *queued; unsigned songOrder; - if (song >= queue_length(&playlist->queue)) - return PLAYLIST_RESULT_BAD_RANGE; - - queued = playlist_get_queued_song(playlist); + assert(song < queue_length(&playlist->queue)); songOrder = queue_position_to_order(&playlist->queue, song); if (playlist->playing && playlist->current == (int)songOrder) { - bool paused = getPlayerState() == PLAYER_STATE_PAUSE; + bool paused = pc_get_state() == PLAYER_STATE_PAUSE; /* the current song is going to be deleted: stop the player */ - playerWait(); + pc_stop(); playlist->playing = false; /* see which song is going to be played instead */ @@ -237,13 +235,13 @@ deleteFromPlaylist(struct playlist *playlist, unsigned song) if (playlist->current >= 0 && !paused) /* play the song after the deleted one */ - playPlaylistOrderNumber(playlist, playlist->current); + playlist_play_order(playlist, playlist->current); else /* no songs left to play, stop playback completely */ - stopPlaylist(playlist); + playlist_stop(playlist); - queued = NULL; + *queued_p = NULL; } else if (playlist->current == (int)songOrder) /* there's a "current song" but we're not playing currently - clear "current" */ @@ -256,41 +254,80 @@ deleteFromPlaylist(struct playlist *playlist, unsigned song) queue_delete(&playlist->queue, song); - incrPlaylistVersion(playlist); - /* update the "current" and "queued" variables */ if (playlist->current > (int)songOrder) { playlist->current--; } +} + +enum playlist_result +playlist_delete(struct playlist *playlist, unsigned song) +{ + const struct song *queued; + + if (song >= queue_length(&playlist->queue)) + return PLAYLIST_RESULT_BAD_RANGE; + + queued = playlist_get_queued_song(playlist); + + playlist_delete_internal(playlist, song, &queued); + playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -deleteFromPlaylistById(struct playlist *playlist, unsigned id) +playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end) +{ + const struct song *queued; + + 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; + + queued = playlist_get_queued_song(playlist); + + do { + playlist_delete_internal(playlist, --end, &queued); + } while (end != start); + + playlist_increment_version(playlist); + playlist_update_queued_song(playlist, queued); + + return PLAYLIST_RESULT_SUCCESS; +} + +enum playlist_result +playlist_delete_id(struct playlist *playlist, unsigned id) { int song = queue_id_to_position(&playlist->queue, id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return deleteFromPlaylist(playlist, song); + return playlist_delete(playlist, song); } void -deleteASongFromPlaylist(struct playlist *playlist, const struct song *song) +playlist_delete_song(struct playlist *playlist, const struct song *song) { for (int i = queue_length(&playlist->queue) - 1; i >= 0; --i) if (song == queue_get(&playlist->queue, i)) - deleteFromPlaylist(playlist, i); + playlist_delete(playlist, i); pc_song_deleted(song); } enum playlist_result -moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, int to) +playlist_move_range(struct playlist *playlist, + unsigned start, unsigned end, int to) { const struct song *queued; int currentSong; @@ -342,7 +379,7 @@ moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, } } - incrPlaylistVersion(playlist); + playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); @@ -350,16 +387,17 @@ moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, } enum playlist_result -moveSongInPlaylistById(struct playlist *playlist, unsigned id1, int to) +playlist_move_id(struct playlist *playlist, unsigned id1, int to) { int song = queue_id_to_position(&playlist->queue, id1); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return moveSongRangeInPlaylist(playlist, song, song+1, to); + return playlist_move_range(playlist, song, song+1, to); } -void shufflePlaylist(struct playlist *playlist, unsigned start, unsigned end) +void +playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end) { const struct song *queued; @@ -399,7 +437,7 @@ void shufflePlaylist(struct playlist *playlist, unsigned start, unsigned end) queue_shuffle_range(&playlist->queue, start, end); - incrPlaylistVersion(playlist); + playlist_increment_version(playlist); playlist_update_queued_song(playlist, queued); } diff --git a/src/playlist_global.c b/src/playlist_global.c index fa810bbc3..dcb972490 100644 --- a/src/playlist_global.c +++ b/src/playlist_global.c @@ -37,10 +37,11 @@ playlist_tag_event(void) static void playlist_event(void) { - syncPlayerAndPlaylist(&g_playlist); + playlist_sync(&g_playlist); } -void initPlaylist(void) +void +playlist_global_init(void) { playlist_init(&g_playlist); @@ -48,17 +49,8 @@ void initPlaylist(void) event_pipe_register(PIPE_EVENT_PLAYLIST, playlist_event); } -void finishPlaylist(void) +void +playlist_global_finish(void) { playlist_finish(&g_playlist); } - -void savePlaylistState(FILE *fp) -{ - playlist_state_save(fp, &g_playlist); -} - -void readPlaylistState(FILE *fp) -{ - playlist_state_restore(fp, &g_playlist); -} diff --git a/src/playlist_internal.h b/src/playlist_internal.h index af880691b..8b2f780cc 100644 --- a/src/playlist_internal.h +++ b/src/playlist_internal.h @@ -47,6 +47,6 @@ playlist_update_queued_song(struct playlist *playlist, const struct song *prev); void -playPlaylistOrderNumber(struct playlist *playlist, int orderNum); +playlist_play_order(struct playlist *playlist, int orderNum); #endif diff --git a/src/playlist_list.c b/src/playlist_list.c new file mode 100644 index 000000000..6a0e85c64 --- /dev/null +++ b/src/playlist_list.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2003-2009 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 "playlist_list.h" +#include "playlist_plugin.h" +#include "playlist/m3u_playlist_plugin.h" +#include "input_stream.h" +#include "uri.h" +#include "utils.h" +#include "conf.h" + +#include <glib.h> + +#include <assert.h> +#include <string.h> + +static const struct playlist_plugin *const playlist_plugins[] = { + &m3u_playlist_plugin, + NULL +}; + +/** which plugins have been initialized successfully? */ +static bool playlist_plugins_enabled[G_N_ELEMENTS(playlist_plugins)]; + +/** + * Find the "playlist" configuration block for the specified plugin. + * + * @param plugin_name the name of the playlist plugin + * @return the configuration block, or NULL if none was configured + */ +static const struct config_param * +playlist_plugin_config(const char *plugin_name) +{ + const struct config_param *param = NULL; + + assert(plugin_name != NULL); + + while ((param = config_get_next_param(CONF_PLAYLIST_PLUGIN, param)) != NULL) { + const char *name = + config_get_block_string(param, "name", NULL); + if (name == NULL) + g_error("playlist configuration without 'plugin' name in line %d", + param->line); + + if (strcmp(name, plugin_name) == 0) + return param; + } + + return NULL; +} + +void +playlist_list_global_init(void) +{ + for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) { + const struct playlist_plugin *plugin = playlist_plugins[i]; + const struct config_param *param = + playlist_plugin_config(plugin->name); + + if (!config_get_block_bool(param, "enabled", true)) + /* the plugin is disabled in mpd.conf */ + continue; + + playlist_plugins_enabled[i] = + playlist_plugin_init(playlist_plugins[i], param); + } +} + +void +playlist_list_global_finish(void) +{ + for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) + if (playlist_plugins_enabled[i]) + playlist_plugin_finish(playlist_plugins[i]); +} + +struct playlist_provider * +playlist_list_open_uri(const char *uri) +{ + char *scheme; + struct playlist_provider *playlist = NULL; + + assert(uri != NULL); + + scheme = g_uri_parse_scheme(uri); + if (scheme == NULL) + return NULL; + + for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) { + const struct playlist_plugin *plugin = playlist_plugins[i]; + + if (playlist_plugins_enabled[i] && + stringFoundInStringArray(plugin->schemes, scheme)) { + playlist = playlist_plugin_open_uri(plugin, uri); + if (playlist != NULL) + break; + } + } + + g_free(scheme); + return playlist; +} + +static struct playlist_provider * +playlist_list_open_stream_mime(struct input_stream *is) +{ + struct playlist_provider *playlist; + + assert(is != NULL); + assert(is->mime != NULL); + + for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) { + const struct playlist_plugin *plugin = playlist_plugins[i]; + + if (playlist_plugins_enabled[i] && + stringFoundInStringArray(plugin->mime_types, is->mime)) { + playlist = playlist_plugin_open_stream(plugin, is); + if (playlist != NULL) + return playlist; + } + } + + return NULL; +} + +static struct playlist_provider * +playlist_list_open_stream_suffix(struct input_stream *is, const char *suffix) +{ + struct playlist_provider *playlist; + + assert(is != NULL); + assert(suffix != NULL); + + for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) { + const struct playlist_plugin *plugin = playlist_plugins[i]; + + if (playlist_plugins_enabled[i] && + stringFoundInStringArray(plugin->suffixes, suffix)) { + playlist = playlist_plugin_open_stream(plugin, is); + if (playlist != NULL) + return playlist; + } + } + + return NULL; +} + +struct playlist_provider * +playlist_list_open_stream(struct input_stream *is, const char *uri) +{ + const char *suffix; + struct playlist_provider *playlist; + + if (is->mime != NULL) { + playlist = playlist_list_open_stream_mime(is); + if (playlist != NULL) + return playlist; + } + + suffix = uri != NULL ? uri_get_suffix(uri) : NULL; + if (suffix != NULL) { + playlist = playlist_list_open_stream_suffix(is, suffix); + if (playlist != NULL) + return playlist; + } + + return NULL; +} diff --git a/src/playlist_list.h b/src/playlist_list.h new file mode 100644 index 000000000..b5ac52a6f --- /dev/null +++ b/src/playlist_list.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2003-2009 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_LIST_H +#define MPD_PLAYLIST_LIST_H + +struct playlist_provider; +struct input_stream; + +/** + * Initializes all playlist plugins. + */ +void +playlist_list_global_init(void); + +/** + * Deinitializes all playlist plugins. + */ +void +playlist_list_global_finish(void); + +/** + * Opens a playlist by its URI. + */ +struct playlist_provider * +playlist_list_open_uri(const char *uri); + +/** + * Opens a playlist from an input stream. + * + * @param is an #input_stream object which is open and ready + * @param uri optional URI which was used to open the stream; may be + * used to select the appropriate playlist plugin + */ +struct playlist_provider * +playlist_list_open_stream(struct input_stream *is, const char *uri); + +#endif diff --git a/src/playlist_plugin.h b/src/playlist_plugin.h new file mode 100644 index 000000000..3515af109 --- /dev/null +++ b/src/playlist_plugin.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2003-2009 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_PLUGIN_H +#define MPD_PLAYLIST_PLUGIN_H + +#include <stdbool.h> +#include <stddef.h> + +struct config_param; +struct input_stream; +struct tag; + +/** + * An object which provides the contents of a playlist. + */ +struct playlist_provider { + const struct playlist_plugin *plugin; +}; + +static inline void +playlist_provider_init(struct playlist_provider *playlist, + const struct playlist_plugin *plugin) +{ + playlist->plugin = plugin; +} + +struct playlist_plugin { + const char *name; + + /** + * Initialize the plugin. Optional method. + * + * @param param a configuration block for this plugin, or NULL + * if none is configured + * @return true if the plugin was initialized successfully, + * false if the plugin is not available + */ + bool (*init)(const struct config_param *param); + + /** + * Deinitialize a plugin which was initialized successfully. + * Optional method. + */ + void (*finish)(void); + + /** + * 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); + + /** + * Opens the playlist in the specified input stream. It has + * either matched one of the suffixes or one of the MIME + * types. + */ + struct playlist_provider *(*open_stream)(struct input_stream *is); + + void (*close)(struct playlist_provider *playlist); + + struct song *(*read)(struct playlist_provider *playlist); + + const char *const*schemes; + const char *const*suffixes; + const char *const*mime_types; +}; + +/** + * Initialize a plugin. + * + * @param param a configuration block for this plugin, or NULL if none + * is configured + * @return true if the plugin was initialized successfully, false if + * the plugin is not available + */ +static inline bool +playlist_plugin_init(const struct playlist_plugin *plugin, + const struct config_param *param) +{ + return plugin->init != NULL + ? plugin->init(param) + : true; +} + +/** + * Deinitialize a plugin which was initialized successfully. + */ +static inline void +playlist_plugin_finish(const struct playlist_plugin *plugin) +{ + if (plugin->finish != NULL) + plugin->finish(); +} + +static inline struct playlist_provider * +playlist_plugin_open_uri(const struct playlist_plugin *plugin, const char *uri) +{ + return plugin->open_uri(uri); +} + +static inline struct playlist_provider * +playlist_plugin_open_stream(const struct playlist_plugin *plugin, + struct input_stream *is) +{ + return plugin->open_stream(is); +} + +static inline void +playlist_plugin_close(struct playlist_provider *playlist) +{ + playlist->plugin->close(playlist); +} + +static inline struct song * +playlist_plugin_read(struct playlist_provider *playlist) +{ + return playlist->plugin->read(playlist); +} + +#endif diff --git a/src/playlist_print.c b/src/playlist_print.c index fd61ab62c..1ca11e4c1 100644 --- a/src/playlist_print.c +++ b/src/playlist_print.c @@ -69,7 +69,7 @@ playlist_print_id(struct client *client, const struct playlist *playlist, bool playlist_print_current(struct client *client, const struct playlist *playlist) { - int current_position = getPlaylistCurrentSong(playlist); + int current_position = playlist_get_current_song(playlist); if (current_position < 0) return false; diff --git a/src/playlist_save.c b/src/playlist_save.c index 776d3c385..103a810fb 100644 --- a/src/playlist_save.c +++ b/src/playlist_save.c @@ -115,7 +115,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8) for (unsigned i = 0; i < list->len; ++i) { const char *temp = g_ptr_array_index(list, i); - if ((addToPlaylist(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { + if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { /* for windows compatibility, convert slashes */ char *temp2 = g_strdup(temp); char *p = temp2; @@ -124,7 +124,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8) *p = '/'; p++; } - if ((addToPlaylist(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { + if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { g_warning("can't add file \"%s\"", temp2); } g_free(temp2); diff --git a/src/playlist_state.c b/src/playlist_state.c index af0f7982b..d97fb1369 100644 --- a/src/playlist_state.c +++ b/src/playlist_state.c @@ -51,10 +51,14 @@ void playlist_state_save(FILE *fp, const struct playlist *playlist) { + struct player_status player_status; + + pc_get_status(&player_status); + fprintf(fp, "%s", PLAYLIST_STATE_FILE_STATE); if (playlist->playing) { - switch (getPlayerState()) { + switch (player_status.state) { case PLAYER_STATE_PAUSE: fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_PAUSE); break; @@ -65,10 +69,16 @@ playlist_state_save(FILE *fp, const struct playlist *playlist) queue_order_to_position(&playlist->queue, playlist->current)); fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_TIME, - getPlayerElapsedTime()); - } else + (int)player_status.elapsed_time); + } else { fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_STOP); + if (playlist->current >= 0) + fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CURRENT, + queue_order_to_position(&playlist->queue, + playlist->current)); + } + fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_RANDOM, playlist->queue.random); fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_REPEAT, @@ -78,7 +88,7 @@ playlist_state_save(FILE *fp, const struct playlist *playlist) fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CONSUME, playlist->queue.consume); fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CROSSFADE, - (int)(getPlayerCrossFade())); + (int)(pc_get_cross_fade())); fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_PLAYLIST_BEGIN); queue_save(fp, &playlist->queue); fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_PLAYLIST_END); @@ -109,8 +119,8 @@ playlist_state_load(FILE *fp, struct playlist *playlist, char *buffer) queue_increment_version(&playlist->queue); } -void -playlist_state_restore(FILE *fp, struct playlist *playlist) +bool +playlist_state_restore(const char *line, FILE *fp, struct playlist *playlist) { int current = -1; int seek_time = 0; @@ -118,50 +128,45 @@ playlist_state_restore(FILE *fp, struct playlist *playlist) char buffer[PLAYLIST_BUFFER_SIZE]; bool random_mode = false; + if (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_STATE)) + return false; + + line += sizeof(PLAYLIST_STATE_FILE_STATE) - 1; + + if (strcmp(line, PLAYLIST_STATE_FILE_STATE_PLAY) == 0) + state = PLAYER_STATE_PLAY; + else if (strcmp(line, PLAYLIST_STATE_FILE_STATE_PAUSE) == 0) + state = PLAYER_STATE_PAUSE; + while (fgets(buffer, sizeof(buffer), fp)) { g_strchomp(buffer); - if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_STATE)) { - if (strcmp(&(buffer[strlen(PLAYLIST_STATE_FILE_STATE)]), - PLAYLIST_STATE_FILE_STATE_PLAY) == 0) { - state = PLAYER_STATE_PLAY; - } else - if (strcmp - (&(buffer[strlen(PLAYLIST_STATE_FILE_STATE)]), - PLAYLIST_STATE_FILE_STATE_PAUSE) - == 0) { - state = PLAYER_STATE_PAUSE; - } - } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_TIME)) { + if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_TIME)) { seek_time = atoi(&(buffer[strlen(PLAYLIST_STATE_FILE_TIME)])); } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_REPEAT)) { if (strcmp (&(buffer[strlen(PLAYLIST_STATE_FILE_REPEAT)]), "1") == 0) { - setPlaylistRepeatStatus(playlist, true); + playlist_set_repeat(playlist, true); } else - setPlaylistRepeatStatus(playlist, false); + playlist_set_repeat(playlist, false); } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_SINGLE)) { if (strcmp (&(buffer[strlen(PLAYLIST_STATE_FILE_SINGLE)]), "1") == 0) { - setPlaylistSingleStatus(playlist, true); + playlist_set_single(playlist, true); } else - setPlaylistSingleStatus(playlist, false); + playlist_set_single(playlist, false); } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_CONSUME)) { if (strcmp (&(buffer[strlen(PLAYLIST_STATE_FILE_CONSUME)]), "1") == 0) { - setPlaylistConsumeStatus(playlist, true); + playlist_set_consume(playlist, true); } else - setPlaylistConsumeStatus(playlist, false); + playlist_set_consume(playlist, false); } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_CROSSFADE)) { - setPlayerCrossFade(atoi - (& - (buffer - [strlen - (PLAYLIST_STATE_FILE_CROSSFADE)]))); + pc_set_cross_fade(atoi(buffer + strlen(PLAYLIST_STATE_FILE_CROSSFADE))); } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_RANDOM)) { random_mode = strcmp(buffer + strlen(PLAYLIST_STATE_FILE_RANDOM), @@ -172,24 +177,50 @@ playlist_state_restore(FILE *fp, struct playlist *playlist) (PLAYLIST_STATE_FILE_CURRENT)])); } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_PLAYLIST_BEGIN)) { - if (state == PLAYER_STATE_STOP) - current = -1; playlist_state_load(fp, playlist, buffer); } } - setPlaylistRandomStatus(playlist, random_mode); + playlist_set_random(playlist, random_mode); - if (state != PLAYER_STATE_STOP && !queue_is_empty(&playlist->queue)) { + if (!queue_is_empty(&playlist->queue)) { if (!queue_valid_position(&playlist->queue, current)) current = 0; - if (seek_time == 0) - playPlaylist(playlist, current); + if (state == PLAYER_STATE_STOP /* && config_option */) + playlist->current = current; + else if (seek_time == 0) + playlist_play(playlist, current); else - seekSongInPlaylist(playlist, current, seek_time); + playlist_seek_song(playlist, current, seek_time); if (state == PLAYER_STATE_PAUSE) - playerPause(); + pc_pause(); } + + return true; +} + +unsigned +playlist_state_get_hash(const struct playlist *playlist) +{ + struct player_status player_status; + + pc_get_status(&player_status); + + return playlist->queue.version ^ + (player_status.state != PLAYER_STATE_STOP + ? ((int)player_status.elapsed_time << 8) + : 0) ^ + (playlist->current >= 0 + ? (queue_order_to_position(&playlist->queue, + playlist->current) << 16) + : 0) ^ + ((int)pc_get_cross_fade() << 20) ^ + (player_status.state << 24) ^ + (playlist->queue.random << 27) ^ + (playlist->queue.repeat << 28) ^ + (playlist->queue.single << 29) ^ + (playlist->queue.consume << 30) ^ + (playlist->queue.random << 31); } diff --git a/src/playlist_state.h b/src/playlist_state.h index 989430264..d116aaeb1 100644 --- a/src/playlist_state.h +++ b/src/playlist_state.h @@ -25,6 +25,7 @@ #ifndef PLAYLIST_STATE_H #define PLAYLIST_STATE_H +#include <stdbool.h> #include <stdio.h> struct playlist; @@ -32,7 +33,16 @@ struct playlist; void playlist_state_save(FILE *fp, const struct playlist *playlist); -void -playlist_state_restore(FILE *fp, struct playlist *playlist); +bool +playlist_state_restore(const char *line, FILE *fp, struct playlist *playlist); + +/** + * Generates a hash number for the current state of the playlist and + * the playback options. This is used by timer_save_state_file() to + * determine whether the state has changed and the state file should + * be saved. + */ +unsigned +playlist_state_get_hash(const struct playlist *playlist); #endif |