aboutsummaryrefslogtreecommitdiffstats
path: root/src/playlist
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/playlist.c452
-rw-r--r--src/playlist.h256
-rw-r--r--src/playlist/AsxPlaylistPlugin.cxx285
-rw-r--r--src/playlist/AsxPlaylistPlugin.hxx25
-rw-r--r--src/playlist/CuePlaylistPlugin.cxx91
-rw-r--r--src/playlist/CuePlaylistPlugin.hxx25
-rw-r--r--src/playlist/DespotifyPlaylistPlugin.cxx145
-rw-r--r--src/playlist/DespotifyPlaylistPlugin.hxx25
-rw-r--r--src/playlist/EmbeddedCuePlaylistPlugin.cxx180
-rw-r--r--src/playlist/EmbeddedCuePlaylistPlugin.hxx25
-rw-r--r--src/playlist/ExtM3uPlaylistPlugin.cxx158
-rw-r--r--src/playlist/ExtM3uPlaylistPlugin.hxx25
-rw-r--r--src/playlist/M3uPlaylistPlugin.cxx86
-rw-r--r--src/playlist/M3uPlaylistPlugin.hxx25
-rw-r--r--src/playlist/PlsPlaylistPlugin.cxx185
-rw-r--r--src/playlist/PlsPlaylistPlugin.hxx25
-rw-r--r--src/playlist/RssPlaylistPlugin.cxx283
-rw-r--r--src/playlist/RssPlaylistPlugin.hxx25
-rw-r--r--src/playlist/SoundCloudPlaylistPlugin.cxx421
-rw-r--r--src/playlist/SoundCloudPlaylistPlugin.hxx25
-rw-r--r--src/playlist/XspfPlaylistPlugin.cxx301
-rw-r--r--src/playlist/XspfPlaylistPlugin.hxx25
-rw-r--r--src/playlist/asx_playlist_plugin.c323
-rw-r--r--src/playlist/asx_playlist_plugin.h25
-rw-r--r--src/playlist/cue_playlist_plugin.c108
-rw-r--r--src/playlist/cue_playlist_plugin.h25
-rw-r--r--src/playlist/despotify_playlist_plugin.c217
-rw-r--r--src/playlist/despotify_playlist_plugin.h25
-rw-r--r--src/playlist/embcue_playlist_plugin.c181
-rw-r--r--src/playlist/embcue_playlist_plugin.h25
-rw-r--r--src/playlist/extm3u_playlist_plugin.c162
-rw-r--r--src/playlist/extm3u_playlist_plugin.h25
-rw-r--r--src/playlist/lastfm_playlist_plugin.c296
-rw-r--r--src/playlist/lastfm_playlist_plugin.h25
-rw-r--r--src/playlist/m3u_playlist_plugin.c92
-rw-r--r--src/playlist/m3u_playlist_plugin.h25
-rw-r--r--src/playlist/pls_playlist_plugin.c220
-rw-r--r--src/playlist/pls_playlist_plugin.h25
-rw-r--r--src/playlist/rss_playlist_plugin.c322
-rw-r--r--src/playlist/rss_playlist_plugin.h25
-rw-r--r--src/playlist/soundcloud_playlist_plugin.c448
-rw-r--r--src/playlist/soundcloud_playlist_plugin.h25
-rw-r--r--src/playlist/xspf_playlist_plugin.c343
-rw-r--r--src/playlist/xspf_playlist_plugin.h25
-rw-r--r--src/playlist_any.c71
-rw-r--r--src/playlist_any.h41
-rw-r--r--src/playlist_control.c288
-rw-r--r--src/playlist_database.c79
-rw-r--r--src/playlist_database.h40
-rw-r--r--src/playlist_edit.c492
-rw-r--r--src/playlist_error.h49
-rw-r--r--src/playlist_global.c58
-rw-r--r--src/playlist_internal.h56
-rw-r--r--src/playlist_list.c348
-rw-r--r--src/playlist_list.h85
-rw-r--r--src/playlist_mapper.c110
-rw-r--r--src/playlist_mapper.h39
-rw-r--r--src/playlist_plugin.h141
-rw-r--r--src/playlist_print.c199
-rw-r--r--src/playlist_print.h117
-rw-r--r--src/playlist_queue.c97
-rw-r--r--src/playlist_queue.h61
-rw-r--r--src/playlist_save.c161
-rw-r--r--src/playlist_save.h61
-rw-r--r--src/playlist_song.c169
-rw-r--r--src/playlist_song.h37
-rw-r--r--src/playlist_state.c250
-rw-r--r--src/playlist_state.h53
-rw-r--r--src/playlist_vector.c114
-rw-r--r--src/playlist_vector.h80
70 files changed, 2385 insertions, 6991 deletions
diff --git a/src/playlist.c b/src/playlist.c
deleted file mode 100644
index dc6d8c340..000000000
--- a/src/playlist.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_internal.h"
-#include "playlist_save.h"
-#include "player_control.h"
-#include "command.h"
-#include "tag.h"
-#include "song.h"
-#include "conf.h"
-#include "stored_playlist.h"
-#include "idle.h"
-
-#include <glib.h>
-
-#include <assert.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "playlist"
-
-void
-playlist_increment_version_all(struct playlist *playlist)
-{
- queue_modify_all(&playlist->queue);
- idle_add(IDLE_PLAYLIST);
-}
-
-void
-playlist_tag_changed(struct playlist *playlist)
-{
- if (!playlist->playing)
- return;
-
- assert(playlist->current >= 0);
-
- queue_modify(&playlist->queue, playlist->current);
- idle_add(IDLE_PLAYLIST);
-}
-
-void
-playlist_init(struct playlist *playlist)
-{
- queue_init(&playlist->queue,
- config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
- DEFAULT_PLAYLIST_MAX_LENGTH));
-
- playlist->queued = -1;
- playlist->current = -1;
-}
-
-void
-playlist_finish(struct playlist *playlist)
-{
- queue_finish(&playlist->queue);
-}
-
-/**
- * Queue a song, addressed by its order number.
- */
-static void
-playlist_queue_song_order(struct playlist *playlist, struct player_control *pc,
- unsigned order)
-{
- struct song *song;
- char *uri;
-
- assert(queue_valid_order(&playlist->queue, order));
-
- playlist->queued = order;
-
- song = queue_get_order(&playlist->queue, order);
- uri = song_get_uri(song);
- g_debug("queue song %i:\"%s\"", playlist->queued, uri);
- g_free(uri);
-
- pc_enqueue_song(pc, song);
-}
-
-/**
- * Called if the player thread has started playing the "queued" song.
- */
-static void
-playlist_song_started(struct playlist *playlist, struct player_control *pc)
-{
- assert(pc->next_song == NULL);
- assert(playlist->queued >= -1);
-
- /* queued song has started: copy queued to current,
- and notify the clients */
-
- int current = playlist->current;
- playlist->current = playlist->queued;
- playlist->queued = -1;
-
- if(playlist->queue.consume)
- playlist_delete(playlist, pc,
- queue_order_to_position(&playlist->queue,
- current));
-
- idle_add(IDLE_PLAYER);
-}
-
-const struct song *
-playlist_get_queued_song(struct playlist *playlist)
-{
- if (!playlist->playing || playlist->queued < 0)
- return NULL;
-
- return queue_get_order(&playlist->queue, playlist->queued);
-}
-
-void
-playlist_update_queued_song(struct playlist *playlist,
- struct player_control *pc,
- const struct song *prev)
-{
- int next_order;
- const struct song *next_song;
-
- if (!playlist->playing)
- return;
-
- assert(!queue_is_empty(&playlist->queue));
- assert((playlist->queued < 0) == (prev == NULL));
-
- next_order = playlist->current >= 0
- ? queue_next_order(&playlist->queue, playlist->current)
- : 0;
-
- if (next_order == 0 && playlist->queue.random &&
- !playlist->queue.single) {
- /* shuffle the song order again, so we get a different
- order each time the playlist is played
- completely */
- unsigned current_position =
- queue_order_to_position(&playlist->queue,
- playlist->current);
-
- queue_shuffle_order(&playlist->queue);
-
- /* make sure that the playlist->current still points to
- the current song, after the song order has been
- shuffled */
- playlist->current =
- queue_position_to_order(&playlist->queue,
- current_position);
- }
-
- if (next_order >= 0)
- next_song = queue_get_order(&playlist->queue, next_order);
- else
- next_song = NULL;
-
- if (prev != NULL && next_song != prev) {
- /* clear the currently queued song */
- pc_cancel(pc);
- playlist->queued = -1;
- }
-
- if (next_order >= 0) {
- if (next_song != prev)
- playlist_queue_song_order(playlist, pc, next_order);
- else
- playlist->queued = next_order;
- }
-}
-
-void
-playlist_play_order(struct playlist *playlist, struct player_control *pc,
- int orderNum)
-{
- struct song *song;
- char *uri;
-
- playlist->playing = true;
- playlist->queued = -1;
-
- song = queue_get_order(&playlist->queue, orderNum);
-
- uri = song_get_uri(song);
- g_debug("play %i:\"%s\"", orderNum, uri);
- g_free(uri);
-
- pc_play(pc, song);
- playlist->current = orderNum;
-}
-
-static void
-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, 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(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, 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, pc);
-
- player_lock(pc);
- pc_next_song = pc->next_song;
- player_unlock(pc);
-
- /* make sure the queued song is always set (if
- possible) */
- if (pc_next_song == NULL && playlist->queued < 0)
- playlist_update_queued_song(playlist, pc, NULL);
- }
-}
-
-/**
- * The player has stopped for some reason. Check the error, and
- * decide whether to re-start playback
- */
-static void
-playlist_resume_playback(struct playlist *playlist, struct player_control *pc)
-{
- enum player_error error;
-
- assert(playlist->playing);
- assert(pc_get_state(pc) == PLAYER_STATE_STOP);
-
- error = pc_get_error(pc);
- if (error == PLAYER_ERROR_NOERROR)
- playlist->error_count = 0;
- else
- ++playlist->error_count;
-
- if ((playlist->stop_on_error && error != PLAYER_ERROR_NOERROR) ||
- error == PLAYER_ERROR_AUDIO || error == PLAYER_ERROR_SYSTEM ||
- playlist->error_count >= queue_length(&playlist->queue))
- /* too many errors, or critical error: stop
- playback */
- playlist_stop(playlist, pc);
- else
- /* continue playback at the next song */
- playlist_next(playlist, pc);
-}
-
-bool
-playlist_get_repeat(const struct playlist *playlist)
-{
- return playlist->queue.repeat;
-}
-
-bool
-playlist_get_random(const struct playlist *playlist)
-{
- return playlist->queue.random;
-}
-
-bool
-playlist_get_single(const struct playlist *playlist)
-{
- return playlist->queue.single;
-}
-
-bool
-playlist_get_consume(const struct playlist *playlist)
-{
- return playlist->queue.consume;
-}
-
-void
-playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
- bool status)
-{
- if (status == playlist->queue.repeat)
- return;
-
- struct queue *queue = &playlist->queue;
-
- queue->repeat = status;
-
- pc_set_border_pause(pc, queue->single && !queue->repeat);
-
- /* if the last song is currently being played, the "next song"
- might change when repeat mode is toggled */
- playlist_update_queued_song(playlist, pc,
- playlist_get_queued_song(playlist));
-
- idle_add(IDLE_OPTIONS);
-}
-
-static void
-playlist_order(struct playlist *playlist)
-{
- if (playlist->current >= 0)
- /* update playlist.current, order==position now */
- playlist->current = queue_order_to_position(&playlist->queue,
- playlist->current);
-
- queue_restore_order(&playlist->queue);
-}
-
-void
-playlist_set_single(struct playlist *playlist, struct player_control *pc,
- bool status)
-{
- if (status == playlist->queue.single)
- return;
-
- struct queue *queue = &playlist->queue;
-
- queue->single = status;
-
- pc_set_border_pause(pc, queue->single && !queue->repeat);
-
- /* if the last song is currently being played, the "next song"
- might change when single mode is toggled */
- playlist_update_queued_song(playlist, pc,
- playlist_get_queued_song(playlist));
-
- idle_add(IDLE_OPTIONS);
-}
-
-void
-playlist_set_consume(struct playlist *playlist, bool status)
-{
- if (status == playlist->queue.consume)
- return;
-
- playlist->queue.consume = status;
- idle_add(IDLE_OPTIONS);
-}
-
-void
-playlist_set_random(struct playlist *playlist, struct player_control *pc,
- bool status)
-{
- const struct song *queued;
-
- if (status == playlist->queue.random)
- return;
-
- queued = playlist_get_queued_song(playlist);
-
- playlist->queue.random = status;
-
- if (playlist->queue.random) {
- /* shuffle the queue order, but preserve
- playlist->current */
-
- int current_position =
- playlist->playing && playlist->current >= 0
- ? (int)queue_order_to_position(&playlist->queue,
- playlist->current)
- : -1;
-
- queue_shuffle_order(&playlist->queue);
-
- if (current_position >= 0) {
- /* make sure the current song is the first in
- the order list, so the whole rest of the
- playlist is played after that */
- unsigned current_order =
- queue_position_to_order(&playlist->queue,
- current_position);
- queue_swap_order(&playlist->queue, 0, current_order);
- playlist->current = 0;
- } else
- playlist->current = -1;
- } else
- playlist_order(playlist);
-
- playlist_update_queued_song(playlist, pc, queued);
-
- idle_add(IDLE_OPTIONS);
-}
-
-int
-playlist_get_current_song(const struct playlist *playlist)
-{
- if (playlist->current >= 0)
- return queue_order_to_position(&playlist->queue,
- playlist->current);
-
- return -1;
-}
-
-int
-playlist_get_next_song(const struct playlist *playlist)
-{
- if (playlist->current >= 0)
- {
- if (playlist->queue.single == 1 && playlist->queue.repeat == 1)
- return queue_order_to_position(&playlist->queue,
- playlist->current);
- else if (playlist->current + 1 < (int)queue_length(&playlist->queue))
- return queue_order_to_position(&playlist->queue,
- playlist->current + 1);
- else if (playlist->queue.repeat == 1)
- return queue_order_to_position(&playlist->queue, 0);
- }
-
- return -1;
-}
-
-unsigned long
-playlist_get_version(const struct playlist *playlist)
-{
- return playlist->queue.version;
-}
-
-int
-playlist_get_length(const struct playlist *playlist)
-{
- return queue_length(&playlist->queue);
-}
-
-unsigned
-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
deleted file mode 100644
index a21bdf24a..000000000
--- a/src/playlist.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * 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_H
-#define MPD_PLAYLIST_H
-
-#include "queue.h"
-#include "playlist_error.h"
-
-#include <stdbool.h>
-
-struct player_control;
-
-struct playlist {
- /**
- * The song queue - it contains the "real" playlist.
- */
- struct queue queue;
-
- /**
- * This value is true if the player is currently playing (or
- * should be playing).
- */
- bool playing;
-
- /**
- * If true, then any error is fatal; if false, MPD will
- * attempt to play the next song on non-fatal errors. During
- * seeking, this flag is set.
- */
- bool stop_on_error;
-
- /**
- * Number of errors since playback was started. If this
- * number exceeds the length of the playlist, MPD gives up,
- * because all songs have been tried.
- */
- unsigned error_count;
-
- /**
- * The "current song pointer". This is the song which is
- * played when we get the "play" command. It is also the song
- * which is currently being played.
- */
- int current;
-
- /**
- * The "next" song to be played, when the current one
- * finishes. The decoder thread may start decoding and
- * buffering it, while the "current" song is still playing.
- *
- * This variable is only valid if #playing is true.
- */
- int queued;
-};
-
-/** the global playlist object */
-extern struct playlist g_playlist;
-
-void
-playlist_global_init(void);
-
-void
-playlist_global_finish(void);
-
-void
-playlist_init(struct playlist *playlist);
-
-void
-playlist_finish(struct playlist *playlist);
-
-void
-playlist_tag_changed(struct playlist *playlist);
-
-/**
- * Returns the "queue" object of the global playlist instance.
- */
-static inline const struct queue *
-playlist_get_queue(const struct playlist *playlist)
-{
- return &playlist->queue;
-}
-
-void
-playlist_clear(struct playlist *playlist, struct player_control *pc);
-
-/**
- * Appends a local file (outside the music database) to the playlist.
- *
- * Note: the caller is responsible for checking permissions.
- */
-enum playlist_result
-playlist_append_file(struct playlist *playlist, struct player_control *pc,
- const char *path_fs, unsigned *added_id);
-
-enum playlist_result
-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, struct player_control *pc,
- struct song *song, unsigned *added_id);
-
-enum playlist_result
-playlist_delete(struct playlist *playlist, struct player_control *pc,
- 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, struct player_control *pc,
- unsigned start, unsigned end);
-
-enum playlist_result
-playlist_delete_id(struct playlist *playlist, struct player_control *pc,
- unsigned song);
-
-void
-playlist_stop(struct playlist *playlist, struct player_control *pc);
-
-enum playlist_result
-playlist_play(struct playlist *playlist, struct player_control *pc,
- int song);
-
-enum playlist_result
-playlist_play_id(struct playlist *playlist, struct player_control *pc,
- int song);
-
-void
-playlist_next(struct playlist *playlist, struct player_control *pc);
-
-void
-playlist_sync(struct playlist *playlist, struct player_control *pc);
-
-void
-playlist_previous(struct playlist *playlist, struct player_control *pc);
-
-void
-playlist_shuffle(struct playlist *playlist, struct player_control *pc,
- unsigned start, unsigned end);
-
-void
-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_swap_songs(struct playlist *playlist, struct player_control *pc,
- unsigned song1, unsigned song2);
-
-enum playlist_result
-playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc,
- unsigned id1, unsigned id2);
-
-enum playlist_result
-playlist_set_priority(struct playlist *playlist, struct player_control *pc,
- unsigned start_position, unsigned end_position,
- uint8_t priority);
-
-enum playlist_result
-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, struct player_control *pc,
- bool status);
-
-bool
-playlist_get_random(const struct playlist *playlist);
-
-void
-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, struct player_control *pc,
- bool status);
-
-bool
-playlist_get_consume(const struct playlist *playlist);
-
-void
-playlist_set_consume(struct playlist *playlist, bool status);
-
-int
-playlist_get_current_song(const struct playlist *playlist);
-
-int
-playlist_get_next_song(const struct playlist *playlist);
-
-unsigned
-playlist_get_song_id(const struct playlist *playlist, unsigned song);
-
-int
-playlist_get_length(const struct playlist *playlist);
-
-unsigned long
-playlist_get_version(const struct playlist *playlist);
-
-enum playlist_result
-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, 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);
-
-#endif
diff --git a/src/playlist/AsxPlaylistPlugin.cxx b/src/playlist/AsxPlaylistPlugin.cxx
new file mode 100644
index 000000000..4dcbf56b9
--- /dev/null
+++ b/src/playlist/AsxPlaylistPlugin.cxx
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2003-2013 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 "AsxPlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "MemorySongEnumerator.hxx"
+#include "InputStream.hxx"
+#include "Song.hxx"
+#include "tag/Tag.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+#include "Log.hxx"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+
+static constexpr Domain asx_domain("asx");
+
+/**
+ * This is the state object for the GLib XML parser.
+ */
+struct AsxParser {
+ /**
+ * The list of songs (in reverse order because that's faster
+ * while adding).
+ */
+ std::forward_list<SongPointer> songs;
+
+ /**
+ * The current position in the XML file.
+ */
+ enum {
+ ROOT, ENTRY,
+ } state;
+
+ /**
+ * The current tag within the "entry" element. This is only
+ * valid if state==ENTRY. TAG_NUM_OF_ITEM_TYPES means there
+ * is no (known) tag.
+ */
+ enum tag_type tag;
+
+ /**
+ * The current song. It is allocated after the "location"
+ * element.
+ */
+ Song *song;
+
+ AsxParser()
+ :state(ROOT) {}
+
+};
+
+static const gchar *
+get_attribute(const gchar **attribute_names, const gchar **attribute_values,
+ const gchar *name)
+{
+ for (unsigned i = 0; attribute_names[i] != NULL; ++i)
+ if (g_ascii_strcasecmp(attribute_names[i], name) == 0)
+ return attribute_values[i];
+
+ return NULL;
+}
+
+static void
+asx_start_element(gcc_unused GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data, gcc_unused GError **error)
+{
+ AsxParser *parser = (AsxParser *)user_data;
+
+ switch (parser->state) {
+ case AsxParser::ROOT:
+ if (g_ascii_strcasecmp(element_name, "entry") == 0) {
+ parser->state = AsxParser::ENTRY;
+ parser->song = Song::NewRemote("asx:");
+ parser->tag = TAG_NUM_OF_ITEM_TYPES;
+ }
+
+ break;
+
+ case AsxParser::ENTRY:
+ if (g_ascii_strcasecmp(element_name, "ref") == 0) {
+ const gchar *href = get_attribute(attribute_names,
+ attribute_values,
+ "href");
+ if (href != NULL) {
+ /* create new song object, and copy
+ the existing tag over; we cannot
+ replace the existing song's URI,
+ because that attribute is
+ immutable */
+ Song *song = Song::NewRemote(href);
+
+ if (parser->song != NULL) {
+ song->tag = parser->song->tag;
+ parser->song->tag = NULL;
+ parser->song->Free();
+ }
+
+ parser->song = song;
+ }
+ } else if (g_ascii_strcasecmp(element_name, "author") == 0)
+ /* is that correct? or should it be COMPOSER
+ or PERFORMER? */
+ parser->tag = TAG_ARTIST;
+ else if (g_ascii_strcasecmp(element_name, "title") == 0)
+ parser->tag = TAG_TITLE;
+
+ break;
+ }
+}
+
+static void
+asx_end_element(gcc_unused GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data, gcc_unused GError **error)
+{
+ AsxParser *parser = (AsxParser *)user_data;
+
+ switch (parser->state) {
+ case AsxParser::ROOT:
+ break;
+
+ case AsxParser::ENTRY:
+ if (g_ascii_strcasecmp(element_name, "entry") == 0) {
+ if (strcmp(parser->song->uri, "asx:") != 0)
+ parser->songs.emplace_front(parser->song);
+ else
+ parser->song->Free();
+
+ parser->state = AsxParser::ROOT;
+ } else
+ parser->tag = TAG_NUM_OF_ITEM_TYPES;
+
+ break;
+ }
+}
+
+static void
+asx_text(gcc_unused GMarkupParseContext *context,
+ const gchar *text, gsize text_len,
+ gpointer user_data, gcc_unused GError **error)
+{
+ AsxParser *parser = (AsxParser *)user_data;
+
+ switch (parser->state) {
+ case AsxParser::ROOT:
+ break;
+
+ case AsxParser::ENTRY:
+ if (parser->tag != TAG_NUM_OF_ITEM_TYPES) {
+ if (parser->song->tag == NULL)
+ parser->song->tag = new Tag();
+ parser->song->tag->AddItem(parser->tag,
+ text, text_len);
+ }
+
+ break;
+ }
+}
+
+static const GMarkupParser asx_parser = {
+ asx_start_element,
+ asx_end_element,
+ asx_text,
+ nullptr,
+ nullptr,
+};
+
+static void
+asx_parser_destroy(gpointer data)
+{
+ AsxParser *parser = (AsxParser *)data;
+
+ if (parser->state >= AsxParser::ENTRY)
+ parser->song->Free();
+}
+
+/*
+ * The playlist object
+ *
+ */
+
+static SongEnumerator *
+asx_open_stream(struct input_stream *is)
+{
+ AsxParser parser;
+ GMarkupParseContext *context;
+ char buffer[1024];
+ size_t nbytes;
+ bool success;
+ Error error2;
+ GError *error = NULL;
+
+ /* parse the ASX XML file */
+
+ context = g_markup_parse_context_new(&asx_parser,
+ G_MARKUP_TREAT_CDATA_AS_TEXT,
+ &parser, asx_parser_destroy);
+
+ while (true) {
+ nbytes = is->LockRead(buffer, sizeof(buffer), error2);
+ if (nbytes == 0) {
+ if (error2.IsDefined()) {
+ g_markup_parse_context_free(context);
+ LogError(error2);
+ return NULL;
+ }
+
+ break;
+ }
+
+ success = g_markup_parse_context_parse(context, buffer, nbytes,
+ &error);
+ if (!success) {
+ FormatErrno(asx_domain,
+ "XML parser failed: %s", error->message);
+ g_error_free(error);
+ g_markup_parse_context_free(context);
+ return NULL;
+ }
+ }
+
+ success = g_markup_parse_context_end_parse(context, &error);
+ if (!success) {
+ FormatErrno(asx_domain,
+ "XML parser failed: %s", error->message);
+ g_error_free(error);
+ g_markup_parse_context_free(context);
+ return NULL;
+ }
+
+ parser.songs.reverse();
+ MemorySongEnumerator *playlist =
+ new MemorySongEnumerator(std::move(parser.songs));
+
+ g_markup_parse_context_free(context);
+
+ return playlist;
+}
+
+static const char *const asx_suffixes[] = {
+ "asx",
+ NULL
+};
+
+static const char *const asx_mime_types[] = {
+ "video/x-ms-asf",
+ NULL
+};
+
+const struct playlist_plugin asx_playlist_plugin = {
+ "asx",
+
+ nullptr,
+ nullptr,
+ nullptr,
+ asx_open_stream,
+
+ nullptr,
+ asx_suffixes,
+ asx_mime_types,
+};
diff --git a/src/playlist/AsxPlaylistPlugin.hxx b/src/playlist/AsxPlaylistPlugin.hxx
new file mode 100644
index 000000000..240c1824a
--- /dev/null
+++ b/src/playlist/AsxPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_ASX_PLAYLIST_PLUGIN_HXX
+#define MPD_ASX_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin asx_playlist_plugin;
+
+#endif
diff --git a/src/playlist/CuePlaylistPlugin.cxx b/src/playlist/CuePlaylistPlugin.cxx
new file mode 100644
index 000000000..5b0b6c6d2
--- /dev/null
+++ b/src/playlist/CuePlaylistPlugin.cxx
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2003-2013 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 "CuePlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "SongEnumerator.hxx"
+#include "tag/Tag.hxx"
+#include "Song.hxx"
+#include "cue/CueParser.hxx"
+#include "TextInputStream.hxx"
+
+#include <assert.h>
+#include <string.h>
+
+class CuePlaylist final : public SongEnumerator {
+ struct input_stream *is;
+ TextInputStream tis;
+ CueParser parser;
+
+ public:
+ CuePlaylist(struct input_stream *_is)
+ :is(_is), tis(is) {
+ }
+
+ virtual Song *NextSong() override;
+};
+
+static SongEnumerator *
+cue_playlist_open_stream(struct input_stream *is)
+{
+ return new CuePlaylist(is);
+}
+
+Song *
+CuePlaylist::NextSong()
+{
+ Song *song = parser.Get();
+ if (song != NULL)
+ return song;
+
+ std::string line;
+ while (tis.ReadLine(line)) {
+ parser.Feed(line.c_str());
+ song = parser.Get();
+ if (song != NULL)
+ return song;
+ }
+
+ parser.Finish();
+ return parser.Get();
+}
+
+static const char *const cue_playlist_suffixes[] = {
+ "cue",
+ NULL
+};
+
+static const char *const cue_playlist_mime_types[] = {
+ "application/x-cue",
+ NULL
+};
+
+const struct playlist_plugin cue_playlist_plugin = {
+ "cue",
+
+ nullptr,
+ nullptr,
+ nullptr,
+ cue_playlist_open_stream,
+
+ nullptr,
+ cue_playlist_suffixes,
+ cue_playlist_mime_types,
+};
diff --git a/src/playlist/CuePlaylistPlugin.hxx b/src/playlist/CuePlaylistPlugin.hxx
new file mode 100644
index 000000000..cf5e3a8f0
--- /dev/null
+++ b/src/playlist/CuePlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_CUE_PLAYLIST_PLUGIN_HXX
+#define MPD_CUE_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin cue_playlist_plugin;
+
+#endif
diff --git a/src/playlist/DespotifyPlaylistPlugin.cxx b/src/playlist/DespotifyPlaylistPlugin.cxx
new file mode 100644
index 000000000..a1a865c08
--- /dev/null
+++ b/src/playlist/DespotifyPlaylistPlugin.cxx
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2011-2013 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 "DespotifyPlaylistPlugin.hxx"
+#include "DespotifyUtils.hxx"
+#include "PlaylistPlugin.hxx"
+#include "MemorySongEnumerator.hxx"
+#include "tag/Tag.hxx"
+#include "Song.hxx"
+#include "Log.hxx"
+
+extern "C" {
+#include <despotify.h>
+}
+
+#include <string.h>
+#include <stdlib.h>
+
+static void
+add_song(std::forward_list<SongPointer> &songs, struct ds_track *track)
+{
+ const char *dsp_scheme = despotify_playlist_plugin.schemes[0];
+ Song *song;
+ char uri[128];
+ char *ds_uri;
+
+ /* Create a spt://... URI for MPD */
+ 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 */
+ FormatDebug(despotify_domain,
+ "Can't add track %s", track->title);
+ return;
+ }
+
+ song = Song::NewRemote(uri);
+ song->tag = mpd_despotify_tag_from_track(track);
+
+ songs.emplace_front(song);
+}
+
+static bool
+parse_track(struct despotify_session *session,
+ std::forward_list<SongPointer> &songs,
+ struct ds_link *link)
+{
+ struct ds_track *track = despotify_link_get_track(session, link);
+ if (track == nullptr)
+ return false;
+
+ add_song(songs, track);
+ return true;
+}
+
+static bool
+parse_playlist(struct despotify_session *session,
+ std::forward_list<SongPointer> &songs,
+ struct ds_link *link)
+{
+ ds_playlist *playlist = despotify_link_get_playlist(session, link);
+ if (playlist == nullptr)
+ return false;
+
+ for (ds_track *track = playlist->tracks; track != nullptr;
+ track = track->next)
+ add_song(songs, track);
+
+ return true;
+}
+
+static SongEnumerator *
+despotify_playlist_open_uri(const char *url,
+ gcc_unused Mutex &mutex, gcc_unused Cond &cond)
+{
+ despotify_session *session = mpd_despotify_get_session();
+ if (session == nullptr)
+ return nullptr;
+
+ /* Get link without spt:// */
+ ds_link *link =
+ despotify_link_from_uri(url + strlen(despotify_playlist_plugin.schemes[0]) + 3);
+ if (link == nullptr) {
+ FormatDebug(despotify_domain, "Can't find %s\n", url);
+ return nullptr;
+ }
+
+ std::forward_list<SongPointer> songs;
+
+ bool parse_result;
+ switch (link->type) {
+ case LINK_TYPE_TRACK:
+ parse_result = parse_track(session, songs, link);
+ break;
+ case LINK_TYPE_PLAYLIST:
+ parse_result = parse_playlist(session, songs, link);
+ break;
+ default:
+ parse_result = false;
+ break;
+ }
+
+ despotify_free_link(link);
+ if (!parse_result)
+ return nullptr;
+
+ songs.reverse();
+ return new MemorySongEnumerator(std::move(songs));
+}
+
+static const char *const despotify_schemes[] = {
+ "spt",
+ nullptr
+};
+
+const struct playlist_plugin despotify_playlist_plugin = {
+ "despotify",
+
+ nullptr,
+ nullptr,
+ despotify_playlist_open_uri,
+ nullptr,
+
+ despotify_schemes,
+ nullptr,
+ nullptr,
+};
diff --git a/src/playlist/DespotifyPlaylistPlugin.hxx b/src/playlist/DespotifyPlaylistPlugin.hxx
new file mode 100644
index 000000000..c1e5b7f39
--- /dev/null
+++ b/src/playlist/DespotifyPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011-2013 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_HXX
+#define MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin despotify_playlist_plugin;
+
+#endif
diff --git a/src/playlist/EmbeddedCuePlaylistPlugin.cxx b/src/playlist/EmbeddedCuePlaylistPlugin.cxx
new file mode 100644
index 000000000..5fc1f28e0
--- /dev/null
+++ b/src/playlist/EmbeddedCuePlaylistPlugin.cxx
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2003-2013 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.
+ */
+
+/** \file
+ *
+ * Playlist plugin that reads embedded cue sheets from the "CUESHEET"
+ * tag of a music file.
+ */
+
+#include "config.h"
+#include "EmbeddedCuePlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "SongEnumerator.hxx"
+#include "tag/Tag.hxx"
+#include "tag/TagHandler.hxx"
+#include "tag/TagId3.hxx"
+#include "tag/ApeTag.hxx"
+#include "Song.hxx"
+#include "TagFile.hxx"
+#include "cue/CueParser.hxx"
+
+#include <glib.h>
+#include <assert.h>
+#include <string.h>
+
+class EmbeddedCuePlaylist final : public SongEnumerator {
+public:
+ /**
+ * This is an override for the CUE's "FILE". An embedded CUE
+ * sheet must always point to the song file it is contained
+ * in.
+ */
+ char *filename;
+
+ /**
+ * The value of the file's "CUESHEET" tag.
+ */
+ char *cuesheet;
+
+ /**
+ * The offset of the next line within "cuesheet".
+ */
+ char *next;
+
+ CueParser *parser;
+
+public:
+ EmbeddedCuePlaylist()
+ :filename(nullptr), cuesheet(nullptr), parser(nullptr) {
+ }
+
+ virtual ~EmbeddedCuePlaylist() {
+ delete parser;
+ g_free(cuesheet);
+ g_free(filename);
+ }
+
+ virtual Song *NextSong() override;
+};
+
+static void
+embcue_tag_pair(const char *name, const char *value, void *ctx)
+{
+ EmbeddedCuePlaylist *playlist = (EmbeddedCuePlaylist *)ctx;
+
+ if (playlist->cuesheet == NULL &&
+ g_ascii_strcasecmp(name, "cuesheet") == 0)
+ playlist->cuesheet = g_strdup(value);
+}
+
+static const struct tag_handler embcue_tag_handler = {
+ nullptr,
+ nullptr,
+ embcue_tag_pair,
+};
+
+static SongEnumerator *
+embcue_playlist_open_uri(const char *uri,
+ gcc_unused Mutex &mutex,
+ gcc_unused Cond &cond)
+{
+ if (!g_path_is_absolute(uri))
+ /* only local files supported */
+ return NULL;
+
+ const auto playlist = new EmbeddedCuePlaylist();
+
+ tag_file_scan(uri, &embcue_tag_handler, playlist);
+ if (playlist->cuesheet == NULL) {
+ tag_ape_scan2(uri, &embcue_tag_handler, playlist);
+ if (playlist->cuesheet == NULL)
+ tag_id3_scan(uri, &embcue_tag_handler, playlist);
+ }
+
+ if (playlist->cuesheet == NULL) {
+ /* no "CUESHEET" tag found */
+ delete playlist;
+ return NULL;
+ }
+
+ playlist->filename = g_path_get_basename(uri);
+
+ playlist->next = playlist->cuesheet;
+ playlist->parser = new CueParser();
+
+ return playlist;
+}
+
+Song *
+EmbeddedCuePlaylist::NextSong()
+{
+ Song *song = parser->Get();
+ if (song != NULL)
+ return song;
+
+ while (*next != 0) {
+ const char *line = next;
+ char *eol = strpbrk(next, "\r\n");
+ if (eol != NULL) {
+ /* null-terminate the line */
+ *eol = 0;
+ next = eol + 1;
+ } else
+ /* last line; put the "next" pointer to the
+ end of the buffer */
+ next += strlen(line);
+
+ parser->Feed(line);
+ song = parser->Get();
+ if (song != NULL)
+ return song->ReplaceURI(filename);
+ }
+
+ parser->Finish();
+ song = parser->Get();
+ if (song != NULL)
+ song = song->ReplaceURI(filename);
+ return song;
+}
+
+static const char *const embcue_playlist_suffixes[] = {
+ /* a few codecs that are known to be supported; there are
+ probably many more */
+ "flac",
+ "mp3", "mp2",
+ "mp4", "mp4a", "m4b",
+ "ape",
+ "wv",
+ "ogg", "oga",
+ NULL
+};
+
+const struct playlist_plugin embcue_playlist_plugin = {
+ "cue",
+
+ nullptr,
+ nullptr,
+ embcue_playlist_open_uri,
+ nullptr,
+
+ embcue_playlist_suffixes,
+ nullptr,
+ nullptr,
+};
diff --git a/src/playlist/EmbeddedCuePlaylistPlugin.hxx b/src/playlist/EmbeddedCuePlaylistPlugin.hxx
new file mode 100644
index 000000000..e306730f4
--- /dev/null
+++ b/src/playlist/EmbeddedCuePlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_EMBCUE_PLAYLIST_PLUGIN_HXX
+#define MPD_EMBCUE_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin embcue_playlist_plugin;
+
+#endif
diff --git a/src/playlist/ExtM3uPlaylistPlugin.cxx b/src/playlist/ExtM3uPlaylistPlugin.cxx
new file mode 100644
index 000000000..177e8857d
--- /dev/null
+++ b/src/playlist/ExtM3uPlaylistPlugin.cxx
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2003-2013 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 "ExtM3uPlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "SongEnumerator.hxx"
+#include "Song.hxx"
+#include "tag/Tag.hxx"
+#include "util/StringUtil.hxx"
+#include "TextInputStream.hxx"
+
+#include <glib.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+class ExtM3uPlaylist final : public SongEnumerator {
+ TextInputStream tis;
+
+public:
+ ExtM3uPlaylist(input_stream *is)
+ :tis(is) {
+ }
+
+ bool CheckFirstLine() {
+ std::string line;
+ return tis.ReadLine(line) &&
+ strcmp(line.c_str(), "#EXTM3U") == 0;
+ }
+
+ virtual Song *NextSong() override;
+};
+
+static SongEnumerator *
+extm3u_open_stream(struct input_stream *is)
+{
+ ExtM3uPlaylist *playlist = new ExtM3uPlaylist(is);
+
+ if (!playlist->CheckFirstLine()) {
+ /* no EXTM3U header: fall back to the plain m3u
+ plugin */
+ delete playlist;
+ return NULL;
+ }
+
+ return playlist;
+}
+
+/**
+ * Parse a EXTINF line.
+ *
+ * @param line the rest of the input line after the colon
+ */
+static Tag *
+extm3u_parse_tag(const char *line)
+{
+ long duration;
+ char *endptr;
+ const char *name;
+ Tag *tag;
+
+ duration = strtol(line, &endptr, 10);
+ if (endptr[0] != ',')
+ /* malformed line */
+ return NULL;
+
+ if (duration < 0)
+ /* 0 means unknown duration */
+ duration = 0;
+
+ name = strchug_fast_c(endptr + 1);
+ if (*name == 0 && duration == 0)
+ /* no information available; don't allocate a tag
+ object */
+ return NULL;
+
+ tag = new Tag();
+ tag->time = duration;
+
+ /* unfortunately, there is no real specification for the
+ EXTM3U format, so we must assume that the string after the
+ comma is opaque, and is just the song name*/
+ if (*name != 0)
+ tag->AddItem(TAG_NAME, name);
+
+ return tag;
+}
+
+Song *
+ExtM3uPlaylist::NextSong()
+{
+ Tag *tag = NULL;
+ std::string line;
+ const char *line_s;
+ Song *song;
+
+ do {
+ if (!tis.ReadLine(line)) {
+ delete tag;
+ return NULL;
+ }
+
+ line_s = line.c_str();
+
+ if (g_str_has_prefix(line_s, "#EXTINF:")) {
+ delete tag;
+ tag = extm3u_parse_tag(line_s + 8);
+ continue;
+ }
+
+ while (*line_s != 0 && g_ascii_isspace(*line_s))
+ ++line_s;
+ } while (line_s[0] == '#' || *line_s == 0);
+
+ song = Song::NewRemote(line_s);
+ song->tag = tag;
+ return song;
+}
+
+static const char *const extm3u_suffixes[] = {
+ "m3u",
+ NULL
+};
+
+static const char *const extm3u_mime_types[] = {
+ "audio/x-mpegurl",
+ NULL
+};
+
+const struct playlist_plugin extm3u_playlist_plugin = {
+ "extm3u",
+
+ nullptr,
+ nullptr,
+ nullptr,
+ extm3u_open_stream,
+
+ nullptr,
+ extm3u_suffixes,
+ extm3u_mime_types,
+};
diff --git a/src/playlist/ExtM3uPlaylistPlugin.hxx b/src/playlist/ExtM3uPlaylistPlugin.hxx
new file mode 100644
index 000000000..844fba15c
--- /dev/null
+++ b/src/playlist/ExtM3uPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_EXTM3U_PLAYLIST_PLUGIN_HXX
+#define MPD_EXTM3U_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin extm3u_playlist_plugin;
+
+#endif
diff --git a/src/playlist/M3uPlaylistPlugin.cxx b/src/playlist/M3uPlaylistPlugin.cxx
new file mode 100644
index 000000000..8854be8d7
--- /dev/null
+++ b/src/playlist/M3uPlaylistPlugin.cxx
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2003-2013 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 "M3uPlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "SongEnumerator.hxx"
+#include "Song.hxx"
+#include "TextInputStream.hxx"
+
+#include <glib.h>
+
+class M3uPlaylist final : public SongEnumerator {
+ TextInputStream tis;
+
+public:
+ M3uPlaylist(input_stream *is)
+ :tis(is) {
+ }
+
+ virtual Song *NextSong() override;
+};
+
+static SongEnumerator *
+m3u_open_stream(struct input_stream *is)
+{
+ return new M3uPlaylist(is);
+}
+
+Song *
+M3uPlaylist::NextSong()
+{
+ std::string line;
+ const char *line_s;
+
+ do {
+ if (!tis.ReadLine(line))
+ return NULL;
+
+ line_s = line.c_str();
+
+ while (*line_s != 0 && g_ascii_isspace(*line_s))
+ ++line_s;
+ } while (line_s[0] == '#' || *line_s == 0);
+
+ return Song::NewRemote(line_s);
+}
+
+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 = {
+ "m3u",
+
+ nullptr,
+ nullptr,
+ nullptr,
+ m3u_open_stream,
+
+ nullptr,
+ m3u_suffixes,
+ m3u_mime_types,
+};
diff --git a/src/playlist/M3uPlaylistPlugin.hxx b/src/playlist/M3uPlaylistPlugin.hxx
new file mode 100644
index 000000000..a2058bb29
--- /dev/null
+++ b/src/playlist/M3uPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_M3U_PLAYLIST_PLUGIN_HXX
+#define MPD_M3U_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin m3u_playlist_plugin;
+
+#endif
diff --git a/src/playlist/PlsPlaylistPlugin.cxx b/src/playlist/PlsPlaylistPlugin.cxx
new file mode 100644
index 000000000..567add465
--- /dev/null
+++ b/src/playlist/PlsPlaylistPlugin.cxx
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2003-2013 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 "PlsPlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "MemorySongEnumerator.hxx"
+#include "InputStream.hxx"
+#include "Song.hxx"
+#include "tag/Tag.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+#include "Log.hxx"
+
+#include <glib.h>
+
+#include <string>
+
+static constexpr Domain pls_domain("pls");
+
+static void
+pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
+{
+ gchar *key;
+ gchar *value;
+ int length;
+ GError *error = NULL;
+ int num_entries = g_key_file_get_integer(keyfile, "playlist",
+ "NumberOfEntries", &error);
+ if (error) {
+ FormatError(pls_domain,
+ "Invalid PLS file: '%s'", error->message);
+ g_error_free(error);
+ error = NULL;
+
+ /* Hack to work around shoutcast failure to comform to spec */
+ num_entries = g_key_file_get_integer(keyfile, "playlist",
+ "numberofentries", &error);
+ if (error) {
+ g_error_free(error);
+ error = NULL;
+ }
+ }
+
+ while (num_entries > 0) {
+ Song *song;
+ key = g_strdup_printf("File%i", num_entries);
+ value = g_key_file_get_string(keyfile, "playlist", key,
+ &error);
+ if(error) {
+ FormatError(pls_domain, "Invalid PLS entry %s: '%s'",
+ key, error->message);
+ g_error_free(error);
+ g_free(key);
+ return;
+ }
+ g_free(key);
+
+ song = Song::NewRemote(value);
+ g_free(value);
+
+ key = g_strdup_printf("Title%i", num_entries);
+ value = g_key_file_get_string(keyfile, "playlist", key,
+ &error);
+ g_free(key);
+ if(error == NULL && value){
+ if (song->tag == NULL)
+ song->tag = new Tag();
+ song->tag->AddItem(TAG_TITLE, value);
+ }
+ /* Ignore errors? Most likely value not present */
+ if(error) g_error_free(error);
+ error = NULL;
+ g_free(value);
+
+ key = g_strdup_printf("Length%i", num_entries);
+ length = g_key_file_get_integer(keyfile, "playlist", key,
+ &error);
+ g_free(key);
+ if(error == NULL && length > 0){
+ if (song->tag == NULL)
+ song->tag = new Tag();
+ song->tag->time = length;
+ }
+ /* Ignore errors? Most likely value not present */
+ if(error) g_error_free(error);
+ error = NULL;
+
+ songs.emplace_front(song);
+ num_entries--;
+ }
+
+}
+
+static SongEnumerator *
+pls_open_stream(struct input_stream *is)
+{
+ GError *error = NULL;
+ Error error2;
+ size_t nbytes;
+ char buffer[1024];
+ bool success;
+ GKeyFile *keyfile;
+
+ std::string kf_data;
+
+ do {
+ nbytes = is->LockRead(buffer, sizeof(buffer), error2);
+ if (nbytes == 0) {
+ if (error2.IsDefined()) {
+ LogError(error2);
+ return NULL;
+ }
+
+ break;
+ }
+
+ kf_data.append(buffer, nbytes);
+ /* Limit to 64k */
+ } while (kf_data.length() < 65536);
+
+ if (kf_data.empty()) {
+ LogWarning(pls_domain, "KeyFile parser failed: No Data");
+ return NULL;
+ }
+
+ keyfile = g_key_file_new();
+ success = g_key_file_load_from_data(keyfile,
+ kf_data.data(), kf_data.length(),
+ G_KEY_FILE_NONE, &error);
+
+ if (!success) {
+ FormatError(pls_domain,
+ "KeyFile parser failed: %s", error->message);
+ g_error_free(error);
+ g_key_file_free(keyfile);
+ return NULL;
+ }
+
+ std::forward_list<SongPointer> songs;
+ pls_parser(keyfile, songs);
+ g_key_file_free(keyfile);
+
+ songs.reverse();
+ return new MemorySongEnumerator(std::move(songs));
+}
+
+static const char *const pls_suffixes[] = {
+ "pls",
+ NULL
+};
+
+static const char *const pls_mime_types[] = {
+ "audio/x-scpls",
+ NULL
+};
+
+const struct playlist_plugin pls_playlist_plugin = {
+ "pls",
+
+ nullptr,
+ nullptr,
+ nullptr,
+ pls_open_stream,
+
+ nullptr,
+ pls_suffixes,
+ pls_mime_types,
+};
diff --git a/src/playlist/PlsPlaylistPlugin.hxx b/src/playlist/PlsPlaylistPlugin.hxx
new file mode 100644
index 000000000..3fafd36d0
--- /dev/null
+++ b/src/playlist/PlsPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_PLS_PLAYLIST_PLUGIN_HXX
+#define MPD_PLS_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin pls_playlist_plugin;
+
+#endif
diff --git a/src/playlist/RssPlaylistPlugin.cxx b/src/playlist/RssPlaylistPlugin.cxx
new file mode 100644
index 000000000..c2becc15a
--- /dev/null
+++ b/src/playlist/RssPlaylistPlugin.cxx
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2003-2013 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 "RssPlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "MemorySongEnumerator.hxx"
+#include "InputStream.hxx"
+#include "Song.hxx"
+#include "tag/Tag.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+#include "Log.hxx"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+
+static constexpr Domain rss_domain("rss");
+
+/**
+ * This is the state object for the GLib XML parser.
+ */
+struct RssParser {
+ /**
+ * The list of songs (in reverse order because that's faster
+ * while adding).
+ */
+ std::forward_list<SongPointer> songs;
+
+ /**
+ * The current position in the XML file.
+ */
+ enum {
+ ROOT, ITEM,
+ } state;
+
+ /**
+ * The current tag within the "entry" element. This is only
+ * valid if state==ITEM. TAG_NUM_OF_ITEM_TYPES means there
+ * is no (known) tag.
+ */
+ enum tag_type tag;
+
+ /**
+ * The current song. It is allocated after the "location"
+ * element.
+ */
+ Song *song;
+
+ RssParser()
+ :state(ROOT) {}
+};
+
+static const gchar *
+get_attribute(const gchar **attribute_names, const gchar **attribute_values,
+ const gchar *name)
+{
+ for (unsigned i = 0; attribute_names[i] != NULL; ++i)
+ if (g_ascii_strcasecmp(attribute_names[i], name) == 0)
+ return attribute_values[i];
+
+ return NULL;
+}
+
+static void
+rss_start_element(gcc_unused GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data, gcc_unused GError **error)
+{
+ RssParser *parser = (RssParser *)user_data;
+
+ switch (parser->state) {
+ case RssParser::ROOT:
+ if (g_ascii_strcasecmp(element_name, "item") == 0) {
+ parser->state = RssParser::ITEM;
+ parser->song = Song::NewRemote("rss:");
+ parser->tag = TAG_NUM_OF_ITEM_TYPES;
+ }
+
+ break;
+
+ case RssParser::ITEM:
+ if (g_ascii_strcasecmp(element_name, "enclosure") == 0) {
+ const gchar *href = get_attribute(attribute_names,
+ attribute_values,
+ "url");
+ if (href != NULL) {
+ /* create new song object, and copy
+ the existing tag over; we cannot
+ replace the existing song's URI,
+ because that attribute is
+ immutable */
+ Song *song = Song::NewRemote(href);
+
+ if (parser->song != NULL) {
+ song->tag = parser->song->tag;
+ parser->song->tag = NULL;
+ parser->song->Free();
+ }
+
+ parser->song = song;
+ }
+ } else if (g_ascii_strcasecmp(element_name, "title") == 0)
+ parser->tag = TAG_TITLE;
+ else if (g_ascii_strcasecmp(element_name, "itunes:author") == 0)
+ parser->tag = TAG_ARTIST;
+
+ break;
+ }
+}
+
+static void
+rss_end_element(gcc_unused GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data, gcc_unused GError **error)
+{
+ RssParser *parser = (RssParser *)user_data;
+
+ switch (parser->state) {
+ case RssParser::ROOT:
+ break;
+
+ case RssParser::ITEM:
+ if (g_ascii_strcasecmp(element_name, "item") == 0) {
+ if (strcmp(parser->song->uri, "rss:") != 0)
+ parser->songs.emplace_front(parser->song);
+ else
+ parser->song->Free();
+
+ parser->state = RssParser::ROOT;
+ } else
+ parser->tag = TAG_NUM_OF_ITEM_TYPES;
+
+ break;
+ }
+}
+
+static void
+rss_text(gcc_unused GMarkupParseContext *context,
+ const gchar *text, gsize text_len,
+ gpointer user_data, gcc_unused GError **error)
+{
+ RssParser *parser = (RssParser *)user_data;
+
+ switch (parser->state) {
+ case RssParser::ROOT:
+ break;
+
+ case RssParser::ITEM:
+ if (parser->tag != TAG_NUM_OF_ITEM_TYPES) {
+ if (parser->song->tag == NULL)
+ parser->song->tag = new Tag();
+ parser->song->tag->AddItem(parser->tag,
+ text, text_len);
+ }
+
+ break;
+ }
+}
+
+static const GMarkupParser rss_parser = {
+ rss_start_element,
+ rss_end_element,
+ rss_text,
+ nullptr,
+ nullptr,
+};
+
+static void
+rss_parser_destroy(gpointer data)
+{
+ RssParser *parser = (RssParser *)data;
+
+ if (parser->state >= RssParser::ITEM)
+ parser->song->Free();
+}
+
+/*
+ * The playlist object
+ *
+ */
+
+static SongEnumerator *
+rss_open_stream(struct input_stream *is)
+{
+ RssParser parser;
+ GMarkupParseContext *context;
+ char buffer[1024];
+ size_t nbytes;
+ bool success;
+ Error error2;
+ GError *error = NULL;
+
+ /* parse the RSS XML file */
+
+ context = g_markup_parse_context_new(&rss_parser,
+ G_MARKUP_TREAT_CDATA_AS_TEXT,
+ &parser, rss_parser_destroy);
+
+ while (true) {
+ nbytes = is->LockRead(buffer, sizeof(buffer), error2);
+ if (nbytes == 0) {
+ if (error2.IsDefined()) {
+ g_markup_parse_context_free(context);
+ LogError(error2);
+ return NULL;
+ }
+
+ break;
+ }
+
+ success = g_markup_parse_context_parse(context, buffer, nbytes,
+ &error);
+ if (!success) {
+ FormatError(rss_domain,
+ "XML parser failed: %s", error->message);
+ g_error_free(error);
+ g_markup_parse_context_free(context);
+ return NULL;
+ }
+ }
+
+ success = g_markup_parse_context_end_parse(context, &error);
+ if (!success) {
+ FormatError(rss_domain,
+ "XML parser failed: %s", error->message);
+ g_error_free(error);
+ g_markup_parse_context_free(context);
+ return NULL;
+ }
+
+ parser.songs.reverse();
+ MemorySongEnumerator *playlist =
+ new MemorySongEnumerator(std::move(parser.songs));
+
+ g_markup_parse_context_free(context);
+
+ return playlist;
+}
+
+static const char *const rss_suffixes[] = {
+ "rss",
+ NULL
+};
+
+static const char *const rss_mime_types[] = {
+ "application/rss+xml",
+ "text/xml",
+ NULL
+};
+
+const struct playlist_plugin rss_playlist_plugin = {
+ "rss",
+
+ nullptr,
+ nullptr,
+ nullptr,
+ rss_open_stream,
+
+ nullptr,
+ rss_suffixes,
+ rss_mime_types,
+};
diff --git a/src/playlist/RssPlaylistPlugin.hxx b/src/playlist/RssPlaylistPlugin.hxx
new file mode 100644
index 000000000..f49f7e9cf
--- /dev/null
+++ b/src/playlist/RssPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_RSS_PLAYLIST_PLUGIN_HXX
+#define MPD_RSS_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin rss_playlist_plugin;
+
+#endif
diff --git a/src/playlist/SoundCloudPlaylistPlugin.cxx b/src/playlist/SoundCloudPlaylistPlugin.cxx
new file mode 100644
index 000000000..99bef29e7
--- /dev/null
+++ b/src/playlist/SoundCloudPlaylistPlugin.cxx
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2003-2013 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 "SoundCloudPlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "MemorySongEnumerator.hxx"
+#include "ConfigData.hxx"
+#include "InputStream.hxx"
+#include "Song.hxx"
+#include "tag/Tag.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+#include "Log.hxx"
+
+#include <glib.h>
+#include <yajl/yajl_parse.h>
+
+#include <string.h>
+
+static struct {
+ char *apikey;
+} soundcloud_config;
+
+static constexpr Domain soundcloud_domain("soundcloud");
+
+static bool
+soundcloud_init(const config_param &param)
+{
+ soundcloud_config.apikey = param.DupBlockString("apikey");
+ if (soundcloud_config.apikey == NULL) {
+ LogDebug(soundcloud_domain,
+ "disabling the soundcloud playlist plugin "
+ "because API key is not set");
+ return false;
+ }
+
+ return true;
+}
+
+static void
+soundcloud_finish(void)
+{
+ g_free(soundcloud_config.apikey);
+}
+
+/**
+ * Construct a full soundcloud resolver URL from the given fragment.
+ * @param uri uri of a soundcloud page (or just the path)
+ * @return Constructed URL. Must be freed with g_free.
+ */
+static char *
+soundcloud_resolve(const char* uri) {
+ char *u, *ru;
+
+ if (g_str_has_prefix(uri, "http://")) {
+ u = g_strdup(uri);
+ } else if (g_str_has_prefix(uri, "soundcloud.com")) {
+ u = g_strconcat("http://", uri, NULL);
+ } else {
+ /* assume it's just a path on soundcloud.com */
+ u = g_strconcat("http://soundcloud.com/", uri, NULL);
+ }
+
+ ru = g_strconcat("http://api.soundcloud.com/resolve.json?url=",
+ u, "&client_id=", soundcloud_config.apikey, NULL);
+ g_free(u);
+
+ return ru;
+}
+
+/* YAJL parser for track data from both /tracks/ and /playlists/ JSON */
+
+enum key {
+ Duration,
+ Title,
+ Stream_URL,
+ Other,
+};
+
+const char* key_str[] = {
+ "duration",
+ "title",
+ "stream_url",
+ NULL,
+};
+
+struct parse_data {
+ int key;
+ char* stream_url;
+ long duration;
+ char* title;
+ int got_url; /* nesting level of last stream_url */
+
+ std::forward_list<SongPointer> songs;
+};
+
+static int handle_integer(void *ctx,
+ long
+#ifndef HAVE_YAJL1
+ long
+#endif
+ intval)
+{
+ struct parse_data *data = (struct parse_data *) ctx;
+
+ switch (data->key) {
+ case Duration:
+ data->duration = intval;
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+static int handle_string(void *ctx, const unsigned char* stringval,
+#ifdef HAVE_YAJL1
+ unsigned int
+#else
+ size_t
+#endif
+ stringlen)
+{
+ struct parse_data *data = (struct parse_data *) ctx;
+ const char *s = (const char *) stringval;
+
+ switch (data->key) {
+ case Title:
+ if (data->title != NULL)
+ g_free(data->title);
+ data->title = g_strndup(s, stringlen);
+ break;
+ case Stream_URL:
+ if (data->stream_url != NULL)
+ g_free(data->stream_url);
+ data->stream_url = g_strndup(s, stringlen);
+ data->got_url = 1;
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+static int handle_mapkey(void *ctx, const unsigned char* stringval,
+#ifdef HAVE_YAJL1
+ unsigned int
+#else
+ size_t
+#endif
+ stringlen)
+{
+ struct parse_data *data = (struct parse_data *) ctx;
+
+ int i;
+ data->key = Other;
+
+ for (i = 0; i < Other; ++i) {
+ if (strncmp((const char *)stringval, key_str[i], stringlen) == 0) {
+ data->key = i;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+static int handle_start_map(void *ctx)
+{
+ struct parse_data *data = (struct parse_data *) ctx;
+
+ if (data->got_url > 0)
+ data->got_url++;
+
+ return 1;
+}
+
+static int handle_end_map(void *ctx)
+{
+ struct parse_data *data = (struct parse_data *) ctx;
+
+ if (data->got_url > 1) {
+ data->got_url--;
+ return 1;
+ }
+
+ if (data->got_url == 0)
+ return 1;
+
+ /* got_url == 1, track finished, make it into a song */
+ data->got_url = 0;
+
+ Song *s;
+ char *u;
+
+ u = g_strconcat(data->stream_url, "?client_id=", soundcloud_config.apikey, NULL);
+ s = Song::NewRemote(u);
+ g_free(u);
+
+ Tag *t = new Tag();
+ t->time = data->duration / 1000;
+ if (data->title != NULL)
+ t->AddItem(TAG_NAME, data->title);
+ s->tag = t;
+
+ data->songs.emplace_front(s);
+
+ return 1;
+}
+
+static yajl_callbacks parse_callbacks = {
+ NULL,
+ NULL,
+ handle_integer,
+ NULL,
+ NULL,
+ handle_string,
+ handle_start_map,
+ handle_mapkey,
+ handle_end_map,
+ NULL,
+ NULL,
+};
+
+/**
+ * Read JSON data and parse it using the given YAJL parser.
+ * @param url URL of the JSON data.
+ * @param hand YAJL parser handle.
+ * @return -1 on error, 0 on success.
+ */
+static int
+soundcloud_parse_json(const char *url, yajl_handle hand,
+ Mutex &mutex, Cond &cond)
+{
+ char buffer[4096];
+ unsigned char *ubuffer = (unsigned char *)buffer;
+
+ Error error;
+ input_stream *input_stream = input_stream::Open(url, mutex, cond,
+ error);
+ if (input_stream == NULL) {
+ if (error.IsDefined())
+ LogError(error);
+ return -1;
+ }
+
+ mutex.lock();
+ input_stream->WaitReady();
+
+ yajl_status stat;
+ int done = 0;
+
+ while (!done) {
+ const size_t nbytes =
+ input_stream->Read(buffer, sizeof(buffer), error);
+ if (nbytes == 0) {
+ if (error.IsDefined())
+ LogError(error);
+
+ if (input_stream->IsEOF()) {
+ done = true;
+ } else {
+ mutex.unlock();
+ input_stream->Close();
+ return -1;
+ }
+ }
+
+ if (done) {
+#ifdef HAVE_YAJL1
+ stat = yajl_parse_complete(hand);
+#else
+ stat = yajl_complete_parse(hand);
+#endif
+ } else
+ stat = yajl_parse(hand, ubuffer, nbytes);
+
+ if (stat != yajl_status_ok
+#ifdef HAVE_YAJL1
+ && stat != yajl_status_insufficient_data
+#endif
+ )
+ {
+ unsigned char *str = yajl_get_error(hand, 1, ubuffer, nbytes);
+ LogError(soundcloud_domain, (const char *)str);
+ yajl_free_error(hand, str);
+ break;
+ }
+ }
+
+ mutex.unlock();
+ input_stream->Close();
+
+ return 0;
+}
+
+/**
+ * Parse a soundcloud:// URL and create a playlist.
+ * @param uri A soundcloud URL. Accepted forms:
+ * soundcloud://track/<track-id>
+ * soundcloud://playlist/<playlist-id>
+ * soundcloud://url/<url or path of soundcloud page>
+ */
+
+static SongEnumerator *
+soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
+{
+ char *s, *p;
+ char *scheme, *arg, *rest;
+ s = g_strdup(uri);
+ scheme = s;
+ for (p = s; *p; p++) {
+ if (*p == ':' && *(p+1) == '/' && *(p+2) == '/') {
+ *p = 0;
+ p += 3;
+ break;
+ }
+ }
+ arg = p;
+ for (; *p; p++) {
+ if (*p == '/') {
+ *p = 0;
+ p++;
+ break;
+ }
+ }
+ rest = p;
+
+ if (strcmp(scheme, "soundcloud") != 0) {
+ FormatWarning(soundcloud_domain,
+ "incompatible scheme for soundcloud plugin: %s",
+ scheme);
+ g_free(s);
+ return NULL;
+ }
+
+ char *u = NULL;
+ if (strcmp(arg, "track") == 0) {
+ u = g_strconcat("http://api.soundcloud.com/tracks/",
+ rest, ".json?client_id=", soundcloud_config.apikey, NULL);
+ } else if (strcmp(arg, "playlist") == 0) {
+ u = g_strconcat("http://api.soundcloud.com/playlists/",
+ rest, ".json?client_id=", soundcloud_config.apikey, NULL);
+ } else if (strcmp(arg, "url") == 0) {
+ /* Translate to soundcloud resolver call. libcurl will automatically
+ follow the redirect to the right resource. */
+ u = soundcloud_resolve(rest);
+ }
+ g_free(s);
+
+ if (u == NULL) {
+ LogWarning(soundcloud_domain, "unknown soundcloud URI");
+ return NULL;
+ }
+
+ yajl_handle hand;
+ struct parse_data data;
+
+ data.got_url = 0;
+ data.title = NULL;
+ data.stream_url = NULL;
+#ifdef HAVE_YAJL1
+ hand = yajl_alloc(&parse_callbacks, NULL, NULL, (void *) &data);
+#else
+ hand = yajl_alloc(&parse_callbacks, NULL, (void *) &data);
+#endif
+
+ int ret = soundcloud_parse_json(u, hand, mutex, cond);
+
+ g_free(u);
+ yajl_free(hand);
+ if (data.title != NULL)
+ g_free(data.title);
+ if (data.stream_url != NULL)
+ g_free(data.stream_url);
+
+ if (ret == -1)
+ return NULL;
+
+ data.songs.reverse();
+ return new MemorySongEnumerator(std::move(data.songs));
+}
+
+static const char *const soundcloud_schemes[] = {
+ "soundcloud",
+ NULL
+};
+
+const struct playlist_plugin soundcloud_playlist_plugin = {
+ "soundcloud",
+
+ soundcloud_init,
+ soundcloud_finish,
+ soundcloud_open_uri,
+ nullptr,
+
+ soundcloud_schemes,
+ nullptr,
+ nullptr,
+};
+
+
diff --git a/src/playlist/SoundCloudPlaylistPlugin.hxx b/src/playlist/SoundCloudPlaylistPlugin.hxx
new file mode 100644
index 000000000..7c121328c
--- /dev/null
+++ b/src/playlist/SoundCloudPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_SOUNDCLOUD_PLAYLIST_PLUGIN_HXX
+#define MPD_SOUNDCLOUD_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin soundcloud_playlist_plugin;
+
+#endif
diff --git a/src/playlist/XspfPlaylistPlugin.cxx b/src/playlist/XspfPlaylistPlugin.cxx
new file mode 100644
index 000000000..9b55f1962
--- /dev/null
+++ b/src/playlist/XspfPlaylistPlugin.cxx
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2003-2013 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 "XspfPlaylistPlugin.hxx"
+#include "PlaylistPlugin.hxx"
+#include "MemorySongEnumerator.hxx"
+#include "InputStream.hxx"
+#include "tag/Tag.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+#include "Log.hxx"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+
+static constexpr Domain xspf_domain("xspf");
+
+/**
+ * This is the state object for the GLib XML parser.
+ */
+struct XspfParser {
+ /**
+ * The list of songs (in reverse order because that's faster
+ * while adding).
+ */
+ std::forward_list<SongPointer> songs;
+
+ /**
+ * The current position in the XML file.
+ */
+ enum {
+ ROOT, PLAYLIST, TRACKLIST, TRACK,
+ LOCATION,
+ } state;
+
+ /**
+ * The current tag within the "track" element. This is only
+ * valid if state==TRACK. TAG_NUM_OF_ITEM_TYPES means there
+ * is no (known) tag.
+ */
+ enum tag_type tag;
+
+ /**
+ * The current song. It is allocated after the "location"
+ * element.
+ */
+ Song *song;
+
+ XspfParser()
+ :state(ROOT) {}
+};
+
+static void
+xspf_start_element(gcc_unused GMarkupParseContext *context,
+ const gchar *element_name,
+ gcc_unused const gchar **attribute_names,
+ gcc_unused const gchar **attribute_values,
+ gpointer user_data, gcc_unused GError **error)
+{
+ XspfParser *parser = (XspfParser *)user_data;
+
+ switch (parser->state) {
+ case XspfParser::ROOT:
+ if (strcmp(element_name, "playlist") == 0)
+ parser->state = XspfParser::PLAYLIST;
+
+ break;
+
+ case XspfParser::PLAYLIST:
+ if (strcmp(element_name, "trackList") == 0)
+ parser->state = XspfParser::TRACKLIST;
+
+ break;
+
+ case XspfParser::TRACKLIST:
+ if (strcmp(element_name, "track") == 0) {
+ parser->state = XspfParser::TRACK;
+ parser->song = NULL;
+ parser->tag = TAG_NUM_OF_ITEM_TYPES;
+ }
+
+ break;
+
+ case XspfParser::TRACK:
+ if (strcmp(element_name, "location") == 0)
+ parser->state = XspfParser::LOCATION;
+ else if (strcmp(element_name, "title") == 0)
+ parser->tag = TAG_TITLE;
+ else if (strcmp(element_name, "creator") == 0)
+ /* TAG_COMPOSER would be more correct
+ according to the XSPF spec */
+ parser->tag = TAG_ARTIST;
+ else if (strcmp(element_name, "annotation") == 0)
+ parser->tag = TAG_COMMENT;
+ else if (strcmp(element_name, "album") == 0)
+ parser->tag = TAG_ALBUM;
+ else if (strcmp(element_name, "trackNum") == 0)
+ parser->tag = TAG_TRACK;
+
+ break;
+
+ case XspfParser::LOCATION:
+ break;
+ }
+}
+
+static void
+xspf_end_element(gcc_unused GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data, gcc_unused GError **error)
+{
+ XspfParser *parser = (XspfParser *)user_data;
+
+ switch (parser->state) {
+ case XspfParser::ROOT:
+ break;
+
+ case XspfParser::PLAYLIST:
+ if (strcmp(element_name, "playlist") == 0)
+ parser->state = XspfParser::ROOT;
+
+ break;
+
+ case XspfParser::TRACKLIST:
+ if (strcmp(element_name, "tracklist") == 0)
+ parser->state = XspfParser::PLAYLIST;
+
+ break;
+
+ case XspfParser::TRACK:
+ if (strcmp(element_name, "track") == 0) {
+ if (parser->song != NULL)
+ parser->songs.emplace_front(parser->song);
+
+ parser->state = XspfParser::TRACKLIST;
+ } else
+ parser->tag = TAG_NUM_OF_ITEM_TYPES;
+
+ break;
+
+ case XspfParser::LOCATION:
+ parser->state = XspfParser::TRACK;
+ break;
+ }
+}
+
+static void
+xspf_text(gcc_unused GMarkupParseContext *context,
+ const gchar *text, gsize text_len,
+ gpointer user_data, gcc_unused GError **error)
+{
+ XspfParser *parser = (XspfParser *)user_data;
+
+ switch (parser->state) {
+ case XspfParser::ROOT:
+ case XspfParser::PLAYLIST:
+ case XspfParser::TRACKLIST:
+ break;
+
+ case XspfParser::TRACK:
+ if (parser->song != NULL &&
+ parser->tag != TAG_NUM_OF_ITEM_TYPES) {
+ if (parser->song->tag == NULL)
+ parser->song->tag = new Tag();
+ parser->song->tag->AddItem(parser->tag, text, text_len);
+ }
+
+ break;
+
+ case XspfParser::LOCATION:
+ if (parser->song == NULL) {
+ char *uri = g_strndup(text, text_len);
+ parser->song = Song::NewRemote(uri);
+ g_free(uri);
+ }
+
+ break;
+ }
+}
+
+static const GMarkupParser xspf_parser = {
+ xspf_start_element,
+ xspf_end_element,
+ xspf_text,
+ nullptr,
+ nullptr,
+};
+
+static void
+xspf_parser_destroy(gpointer data)
+{
+ XspfParser *parser = (XspfParser *)data;
+
+ if (parser->state >= XspfParser::TRACK && parser->song != NULL)
+ parser->song->Free();
+}
+
+/*
+ * The playlist object
+ *
+ */
+
+static SongEnumerator *
+xspf_open_stream(struct input_stream *is)
+{
+ XspfParser parser;
+ GMarkupParseContext *context;
+ char buffer[1024];
+ size_t nbytes;
+ bool success;
+ Error error2;
+ GError *error = NULL;
+
+ /* parse the XSPF XML file */
+
+ context = g_markup_parse_context_new(&xspf_parser,
+ G_MARKUP_TREAT_CDATA_AS_TEXT,
+ &parser, xspf_parser_destroy);
+
+ while (true) {
+ nbytes = is->LockRead(buffer, sizeof(buffer), error2);
+ if (nbytes == 0) {
+ if (error2.IsDefined()) {
+ g_markup_parse_context_free(context);
+ LogError(error2);
+ return NULL;
+ }
+
+ break;
+ }
+
+ success = g_markup_parse_context_parse(context, buffer, nbytes,
+ &error);
+ if (!success) {
+ FormatError(xspf_domain,
+ "XML parser failed: %s", error->message);
+ g_error_free(error);
+ g_markup_parse_context_free(context);
+ return NULL;
+ }
+ }
+
+ success = g_markup_parse_context_end_parse(context, &error);
+ if (!success) {
+ FormatError(xspf_domain,
+ "XML parser failed: %s", error->message);
+ g_error_free(error);
+ g_markup_parse_context_free(context);
+ return NULL;
+ }
+
+ parser.songs.reverse();
+ MemorySongEnumerator *playlist =
+ new MemorySongEnumerator(std::move(parser.songs));
+
+ g_markup_parse_context_free(context);
+
+ return playlist;
+}
+
+static const char *const xspf_suffixes[] = {
+ "xspf",
+ NULL
+};
+
+static const char *const xspf_mime_types[] = {
+ "application/xspf+xml",
+ NULL
+};
+
+const struct playlist_plugin xspf_playlist_plugin = {
+ "xspf",
+
+ nullptr,
+ nullptr,
+ nullptr,
+ xspf_open_stream,
+
+ nullptr,
+ xspf_suffixes,
+ xspf_mime_types,
+};
diff --git a/src/playlist/XspfPlaylistPlugin.hxx b/src/playlist/XspfPlaylistPlugin.hxx
new file mode 100644
index 000000000..fc9bbd2c6
--- /dev/null
+++ b/src/playlist/XspfPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2013 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_XSPF_PLAYLIST_PLUGIN_HXX
+#define MPD_XSPF_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin xspf_playlist_plugin;
+
+#endif
diff --git a/src/playlist/asx_playlist_plugin.c b/src/playlist/asx_playlist_plugin.c
deleted file mode 100644
index 298687859..000000000
--- a/src/playlist/asx_playlist_plugin.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist/asx_playlist_plugin.h"
-#include "playlist_plugin.h"
-#include "input_stream.h"
-#include "song.h"
-#include "tag.h"
-
-#include <glib.h>
-
-#include <assert.h>
-#include <string.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "asx"
-
-/**
- * This is the state object for the GLib XML parser.
- */
-struct asx_parser {
- /**
- * The list of songs (in reverse order because that's faster
- * while adding).
- */
- GSList *songs;
-
- /**
- * The current position in the XML file.
- */
- enum {
- ROOT, ENTRY,
- } state;
-
- /**
- * The current tag within the "entry" element. This is only
- * valid if state==ENTRY. TAG_NUM_OF_ITEM_TYPES means there
- * is no (known) tag.
- */
- enum tag_type tag;
-
- /**
- * The current song. It is allocated after the "location"
- * element.
- */
- struct song *song;
-};
-
-static const gchar *
-get_attribute(const gchar **attribute_names, const gchar **attribute_values,
- const gchar *name)
-{
- for (unsigned i = 0; attribute_names[i] != NULL; ++i)
- if (g_ascii_strcasecmp(attribute_names[i], name) == 0)
- return attribute_values[i];
-
- return NULL;
-}
-
-static void
-asx_start_element(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct asx_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- if (g_ascii_strcasecmp(element_name, "entry") == 0) {
- parser->state = ENTRY;
- parser->song = song_remote_new("asx:");
- parser->tag = TAG_NUM_OF_ITEM_TYPES;
- }
-
- break;
-
- case ENTRY:
- if (g_ascii_strcasecmp(element_name, "ref") == 0) {
- const gchar *href = get_attribute(attribute_names,
- attribute_values,
- "href");
- if (href != NULL) {
- /* create new song object, and copy
- the existing tag over; we cannot
- replace the existing song's URI,
- because that attribute is
- immutable */
- struct song *song = song_remote_new(href);
-
- if (parser->song != NULL) {
- song->tag = parser->song->tag;
- parser->song->tag = NULL;
- song_free(parser->song);
- }
-
- parser->song = song;
- }
- } else if (g_ascii_strcasecmp(element_name, "author") == 0)
- /* is that correct? or should it be COMPOSER
- or PERFORMER? */
- parser->tag = TAG_ARTIST;
- else if (g_ascii_strcasecmp(element_name, "title") == 0)
- parser->tag = TAG_TITLE;
-
- break;
- }
-}
-
-static void
-asx_end_element(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct asx_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- break;
-
- case ENTRY:
- if (g_ascii_strcasecmp(element_name, "entry") == 0) {
- if (strcmp(parser->song->uri, "asx:") != 0)
- parser->songs = g_slist_prepend(parser->songs,
- parser->song);
- else
- song_free(parser->song);
-
- parser->state = ROOT;
- } else
- parser->tag = TAG_NUM_OF_ITEM_TYPES;
-
- break;
- }
-}
-
-static void
-asx_text(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *text, gsize text_len,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct asx_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- break;
-
- case ENTRY:
- if (parser->tag != TAG_NUM_OF_ITEM_TYPES) {
- if (parser->song->tag == NULL)
- parser->song->tag = tag_new();
- tag_add_item_n(parser->song->tag, parser->tag,
- text, text_len);
- }
-
- break;
- }
-}
-
-static const GMarkupParser asx_parser = {
- .start_element = asx_start_element,
- .end_element = asx_end_element,
- .text = asx_text,
-};
-
-static void
-song_free_callback(gpointer data, G_GNUC_UNUSED gpointer user_data)
-{
- struct song *song = data;
-
- song_free(song);
-}
-
-static void
-asx_parser_destroy(gpointer data)
-{
- struct asx_parser *parser = data;
-
- if (parser->state >= ENTRY)
- song_free(parser->song);
-
- g_slist_foreach(parser->songs, song_free_callback, NULL);
- g_slist_free(parser->songs);
-}
-
-/*
- * The playlist object
- *
- */
-
-struct asx_playlist {
- struct playlist_provider base;
-
- GSList *songs;
-};
-
-static struct playlist_provider *
-asx_open_stream(struct input_stream *is)
-{
- struct asx_parser parser = {
- .songs = NULL,
- .state = ROOT,
- };
- struct asx_playlist *playlist;
- GMarkupParseContext *context;
- char buffer[1024];
- size_t nbytes;
- bool success;
- GError *error = NULL;
-
- /* parse the ASX XML file */
-
- context = g_markup_parse_context_new(&asx_parser,
- G_MARKUP_TREAT_CDATA_AS_TEXT,
- &parser, asx_parser_destroy);
-
- while (true) {
- nbytes = input_stream_lock_read(is, buffer, sizeof(buffer),
- &error);
- if (nbytes == 0) {
- if (error != NULL) {
- g_markup_parse_context_free(context);
- g_warning("%s", error->message);
- g_error_free(error);
- return NULL;
- }
-
- break;
- }
-
- success = g_markup_parse_context_parse(context, buffer, nbytes,
- &error);
- if (!success) {
- g_warning("XML parser failed: %s", error->message);
- g_error_free(error);
- g_markup_parse_context_free(context);
- return NULL;
- }
- }
-
- success = g_markup_parse_context_end_parse(context, &error);
- if (!success) {
- g_warning("XML parser failed: %s", error->message);
- g_error_free(error);
- g_markup_parse_context_free(context);
- return NULL;
- }
-
- /* create a #asx_playlist object from the parsed song list */
-
- playlist = g_new(struct asx_playlist, 1);
- playlist_provider_init(&playlist->base, &asx_playlist_plugin);
- playlist->songs = g_slist_reverse(parser.songs);
- parser.songs = NULL;
-
- g_markup_parse_context_free(context);
-
- return &playlist->base;
-}
-
-static void
-asx_close(struct playlist_provider *_playlist)
-{
- struct asx_playlist *playlist = (struct asx_playlist *)_playlist;
-
- g_slist_foreach(playlist->songs, song_free_callback, NULL);
- g_slist_free(playlist->songs);
- g_free(playlist);
-}
-
-static struct song *
-asx_read(struct playlist_provider *_playlist)
-{
- struct asx_playlist *playlist = (struct asx_playlist *)_playlist;
- struct song *song;
-
- if (playlist->songs == NULL)
- return NULL;
-
- song = playlist->songs->data;
- playlist->songs = g_slist_remove(playlist->songs, song);
-
- return song;
-}
-
-static const char *const asx_suffixes[] = {
- "asx",
- NULL
-};
-
-static const char *const asx_mime_types[] = {
- "video/x-ms-asf",
- NULL
-};
-
-const struct playlist_plugin asx_playlist_plugin = {
- .name = "asx",
-
- .open_stream = asx_open_stream,
- .close = asx_close,
- .read = asx_read,
-
- .suffixes = asx_suffixes,
- .mime_types = asx_mime_types,
-};
diff --git a/src/playlist/asx_playlist_plugin.h b/src/playlist/asx_playlist_plugin.h
deleted file mode 100644
index 6c01c1209..000000000
--- a/src/playlist/asx_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_ASX_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_ASX_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin asx_playlist_plugin;
-
-#endif
diff --git a/src/playlist/cue_playlist_plugin.c b/src/playlist/cue_playlist_plugin.c
deleted file mode 100644
index b85de77d3..000000000
--- a/src/playlist/cue_playlist_plugin.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist/cue_playlist_plugin.h"
-#include "playlist_plugin.h"
-#include "tag.h"
-#include "song.h"
-#include "cue/cue_parser.h"
-#include "input_stream.h"
-#include "text_input_stream.h"
-
-#include <glib.h>
-#include <assert.h>
-#include <string.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "cue"
-
-struct cue_playlist {
- struct playlist_provider base;
-
- struct input_stream *is;
- struct text_input_stream *tis;
- struct cue_parser *parser;
-};
-
-static struct playlist_provider *
-cue_playlist_open_stream(struct input_stream *is)
-{
- struct cue_playlist *playlist = g_new(struct cue_playlist, 1);
- playlist_provider_init(&playlist->base, &cue_playlist_plugin);
-
- playlist->is = is;
- playlist->tis = text_input_stream_new(is);
- playlist->parser = cue_parser_new();
-
-
- return &playlist->base;
-}
-
-static void
-cue_playlist_close(struct playlist_provider *_playlist)
-{
- struct cue_playlist *playlist = (struct cue_playlist *)_playlist;
-
- cue_parser_free(playlist->parser);
- text_input_stream_free(playlist->tis);
- g_free(playlist);
-}
-
-static struct song *
-cue_playlist_read(struct playlist_provider *_playlist)
-{
- struct cue_playlist *playlist = (struct cue_playlist *)_playlist;
-
- struct song *song = cue_parser_get(playlist->parser);
- if (song != NULL)
- return song;
-
- const char *line;
- while ((line = text_input_stream_read(playlist->tis)) != NULL) {
- cue_parser_feed(playlist->parser, line);
- song = cue_parser_get(playlist->parser);
- if (song != NULL)
- return song;
- }
-
- cue_parser_finish(playlist->parser);
- return cue_parser_get(playlist->parser);
-}
-
-static const char *const cue_playlist_suffixes[] = {
- "cue",
- NULL
-};
-
-static const char *const cue_playlist_mime_types[] = {
- "application/x-cue",
- NULL
-};
-
-const struct playlist_plugin cue_playlist_plugin = {
- .name = "cue",
-
- .open_stream = cue_playlist_open_stream,
- .close = cue_playlist_close,
- .read = cue_playlist_read,
-
- .suffixes = cue_playlist_suffixes,
- .mime_types = cue_playlist_mime_types,
-};
diff --git a/src/playlist/cue_playlist_plugin.h b/src/playlist/cue_playlist_plugin.h
deleted file mode 100644
index c02e2235a..000000000
--- a/src/playlist/cue_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_CUE_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_CUE_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin cue_playlist_plugin;
-
-#endif
diff --git a/src/playlist/despotify_playlist_plugin.c b/src/playlist/despotify_playlist_plugin.c
deleted file mode 100644
index 30b852c73..000000000
--- a/src/playlist/despotify_playlist_plugin.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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 "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
deleted file mode 100644
index f8ee20de0..000000000
--- a/src/playlist/despotify_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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/embcue_playlist_plugin.c b/src/playlist/embcue_playlist_plugin.c
deleted file mode 100644
index 6d9a957f9..000000000
--- a/src/playlist/embcue_playlist_plugin.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2003-2012 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.
- */
-
-/** \file
- *
- * Playlist plugin that reads embedded cue sheets from the "CUESHEET"
- * tag of a music file.
- */
-
-#include "config.h"
-#include "playlist/embcue_playlist_plugin.h"
-#include "playlist_plugin.h"
-#include "tag.h"
-#include "tag_handler.h"
-#include "tag_file.h"
-#include "tag_ape.h"
-#include "tag_id3.h"
-#include "song.h"
-#include "cue/cue_parser.h"
-
-#include <glib.h>
-#include <assert.h>
-#include <string.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "cue"
-
-struct embcue_playlist {
- struct playlist_provider base;
-
- /**
- * This is an override for the CUE's "FILE". An embedded CUE
- * sheet must always point to the song file it is contained
- * in.
- */
- char *filename;
-
- /**
- * The value of the file's "CUESHEET" tag.
- */
- char *cuesheet;
-
- /**
- * The offset of the next line within "cuesheet".
- */
- char *next;
-
- struct cue_parser *parser;
-};
-
-static void
-embcue_tag_pair(const char *name, const char *value, void *ctx)
-{
- struct embcue_playlist *playlist = ctx;
-
- if (playlist->cuesheet == NULL &&
- g_ascii_strcasecmp(name, "cuesheet") == 0)
- playlist->cuesheet = g_strdup(value);
-}
-
-static const struct tag_handler embcue_tag_handler = {
- .pair = embcue_tag_pair,
-};
-
-static struct playlist_provider *
-embcue_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 */
- return NULL;
-
- struct embcue_playlist *playlist = g_new(struct embcue_playlist, 1);
- playlist_provider_init(&playlist->base, &embcue_playlist_plugin);
- playlist->cuesheet = NULL;
-
- tag_file_scan(uri, &embcue_tag_handler, playlist);
- if (playlist->cuesheet == NULL) {
- tag_ape_scan2(uri, &embcue_tag_handler, playlist);
- if (playlist->cuesheet == NULL)
- tag_id3_scan(uri, &embcue_tag_handler, playlist);
- }
-
- if (playlist->cuesheet == NULL) {
- /* no "CUESHEET" tag found */
- g_free(playlist);
- return NULL;
- }
-
- playlist->filename = g_path_get_basename(uri);
-
- playlist->next = playlist->cuesheet;
- playlist->parser = cue_parser_new();
-
- return &playlist->base;
-}
-
-static void
-embcue_playlist_close(struct playlist_provider *_playlist)
-{
- struct embcue_playlist *playlist = (struct embcue_playlist *)_playlist;
-
- cue_parser_free(playlist->parser);
- g_free(playlist->cuesheet);
- g_free(playlist->filename);
- g_free(playlist);
-}
-
-static struct song *
-embcue_playlist_read(struct playlist_provider *_playlist)
-{
- struct embcue_playlist *playlist = (struct embcue_playlist *)_playlist;
-
- struct song *song = cue_parser_get(playlist->parser);
- if (song != NULL)
- return song;
-
- while (*playlist->next != 0) {
- const char *line = playlist->next;
- char *eol = strpbrk(playlist->next, "\r\n");
- if (eol != NULL) {
- /* null-terminate the line */
- *eol = 0;
- playlist->next = eol + 1;
- } else
- /* last line; put the "next" pointer to the
- end of the buffer */
- playlist->next += strlen(line);
-
- cue_parser_feed(playlist->parser, line);
- song = cue_parser_get(playlist->parser);
- if (song != NULL)
- return song_replace_uri(song, playlist->filename);
- }
-
- cue_parser_finish(playlist->parser);
- song = cue_parser_get(playlist->parser);
- if (song != NULL)
- song = song_replace_uri(song, playlist->filename);
- return song;
-}
-
-static const char *const embcue_playlist_suffixes[] = {
- /* a few codecs that are known to be supported; there are
- probably many more */
- "flac",
- "mp3", "mp2",
- "mp4", "mp4a", "m4b",
- "ape",
- "wv",
- "ogg", "oga",
- NULL
-};
-
-const struct playlist_plugin embcue_playlist_plugin = {
- .name = "cue",
-
- .open_uri = embcue_playlist_open_uri,
- .close = embcue_playlist_close,
- .read = embcue_playlist_read,
-
- .suffixes = embcue_playlist_suffixes,
- .mime_types = NULL,
-};
diff --git a/src/playlist/embcue_playlist_plugin.h b/src/playlist/embcue_playlist_plugin.h
deleted file mode 100644
index c5f21b27e..000000000
--- a/src/playlist/embcue_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2003-2012 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_EMBCUE_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_EMBCUE_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin embcue_playlist_plugin;
-
-#endif
diff --git a/src/playlist/extm3u_playlist_plugin.c b/src/playlist/extm3u_playlist_plugin.c
deleted file mode 100644
index 19be8d1c4..000000000
--- a/src/playlist/extm3u_playlist_plugin.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist/extm3u_playlist_plugin.h"
-#include "playlist_plugin.h"
-#include "text_input_stream.h"
-#include "uri.h"
-#include "song.h"
-#include "tag.h"
-#include "string_util.h"
-
-#include <glib.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-struct extm3u_playlist {
- struct playlist_provider base;
-
- struct text_input_stream *tis;
-};
-
-static struct playlist_provider *
-extm3u_open_stream(struct input_stream *is)
-{
- struct extm3u_playlist *playlist;
- const char *line;
-
- playlist = g_new(struct extm3u_playlist, 1);
- playlist->tis = text_input_stream_new(is);
-
- line = text_input_stream_read(playlist->tis);
- if (line == NULL || strcmp(line, "#EXTM3U") != 0) {
- /* no EXTM3U header: fall back to the plain m3u
- plugin */
- text_input_stream_free(playlist->tis);
- g_free(playlist);
- return NULL;
- }
-
- playlist_provider_init(&playlist->base, &extm3u_playlist_plugin);
- return &playlist->base;
-}
-
-static void
-extm3u_close(struct playlist_provider *_playlist)
-{
- struct extm3u_playlist *playlist = (struct extm3u_playlist *)_playlist;
-
- text_input_stream_free(playlist->tis);
- g_free(playlist);
-}
-
-/**
- * Parse a EXTINF line.
- *
- * @param line the rest of the input line after the colon
- */
-static struct tag *
-extm3u_parse_tag(const char *line)
-{
- long duration;
- char *endptr;
- const char *name;
- struct tag *tag;
-
- duration = strtol(line, &endptr, 10);
- if (endptr[0] != ',')
- /* malformed line */
- return NULL;
-
- if (duration < 0)
- /* 0 means unknown duration */
- duration = 0;
-
- name = strchug_fast_c(endptr + 1);
- if (*name == 0 && duration == 0)
- /* no information available; don't allocate a tag
- object */
- return NULL;
-
- tag = tag_new();
- tag->time = duration;
-
- /* unfortunately, there is no real specification for the
- EXTM3U format, so we must assume that the string after the
- comma is opaque, and is just the song name*/
- if (*name != 0)
- tag_add_item(tag, TAG_NAME, name);
-
- return tag;
-}
-
-static struct song *
-extm3u_read(struct playlist_provider *_playlist)
-{
- struct extm3u_playlist *playlist = (struct extm3u_playlist *)_playlist;
- struct tag *tag = NULL;
- const char *line;
- struct song *song;
-
- do {
- line = text_input_stream_read(playlist->tis);
- if (line == NULL) {
- if (tag != NULL)
- tag_free(tag);
- return NULL;
- }
-
- if (g_str_has_prefix(line, "#EXTINF:")) {
- if (tag != NULL)
- tag_free(tag);
- tag = extm3u_parse_tag(line + 8);
- continue;
- }
-
- while (*line != 0 && g_ascii_isspace(*line))
- ++line;
- } while (line[0] == '#' || *line == 0);
-
- song = song_remote_new(line);
- song->tag = tag;
- return song;
-}
-
-static const char *const extm3u_suffixes[] = {
- "m3u",
- NULL
-};
-
-static const char *const extm3u_mime_types[] = {
- "audio/x-mpegurl",
- NULL
-};
-
-const struct playlist_plugin extm3u_playlist_plugin = {
- .name = "extm3u",
-
- .open_stream = extm3u_open_stream,
- .close = extm3u_close,
- .read = extm3u_read,
-
- .suffixes = extm3u_suffixes,
- .mime_types = extm3u_mime_types,
-};
diff --git a/src/playlist/extm3u_playlist_plugin.h b/src/playlist/extm3u_playlist_plugin.h
deleted file mode 100644
index 5f611ac9c..000000000
--- a/src/playlist/extm3u_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_EXTM3U_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_EXTM3U_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin extm3u_playlist_plugin;
-
-#endif
diff --git a/src/playlist/lastfm_playlist_plugin.c b/src/playlist/lastfm_playlist_plugin.c
deleted file mode 100644
index ead14deaa..000000000
--- a/src/playlist/lastfm_playlist_plugin.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist/lastfm_playlist_plugin.h"
-#include "playlist_plugin.h"
-#include "playlist_list.h"
-#include "conf.h"
-#include "uri.h"
-#include "song.h"
-#include "input_stream.h"
-
-#include <glib.h>
-
-#include <assert.h>
-#include <string.h>
-
-struct lastfm_playlist {
- struct playlist_provider base;
-
- struct input_stream *is;
-
- struct playlist_provider *xspf;
-};
-
-static struct {
- char *user;
- char *md5;
-} lastfm_config;
-
-static bool
-lastfm_init(const struct config_param *param)
-{
- const char *user = config_get_block_string(param, "user", NULL);
- const char *passwd = config_get_block_string(param, "password", NULL);
-
- if (user == NULL || passwd == NULL) {
- g_debug("disabling the last.fm playlist plugin "
- "because account is not configured");
- return false;
- }
-
- lastfm_config.user = g_uri_escape_string(user, NULL, false);
-
- if (strlen(passwd) != 32)
- lastfm_config.md5 = g_compute_checksum_for_string(G_CHECKSUM_MD5,
- passwd, strlen(passwd));
- else
- lastfm_config.md5 = g_strdup(passwd);
-
- return true;
-}
-
-static void
-lastfm_finish(void)
-{
- g_free(lastfm_config.user);
- g_free(lastfm_config.md5);
-}
-
-/**
- * Simple data fetcher.
- * @param url path or url of data to fetch.
- * @return data fetched, or NULL on error. Must be freed with g_free.
- */
-static char *
-lastfm_get(const char *url, GMutex *mutex, GCond *cond)
-{
- struct input_stream *input_stream;
- GError *error = NULL;
- char buffer[4096];
- size_t length = 0, nbytes;
-
- input_stream = input_stream_open(url, mutex, cond, &error);
- if (input_stream == NULL) {
- if (error != NULL) {
- 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,
- sizeof(buffer) - length, &error);
- if (nbytes == 0) {
- if (error != NULL) {
- g_warning("%s", error->message);
- g_error_free(error);
- }
-
- if (input_stream_eof(input_stream))
- break;
-
- /* I/O error */
- g_mutex_unlock(mutex);
- input_stream_close(input_stream);
- return NULL;
- }
-
- length += nbytes;
- } while (length < sizeof(buffer));
-
- g_mutex_unlock(mutex);
-
- input_stream_close(input_stream);
- return g_strndup(buffer, length);
-}
-
-/**
- * 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 response or NULL on error. Free with g_free.
- */
-static char *
-lastfm_find(const char *response, const char *name)
-{
- size_t name_length = strlen(name);
-
- while (true) {
- const char *eol = strchr(response, '\n');
- if (eol == NULL)
- return NULL;
-
- if (strncmp(response, name, name_length) == 0 &&
- response[name_length] == '=') {
- response += name_length + 1;
- return g_strndup(response, eol - response);
- }
-
- response = eol + 1;
- }
-}
-
-static struct playlist_provider *
-lastfm_open_uri(const char *uri, GMutex *mutex, GCond *cond)
-{
- struct lastfm_playlist *playlist;
- GError *error = NULL;
- char *p, *q, *response, *session;
-
- /* handshake */
-
- p = g_strconcat("http://ws.audioscrobbler.com/radio/handshake.php?"
- "version=1.1.1&platform=linux&"
- "username=", lastfm_config.user, "&"
- "passwordmd5=", lastfm_config.md5, "&"
- "debug=0&partner=", NULL);
- response = lastfm_get(p, mutex, cond);
- g_free(p);
- if (response == NULL)
- return NULL;
-
- /* extract session id from response */
-
- session = lastfm_find(response, "session");
- g_free(response);
- if (session == NULL) {
- g_warning("last.fm handshake failed");
- return NULL;
- }
-
- q = g_uri_escape_string(session, NULL, false);
- g_free(session);
- session = q;
-
- g_debug("session='%s'", session);
-
- /* "adjust" last.fm radio */
-
- if (strlen(uri) > 9) {
- char *escaped_uri;
-
- escaped_uri = g_uri_escape_string(uri, NULL, false);
-
- p = g_strconcat("http://ws.audioscrobbler.com/radio/adjust.php?"
- "session=", session, "&url=", escaped_uri, "&debug=0",
- NULL);
- g_free(escaped_uri);
-
- response = lastfm_get(p, mutex, cond);
- g_free(response);
- g_free(p);
-
- if (response == NULL) {
- g_free(session);
- return NULL;
- }
- }
-
- /* create the playlist object */
-
- playlist = g_new(struct lastfm_playlist, 1);
- playlist_provider_init(&playlist->base, &lastfm_playlist_plugin);
-
- /* open the last.fm playlist */
-
- p = g_strconcat("http://ws.audioscrobbler.com/radio/xspf.php?"
- "sk=", session, "&discovery=0&desktop=1.5.1.31879",
- NULL);
- g_free(session);
-
- playlist->is = input_stream_open(p, mutex, cond, &error);
- g_free(p);
-
- if (playlist->is == NULL) {
- if (error != NULL) {
- g_warning("Failed to load XSPF playlist: %s",
- error->message);
- g_error_free(error);
- } else
- g_warning("Failed to load XSPF playlist");
- g_free(playlist);
- return NULL;
- }
-
- g_mutex_lock(mutex);
-
- 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);
- if (playlist->xspf == NULL) {
- input_stream_close(playlist->is);
- g_free(playlist);
- g_warning("Failed to parse XSPF playlist");
- return NULL;
- }
-
- return &playlist->base;
-}
-
-static void
-lastfm_close(struct playlist_provider *_playlist)
-{
- struct lastfm_playlist *playlist = (struct lastfm_playlist *)_playlist;
-
- playlist_plugin_close(playlist->xspf);
- input_stream_close(playlist->is);
- g_free(playlist);
-}
-
-static struct song *
-lastfm_read(struct playlist_provider *_playlist)
-{
- struct lastfm_playlist *playlist = (struct lastfm_playlist *)_playlist;
-
- return playlist_plugin_read(playlist->xspf);
-}
-
-static const char *const lastfm_schemes[] = {
- "lastfm",
- NULL
-};
-
-const struct playlist_plugin lastfm_playlist_plugin = {
- .name = "lastfm",
-
- .init = lastfm_init,
- .finish = lastfm_finish,
- .open_uri = lastfm_open_uri,
- .close = lastfm_close,
- .read = lastfm_read,
-
- .schemes = lastfm_schemes,
-};
diff --git a/src/playlist/lastfm_playlist_plugin.h b/src/playlist/lastfm_playlist_plugin.h
deleted file mode 100644
index 46a8b0caf..000000000
--- a/src/playlist/lastfm_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_LASTFM_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_LASTFM_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin lastfm_playlist_plugin;
-
-#endif
diff --git a/src/playlist/m3u_playlist_plugin.c b/src/playlist/m3u_playlist_plugin.c
deleted file mode 100644
index 45b70d2b1..000000000
--- a/src/playlist/m3u_playlist_plugin.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#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] == '#' || *line == 0);
-
- 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
deleted file mode 100644
index 3890a5fc2..000000000
--- a/src/playlist/m3u_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_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/pls_playlist_plugin.c b/src/playlist/pls_playlist_plugin.c
deleted file mode 100644
index c4e5492af..000000000
--- a/src/playlist/pls_playlist_plugin.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist/pls_playlist_plugin.h"
-#include "playlist_plugin.h"
-#include "input_stream.h"
-#include "uri.h"
-#include "song.h"
-#include "tag.h"
-#include <glib.h>
-
-struct pls_playlist {
- struct playlist_provider base;
-
- GSList *songs;
-};
-
-static void pls_parser(GKeyFile *keyfile, struct pls_playlist *playlist)
-{
- gchar *key;
- gchar *value;
- int length;
- GError *error = NULL;
- int num_entries = g_key_file_get_integer(keyfile, "playlist",
- "NumberOfEntries", &error);
- if (error) {
- g_debug("Invalid PLS file: '%s'", error->message);
- g_error_free(error);
- error = NULL;
-
- /* Hack to work around shoutcast failure to comform to spec */
- num_entries = g_key_file_get_integer(keyfile, "playlist",
- "numberofentries", &error);
- if (error) {
- g_error_free(error);
- error = NULL;
- }
- }
-
- while (num_entries > 0) {
- struct song *song;
- key = g_strdup_printf("File%i", num_entries);
- value = g_key_file_get_string(keyfile, "playlist", key,
- &error);
- if(error) {
- g_debug("Invalid PLS entry %s: '%s'",key, error->message);
- g_error_free(error);
- g_free(key);
- return;
- }
- g_free(key);
-
- song = song_remote_new(value);
- g_free(value);
-
- key = g_strdup_printf("Title%i", num_entries);
- value = g_key_file_get_string(keyfile, "playlist", key,
- &error);
- g_free(key);
- if(error == NULL && value){
- if (song->tag == NULL)
- song->tag = tag_new();
- tag_add_item(song->tag,TAG_TITLE, value);
- }
- /* Ignore errors? Most likely value not present */
- if(error) g_error_free(error);
- error = NULL;
- g_free(value);
-
- key = g_strdup_printf("Length%i", num_entries);
- length = g_key_file_get_integer(keyfile, "playlist", key,
- &error);
- g_free(key);
- if(error == NULL && length > 0){
- if (song->tag == NULL)
- song->tag = tag_new();
- song->tag->time = length;
- }
- /* Ignore errors? Most likely value not present */
- if(error) g_error_free(error);
- error = NULL;
-
- playlist->songs = g_slist_prepend(playlist->songs, song);
- num_entries--;
- }
-
-}
-
-static struct playlist_provider *
-pls_open_stream(struct input_stream *is)
-{
- GError *error = NULL;
- size_t nbytes;
- char buffer[1024];
- bool success;
- GKeyFile *keyfile;
- struct pls_playlist *playlist;
- GString *kf_data = g_string_new("");
-
- do {
- nbytes = input_stream_lock_read(is, buffer, sizeof(buffer),
- &error);
- if (nbytes == 0) {
- if (error != NULL) {
- g_string_free(kf_data, TRUE);
- g_warning("%s", error->message);
- g_error_free(error);
- return NULL;
- }
-
- break;
- }
-
- kf_data = g_string_append_len(kf_data, buffer,nbytes);
- /* Limit to 64k */
- } while(kf_data->len < 65536);
-
- if (kf_data->len == 0) {
- g_warning("KeyFile parser failed: No Data");
- g_string_free(kf_data, TRUE);
- return NULL;
- }
-
- keyfile = g_key_file_new();
- success = g_key_file_load_from_data(keyfile,
- kf_data->str, kf_data->len,
- G_KEY_FILE_NONE, &error);
-
- g_string_free(kf_data, TRUE);
-
- if (!success) {
- g_warning("KeyFile parser failed: %s", error->message);
- g_error_free(error);
- g_key_file_free(keyfile);
- return NULL;
- }
-
- playlist = g_new(struct pls_playlist, 1);
- playlist_provider_init(&playlist->base, &pls_playlist_plugin);
- playlist->songs = NULL;
-
- pls_parser(keyfile, playlist);
-
- g_key_file_free(keyfile);
- return &playlist->base;
-}
-
-
-static void
-song_free_callback(gpointer data, G_GNUC_UNUSED gpointer user_data)
-{
- struct song *song = data;
-
- song_free(song);
-}
-
-static void
-pls_close(struct playlist_provider *_playlist)
-{
- struct pls_playlist *playlist = (struct pls_playlist *)_playlist;
-
- g_slist_foreach(playlist->songs, song_free_callback, NULL);
- g_slist_free(playlist->songs);
-
- g_free(playlist);
-
-}
-
-static struct song *
-pls_read(struct playlist_provider *_playlist)
-{
- struct pls_playlist *playlist = (struct pls_playlist *)_playlist;
- struct song *song;
-
- if (playlist->songs == NULL)
- return NULL;
-
- song = playlist->songs->data;
- playlist->songs = g_slist_remove(playlist->songs, song);
-
- return song;
-}
-
-static const char *const pls_suffixes[] = {
- "pls",
- NULL
-};
-
-static const char *const pls_mime_types[] = {
- "audio/x-scpls",
- NULL
-};
-
-const struct playlist_plugin pls_playlist_plugin = {
- .name = "pls",
-
- .open_stream = pls_open_stream,
- .close = pls_close,
- .read = pls_read,
-
- .suffixes = pls_suffixes,
- .mime_types = pls_mime_types,
-};
diff --git a/src/playlist/pls_playlist_plugin.h b/src/playlist/pls_playlist_plugin.h
deleted file mode 100644
index d03435f6d..000000000
--- a/src/playlist/pls_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_PLS_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_PLS_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin pls_playlist_plugin;
-
-#endif
diff --git a/src/playlist/rss_playlist_plugin.c b/src/playlist/rss_playlist_plugin.c
deleted file mode 100644
index 6740cba7e..000000000
--- a/src/playlist/rss_playlist_plugin.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist/rss_playlist_plugin.h"
-#include "playlist_plugin.h"
-#include "input_stream.h"
-#include "song.h"
-#include "tag.h"
-
-#include <glib.h>
-
-#include <assert.h>
-#include <string.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "rss"
-
-/**
- * This is the state object for the GLib XML parser.
- */
-struct rss_parser {
- /**
- * The list of songs (in reverse order because that's faster
- * while adding).
- */
- GSList *songs;
-
- /**
- * The current position in the XML file.
- */
- enum {
- ROOT, ITEM,
- } state;
-
- /**
- * The current tag within the "entry" element. This is only
- * valid if state==ITEM. TAG_NUM_OF_ITEM_TYPES means there
- * is no (known) tag.
- */
- enum tag_type tag;
-
- /**
- * The current song. It is allocated after the "location"
- * element.
- */
- struct song *song;
-};
-
-static const gchar *
-get_attribute(const gchar **attribute_names, const gchar **attribute_values,
- const gchar *name)
-{
- for (unsigned i = 0; attribute_names[i] != NULL; ++i)
- if (g_ascii_strcasecmp(attribute_names[i], name) == 0)
- return attribute_values[i];
-
- return NULL;
-}
-
-static void
-rss_start_element(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct rss_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- if (g_ascii_strcasecmp(element_name, "item") == 0) {
- parser->state = ITEM;
- parser->song = song_remote_new("rss:");
- parser->tag = TAG_NUM_OF_ITEM_TYPES;
- }
-
- break;
-
- case ITEM:
- if (g_ascii_strcasecmp(element_name, "enclosure") == 0) {
- const gchar *href = get_attribute(attribute_names,
- attribute_values,
- "url");
- if (href != NULL) {
- /* create new song object, and copy
- the existing tag over; we cannot
- replace the existing song's URI,
- because that attribute is
- immutable */
- struct song *song = song_remote_new(href);
-
- if (parser->song != NULL) {
- song->tag = parser->song->tag;
- parser->song->tag = NULL;
- song_free(parser->song);
- }
-
- parser->song = song;
- }
- } else if (g_ascii_strcasecmp(element_name, "title") == 0)
- parser->tag = TAG_TITLE;
- else if (g_ascii_strcasecmp(element_name, "itunes:author") == 0)
- parser->tag = TAG_ARTIST;
-
- break;
- }
-}
-
-static void
-rss_end_element(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct rss_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- break;
-
- case ITEM:
- if (g_ascii_strcasecmp(element_name, "item") == 0) {
- if (strcmp(parser->song->uri, "rss:") != 0)
- parser->songs = g_slist_prepend(parser->songs,
- parser->song);
- else
- song_free(parser->song);
-
- parser->state = ROOT;
- } else
- parser->tag = TAG_NUM_OF_ITEM_TYPES;
-
- break;
- }
-}
-
-static void
-rss_text(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *text, gsize text_len,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct rss_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- break;
-
- case ITEM:
- if (parser->tag != TAG_NUM_OF_ITEM_TYPES) {
- if (parser->song->tag == NULL)
- parser->song->tag = tag_new();
- tag_add_item_n(parser->song->tag, parser->tag,
- text, text_len);
- }
-
- break;
- }
-}
-
-static const GMarkupParser rss_parser = {
- .start_element = rss_start_element,
- .end_element = rss_end_element,
- .text = rss_text,
-};
-
-static void
-song_free_callback(gpointer data, G_GNUC_UNUSED gpointer user_data)
-{
- struct song *song = data;
-
- song_free(song);
-}
-
-static void
-rss_parser_destroy(gpointer data)
-{
- struct rss_parser *parser = data;
-
- if (parser->state >= ITEM)
- song_free(parser->song);
-
- g_slist_foreach(parser->songs, song_free_callback, NULL);
- g_slist_free(parser->songs);
-}
-
-/*
- * The playlist object
- *
- */
-
-struct rss_playlist {
- struct playlist_provider base;
-
- GSList *songs;
-};
-
-static struct playlist_provider *
-rss_open_stream(struct input_stream *is)
-{
- struct rss_parser parser = {
- .songs = NULL,
- .state = ROOT,
- };
- struct rss_playlist *playlist;
- GMarkupParseContext *context;
- char buffer[1024];
- size_t nbytes;
- bool success;
- GError *error = NULL;
-
- /* parse the RSS XML file */
-
- context = g_markup_parse_context_new(&rss_parser,
- G_MARKUP_TREAT_CDATA_AS_TEXT,
- &parser, rss_parser_destroy);
-
- while (true) {
- nbytes = input_stream_lock_read(is, buffer, sizeof(buffer),
- &error);
- if (nbytes == 0) {
- if (error != NULL) {
- g_markup_parse_context_free(context);
- g_warning("%s", error->message);
- g_error_free(error);
- return NULL;
- }
-
- break;
- }
-
- success = g_markup_parse_context_parse(context, buffer, nbytes,
- &error);
- if (!success) {
- g_warning("XML parser failed: %s", error->message);
- g_error_free(error);
- g_markup_parse_context_free(context);
- return NULL;
- }
- }
-
- success = g_markup_parse_context_end_parse(context, &error);
- if (!success) {
- g_warning("XML parser failed: %s", error->message);
- g_error_free(error);
- g_markup_parse_context_free(context);
- return NULL;
- }
-
- /* create a #rss_playlist object from the parsed song list */
-
- playlist = g_new(struct rss_playlist, 1);
- playlist_provider_init(&playlist->base, &rss_playlist_plugin);
- playlist->songs = g_slist_reverse(parser.songs);
- parser.songs = NULL;
-
- g_markup_parse_context_free(context);
-
- return &playlist->base;
-}
-
-static void
-rss_close(struct playlist_provider *_playlist)
-{
- struct rss_playlist *playlist = (struct rss_playlist *)_playlist;
-
- g_slist_foreach(playlist->songs, song_free_callback, NULL);
- g_slist_free(playlist->songs);
- g_free(playlist);
-}
-
-static struct song *
-rss_read(struct playlist_provider *_playlist)
-{
- struct rss_playlist *playlist = (struct rss_playlist *)_playlist;
- struct song *song;
-
- if (playlist->songs == NULL)
- return NULL;
-
- song = playlist->songs->data;
- playlist->songs = g_slist_remove(playlist->songs, song);
-
- return song;
-}
-
-static const char *const rss_suffixes[] = {
- "rss",
- NULL
-};
-
-static const char *const rss_mime_types[] = {
- "application/rss+xml",
- "text/xml",
- NULL
-};
-
-const struct playlist_plugin rss_playlist_plugin = {
- .name = "rss",
-
- .open_stream = rss_open_stream,
- .close = rss_close,
- .read = rss_read,
-
- .suffixes = rss_suffixes,
- .mime_types = rss_mime_types,
-};
diff --git a/src/playlist/rss_playlist_plugin.h b/src/playlist/rss_playlist_plugin.h
deleted file mode 100644
index 3b376de79..000000000
--- a/src/playlist/rss_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_RSS_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_RSS_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin rss_playlist_plugin;
-
-#endif
diff --git a/src/playlist/soundcloud_playlist_plugin.c b/src/playlist/soundcloud_playlist_plugin.c
deleted file mode 100644
index 7c79f880a..000000000
--- a/src/playlist/soundcloud_playlist_plugin.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist/soundcloud_playlist_plugin.h"
-#include "conf.h"
-#include "input_stream.h"
-#include "playlist_plugin.h"
-#include "song.h"
-#include "tag.h"
-
-#include <glib.h>
-#include <yajl/yajl_parse.h>
-
-#include <string.h>
-
-struct soundcloud_playlist {
- struct playlist_provider base;
-
- GSList *songs;
-};
-
-static struct {
- char *apikey;
-} soundcloud_config;
-
-static bool
-soundcloud_init(const struct config_param *param)
-{
- soundcloud_config.apikey =
- config_dup_block_string(param, "apikey", NULL);
- if (soundcloud_config.apikey == NULL) {
- g_debug("disabling the soundcloud playlist plugin "
- "because API key is not set");
- return false;
- }
-
- return true;
-}
-
-static void
-soundcloud_finish(void)
-{
- g_free(soundcloud_config.apikey);
-}
-
-/**
- * Construct a full soundcloud resolver URL from the given fragment.
- * @param uri uri of a soundcloud page (or just the path)
- * @return Constructed URL. Must be freed with g_free.
- */
-static char *
-soundcloud_resolve(const char* uri) {
- char *u, *ru;
-
- if (g_str_has_prefix(uri, "http://")) {
- u = g_strdup(uri);
- } else if (g_str_has_prefix(uri, "soundcloud.com")) {
- u = g_strconcat("http://", uri, NULL);
- } else {
- /* assume it's just a path on soundcloud.com */
- u = g_strconcat("http://soundcloud.com/", uri, NULL);
- }
-
- ru = g_strconcat("http://api.soundcloud.com/resolve.json?url=",
- u, "&client_id=", soundcloud_config.apikey, NULL);
- g_free(u);
-
- return ru;
-}
-
-/* YAJL parser for track data from both /tracks/ and /playlists/ JSON */
-
-enum key {
- Duration,
- Title,
- Stream_URL,
- Other,
-};
-
-const char* key_str[] = {
- "duration",
- "title",
- "stream_url",
- NULL,
-};
-
-struct parse_data {
- int key;
- char* stream_url;
- long duration;
- char* title;
- int got_url; /* nesting level of last stream_url */
- GSList* songs;
-};
-
-static int handle_integer(void *ctx,
- long
-#ifndef HAVE_YAJL1
- long
-#endif
- intval)
-{
- struct parse_data *data = (struct parse_data *) ctx;
-
- switch (data->key) {
- case Duration:
- data->duration = intval;
- break;
- default:
- break;
- }
-
- return 1;
-}
-
-static int handle_string(void *ctx, const unsigned char* stringval,
-#ifdef HAVE_YAJL1
- unsigned int
-#else
- size_t
-#endif
- stringlen)
-{
- struct parse_data *data = (struct parse_data *) ctx;
- const char *s = (const char *) stringval;
-
- switch (data->key) {
- case Title:
- if (data->title != NULL)
- g_free(data->title);
- data->title = g_strndup(s, stringlen);
- break;
- case Stream_URL:
- if (data->stream_url != NULL)
- g_free(data->stream_url);
- data->stream_url = g_strndup(s, stringlen);
- data->got_url = 1;
- break;
- default:
- break;
- }
-
- return 1;
-}
-
-static int handle_mapkey(void *ctx, const unsigned char* stringval,
-#ifdef HAVE_YAJL1
- unsigned int
-#else
- size_t
-#endif
- stringlen)
-{
- struct parse_data *data = (struct parse_data *) ctx;
-
- int i;
- data->key = Other;
-
- for (i = 0; i < Other; ++i) {
- if (strncmp((const char *)stringval, key_str[i], stringlen) == 0) {
- data->key = i;
- break;
- }
- }
-
- return 1;
-}
-
-static int handle_start_map(void *ctx)
-{
- struct parse_data *data = (struct parse_data *) ctx;
-
- if (data->got_url > 0)
- data->got_url++;
-
- return 1;
-}
-
-static int handle_end_map(void *ctx)
-{
- struct parse_data *data = (struct parse_data *) ctx;
-
- if (data->got_url > 1) {
- data->got_url--;
- return 1;
- }
-
- if (data->got_url == 0)
- return 1;
-
- /* got_url == 1, track finished, make it into a song */
- data->got_url = 0;
-
- struct song *s;
- struct tag *t;
- char *u;
-
- u = g_strconcat(data->stream_url, "?client_id=", soundcloud_config.apikey, NULL);
- s = song_remote_new(u);
- g_free(u);
- t = tag_new();
- t->time = data->duration / 1000;
- if (data->title != NULL)
- tag_add_item(t, TAG_NAME, data->title);
- s->tag = t;
-
- data->songs = g_slist_prepend(data->songs, s);
-
- return 1;
-}
-
-static yajl_callbacks parse_callbacks = {
- NULL,
- NULL,
- handle_integer,
- NULL,
- NULL,
- handle_string,
- handle_start_map,
- handle_mapkey,
- handle_end_map,
- NULL,
- NULL,
-};
-
-/**
- * Read JSON data and parse it using the given YAJL parser.
- * @param url URL of the JSON data.
- * @param hand YAJL parser handle.
- * @return -1 on error, 0 on success.
- */
-static int
-soundcloud_parse_json(const char *url, yajl_handle hand, GMutex* mutex, GCond* cond)
-{
- struct input_stream *input_stream;
- GError *error = NULL;
- char buffer[4096];
- unsigned char *ubuffer = (unsigned char *)buffer;
- size_t nbytes;
-
- input_stream = input_stream_open(url, mutex, cond, &error);
- if (input_stream == NULL) {
- if (error != NULL) {
- g_warning("%s", error->message);
- g_error_free(error);
- }
- return -1;
- }
-
- g_mutex_lock(mutex);
- input_stream_wait_ready(input_stream);
-
- yajl_status stat;
- int done = 0;
-
- while (!done) {
- nbytes = input_stream_read(input_stream, buffer, sizeof(buffer), &error);
- if (nbytes == 0) {
- if (error != NULL) {
- g_warning("%s", error->message);
- g_error_free(error);
- }
- if (input_stream_eof(input_stream)) {
- done = true;
- } else {
- g_mutex_unlock(mutex);
- input_stream_close(input_stream);
- return -1;
- }
- }
-
- if (done) {
-#ifdef HAVE_YAJL1
- stat = yajl_parse_complete(hand);
-#else
- stat = yajl_complete_parse(hand);
-#endif
- } else
- stat = yajl_parse(hand, ubuffer, nbytes);
-
- if (stat != yajl_status_ok
-#ifdef HAVE_YAJL1
- && stat != yajl_status_insufficient_data
-#endif
- )
- {
- unsigned char *str = yajl_get_error(hand, 1, ubuffer, nbytes);
- g_warning("%s", str);
- yajl_free_error(hand, str);
- break;
- }
- }
-
- g_mutex_unlock(mutex);
- input_stream_close(input_stream);
-
- return 0;
-}
-
-/**
- * Parse a soundcloud:// URL and create a playlist.
- * @param uri A soundcloud URL. Accepted forms:
- * soundcloud://track/<track-id>
- * soundcloud://playlist/<playlist-id>
- * soundcloud://url/<url or path of soundcloud page>
- */
-
-static struct playlist_provider *
-soundcloud_open_uri(const char *uri, GMutex *mutex, GCond *cond)
-{
- struct soundcloud_playlist *playlist = NULL;
-
- char *s, *p;
- char *scheme, *arg, *rest;
- s = g_strdup(uri);
- scheme = s;
- for (p = s; *p; p++) {
- if (*p == ':' && *(p+1) == '/' && *(p+2) == '/') {
- *p = 0;
- p += 3;
- break;
- }
- }
- arg = p;
- for (; *p; p++) {
- if (*p == '/') {
- *p = 0;
- p++;
- break;
- }
- }
- rest = p;
-
- if (strcmp(scheme, "soundcloud") != 0) {
- g_warning("incompatible scheme for soundcloud plugin: %s", scheme);
- g_free(s);
- return NULL;
- }
-
- char *u = NULL;
- if (strcmp(arg, "track") == 0) {
- u = g_strconcat("http://api.soundcloud.com/tracks/",
- rest, ".json?client_id=", soundcloud_config.apikey, NULL);
- } else if (strcmp(arg, "playlist") == 0) {
- u = g_strconcat("http://api.soundcloud.com/playlists/",
- rest, ".json?client_id=", soundcloud_config.apikey, NULL);
- } else if (strcmp(arg, "url") == 0) {
- /* Translate to soundcloud resolver call. libcurl will automatically
- follow the redirect to the right resource. */
- u = soundcloud_resolve(rest);
- }
- g_free(s);
-
- if (u == NULL) {
- g_warning("unknown soundcloud URI");
- return NULL;
- }
-
- yajl_handle hand;
- struct parse_data data;
-
- data.got_url = 0;
- data.songs = NULL;
- data.title = NULL;
- data.stream_url = NULL;
-#ifdef HAVE_YAJL1
- hand = yajl_alloc(&parse_callbacks, NULL, NULL, (void *) &data);
-#else
- hand = yajl_alloc(&parse_callbacks, NULL, (void *) &data);
-#endif
-
- int ret = soundcloud_parse_json(u, hand, mutex, cond);
-
- g_free(u);
- yajl_free(hand);
- if (data.title != NULL)
- g_free(data.title);
- if (data.stream_url != NULL)
- g_free(data.stream_url);
-
- if (ret == -1)
- return NULL;
-
- playlist = g_new(struct soundcloud_playlist, 1);
- playlist_provider_init(&playlist->base, &soundcloud_playlist_plugin);
- playlist->songs = g_slist_reverse(data.songs);
-
- return &playlist->base;
-}
-
-static void
-soundcloud_close(struct playlist_provider *_playlist)
-{
- struct soundcloud_playlist *playlist = (struct soundcloud_playlist *)_playlist;
-
- g_free(playlist);
-}
-
-
-static struct song *
-soundcloud_read(struct playlist_provider *_playlist)
-{
- struct soundcloud_playlist *playlist = (struct soundcloud_playlist *)_playlist;
-
- if (playlist->songs == NULL)
- return NULL;
-
- struct song* s;
- s = (struct song *)playlist->songs->data;
- playlist->songs = g_slist_remove(playlist->songs, s);
- return s;
-}
-
-static const char *const soundcloud_schemes[] = {
- "soundcloud",
- NULL
-};
-
-const struct playlist_plugin soundcloud_playlist_plugin = {
- .name = "soundcloud",
-
- .init = soundcloud_init,
- .finish = soundcloud_finish,
- .open_uri = soundcloud_open_uri,
- .close = soundcloud_close,
- .read = soundcloud_read,
-
- .schemes = soundcloud_schemes,
-};
-
-
diff --git a/src/playlist/soundcloud_playlist_plugin.h b/src/playlist/soundcloud_playlist_plugin.h
deleted file mode 100644
index e09e2dd46..000000000
--- a/src/playlist/soundcloud_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_SOUNDCLOUD_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_SOUNDCLOUD_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin soundcloud_playlist_plugin;
-
-#endif
diff --git a/src/playlist/xspf_playlist_plugin.c b/src/playlist/xspf_playlist_plugin.c
deleted file mode 100644
index 17d9040e2..000000000
--- a/src/playlist/xspf_playlist_plugin.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist/xspf_playlist_plugin.h"
-#include "playlist_plugin.h"
-#include "input_stream.h"
-#include "uri.h"
-#include "song.h"
-#include "tag.h"
-
-#include <glib.h>
-
-#include <assert.h>
-#include <string.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "xspf"
-
-/**
- * This is the state object for the GLib XML parser.
- */
-struct xspf_parser {
- /**
- * The list of songs (in reverse order because that's faster
- * while adding).
- */
- GSList *songs;
-
- /**
- * The current position in the XML file.
- */
- enum {
- ROOT, PLAYLIST, TRACKLIST, TRACK,
- LOCATION,
- } state;
-
- /**
- * The current tag within the "track" element. This is only
- * valid if state==TRACK. TAG_NUM_OF_ITEM_TYPES means there
- * is no (known) tag.
- */
- enum tag_type tag;
-
- /**
- * The current song. It is allocated after the "location"
- * element.
- */
- struct song *song;
-};
-
-static void
-xspf_start_element(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *element_name,
- G_GNUC_UNUSED const gchar **attribute_names,
- G_GNUC_UNUSED const gchar **attribute_values,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct xspf_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- if (strcmp(element_name, "playlist") == 0)
- parser->state = PLAYLIST;
-
- break;
-
- case PLAYLIST:
- if (strcmp(element_name, "trackList") == 0)
- parser->state = TRACKLIST;
-
- break;
-
- case TRACKLIST:
- if (strcmp(element_name, "track") == 0) {
- parser->state = TRACK;
- parser->song = NULL;
- parser->tag = TAG_NUM_OF_ITEM_TYPES;
- }
-
- break;
-
- case TRACK:
- if (strcmp(element_name, "location") == 0)
- parser->state = LOCATION;
- else if (strcmp(element_name, "title") == 0)
- parser->tag = TAG_TITLE;
- else if (strcmp(element_name, "creator") == 0)
- /* TAG_COMPOSER would be more correct
- according to the XSPF spec */
- parser->tag = TAG_ARTIST;
- else if (strcmp(element_name, "annotation") == 0)
- parser->tag = TAG_COMMENT;
- else if (strcmp(element_name, "album") == 0)
- parser->tag = TAG_ALBUM;
- else if (strcmp(element_name, "trackNum") == 0)
- parser->tag = TAG_TRACK;
-
- break;
-
- case LOCATION:
- break;
- }
-}
-
-static void
-xspf_end_element(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct xspf_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- break;
-
- case PLAYLIST:
- if (strcmp(element_name, "playlist") == 0)
- parser->state = ROOT;
-
- break;
-
- case TRACKLIST:
- if (strcmp(element_name, "tracklist") == 0)
- parser->state = PLAYLIST;
-
- break;
-
- case TRACK:
- if (strcmp(element_name, "track") == 0) {
- if (parser->song != NULL)
- parser->songs = g_slist_prepend(parser->songs,
- parser->song);
-
- parser->state = TRACKLIST;
- } else
- parser->tag = TAG_NUM_OF_ITEM_TYPES;
-
- break;
-
- case LOCATION:
- parser->state = TRACK;
- break;
- }
-}
-
-static void
-xspf_text(G_GNUC_UNUSED GMarkupParseContext *context,
- const gchar *text, gsize text_len,
- gpointer user_data, G_GNUC_UNUSED GError **error)
-{
- struct xspf_parser *parser = user_data;
-
- switch (parser->state) {
- case ROOT:
- case PLAYLIST:
- case TRACKLIST:
- break;
-
- case TRACK:
- if (parser->song != NULL &&
- parser->tag != TAG_NUM_OF_ITEM_TYPES) {
- if (parser->song->tag == NULL)
- parser->song->tag = tag_new();
- tag_add_item_n(parser->song->tag, parser->tag,
- text, text_len);
- }
-
- break;
-
- case LOCATION:
- if (parser->song == NULL) {
- char *uri = g_strndup(text, text_len);
- parser->song = song_remote_new(uri);
- g_free(uri);
- }
-
- break;
- }
-}
-
-static const GMarkupParser xspf_parser = {
- .start_element = xspf_start_element,
- .end_element = xspf_end_element,
- .text = xspf_text,
-};
-
-static void
-song_free_callback(gpointer data, G_GNUC_UNUSED gpointer user_data)
-{
- struct song *song = data;
-
- song_free(song);
-}
-
-static void
-xspf_parser_destroy(gpointer data)
-{
- struct xspf_parser *parser = data;
-
- if (parser->state >= TRACK && parser->song != NULL)
- song_free(parser->song);
-
- g_slist_foreach(parser->songs, song_free_callback, NULL);
- g_slist_free(parser->songs);
-}
-
-/*
- * The playlist object
- *
- */
-
-struct xspf_playlist {
- struct playlist_provider base;
-
- GSList *songs;
-};
-
-static struct playlist_provider *
-xspf_open_stream(struct input_stream *is)
-{
- struct xspf_parser parser = {
- .songs = NULL,
- .state = ROOT,
- };
- struct xspf_playlist *playlist;
- GMarkupParseContext *context;
- char buffer[1024];
- size_t nbytes;
- bool success;
- GError *error = NULL;
-
- /* parse the XSPF XML file */
-
- context = g_markup_parse_context_new(&xspf_parser,
- G_MARKUP_TREAT_CDATA_AS_TEXT,
- &parser, xspf_parser_destroy);
-
- while (true) {
- nbytes = input_stream_lock_read(is, buffer, sizeof(buffer),
- &error);
- if (nbytes == 0) {
- if (error != NULL) {
- g_markup_parse_context_free(context);
- g_warning("%s", error->message);
- g_error_free(error);
- return NULL;
- }
-
- break;
- }
-
- success = g_markup_parse_context_parse(context, buffer, nbytes,
- &error);
- if (!success) {
- g_warning("XML parser failed: %s", error->message);
- g_error_free(error);
- g_markup_parse_context_free(context);
- return NULL;
- }
- }
-
- success = g_markup_parse_context_end_parse(context, &error);
- if (!success) {
- g_warning("XML parser failed: %s", error->message);
- g_error_free(error);
- g_markup_parse_context_free(context);
- return NULL;
- }
-
- /* create a #xspf_playlist object from the parsed song list */
-
- playlist = g_new(struct xspf_playlist, 1);
- playlist_provider_init(&playlist->base, &xspf_playlist_plugin);
- playlist->songs = g_slist_reverse(parser.songs);
- parser.songs = NULL;
-
- g_markup_parse_context_free(context);
-
- return &playlist->base;
-}
-
-static void
-xspf_close(struct playlist_provider *_playlist)
-{
- struct xspf_playlist *playlist = (struct xspf_playlist *)_playlist;
-
- g_slist_foreach(playlist->songs, song_free_callback, NULL);
- g_slist_free(playlist->songs);
- g_free(playlist);
-}
-
-static struct song *
-xspf_read(struct playlist_provider *_playlist)
-{
- struct xspf_playlist *playlist = (struct xspf_playlist *)_playlist;
- struct song *song;
-
- if (playlist->songs == NULL)
- return NULL;
-
- song = playlist->songs->data;
- playlist->songs = g_slist_remove(playlist->songs, song);
-
- return song;
-}
-
-static const char *const xspf_suffixes[] = {
- "xspf",
- NULL
-};
-
-static const char *const xspf_mime_types[] = {
- "application/xspf+xml",
- NULL
-};
-
-const struct playlist_plugin xspf_playlist_plugin = {
- .name = "xspf",
-
- .open_stream = xspf_open_stream,
- .close = xspf_close,
- .read = xspf_read,
-
- .suffixes = xspf_suffixes,
- .mime_types = xspf_mime_types,
-};
diff --git a/src/playlist/xspf_playlist_plugin.h b/src/playlist/xspf_playlist_plugin.h
deleted file mode 100644
index 4636d7e83..000000000
--- a/src/playlist/xspf_playlist_plugin.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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_XSPF_PLAYLIST_PLUGIN_H
-#define MPD_PLAYLIST_XSPF_PLAYLIST_PLUGIN_H
-
-extern const struct playlist_plugin xspf_playlist_plugin;
-
-#endif
diff --git a/src/playlist_any.c b/src/playlist_any.c
deleted file mode 100644
index 450ca5932..000000000
--- a/src/playlist_any.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_any.h"
-#include "playlist_list.h"
-#include "playlist_mapper.h"
-#include "uri.h"
-#include "input_stream.h"
-
-#include <assert.h>
-
-static struct playlist_provider *
-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, mutex, cond);
- if (playlist != NULL) {
- *is_r = NULL;
- return playlist;
- }
-
- GError *error = NULL;
- struct input_stream *is = input_stream_open(uri, mutex, cond, &error);
- if (is == NULL) {
- if (error != NULL) {
- g_warning("Failed to open %s: %s",
- uri, error->message);
- g_error_free(error);
- }
-
- return NULL;
- }
-
- playlist = playlist_list_open_stream(is, uri);
- if (playlist == NULL) {
- input_stream_close(is);
- return NULL;
- }
-
- *is_r = is;
- return playlist;
-}
-
-struct playlist_provider *
-playlist_open_any(const char *uri, GMutex *mutex, GCond *cond,
- struct input_stream **is_r)
-{
- return uri_has_scheme(uri)
- ? 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
deleted file mode 100644
index 310913de9..000000000
--- a/src/playlist_any.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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_ANY_H
-#define MPD_PLAYLIST_ANY_H
-
-#include <glib.h>
-
-struct playlist_provider;
-struct input_stream;
-
-/**
- * Opens a playlist from the specified URI, which can be either an
- * absolute remote URI (with a scheme) or a relative path to the
- * music orplaylist directory.
- *
- * @param is_r on success, an input_stream object may be returned
- * here, which must be closed after the playlist_provider object is
- * freed
- */
-struct playlist_provider *
-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
deleted file mode 100644
index 0dea7676a..000000000
--- a/src/playlist_control.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Functions for controlling playback on the playlist level.
- *
- */
-
-#include "config.h"
-#include "playlist_internal.h"
-#include "player_control.h"
-#include "idle.h"
-
-#include <glib.h>
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "playlist"
-
-void
-playlist_stop(struct playlist *playlist, struct player_control *pc)
-{
- if (!playlist->playing)
- return;
-
- assert(playlist->current >= 0);
-
- g_debug("stop");
- pc_stop(pc);
- playlist->queued = -1;
- playlist->playing = false;
-
- if (playlist->queue.random) {
- /* shuffle the playlist, so the next playback will
- result in a new random order */
-
- unsigned current_position =
- queue_order_to_position(&playlist->queue,
- playlist->current);
-
- queue_shuffle_order(&playlist->queue);
-
- /* make sure that "current" stays valid, and the next
- "play" command plays the same song again */
- playlist->current =
- queue_position_to_order(&playlist->queue,
- current_position);
- }
-}
-
-enum playlist_result
-playlist_play(struct playlist *playlist, struct player_control *pc,
- int song)
-{
- unsigned i = song;
-
- pc_clear_error(pc);
-
- if (song == -1) {
- /* play any song ("current" song, or the first song */
-
- if (queue_is_empty(&playlist->queue))
- return PLAYLIST_RESULT_SUCCESS;
-
- if (playlist->playing) {
- /* already playing: unpause playback, just in
- case it was paused, and return */
- pc_set_pause(pc, false);
- return PLAYLIST_RESULT_SUCCESS;
- }
-
- /* select a song: "current" song, or the first one */
- i = playlist->current >= 0
- ? playlist->current
- : 0;
- } else if (!queue_valid_position(&playlist->queue, song))
- return PLAYLIST_RESULT_BAD_RANGE;
-
- if (playlist->queue.random) {
- if (song >= 0)
- /* "i" is currently the song position (which
- would be equal to the order number in
- no-random mode); convert it to a order
- number, because random mode is enabled */
- i = queue_position_to_order(&playlist->queue, song);
-
- if (!playlist->playing)
- playlist->current = 0;
-
- /* swap the new song with the previous "current" one,
- so playback continues as planned */
- queue_swap_order(&playlist->queue,
- i, playlist->current);
- i = playlist->current;
- }
-
- playlist->stop_on_error = false;
- playlist->error_count = 0;
-
- playlist_play_order(playlist, pc, i);
- return PLAYLIST_RESULT_SUCCESS;
-}
-
-enum playlist_result
-playlist_play_id(struct playlist *playlist, struct player_control *pc,
- int id)
-{
- int song;
-
- if (id == -1) {
- 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, pc, song);
-}
-
-void
-playlist_next(struct playlist *playlist, struct player_control *pc)
-{
- int next_order;
- int current;
-
- if (!playlist->playing)
- return;
-
- assert(!queue_is_empty(&playlist->queue));
- assert(queue_valid_order(&playlist->queue, playlist->current));
-
- current = playlist->current;
- playlist->stop_on_error = false;
-
- /* determine the next song from the queue's order list */
-
- next_order = queue_next_order(&playlist->queue, playlist->current);
- if (next_order < 0) {
- /* no song after this one: stop playback */
- playlist_stop(playlist, pc);
-
- /* reset "current song" */
- playlist->current = -1;
- }
- else
- {
- if (next_order == 0 && playlist->queue.random) {
- /* The queue told us that the next song is the first
- song. This means we are in repeat mode. Shuffle
- the queue order, so this time, the user hears the
- songs in a different than before */
- assert(playlist->queue.repeat);
-
- queue_shuffle_order(&playlist->queue);
-
- /* note that playlist->current and playlist->queued are
- now invalid, but playlist_play_order() will
- discard them anyway */
- }
-
- playlist_play_order(playlist, pc, next_order);
- }
-
- /* Consume mode removes each played songs. */
- if(playlist->queue.consume)
- playlist_delete(playlist, pc,
- queue_order_to_position(&playlist->queue,
- current));
-}
-
-void
-playlist_previous(struct playlist *playlist, struct player_control *pc)
-{
- if (!playlist->playing)
- return;
-
- assert(queue_length(&playlist->queue) > 0);
-
- if (playlist->current > 0) {
- /* play the preceding song */
- playlist_play_order(playlist, pc,
- playlist->current - 1);
- } else if (playlist->queue.repeat) {
- /* play the last song in "repeat" mode */
- 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, pc, playlist->current);
- }
-}
-
-enum playlist_result
-playlist_seek_song(struct playlist *playlist, struct player_control *pc,
- unsigned song, float seek_time)
-{
- const struct song *queued;
- unsigned i;
- bool success;
-
- if (!queue_valid_position(&playlist->queue, song))
- return PLAYLIST_RESULT_BAD_RANGE;
-
- queued = playlist_get_queued_song(playlist);
-
- if (playlist->queue.random)
- i = queue_position_to_order(&playlist->queue, song);
- else
- i = song;
-
- pc_clear_error(pc);
- playlist->stop_on_error = true;
- playlist->error_count = 0;
-
- if (!playlist->playing || (unsigned)playlist->current != i) {
- /* seeking is not within the current song - prepare
- song change */
-
- playlist->playing = true;
- playlist->current = i;
-
- queued = NULL;
- }
-
- success = pc_seek(pc, queue_get_order(&playlist->queue, i), seek_time);
- if (!success) {
- playlist_update_queued_song(playlist, pc, queued);
-
- return PLAYLIST_RESULT_NOT_PLAYING;
- }
-
- playlist->queued = -1;
- playlist_update_queued_song(playlist, pc, NULL);
-
- return PLAYLIST_RESULT_SUCCESS;
-}
-
-enum playlist_result
-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, 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
deleted file mode 100644
index 6b9d87155..000000000
--- a/src/playlist_database.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_database.h"
-#include "playlist_vector.h"
-#include "text_file.h"
-#include "string_util.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-static GQuark
-playlist_database_quark(void)
-{
- return g_quark_from_static_string("playlist_database");
-}
-
-void
-playlist_vector_save(FILE *fp, const struct list_head *pv)
-{
- struct playlist_metadata *pm;
- playlist_vector_for_each(pm, pv)
- fprintf(fp, PLAYLIST_META_BEGIN "%s\n"
- "mtime: %li\n"
- "playlist_end\n",
- pm->name, (long)pm->mtime);
-}
-
-bool
-playlist_metadata_load(FILE *fp, struct list_head *pv, const char *name,
- GString *buffer, GError **error_r)
-{
- struct playlist_metadata pm = {
- .mtime = 0,
- };
- char *line, *colon;
- const char *value;
-
- while ((line = read_text_line(fp, buffer)) != NULL &&
- strcmp(line, "playlist_end") != 0) {
- colon = strchr(line, ':');
- if (colon == NULL || colon == line) {
- g_set_error(error_r, playlist_database_quark(), 0,
- "unknown line in db: %s", line);
- return false;
- }
-
- *colon++ = 0;
- value = strchug_fast_c(colon);
-
- if (strcmp(line, "mtime") == 0)
- pm.mtime = strtol(value, NULL, 10);
- else {
- g_set_error(error_r, playlist_database_quark(), 0,
- "unknown line in db: %s", line);
- return false;
- }
- }
-
- playlist_vector_update_or_add(pv, name, pm.mtime);
- return true;
-}
diff --git a/src/playlist_database.h b/src/playlist_database.h
deleted file mode 100644
index 3238fa06b..000000000
--- a/src/playlist_database.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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_DATABASE_H
-#define MPD_PLAYLIST_DATABASE_H
-
-#include "check.h"
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <glib.h>
-
-#define PLAYLIST_META_BEGIN "playlist_begin: "
-
-struct list_head;
-
-void
-playlist_vector_save(FILE *fp, const struct list_head *pv);
-
-bool
-playlist_metadata_load(FILE *fp, struct list_head *pv, const char *name,
- GString *buffer, GError **error_r);
-
-#endif
diff --git a/src/playlist_edit.c b/src/playlist_edit.c
deleted file mode 100644
index 8042f2f76..000000000
--- a/src/playlist_edit.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Functions for editing the playlist (adding, removing, reordering
- * songs in the queue).
- *
- */
-
-#include "config.h"
-#include "playlist_internal.h"
-#include "player_control.h"
-#include "database.h"
-#include "uri.h"
-#include "song.h"
-#include "idle.h"
-
-#include <stdlib.h>
-
-static void playlist_increment_version(struct playlist *playlist)
-{
- queue_increment_version(&playlist->queue);
-
- idle_add(IDLE_PLAYLIST);
-}
-
-void
-playlist_clear(struct playlist *playlist, struct player_control *pc)
-{
- 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(pc, song);
- }
-
- queue_clear(&playlist->queue);
-
- playlist->current = -1;
-
- playlist_increment_version(playlist);
-}
-
-enum playlist_result
-playlist_append_file(struct playlist *playlist, struct player_control *pc,
- const char *path_fs, unsigned *added_id)
-{
- struct song *song = song_file_load(path_fs, NULL);
- if (song == NULL)
- return PLAYLIST_RESULT_NO_SUCH_SONG;
-
- return playlist_append_song(playlist, pc, song, added_id);
-}
-
-enum playlist_result
-playlist_append_song(struct playlist *playlist, struct player_control *pc,
- struct song *song, unsigned *added_id)
-{
- const struct song *queued;
- unsigned id;
-
- if (queue_is_full(&playlist->queue))
- return PLAYLIST_RESULT_TOO_LARGE;
-
- queued = playlist_get_queued_song(playlist);
-
- id = queue_append(&playlist->queue, song, 0);
-
- if (playlist->queue.random) {
- /* shuffle the new song into the list of remaining
- songs to play */
-
- unsigned start;
- if (playlist->queued >= 0)
- start = playlist->queued + 1;
- else
- start = playlist->current + 1;
- if (start < queue_length(&playlist->queue))
- queue_shuffle_order_last(&playlist->queue, start,
- queue_length(&playlist->queue));
- }
-
- playlist_increment_version(playlist);
-
- playlist_update_queued_song(playlist, pc, queued);
-
- if (added_id)
- *added_id = id;
-
- 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, struct player_control *pc,
- 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, pc, song, added_id);
-}
-
-enum playlist_result
-playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
- unsigned song1, unsigned song2)
-{
- const struct song *queued;
-
- if (!queue_valid_position(&playlist->queue, song1) ||
- !queue_valid_position(&playlist->queue, song2))
- return PLAYLIST_RESULT_BAD_RANGE;
-
- queued = playlist_get_queued_song(playlist);
-
- queue_swap(&playlist->queue, song1, song2);
-
- if (playlist->queue.random) {
- /* update the queue order, so that playlist->current
- still points to the current song order */
-
- queue_swap_order(&playlist->queue,
- queue_position_to_order(&playlist->queue,
- song1),
- queue_position_to_order(&playlist->queue,
- song2));
- } else {
- /* correct the "current" song order */
-
- if (playlist->current == (int)song1)
- playlist->current = song2;
- else if (playlist->current == (int)song2)
- playlist->current = song1;
- }
-
- playlist_increment_version(playlist);
-
- playlist_update_queued_song(playlist, pc, queued);
-
- return PLAYLIST_RESULT_SUCCESS;
-}
-
-enum playlist_result
-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);
-
- if (song1 < 0 || song2 < 0)
- return PLAYLIST_RESULT_NO_SUCH_SONG;
-
- 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, struct player_control *pc,
- unsigned song, const struct song **queued_p)
-{
- unsigned songOrder;
-
- assert(song < queue_length(&playlist->queue));
-
- songOrder = queue_position_to_order(&playlist->queue, song);
-
- if (playlist->playing && playlist->current == (int)songOrder) {
- bool paused = pc_get_state(pc) == PLAYER_STATE_PAUSE;
-
- /* the current song is going to be deleted: stop the player */
-
- pc_stop(pc);
- playlist->playing = false;
-
- /* see which song is going to be played instead */
-
- playlist->current = queue_next_order(&playlist->queue,
- playlist->current);
- if (playlist->current == (int)songOrder)
- playlist->current = -1;
-
- if (playlist->current >= 0 && !paused)
- /* play the song after the deleted one */
- playlist_play_order(playlist, pc, playlist->current);
- else
- /* no songs left to play, stop playback
- completely */
- playlist_stop(playlist, pc);
-
- *queued_p = NULL;
- } else if (playlist->current == (int)songOrder)
- /* there's a "current song" but we're not playing
- currently - clear "current" */
- playlist->current = -1;
-
- /* now do it: remove the song */
-
- if (!song_in_database(queue_get(&playlist->queue, song)))
- pc_song_deleted(pc, queue_get(&playlist->queue, song));
-
- queue_delete(&playlist->queue, song);
-
- /* update the "current" and "queued" variables */
-
- if (playlist->current > (int)songOrder) {
- playlist->current--;
- }
-}
-
-enum playlist_result
-playlist_delete(struct playlist *playlist, struct player_control *pc,
- 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, pc, song, &queued);
-
- playlist_increment_version(playlist);
- playlist_update_queued_song(playlist, pc, queued);
-
- return PLAYLIST_RESULT_SUCCESS;
-}
-
-enum playlist_result
-playlist_delete_range(struct playlist *playlist, struct player_control *pc,
- 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, pc, --end, &queued);
- } while (end != start);
-
- playlist_increment_version(playlist);
- playlist_update_queued_song(playlist, pc, queued);
-
- return PLAYLIST_RESULT_SUCCESS;
-}
-
-enum playlist_result
-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, pc, song);
-}
-
-void
-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, pc, i);
-
- pc_song_deleted(pc, song);
-}
-
-enum playlist_result
-playlist_move_range(struct playlist *playlist, struct player_control *pc,
- unsigned start, unsigned end, int to)
-{
- const struct song *queued;
- int currentSong;
-
- if (!queue_valid_position(&playlist->queue, start) ||
- !queue_valid_position(&playlist->queue, end - 1))
- return PLAYLIST_RESULT_BAD_RANGE;
-
- if ((to >= 0 && to + end - start - 1 >= queue_length(&playlist->queue)) ||
- (to < 0 && abs(to) > (int)queue_length(&playlist->queue)))
- return PLAYLIST_RESULT_BAD_RANGE;
-
- if ((int)start == to)
- /* nothing happens */
- return PLAYLIST_RESULT_SUCCESS;
-
- queued = playlist_get_queued_song(playlist);
-
- /*
- * (to < 0) => move to offset from current song
- * (-playlist.length == to) => move to position BEFORE current song
- */
- currentSong = playlist->current >= 0
- ? (int)queue_order_to_position(&playlist->queue,
- playlist->current)
- : -1;
- if (to < 0) {
- if (currentSong < 0)
- /* can't move relative to current song,
- because there is no current song */
- return PLAYLIST_RESULT_BAD_RANGE;
-
- if (start <= (unsigned)currentSong && (unsigned)currentSong < end)
- /* no-op, can't be moved to offset of itself */
- return PLAYLIST_RESULT_SUCCESS;
- to = (currentSong + abs(to)) % queue_length(&playlist->queue);
- if (start < (unsigned)to)
- to--;
- }
-
- queue_move_range(&playlist->queue, start, end, to);
-
- if (!playlist->queue.random) {
- /* update current/queued */
- if ((int)start <= playlist->current &&
- (unsigned)playlist->current < end)
- playlist->current += to - start;
- else if (playlist->current >= (int)end &&
- playlist->current <= to) {
- playlist->current -= end - start;
- } else if (playlist->current >= to &&
- playlist->current < (int)start) {
- playlist->current += end - start;
- }
- }
-
- playlist_increment_version(playlist);
-
- playlist_update_queued_song(playlist, pc, queued);
-
- return PLAYLIST_RESULT_SUCCESS;
-}
-
-enum playlist_result
-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, pc, song, song+1, to);
-}
-
-void
-playlist_shuffle(struct playlist *playlist, struct player_control *pc,
- unsigned start, unsigned end)
-{
- const struct song *queued;
-
- if (end > queue_length(&playlist->queue))
- /* correct the "end" offset */
- end = queue_length(&playlist->queue);
-
- if ((start+1) >= end)
- /* needs at least two entries. */
- return;
-
- queued = playlist_get_queued_song(playlist);
- if (playlist->playing && playlist->current >= 0) {
- unsigned current_position;
- current_position = queue_order_to_position(&playlist->queue,
- playlist->current);
-
- if (current_position >= start && current_position < end)
- {
- /* put current playing song first */
- queue_swap(&playlist->queue, start, current_position);
-
- if (playlist->queue.random) {
- playlist->current =
- queue_position_to_order(&playlist->queue, start);
- } else
- playlist->current = start;
-
- /* start shuffle after the current song */
- start++;
- }
- } else {
- /* no playback currently: reset playlist->current */
-
- playlist->current = -1;
- }
-
- queue_shuffle_range(&playlist->queue, start, end);
-
- playlist_increment_version(playlist);
-
- playlist_update_queued_song(playlist, pc, queued);
-}
diff --git a/src/playlist_error.h b/src/playlist_error.h
deleted file mode 100644
index ad9c62cf1..000000000
--- a/src/playlist_error.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 650b88bb8..000000000
--- a/src/playlist_global.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * The manager of the global "struct playlist" instance (g_playlist).
- *
- */
-
-#include "config.h"
-#include "playlist.h"
-#include "playlist_state.h"
-#include "event_pipe.h"
-#include "main.h"
-
-struct playlist g_playlist;
-
-static void
-playlist_tag_event(void)
-{
- playlist_tag_changed(&g_playlist);
-}
-
-static void
-playlist_event(void)
-{
- playlist_sync(&g_playlist, global_player_control);
-}
-
-void
-playlist_global_init(void)
-{
- playlist_init(&g_playlist);
-
- event_pipe_register(PIPE_EVENT_TAG, playlist_tag_event);
- event_pipe_register(PIPE_EVENT_PLAYLIST, playlist_event);
-}
-
-void
-playlist_global_finish(void)
-{
- playlist_finish(&g_playlist);
-}
diff --git a/src/playlist_internal.h b/src/playlist_internal.h
deleted file mode 100644
index 81b175176..000000000
--- a/src/playlist_internal.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Internal header for the components of the playlist code.
- *
- */
-
-#ifndef PLAYLIST_INTERNAL_H
-#define PLAYLIST_INTERNAL_H
-
-#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.
- */
-const struct song *
-playlist_get_queued_song(struct playlist *playlist);
-
-/**
- * Updates the "queued song". Calculates the next song according to
- * the current one (if MPD isn't playing, it takes the first song),
- * and queues this song. Clears the old queued song if there was one.
- *
- * @param prev the song which was previously queued, as determined by
- * playlist_get_queued_song()
- */
-void
-playlist_update_queued_song(struct playlist *playlist,
- struct player_control *pc,
- const struct song *prev);
-
-void
-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
deleted file mode 100644
index 68d24fe49..000000000
--- a/src/playlist_list.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_list.h"
-#include "playlist_plugin.h"
-#include "playlist/extm3u_playlist_plugin.h"
-#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/soundcloud_playlist_plugin.h"
-#include "playlist/pls_playlist_plugin.h"
-#include "playlist/asx_playlist_plugin.h"
-#include "playlist/rss_playlist_plugin.h"
-#include "playlist/cue_playlist_plugin.h"
-#include "playlist/embcue_playlist_plugin.h"
-#include "input_stream.h"
-#include "uri.h"
-#include "string_util.h"
-#include "conf.h"
-#include "mpd_error.h"
-
-#include <assert.h>
-#include <string.h>
-#include <stdio.h>
-
-const struct playlist_plugin *const playlist_plugins[] = {
- &extm3u_playlist_plugin,
- &m3u_playlist_plugin,
- &xspf_playlist_plugin,
- &pls_playlist_plugin,
- &asx_playlist_plugin,
- &rss_playlist_plugin,
-#ifdef ENABLE_DESPOTIFY
- &despotify_playlist_plugin,
-#endif
-#ifdef ENABLE_LASTFM
- &lastfm_playlist_plugin,
-#endif
-#ifdef ENABLE_SOUNDCLOUD
- &soundcloud_playlist_plugin,
-#endif
- &cue_playlist_plugin,
- &embcue_playlist_plugin,
- NULL
-};
-
-/** which plugins have been initialized successfully? */
-static bool playlist_plugins_enabled[G_N_ELEMENTS(playlist_plugins)];
-
-#define playlist_plugins_for_each_enabled(plugin) \
- playlist_plugins_for_each(plugin) \
- if (playlist_plugins_enabled[playlist_plugin_iterator - 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)
- MPD_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)
-{
- playlist_plugins_for_each_enabled(plugin)
- playlist_plugin_finish(plugin);
-}
-
-static struct playlist_provider *
-playlist_list_open_uri_scheme(const char *uri, GMutex *mutex, GCond *cond,
- bool *tried)
-{
- 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];
-
- assert(!tried[i]);
-
- 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,
- mutex, cond);
- if (playlist != NULL)
- break;
-
- tried[i] = true;
- }
- }
-
- g_free(scheme);
- return playlist;
-}
-
-static struct playlist_provider *
-playlist_list_open_uri_suffix(const char *uri, GMutex *mutex, GCond *cond,
- const bool *tried)
-{
- const char *suffix;
- struct playlist_provider *playlist = NULL;
-
- assert(uri != NULL);
-
- suffix = uri_get_suffix(uri);
- if (suffix == 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] && !tried[i] &&
- plugin->open_uri != NULL && plugin->suffixes != NULL &&
- string_array_contains(plugin->suffixes, suffix)) {
- playlist = playlist_plugin_open_uri(plugin, uri,
- mutex, cond);
- if (playlist != NULL)
- break;
- }
- }
-
- return playlist;
-}
-
-struct playlist_provider *
-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
- playlist_list_open_uri_scheme() */
- bool tried[G_N_ELEMENTS(playlist_plugins) - 1];
-
- assert(uri != NULL);
-
- memset(tried, false, sizeof(tried));
-
- playlist = playlist_list_open_uri_scheme(uri, mutex, cond, tried);
- if (playlist == NULL)
- playlist = playlist_list_open_uri_suffix(uri, mutex, cond,
- tried);
-
- return playlist;
-}
-
-static struct playlist_provider *
-playlist_list_open_stream_mime2(struct input_stream *is, const char *mime)
-{
- struct playlist_provider *playlist;
-
- assert(is != NULL);
- assert(mime != NULL);
-
- playlist_plugins_for_each_enabled(plugin) {
- if (plugin->open_stream != NULL &&
- plugin->mime_types != NULL &&
- string_array_contains(plugin->mime_types, mime)) {
- /* rewind the stream, so each plugin gets a
- fresh start */
- input_stream_seek(is, 0, SEEK_SET, NULL);
-
- playlist = playlist_plugin_open_stream(plugin, is);
- if (playlist != NULL)
- return playlist;
- }
- }
-
- return NULL;
-}
-
-static struct playlist_provider *
-playlist_list_open_stream_mime(struct input_stream *is)
-{
- assert(is->mime != NULL);
-
- const char *semicolon = strchr(is->mime, ';');
- if (semicolon == NULL)
- return playlist_list_open_stream_mime2(is, is->mime);
-
- if (semicolon == is->mime)
- return NULL;
-
- /* probe only the portion before the semicolon*/
- char *mime = g_strndup(is->mime, semicolon - is->mime);
- struct playlist_provider *playlist =
- playlist_list_open_stream_mime2(is, mime);
- g_free(mime);
- return playlist;
-}
-
-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);
-
- playlist_plugins_for_each_enabled(plugin) {
- if (plugin->open_stream != NULL &&
- plugin->suffixes != NULL &&
- string_array_contains(plugin->suffixes, suffix)) {
- /* rewind the stream, so each plugin gets a
- fresh start */
- input_stream_seek(is, 0, SEEK_SET, NULL);
-
- 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;
-
- input_stream_lock_wait_ready(is);
-
- 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;
-}
-
-bool
-playlist_suffix_supported(const char *suffix)
-{
- assert(suffix != NULL);
-
- playlist_plugins_for_each_enabled(plugin) {
- if (plugin->suffixes != NULL &&
- string_array_contains(plugin->suffixes, suffix))
- return true;
- }
-
- return false;
-}
-
-struct playlist_provider *
-playlist_list_open_path(const char *path_fs, GMutex *mutex, GCond *cond,
- struct input_stream **is_r)
-{
- GError *error = NULL;
- const char *suffix;
- struct input_stream *is;
- struct playlist_provider *playlist;
-
- assert(path_fs != NULL);
-
- suffix = uri_get_suffix(path_fs);
- if (suffix == NULL || !playlist_suffix_supported(suffix))
- return NULL;
-
- is = input_stream_open(path_fs, mutex, cond, &error);
- if (is == NULL) {
- if (error != NULL) {
- 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)
- *is_r = is;
- else
- input_stream_close(is);
-
- return playlist;
-}
diff --git a/src/playlist_list.h b/src/playlist_list.h
deleted file mode 100644
index c3967d5ae..000000000
--- a/src/playlist_list.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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_LIST_H
-#define MPD_PLAYLIST_LIST_H
-
-#include <glib.h>
-
-#include <stdbool.h>
-
-struct playlist_provider;
-struct input_stream;
-
-extern const struct playlist_plugin *const playlist_plugins[];
-
-#define playlist_plugins_for_each(plugin) \
- for (const struct playlist_plugin *plugin, \
- *const*playlist_plugin_iterator = &playlist_plugins[0]; \
- (plugin = *playlist_plugin_iterator) != NULL; \
- ++playlist_plugin_iterator)
-
-/**
- * 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, GMutex *mutex, GCond *cond);
-
-/**
- * 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);
-
-/**
- * Determines if there is a playlist plugin which can handle the
- * specified file name suffix.
- */
-bool
-playlist_suffix_supported(const char *suffix);
-
-/**
- * Opens a playlist from a local file.
- *
- * @param path_fs the path of the playlist file
- * @param is_r on success, an input_stream object is returned here,
- * which must be closed after the playlist_provider object is freed
- * @return a playlist, or NULL on error
- */
-struct playlist_provider *
-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
deleted file mode 100644
index 13adb80d0..000000000
--- a/src/playlist_mapper.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_mapper.h"
-#include "playlist_list.h"
-#include "stored_playlist.h"
-#include "mapper.h"
-#include "uri.h"
-
-#include <assert.h>
-
-static struct playlist_provider *
-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, mutex, cond);
- if (playlist != NULL)
- *is_r = NULL;
- else
- playlist = playlist_list_open_path(path_fs, mutex, cond, is_r);
-
- return playlist;
-}
-
-/**
- * Load a playlist from the configured playlist directory.
- */
-static struct playlist_provider *
-playlist_open_in_playlist_dir(const char *uri, GMutex *mutex, GCond *cond,
- struct input_stream **is_r)
-{
- char *path_fs;
-
- assert(spl_valid_name(uri));
-
- const char *playlist_directory_fs = map_spl_path();
- if (playlist_directory_fs == NULL)
- return NULL;
-
- path_fs = g_build_filename(playlist_directory_fs, uri, NULL);
-
- struct playlist_provider *playlist =
- playlist_open_path(path_fs, mutex, cond, is_r);
- g_free(path_fs);
-
- return playlist;
-}
-
-/**
- * Load a playlist from the configured music directory.
- */
-static struct playlist_provider *
-playlist_open_in_music_dir(const char *uri, GMutex *mutex, GCond *cond,
- struct input_stream **is_r)
-{
- char *path_fs;
-
- assert(uri_safe_local(uri));
-
- path_fs = map_uri_fs(uri);
- if (path_fs == NULL)
- return NULL;
-
- 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, 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, mutex, cond,
- is_r);
- if (playlist != NULL)
- return playlist;
- }
-
- if (uri_safe_local(uri)) {
- playlist = playlist_open_in_music_dir(uri, mutex, cond, is_r);
- if (playlist != NULL)
- return playlist;
- }
-
- return NULL;
-}
diff --git a/src/playlist_mapper.h b/src/playlist_mapper.h
deleted file mode 100644
index 9a7187d93..000000000
--- a/src/playlist_mapper.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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_MAPPER_H
-#define MPD_PLAYLIST_MAPPER_H
-
-#include <glib.h>
-
-struct input_stream;
-
-/**
- * Opens a playlist from an URI relative to the playlist or music
- * directory.
- *
- * @param is_r on success, an input_stream object may be returned
- * here, which must be closed after the playlist_provider object is
- * freed
- */
-struct playlist_provider *
-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
deleted file mode 100644
index a27f651c0..000000000
--- a/src/playlist_plugin.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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_PLUGIN_H
-#define MPD_PLAYLIST_PLUGIN_H
-
-#include <glib.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,
- GMutex *mutex, GCond *cond);
-
- /**
- * 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,
- GMutex *mutex, GCond *cond)
-{
- return plugin->open_uri(uri, mutex, cond);
-}
-
-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
deleted file mode 100644
index 59c42f969..000000000
--- a/src/playlist_print.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_print.h"
-#include "playlist_list.h"
-#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"
-#include "song.h"
-#include "database.h"
-#include "client.h"
-#include "input_stream.h"
-
-void
-playlist_print_uris(struct client *client, const struct playlist *playlist)
-{
- const struct queue *queue = &playlist->queue;
-
- queue_print_uris(client, queue, 0, queue_length(queue));
-}
-
-bool
-playlist_print_info(struct client *client, const struct playlist *playlist,
- unsigned start, unsigned end)
-{
- const struct queue *queue = &playlist->queue;
-
- if (end > queue_length(queue))
- /* correct the "end" offset */
- end = queue_length(queue);
-
- if (start > end)
- /* an invalid "start" offset is fatal */
- return false;
-
- queue_print_info(client, queue, start, end);
- return true;
-}
-
-bool
-playlist_print_id(struct client *client, const struct playlist *playlist,
- unsigned id)
-{
- const struct queue *queue = &playlist->queue;
- int position;
-
- position = queue_id_to_position(queue, id);
- if (position < 0)
- /* no such song */
- return false;
-
- return playlist_print_info(client, playlist, position, position + 1);
-}
-
-bool
-playlist_print_current(struct client *client, const struct playlist *playlist)
-{
- int current_position = playlist_get_current_song(playlist);
-
- if (current_position < 0)
- return false;
-
- queue_print_info(client, &playlist->queue,
- current_position, current_position + 1);
- return true;
-}
-
-void
-playlist_print_find(struct client *client, const struct playlist *playlist,
- const struct locate_item_list *list)
-{
- queue_find(client, &playlist->queue, list);
-}
-
-void
-playlist_print_search(struct client *client, const struct playlist *playlist,
- const struct locate_item_list *list)
-{
- queue_search(client, &playlist->queue, list);
-}
-
-void
-playlist_print_changes_info(struct client *client,
- const struct playlist *playlist,
- uint32_t version)
-{
- queue_print_changes_info(client, &playlist->queue, version);
-}
-
-void
-playlist_print_changes_position(struct client *client,
- const struct playlist *playlist,
- uint32_t version)
-{
- queue_print_changes_position(client, &playlist->queue, version);
-}
-
-bool
-spl_print(struct client *client, const char *name_utf8, bool detail,
- GError **error_r)
-{
- GPtrArray *list;
-
- list = spl_load(name_utf8, error_r);
- if (list == NULL)
- return false;
-
- for (unsigned i = 0; i < list->len; ++i) {
- const char *temp = g_ptr_array_index(list, i);
- bool wrote = false;
-
- if (detail) {
- struct song *song = db_get_song(temp);
- if (song) {
- song_print_info(client, song);
- wrote = true;
- }
- }
-
- if (!wrote) {
- client_printf(client, SONG_FILE "%s\n", temp);
- }
- }
-
- spl_free(list);
- return true;
-}
-
-static void
-playlist_provider_print(struct client *client, const char *uri,
- struct playlist_provider *playlist, bool detail)
-{
- struct song *song;
- 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, false);
- if (song == NULL)
- continue;
-
- if (detail)
- song_print_info(client, song);
- else
- song_print_uri(client, song);
-
- if (!song_in_database(song))
- song_free(song);
- }
-
- g_free(base_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, 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);
-
- 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
deleted file mode 100644
index d4f1911d2..000000000
--- a/src/playlist_print.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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 PLAYLIST_PRINT_H
-#define PLAYLIST_PRINT_H
-
-#include <glib.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-struct client;
-struct playlist;
-struct locate_item_list;
-
-/**
- * Sends the whole playlist to the client, song URIs only.
- */
-void
-playlist_print_uris(struct client *client, const struct playlist *playlist);
-
-/**
- * Sends a range of the playlist to the client, including all known
- * information about the songs. The "end" offset is decreased
- * automatically if it is too large; passing UINT_MAX is allowed.
- * This function however fails when the start offset is invalid.
- */
-bool
-playlist_print_info(struct client *client, const struct playlist *playlist,
- unsigned start, unsigned end);
-
-/**
- * Sends the song with the specified id to the client.
- *
- * @return true on suite, false if there is no such song
- */
-bool
-playlist_print_id(struct client *client, const struct playlist *playlist,
- unsigned id);
-
-/**
- * Sends the current song to the client.
- *
- * @return true on success, false if there is no current song
- */
-bool
-playlist_print_current(struct client *client, const struct playlist *playlist);
-
-/**
- * Find songs in the playlist.
- */
-void
-playlist_print_find(struct client *client, const struct playlist *playlist,
- const struct locate_item_list *list);
-
-/**
- * Search for songs in the playlist.
- */
-void
-playlist_print_search(struct client *client, const struct playlist *playlist,
- const struct locate_item_list *list);
-
-/**
- * Print detailed changes since the specified playlist version.
- */
-void
-playlist_print_changes_info(struct client *client,
- const struct playlist *playlist,
- uint32_t version);
-
-/**
- * Print changes since the specified playlist version, position only.
- */
-void
-playlist_print_changes_position(struct client *client,
- const struct playlist *playlist,
- uint32_t version);
-
-/**
- * Send the stored playlist to the client.
- *
- * @param client the client which requested the playlist
- * @param name_utf8 the name of the stored playlist in UTF-8 encoding
- * @param detail true if all details should be printed
- * @return true on success, false if the playlist does not exist
- */
-bool
-spl_print(struct client *client, const char *name_utf8, bool detail,
- GError **error_r);
-
-/**
- * Send the playlist file to the client.
- *
- * @param client the client which requested the playlist
- * @param uri the URI of the playlist file in UTF-8 encoding
- * @param detail true if all details should be printed
- * @return true on success, false if the playlist does not exist
- */
-bool
-playlist_file_print(struct client *client, const char *uri, bool detail);
-
-#endif
diff --git a/src/playlist_queue.c b/src/playlist_queue.c
deleted file mode 100644
index aada94984..000000000
--- a/src/playlist_queue.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_queue.h"
-#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,
- unsigned start_index, unsigned end_index,
- 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;
-
- for (unsigned i = 0;
- i < end_index && (song = playlist_plugin_read(source)) != NULL;
- ++i) {
- if (i < start_index) {
- /* skip songs before the start index */
- if (!song_in_database(song))
- song_free(song);
- continue;
- }
-
- song = playlist_check_translate_song(song, base_uri, secure);
- if (song == NULL)
- continue;
-
- result = playlist_append_song(dest, pc, song, NULL);
- if (result != PLAYLIST_RESULT_SUCCESS) {
- if (!song_in_database(song))
- song_free(song);
- g_free(base_uri);
- return result;
- }
- }
-
- g_free(base_uri);
-
- return PLAYLIST_RESULT_SUCCESS;
-}
-
-enum playlist_result
-playlist_open_into_queue(const char *uri,
- unsigned start_index, unsigned end_index,
- 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, 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, start_index, end_index,
- 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
deleted file mode 100644
index 24a851aab..000000000
--- a/src/playlist_queue.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.
- */
-
-/*! \file
- * \brief Glue between playlist plugin and the play queue
- */
-
-#ifndef MPD_PLAYLIST_QUEUE_H
-#define MPD_PLAYLIST_QUEUE_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
- * play queue.
- *
- * @param uri the URI of the playlist, used to resolve relative song
- * URIs
- * @param start_index the index of the first song
- * @param end_index the index of the last song (excluding)
- */
-enum playlist_result
-playlist_load_into_queue(const char *uri, struct playlist_provider *source,
- unsigned start_index, unsigned end_index,
- 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,
- unsigned start_index, unsigned end_index,
- struct playlist *dest, struct player_control *pc,
- bool secure);
-
-#endif
-
diff --git a/src/playlist_save.c b/src/playlist_save.c
deleted file mode 100644
index 194bff057..000000000
--- a/src/playlist_save.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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.
- */
-
-#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"
-#include "uri.h"
-#include "database.h"
-#include "idle.h"
-#include "glib_compat.h"
-
-#include <glib.h>
-
-#include <string.h>
-
-void
-playlist_print_song(FILE *file, const struct song *song)
-{
- if (playlist_saveAbsolutePaths && song_in_database(song)) {
- char *path = map_song_fs(song);
- if (path != NULL) {
- fprintf(file, "%s\n", path);
- g_free(path);
- }
- } else {
- char *uri = song_get_uri(song), *uri_fs;
-
- uri_fs = utf8_to_fs_charset(uri);
- g_free(uri);
-
- fprintf(file, "%s\n", uri_fs);
- g_free(uri_fs);
- }
-}
-
-void
-playlist_print_uri(FILE *file, const char *uri)
-{
- char *s;
-
- if (playlist_saveAbsolutePaths && !uri_has_scheme(uri) &&
- !g_path_is_absolute(uri))
- s = map_uri_fs(uri);
- else
- s = utf8_to_fs_charset(uri);
-
- if (s != NULL) {
- fprintf(file, "%s\n", s);
- g_free(s);
- }
-}
-
-enum playlist_result
-spl_save_queue(const char *name_utf8, const struct queue *queue)
-{
- char *path_fs;
- FILE *file;
-
- if (map_spl_path() == NULL)
- return PLAYLIST_RESULT_DISABLED;
-
- if (!spl_valid_name(name_utf8))
- return PLAYLIST_RESULT_BAD_NAME;
-
- path_fs = map_spl_utf8_to_fs(name_utf8);
- if (path_fs == NULL)
- return PLAYLIST_RESULT_BAD_NAME;
-
- if (g_file_test(path_fs, G_FILE_TEST_EXISTS)) {
- g_free(path_fs);
- return PLAYLIST_RESULT_LIST_EXISTS;
- }
-
- file = fopen(path_fs, "w");
- g_free(path_fs);
-
- if (file == NULL)
- return PLAYLIST_RESULT_ERRNO;
-
- for (unsigned i = 0; i < queue_length(queue); i++)
- playlist_print_song(file, queue_get(queue, i));
-
- fclose(file);
-
- idle_add(IDLE_STORED_PLAYLIST);
- return PLAYLIST_RESULT_SUCCESS;
-}
-
-enum playlist_result
-spl_save_playlist(const char *name_utf8, const struct playlist *playlist)
-{
- return spl_save_queue(name_utf8, &playlist->queue);
-}
-
-bool
-playlist_load_spl(struct playlist *playlist, struct player_control *pc,
- const char *name_utf8,
- unsigned start_index, unsigned end_index,
- GError **error_r)
-{
- GPtrArray *list;
-
- list = spl_load(name_utf8, error_r);
- if (list == NULL)
- return false;
-
- if (list->len < end_index)
- end_index = list->len;
-
- for (unsigned i = start_index; i < end_index; ++i) {
- const char *temp = g_ptr_array_index(list, i);
-
- if (memcmp(temp, "file:///", 8) == 0) {
- const char *path = temp + 7;
-
- if (playlist_append_file(playlist, pc, path, NULL) != PLAYLIST_RESULT_SUCCESS)
- g_warning("can't add file \"%s\"", path);
- continue;
- }
-
- if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
- /* for windows compatibility, convert slashes */
- char *temp2 = g_strdup(temp);
- char *p = temp2;
- while (*p) {
- if (*p == '\\')
- *p = '/';
- p++;
- }
- if ((playlist_append_uri(playlist, pc, temp2,
- NULL)) != PLAYLIST_RESULT_SUCCESS) {
- g_warning("can't add file \"%s\"", temp2);
- }
- g_free(temp2);
- }
- }
-
- spl_free(list);
- return true;
-}
diff --git a/src/playlist_save.h b/src/playlist_save.h
deleted file mode 100644
index a6c31a9a6..000000000
--- a/src/playlist_save.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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_SAVE_H
-#define MPD_PLAYLIST_SAVE_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);
-
-void
-playlist_print_uri(FILE *fp, const char *uri);
-
-/**
- * Saves a queue object into a stored playlist file.
- */
-enum playlist_result
-spl_save_queue(const char *name_utf8, const struct queue *queue);
-
-/**
- * Saves a playlist object into a stored playlist file.
- */
-enum playlist_result
-spl_save_playlist(const char *name_utf8, const struct playlist *playlist);
-
-/**
- * Loads a stored playlist file, and append all songs to the global
- * playlist.
- */
-bool
-playlist_load_spl(struct playlist *playlist, struct player_control *pc,
- const char *name_utf8,
- unsigned start_index, unsigned end_index,
- GError **error_r);
-
-#endif
diff --git a/src/playlist_song.c b/src/playlist_song.c
deleted file mode 100644
index a3d9ab4d9..000000000
--- a/src/playlist_song.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_song.h"
-#include "database.h"
-#include "mapper.h"
-#include "song.h"
-#include "uri.h"
-#include "path.h"
-#include "ls.h"
-#include "tag.h"
-
-#include <assert.h>
-#include <string.h>
-
-static void
-merge_song_metadata(struct song *dest, const struct song *base,
- const struct song *add)
-{
- dest->tag = base->tag != NULL
- ? (add->tag != NULL
- ? tag_merge(base->tag, add->tag)
- : tag_dup(base->tag))
- : (add->tag != NULL
- ? tag_dup(add->tag)
- : NULL);
-
- dest->mtime = base->mtime;
- dest->start_ms = add->start_ms;
- dest->end_ms = add->end_ms;
-}
-
-static struct song *
-apply_song_metadata(struct song *dest, const struct song *src)
-{
- struct song *tmp;
-
- assert(dest != NULL);
- assert(src != NULL);
-
- if (src->tag == NULL && src->start_ms == 0 && src->end_ms == 0)
- return dest;
-
- if (song_in_database(dest)) {
- char *path_fs = map_song_fs(dest);
- if (path_fs == NULL)
- return dest;
-
- char *path_utf8 = fs_charset_to_utf8(path_fs);
- if (path_utf8 != NULL)
- g_free(path_fs);
- else
- path_utf8 = path_fs;
-
- tmp = song_file_new(path_utf8, NULL);
- g_free(path_utf8);
-
- merge_song_metadata(tmp, dest, src);
- } else {
- tmp = song_file_new(dest->uri, NULL);
- merge_song_metadata(tmp, dest, src);
- }
-
- if (dest->tag != NULL && dest->tag->time > 0 &&
- src->start_ms > 0 && src->end_ms == 0 &&
- src->start_ms / 1000 < (unsigned)dest->tag->time)
- /* the range is open-ended, and the playlist plugin
- did not know the total length of the song file
- (e.g. last track on a CUE file); fix it up here */
- tmp->tag->time = dest->tag->time - src->start_ms / 1000;
-
- if (!song_in_database(dest))
- song_free(dest);
-
- return tmp;
-}
-
-static struct song *
-playlist_check_load_song(const struct song *song, const char *uri, bool secure)
-{
- struct song *dest;
-
- if (uri_has_scheme(uri)) {
- dest = song_remote_new(uri);
- } else if (g_path_is_absolute(uri) && secure) {
- dest = song_file_load(uri, NULL);
- if (dest == NULL)
- return NULL;
- } else {
- dest = db_get_song(uri);
- if (dest == NULL)
- /* not found in database */
- return NULL;
- }
-
- return apply_song_metadata(dest, song);
-}
-
-struct song *
-playlist_check_translate_song(struct song *song, const char *base_uri,
- bool secure)
-{
- if (song_in_database(song))
- /* already ok */
- return song;
-
- const char *uri = song->uri;
-
- if (uri_has_scheme(uri)) {
- if (uri_supported_scheme(uri))
- /* valid remote song */
- return song;
- else {
- /* unsupported remote song */
- song_free(song);
- return NULL;
- }
- }
-
- if (base_uri != NULL && strcmp(base_uri, ".") == 0)
- /* g_path_get_dirname() returns "." when there is no
- directory name in the given path; clear that now,
- because it would break the database lookup
- functions */
- base_uri = NULL;
-
- if (g_path_is_absolute(uri)) {
- /* XXX fs_charset vs utf8? */
- const char *suffix = map_to_relative_path(uri);
- assert(suffix != NULL);
-
- if (suffix != uri)
- uri = suffix;
- else if (!secure) {
- /* local files must be relative to the music
- directory when "secure" is enabled */
- song_free(song);
- return NULL;
- }
-
- base_uri = NULL;
- }
-
- char *allocated = NULL;
- if (base_uri != NULL)
- uri = allocated = g_build_filename(base_uri, uri, NULL);
-
- struct song *dest = playlist_check_load_song(song, uri, secure);
- song_free(song);
- g_free(allocated);
- return dest;
-}
diff --git a/src/playlist_song.h b/src/playlist_song.h
deleted file mode 100644
index ea8786912..000000000
--- a/src/playlist_song.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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_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,
- bool secure);
-
-#endif
diff --git a/src/playlist_state.c b/src/playlist_state.c
deleted file mode 100644
index 4aa2c2c92..000000000
--- a/src/playlist_state.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Saving and loading the playlist to/from the state file.
- *
- */
-
-#include "config.h"
-#include "playlist_state.h"
-#include "playlist.h"
-#include "player_control.h"
-#include "queue_save.h"
-#include "path.h"
-#include "text_file.h"
-#include "conf.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-#define PLAYLIST_STATE_FILE_STATE "state: "
-#define PLAYLIST_STATE_FILE_RANDOM "random: "
-#define PLAYLIST_STATE_FILE_REPEAT "repeat: "
-#define PLAYLIST_STATE_FILE_SINGLE "single: "
-#define PLAYLIST_STATE_FILE_CONSUME "consume: "
-#define PLAYLIST_STATE_FILE_CURRENT "current: "
-#define PLAYLIST_STATE_FILE_TIME "time: "
-#define PLAYLIST_STATE_FILE_CROSSFADE "crossfade: "
-#define PLAYLIST_STATE_FILE_MIXRAMPDB "mixrampdb: "
-#define PLAYLIST_STATE_FILE_MIXRAMPDELAY "mixrampdelay: "
-#define PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "playlist_begin"
-#define PLAYLIST_STATE_FILE_PLAYLIST_END "playlist_end"
-
-#define PLAYLIST_STATE_FILE_STATE_PLAY "play"
-#define PLAYLIST_STATE_FILE_STATE_PAUSE "pause"
-#define PLAYLIST_STATE_FILE_STATE_STOP "stop"
-
-#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
-
-void
-playlist_state_save(FILE *fp, const struct playlist *playlist,
- struct player_control *pc)
-{
- struct player_status player_status;
-
- pc_get_status(pc, &player_status);
-
- fputs(PLAYLIST_STATE_FILE_STATE, fp);
-
- if (playlist->playing) {
- switch (player_status.state) {
- case PLAYER_STATE_PAUSE:
- fputs(PLAYLIST_STATE_FILE_STATE_PAUSE "\n", fp);
- break;
- default:
- fputs(PLAYLIST_STATE_FILE_STATE_PLAY "\n", fp);
- }
- fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n",
- queue_order_to_position(&playlist->queue,
- playlist->current));
- fprintf(fp, PLAYLIST_STATE_FILE_TIME "%i\n",
- (int)player_status.elapsed_time);
- } else {
- fputs(PLAYLIST_STATE_FILE_STATE_STOP "\n", fp);
-
- if (playlist->current >= 0)
- fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n",
- queue_order_to_position(&playlist->queue,
- playlist->current));
- }
-
- fprintf(fp, PLAYLIST_STATE_FILE_RANDOM "%i\n", playlist->queue.random);
- fprintf(fp, PLAYLIST_STATE_FILE_REPEAT "%i\n", playlist->queue.repeat);
- fprintf(fp, PLAYLIST_STATE_FILE_SINGLE "%i\n", playlist->queue.single);
- fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n",
- playlist->queue.consume);
- fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n",
- (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));
- fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp);
- queue_save(fp, &playlist->queue);
- fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp);
-}
-
-static void
-playlist_state_load(FILE *fp, GString *buffer, struct playlist *playlist)
-{
- const char *line = read_text_line(fp, buffer);
- if (line == NULL) {
- g_warning("No playlist in state file");
- return;
- }
-
- while (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_PLAYLIST_END)) {
- queue_load_song(fp, buffer, line, &playlist->queue);
-
- line = read_text_line(fp, buffer);
- if (line == NULL) {
- g_warning("'" PLAYLIST_STATE_FILE_PLAYLIST_END
- "' not found in state file");
- break;
- }
- }
-
- queue_increment_version(&playlist->queue);
-}
-
-bool
-playlist_state_restore(const char *line, FILE *fp, GString *buffer,
- struct playlist *playlist, struct player_control *pc)
-{
- int current = -1;
- int seek_time = 0;
- enum player_state state = PLAYER_STATE_STOP;
- 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 ((line = read_text_line(fp, buffer)) != NULL) {
- if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_TIME)) {
- seek_time =
- atoi(&(line[strlen(PLAYLIST_STATE_FILE_TIME)]));
- } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_REPEAT)) {
- if (strcmp
- (&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
- "1") == 0) {
- playlist_set_repeat(playlist, pc, true);
- } else
- 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, pc, true);
- } else
- 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)]),
- "1") == 0) {
- playlist_set_consume(playlist, true);
- } else
- playlist_set_consume(playlist, false);
- } else if (g_str_has_prefix(line, 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(pc,
- atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB)));
- } else if (g_str_has_prefix(line, 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),
- "1") == 0;
- } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CURRENT)) {
- current = atoi(&(line
- [strlen
- (PLAYLIST_STATE_FILE_CURRENT)]));
- } else if (g_str_has_prefix(line,
- PLAYLIST_STATE_FILE_PLAYLIST_BEGIN)) {
- playlist_state_load(fp, buffer, playlist);
- }
- }
-
- 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);
-
- if (state == PLAYER_STATE_STOP /* && config_option */)
- playlist->current = current;
- else if (seek_time == 0)
- playlist_play(playlist, pc, current);
- else
- playlist_seek_song(playlist, pc, current, seek_time);
-
- if (state == PLAYER_STATE_PAUSE)
- pc_pause(pc);
- }
-
- return true;
-}
-
-unsigned
-playlist_state_get_hash(const struct playlist *playlist,
- struct player_control *pc)
-{
- struct player_status player_status;
-
- pc_get_status(pc, &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(pc) << 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
deleted file mode 100644
index f67d01d2c..000000000
--- a/src/playlist_state.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Saving and loading the playlist to/from the state file.
- *
- */
-
-#ifndef PLAYLIST_STATE_H
-#define PLAYLIST_STATE_H
-
-#include <glib.h>
-#include <stdbool.h>
-#include <stdio.h>
-
-struct playlist;
-struct player_control;
-
-void
-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 player_control *pc);
-
-/**
- * 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,
- struct player_control *pc);
-
-#endif
diff --git a/src/playlist_vector.c b/src/playlist_vector.c
deleted file mode 100644
index 74c7bf089..000000000
--- a/src/playlist_vector.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.
- */
-
-#include "config.h"
-#include "playlist_vector.h"
-#include "db_lock.h"
-
-#include <assert.h>
-#include <string.h>
-#include <glib.h>
-
-static struct playlist_metadata *
-playlist_metadata_new(const char *name, time_t mtime)
-{
- assert(name != NULL);
-
- struct playlist_metadata *pm = g_slice_new(struct playlist_metadata);
- pm->name = g_strdup(name);
- pm->mtime = mtime;
- return pm;
-}
-
-static void
-playlist_metadata_free(struct playlist_metadata *pm)
-{
- assert(pm != NULL);
- assert(pm->name != NULL);
-
- g_free(pm->name);
- g_slice_free(struct playlist_metadata, pm);
-}
-
-void
-playlist_vector_deinit(struct list_head *pv)
-{
- assert(pv != NULL);
-
- struct playlist_metadata *pm, *n;
- playlist_vector_for_each_safe(pm, n, pv)
- playlist_metadata_free(pm);
-}
-
-struct playlist_metadata *
-playlist_vector_find(struct list_head *pv, const char *name)
-{
- assert(holding_db_lock());
- assert(pv != NULL);
- assert(name != NULL);
-
- struct playlist_metadata *pm;
- playlist_vector_for_each(pm, pv)
- if (strcmp(pm->name, name) == 0)
- return pm;
-
- return NULL;
-}
-
-void
-playlist_vector_add(struct list_head *pv,
- const char *name, time_t mtime)
-{
- assert(holding_db_lock());
-
- struct playlist_metadata *pm = playlist_metadata_new(name, mtime);
- list_add_tail(&pm->siblings, pv);
-}
-
-bool
-playlist_vector_update_or_add(struct list_head *pv,
- const char *name, time_t mtime)
-{
- assert(holding_db_lock());
-
- struct playlist_metadata *pm = playlist_vector_find(pv, name);
- if (pm != NULL) {
- if (mtime == pm->mtime)
- return false;
-
- pm->mtime = mtime;
- } else
- playlist_vector_add(pv, name, mtime);
-
- return true;
-}
-
-bool
-playlist_vector_remove(struct list_head *pv, const char *name)
-{
- assert(holding_db_lock());
-
- struct playlist_metadata *pm = playlist_vector_find(pv, name);
- if (pm == NULL)
- return false;
-
- list_del(&pm->siblings);
- playlist_metadata_free(pm);
- return true;
-}
diff --git a/src/playlist_vector.h b/src/playlist_vector.h
deleted file mode 100644
index 0af6df8b4..000000000
--- a/src/playlist_vector.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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_VECTOR_H
-#define MPD_PLAYLIST_VECTOR_H
-
-#include "util/list.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <sys/time.h>
-
-#define playlist_vector_for_each(pos, head) \
- list_for_each_entry(pos, head, siblings)
-
-#define playlist_vector_for_each_safe(pos, n, head) \
- list_for_each_entry_safe(pos, n, head, siblings)
-
-/**
- * A directory entry pointing to a playlist file.
- */
-struct playlist_metadata {
- struct list_head siblings;
-
- /**
- * The UTF-8 encoded name of the playlist file.
- */
- char *name;
-
- time_t mtime;
-};
-
-void
-playlist_vector_deinit(struct list_head *pv);
-
-/**
- * Caller must lock the #db_mutex.
- */
-struct playlist_metadata *
-playlist_vector_find(struct list_head *pv, const char *name);
-
-/**
- * Caller must lock the #db_mutex.
- */
-void
-playlist_vector_add(struct list_head *pv,
- const char *name, time_t mtime);
-
-/**
- * Caller must lock the #db_mutex.
- *
- * @return true if the vector or one of its items was modified
- */
-bool
-playlist_vector_update_or_add(struct list_head *pv,
- const char *name, time_t mtime);
-
-/**
- * Caller must lock the #db_mutex.
- */
-bool
-playlist_vector_remove(struct list_head *pv, const char *name);
-
-#endif /* SONGVEC_H */