Playlist: convert functions to methods
This commit is contained in:
@@ -113,7 +113,6 @@ mpd_headers = \
|
|||||||
src/page.h \
|
src/page.h \
|
||||||
src/Playlist.hxx \
|
src/Playlist.hxx \
|
||||||
src/playlist_error.h \
|
src/playlist_error.h \
|
||||||
src/PlaylistInternal.hxx \
|
|
||||||
src/playlist_plugin.h \
|
src/playlist_plugin.h \
|
||||||
src/playlist_list.h \
|
src/playlist_list.h \
|
||||||
src/playlist/extm3u_playlist_plugin.h \
|
src/playlist/extm3u_playlist_plugin.h \
|
||||||
|
@@ -30,8 +30,7 @@ static bool
|
|||||||
AddToQueue(Partition &partition, song &song, GError **error_r)
|
AddToQueue(Partition &partition, song &song, GError **error_r)
|
||||||
{
|
{
|
||||||
enum playlist_result result =
|
enum playlist_result result =
|
||||||
playlist_append_song(&partition.playlist, &partition.pc,
|
partition.playlist.AppendSong(partition.pc, &song, NULL);
|
||||||
&song, NULL);
|
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS) {
|
if (result != PLAYLIST_RESULT_SUCCESS) {
|
||||||
g_set_error(error_r, playlist_quark(), result,
|
g_set_error(error_r, playlist_quark(), result,
|
||||||
"Playlist error");
|
"Playlist error");
|
||||||
|
@@ -38,6 +38,128 @@ struct Partition {
|
|||||||
:playlist(max_length),
|
:playlist(max_length),
|
||||||
pc(buffer_chunks, buffered_before_play) {
|
pc(buffer_chunks, buffered_before_play) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearQueue() {
|
||||||
|
playlist.Clear(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result AppendFile(const char *path_fs,
|
||||||
|
unsigned *added_id=nullptr) {
|
||||||
|
return playlist.AppendFile(pc, path_fs, added_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result AppendURI(const char *uri_utf8,
|
||||||
|
unsigned *added_id=nullptr) {
|
||||||
|
return playlist.AppendURI(pc, uri_utf8, added_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result DeletePosition(unsigned position) {
|
||||||
|
return playlist.DeletePosition(pc, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result DeleteId(unsigned id) {
|
||||||
|
return playlist.DeleteId(pc, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 DeleteRange(unsigned start, unsigned end) {
|
||||||
|
return playlist.DeleteRange(pc, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteSong(const song &song) {
|
||||||
|
playlist.DeleteSong(pc, song);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shuffle(unsigned start, unsigned end) {
|
||||||
|
playlist.Shuffle(pc, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result MoveRange(unsigned start, unsigned end, int to) {
|
||||||
|
return playlist.MoveRange(pc, start, end, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result MoveId(unsigned id, int to) {
|
||||||
|
return playlist.MoveId(pc, id, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result SwapPositions(unsigned song1, unsigned song2) {
|
||||||
|
return playlist.SwapPositions(pc, song1, song2);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result SwapIds(unsigned id1, unsigned id2) {
|
||||||
|
return playlist.SwapIds(pc, id1, id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result SetPriorityRange(unsigned start_position,
|
||||||
|
unsigned end_position,
|
||||||
|
uint8_t priority) {
|
||||||
|
return playlist.SetPriorityRange(pc,
|
||||||
|
start_position, end_position,
|
||||||
|
priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result SetPriorityId(unsigned song_id,
|
||||||
|
uint8_t priority) {
|
||||||
|
return playlist.SetPriorityId(pc, song_id, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop() {
|
||||||
|
playlist.Stop(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result PlayPosition(int position) {
|
||||||
|
return playlist.PlayPosition(pc, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result PlayId(int id) {
|
||||||
|
return playlist.PlayId(pc, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayNext() {
|
||||||
|
return playlist.PlayNext(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayPrevious() {
|
||||||
|
return playlist.PlayPrevious(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result SeekSongPosition(unsigned song_position,
|
||||||
|
float seek_time) {
|
||||||
|
return playlist.SeekSongPosition(pc, song_position, seek_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result SeekSongId(unsigned song_id, float seek_time) {
|
||||||
|
return playlist.SeekSongId(pc, song_id, seek_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result SeekCurrent(float seek_time, bool relative) {
|
||||||
|
return playlist.SeekCurrent(pc, seek_time, relative);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRepeat(bool new_value) {
|
||||||
|
playlist.SetRepeat(pc, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetRandom() const {
|
||||||
|
return playlist.GetRandom();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRandom(bool new_value) {
|
||||||
|
playlist.SetRandom(pc, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSingle(bool new_value) {
|
||||||
|
playlist.SetSingle(pc, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetConsume(bool new_value) {
|
||||||
|
playlist.SetConsume(new_value);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "ClientInternal.hxx"
|
#include "ClientInternal.hxx"
|
||||||
#include "Volume.hxx"
|
#include "Volume.hxx"
|
||||||
#include "OutputAll.hxx"
|
#include "OutputAll.hxx"
|
||||||
|
#include "Partition.hxx"
|
||||||
#include "protocol/Result.hxx"
|
#include "protocol/Result.hxx"
|
||||||
#include "protocol/ArgParser.hxx"
|
#include "protocol/ArgParser.hxx"
|
||||||
|
|
||||||
@@ -34,7 +35,6 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "replay_gain_config.h"
|
#include "replay_gain_config.h"
|
||||||
#include "PlayerControl.hxx"
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
@@ -62,12 +62,10 @@ enum command_return
|
|||||||
handle_play(Client *client, int argc, char *argv[])
|
handle_play(Client *client, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int song = -1;
|
int song = -1;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (argc == 2 && !check_int(client, &song, argv[1]))
|
if (argc == 2 && !check_int(client, &song, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_play(&client->playlist, client->player_control,
|
enum playlist_result result = client->partition.PlayPosition(song);
|
||||||
song);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,13 +73,11 @@ enum command_return
|
|||||||
handle_playid(Client *client, int argc, char *argv[])
|
handle_playid(Client *client, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int id = -1;
|
int id = -1;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (argc == 2 && !check_int(client, &id, argv[1]))
|
if (argc == 2 && !check_int(client, &id, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_play_id(&client->playlist, client->player_control,
|
enum playlist_result result = client->partition.PlayId(id);
|
||||||
id);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +85,7 @@ enum command_return
|
|||||||
handle_stop(Client *client,
|
handle_stop(Client *client,
|
||||||
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
||||||
{
|
{
|
||||||
playlist_stop(&client->playlist, client->player_control);
|
client->partition.Stop();
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,23 +151,23 @@ handle_status(Client *client,
|
|||||||
COMMAND_STATUS_MIXRAMPDELAY ": %f\n"
|
COMMAND_STATUS_MIXRAMPDELAY ": %f\n"
|
||||||
COMMAND_STATUS_STATE ": %s\n",
|
COMMAND_STATUS_STATE ": %s\n",
|
||||||
volume_level_get(),
|
volume_level_get(),
|
||||||
playlist_get_repeat(&playlist),
|
playlist.GetRepeat(),
|
||||||
playlist_get_random(&playlist),
|
playlist.GetRandom(),
|
||||||
playlist_get_single(&playlist),
|
playlist.GetSingle(),
|
||||||
playlist_get_consume(&playlist),
|
playlist.GetConsume(),
|
||||||
playlist_get_version(&playlist),
|
(unsigned long)playlist.GetVersion(),
|
||||||
playlist_get_length(&playlist),
|
playlist.GetLength(),
|
||||||
(int)(pc_get_cross_fade(client->player_control) + 0.5),
|
(int)(pc_get_cross_fade(client->player_control) + 0.5),
|
||||||
pc_get_mixramp_db(client->player_control),
|
pc_get_mixramp_db(client->player_control),
|
||||||
pc_get_mixramp_delay(client->player_control),
|
pc_get_mixramp_delay(client->player_control),
|
||||||
state);
|
state);
|
||||||
|
|
||||||
song = playlist_get_current_song(&playlist);
|
song = playlist.GetCurrentPosition();
|
||||||
if (song >= 0) {
|
if (song >= 0) {
|
||||||
client_printf(client,
|
client_printf(client,
|
||||||
COMMAND_STATUS_SONG ": %i\n"
|
COMMAND_STATUS_SONG ": %i\n"
|
||||||
COMMAND_STATUS_SONGID ": %u\n",
|
COMMAND_STATUS_SONGID ": %u\n",
|
||||||
song, playlist_get_song_id(&playlist, song));
|
song, playlist.PositionToId(song));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player_status.state != PLAYER_STATE_STOP) {
|
if (player_status.state != PLAYER_STATE_STOP) {
|
||||||
@@ -204,12 +200,12 @@ handle_status(Client *client,
|
|||||||
g_free(error);
|
g_free(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
song = playlist_get_next_song(&playlist);
|
song = playlist.GetNextPosition();
|
||||||
if (song >= 0) {
|
if (song >= 0) {
|
||||||
client_printf(client,
|
client_printf(client,
|
||||||
COMMAND_STATUS_NEXTSONG ": %i\n"
|
COMMAND_STATUS_NEXTSONG ": %i\n"
|
||||||
COMMAND_STATUS_NEXTSONGID ": %u\n",
|
COMMAND_STATUS_NEXTSONGID ": %u\n",
|
||||||
song, playlist_get_song_id(&playlist, song));
|
song, playlist.PositionToId(song));
|
||||||
}
|
}
|
||||||
|
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
@@ -226,7 +222,7 @@ handle_next(Client *client,
|
|||||||
const bool single = playlist.queue.single;
|
const bool single = playlist.queue.single;
|
||||||
playlist.queue.single = false;
|
playlist.queue.single = false;
|
||||||
|
|
||||||
playlist_next(&playlist, client->player_control);
|
client->partition.PlayNext();
|
||||||
|
|
||||||
playlist.queue.single = single;
|
playlist.queue.single = single;
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
@@ -236,7 +232,7 @@ enum command_return
|
|||||||
handle_previous(Client *client,
|
handle_previous(Client *client,
|
||||||
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
||||||
{
|
{
|
||||||
playlist_previous(&client->playlist, client->player_control);
|
client->partition.PlayPrevious();
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +243,7 @@ handle_repeat(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!check_bool(client, &status, argv[1]))
|
if (!check_bool(client, &status, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
playlist_set_repeat(&client->playlist, client->player_control, status);
|
client->partition.SetRepeat(status);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +254,7 @@ handle_single(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!check_bool(client, &status, argv[1]))
|
if (!check_bool(client, &status, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
playlist_set_single(&client->playlist, client->player_control, status);
|
client->partition.SetSingle(status);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +265,7 @@ handle_consume(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!check_bool(client, &status, argv[1]))
|
if (!check_bool(client, &status, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
playlist_set_consume(&client->playlist, status);
|
client->partition.SetConsume(status);
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,8 +276,8 @@ handle_random(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!check_bool(client, &status, argv[1]))
|
if (!check_bool(client, &status, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
playlist_set_random(&client->playlist, client->player_control, status);
|
client->partition.SetRandom(status);
|
||||||
audio_output_all_set_replay_gain_mode(replay_gain_get_real_mode(client->playlist.queue.random));
|
audio_output_all_set_replay_gain_mode(replay_gain_get_real_mode(client->partition.GetRandom()));
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,15 +293,14 @@ enum command_return
|
|||||||
handle_seek(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
handle_seek(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
||||||
{
|
{
|
||||||
unsigned song, seek_time;
|
unsigned song, seek_time;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (!check_unsigned(client, &song, argv[1]))
|
if (!check_unsigned(client, &song, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_unsigned(client, &seek_time, argv[2]))
|
if (!check_unsigned(client, &seek_time, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_seek_song(&client->playlist, client->player_control,
|
enum playlist_result result =
|
||||||
song, seek_time);
|
client->partition.SeekSongPosition(song, seek_time);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,16 +308,14 @@ enum command_return
|
|||||||
handle_seekid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
handle_seekid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
||||||
{
|
{
|
||||||
unsigned id, seek_time;
|
unsigned id, seek_time;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (!check_unsigned(client, &id, argv[1]))
|
if (!check_unsigned(client, &id, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_unsigned(client, &seek_time, argv[2]))
|
if (!check_unsigned(client, &seek_time, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_seek_song_id(&client->playlist,
|
enum playlist_result result =
|
||||||
client->player_control,
|
client->partition.SeekSongId(id, seek_time);
|
||||||
id, seek_time);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,9 +329,7 @@ handle_seekcur(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
enum playlist_result result =
|
enum playlist_result result =
|
||||||
playlist_seek_current(&client->playlist,
|
client->partition.SeekCurrent(seek_time, relative);
|
||||||
client->player_control,
|
|
||||||
seek_time, relative);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
264
src/Playlist.cxx
264
src/Playlist.cxx
@@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "PlaylistInternal.hxx"
|
#include "Playlist.hxx"
|
||||||
#include "PlayerControl.hxx"
|
#include "PlayerControl.hxx"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
|
|
||||||
@@ -41,14 +41,14 @@ playlist_increment_version_all(struct playlist *playlist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_tag_changed(struct playlist *playlist)
|
playlist::TagChanged()
|
||||||
{
|
{
|
||||||
if (!playlist->playing)
|
if (!playing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(playlist->current >= 0);
|
assert(current >= 0);
|
||||||
|
|
||||||
playlist->queue.ModifyAtOrder(playlist->current);
|
queue.ModifyAtOrder(current);
|
||||||
idle_add(IDLE_PLAYLIST);
|
idle_add(IDLE_PLAYLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,135 +92,117 @@ playlist_song_started(struct playlist *playlist, struct player_control *pc)
|
|||||||
playlist->queued = -1;
|
playlist->queued = -1;
|
||||||
|
|
||||||
if(playlist->queue.consume)
|
if(playlist->queue.consume)
|
||||||
playlist_delete(playlist, pc,
|
playlist->DeleteOrder(*pc, current);
|
||||||
playlist->queue.OrderToPosition(current));
|
|
||||||
|
|
||||||
idle_add(IDLE_PLAYER);
|
idle_add(IDLE_PLAYER);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct song *
|
const struct song *
|
||||||
playlist_get_queued_song(struct playlist *playlist)
|
playlist::GetQueuedSong() const
|
||||||
{
|
{
|
||||||
if (!playlist->playing || playlist->queued < 0)
|
return playing && queued >= 0
|
||||||
return NULL;
|
? queue.GetOrder(queued)
|
||||||
|
: nullptr;
|
||||||
return playlist->queue.GetOrder(playlist->queued);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_update_queued_song(struct playlist *playlist,
|
playlist::UpdateQueuedSong(player_control &pc, const song *prev)
|
||||||
struct player_control *pc,
|
|
||||||
const struct song *prev)
|
|
||||||
{
|
{
|
||||||
int next_order;
|
if (!playing)
|
||||||
const struct song *next_song;
|
|
||||||
|
|
||||||
if (!playlist->playing)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(!playlist->queue.IsEmpty());
|
assert(!queue.IsEmpty());
|
||||||
assert((playlist->queued < 0) == (prev == NULL));
|
assert((queued < 0) == (prev == NULL));
|
||||||
|
|
||||||
next_order = playlist->current >= 0
|
const int next_order = current >= 0
|
||||||
? playlist->queue.GetNextOrder(playlist->current)
|
? queue.GetNextOrder(current)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
if (next_order == 0 && playlist->queue.random &&
|
if (next_order == 0 && queue.random && !queue.single) {
|
||||||
!playlist->queue.single) {
|
|
||||||
/* shuffle the song order again, so we get a different
|
/* shuffle the song order again, so we get a different
|
||||||
order each time the playlist is played
|
order each time the playlist is played
|
||||||
completely */
|
completely */
|
||||||
unsigned current_position =
|
const unsigned current_position =
|
||||||
playlist->queue.OrderToPosition(playlist->current);
|
queue.OrderToPosition(current);
|
||||||
|
|
||||||
playlist->queue.ShuffleOrder();
|
queue.ShuffleOrder();
|
||||||
|
|
||||||
/* make sure that the playlist->current still points to
|
/* make sure that the current still points to
|
||||||
the current song, after the song order has been
|
the current song, after the song order has been
|
||||||
shuffled */
|
shuffled */
|
||||||
playlist->current =
|
current = queue.PositionToOrder(current_position);
|
||||||
playlist->queue.PositionToOrder(current_position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_order >= 0)
|
const struct song *const next_song = next_order >= 0
|
||||||
next_song = playlist->queue.GetOrder(next_order);
|
? queue.GetOrder(next_order)
|
||||||
else
|
: nullptr;
|
||||||
next_song = NULL;
|
|
||||||
|
|
||||||
if (prev != NULL && next_song != prev) {
|
if (prev != NULL && next_song != prev) {
|
||||||
/* clear the currently queued song */
|
/* clear the currently queued song */
|
||||||
pc_cancel(pc);
|
pc_cancel(&pc);
|
||||||
playlist->queued = -1;
|
queued = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_order >= 0) {
|
if (next_order >= 0) {
|
||||||
if (next_song != prev)
|
if (next_song != prev)
|
||||||
playlist_queue_song_order(playlist, pc, next_order);
|
playlist_queue_song_order(this, &pc, next_order);
|
||||||
else
|
else
|
||||||
playlist->queued = next_order;
|
queued = next_order;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_play_order(struct playlist *playlist, struct player_control *pc,
|
playlist::PlayOrder(player_control &pc, int order)
|
||||||
int orderNum)
|
|
||||||
{
|
{
|
||||||
char *uri;
|
playing = true;
|
||||||
|
queued = -1;
|
||||||
|
|
||||||
playlist->playing = true;
|
struct song *song = song_dup_detached(queue.GetOrder(order));
|
||||||
playlist->queued = -1;
|
|
||||||
|
|
||||||
struct song *song =
|
char *uri = song_get_uri(song);
|
||||||
song_dup_detached(playlist->queue.GetOrder(orderNum));
|
g_debug("play %i:\"%s\"", order, uri);
|
||||||
|
|
||||||
uri = song_get_uri(song);
|
|
||||||
g_debug("play %i:\"%s\"", orderNum, uri);
|
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
|
|
||||||
pc_play(pc, song);
|
pc_play(&pc, song);
|
||||||
playlist->current = orderNum;
|
current = order;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
playlist_resume_playback(struct playlist *playlist, struct player_control *pc);
|
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
|
void
|
||||||
playlist_sync(struct playlist *playlist, struct player_control *pc)
|
playlist::SyncWithPlayer(player_control &pc)
|
||||||
{
|
{
|
||||||
if (!playlist->playing)
|
if (!playing)
|
||||||
/* this event has reached us out of sync: we aren't
|
/* this event has reached us out of sync: we aren't
|
||||||
playing anymore; ignore the event */
|
playing anymore; ignore the event */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
player_lock(pc);
|
player_lock(&pc);
|
||||||
enum player_state pc_state = pc_get_state(pc);
|
const enum player_state pc_state = pc_get_state(&pc);
|
||||||
const struct song *pc_next_song = pc->next_song;
|
const song *pc_next_song = pc.next_song;
|
||||||
player_unlock(pc);
|
player_unlock(&pc);
|
||||||
|
|
||||||
if (pc_state == PLAYER_STATE_STOP)
|
if (pc_state == PLAYER_STATE_STOP)
|
||||||
/* the player thread has stopped: check if playback
|
/* the player thread has stopped: check if playback
|
||||||
should be restarted with the next song. That can
|
should be restarted with the next song. That can
|
||||||
happen if the playlist isn't filling the queue fast
|
happen if the playlist isn't filling the queue fast
|
||||||
enough */
|
enough */
|
||||||
playlist_resume_playback(playlist, pc);
|
playlist_resume_playback(this, &pc);
|
||||||
else {
|
else {
|
||||||
/* check if the player thread has already started
|
/* check if the player thread has already started
|
||||||
playing the queued song */
|
playing the queued song */
|
||||||
if (pc_next_song == NULL && playlist->queued != -1)
|
if (pc_next_song == nullptr && queued != -1)
|
||||||
playlist_song_started(playlist, pc);
|
playlist_song_started(this, &pc);
|
||||||
|
|
||||||
player_lock(pc);
|
player_lock(&pc);
|
||||||
pc_next_song = pc->next_song;
|
pc_next_song = pc.next_song;
|
||||||
player_unlock(pc);
|
player_unlock(&pc);
|
||||||
|
|
||||||
/* make sure the queued song is always set (if
|
/* make sure the queued song is always set (if
|
||||||
possible) */
|
possible) */
|
||||||
if (pc_next_song == NULL && playlist->queued < 0)
|
if (pc_next_song == nullptr && queued < 0)
|
||||||
playlist_update_queued_song(playlist, pc, NULL);
|
UpdateQueuedSong(pc, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,53 +229,25 @@ playlist_resume_playback(struct playlist *playlist, struct player_control *pc)
|
|||||||
playlist->error_count >= playlist->queue.GetLength())
|
playlist->error_count >= playlist->queue.GetLength())
|
||||||
/* too many errors, or critical error: stop
|
/* too many errors, or critical error: stop
|
||||||
playback */
|
playback */
|
||||||
playlist_stop(playlist, pc);
|
playlist->Stop(*pc);
|
||||||
else
|
else
|
||||||
/* continue playback at the next song */
|
/* continue playback at the next song */
|
||||||
playlist_next(playlist, pc);
|
playlist->PlayNext(*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
|
void
|
||||||
playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
|
playlist::SetRepeat(player_control &pc, bool status)
|
||||||
bool status)
|
|
||||||
{
|
{
|
||||||
if (status == playlist->queue.repeat)
|
if (status == queue.repeat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct queue *queue = &playlist->queue;
|
queue.repeat = status;
|
||||||
|
|
||||||
queue->repeat = status;
|
pc_set_border_pause(&pc, queue.single && !queue.repeat);
|
||||||
|
|
||||||
pc_set_border_pause(pc, queue->single && !queue->repeat);
|
|
||||||
|
|
||||||
/* if the last song is currently being played, the "next song"
|
/* if the last song is currently being played, the "next song"
|
||||||
might change when repeat mode is toggled */
|
might change when repeat mode is toggled */
|
||||||
playlist_update_queued_song(playlist, pc,
|
UpdateQueuedSong(pc, GetQueuedSong());
|
||||||
playlist_get_queued_song(playlist));
|
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
@@ -309,117 +263,87 @@ playlist_order(struct playlist *playlist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_single(struct playlist *playlist, struct player_control *pc,
|
playlist::SetSingle(player_control &pc, bool status)
|
||||||
bool status)
|
|
||||||
{
|
{
|
||||||
if (status == playlist->queue.single)
|
if (status == queue.single)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct queue *queue = &playlist->queue;
|
queue.single = status;
|
||||||
|
|
||||||
queue->single = status;
|
pc_set_border_pause(&pc, queue.single && !queue.repeat);
|
||||||
|
|
||||||
pc_set_border_pause(pc, queue->single && !queue->repeat);
|
|
||||||
|
|
||||||
/* if the last song is currently being played, the "next song"
|
/* if the last song is currently being played, the "next song"
|
||||||
might change when single mode is toggled */
|
might change when single mode is toggled */
|
||||||
playlist_update_queued_song(playlist, pc,
|
UpdateQueuedSong(pc, GetQueuedSong());
|
||||||
playlist_get_queued_song(playlist));
|
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_consume(struct playlist *playlist, bool status)
|
playlist::SetConsume(bool status)
|
||||||
{
|
{
|
||||||
if (status == playlist->queue.consume)
|
if (status == queue.consume)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
playlist->queue.consume = status;
|
queue.consume = status;
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_set_random(struct playlist *playlist, struct player_control *pc,
|
playlist::SetRandom(player_control &pc, bool status)
|
||||||
bool status)
|
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
if (status == queue.random)
|
||||||
|
|
||||||
if (status == playlist->queue.random)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
const struct song *const queued_song = GetQueuedSong();
|
||||||
|
|
||||||
playlist->queue.random = status;
|
queue.random = status;
|
||||||
|
|
||||||
if (playlist->queue.random) {
|
if (queue.random) {
|
||||||
/* shuffle the queue order, but preserve
|
/* shuffle the queue order, but preserve current */
|
||||||
playlist->current */
|
|
||||||
|
|
||||||
int current_position =
|
const int current_position = GetCurrentPosition();
|
||||||
playlist->playing && playlist->current >= 0
|
|
||||||
? (int)playlist->queue.OrderToPosition(playlist->current)
|
|
||||||
: -1;
|
|
||||||
|
|
||||||
playlist->queue.ShuffleOrder();
|
queue.ShuffleOrder();
|
||||||
|
|
||||||
if (current_position >= 0) {
|
if (current_position >= 0) {
|
||||||
/* make sure the current song is the first in
|
/* make sure the current song is the first in
|
||||||
the order list, so the whole rest of the
|
the order list, so the whole rest of the
|
||||||
playlist is played after that */
|
playlist is played after that */
|
||||||
unsigned current_order =
|
unsigned current_order =
|
||||||
playlist->queue.PositionToOrder(current_position);
|
queue.PositionToOrder(current_position);
|
||||||
playlist->queue.SwapOrders(0, current_order);
|
queue.SwapOrders(0, current_order);
|
||||||
playlist->current = 0;
|
current = 0;
|
||||||
} else
|
} else
|
||||||
playlist->current = -1;
|
current = -1;
|
||||||
} else
|
} else
|
||||||
playlist_order(playlist);
|
playlist_order(this);
|
||||||
|
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
|
|
||||||
idle_add(IDLE_OPTIONS);
|
idle_add(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
playlist_get_current_song(const struct playlist *playlist)
|
playlist::GetCurrentPosition() const
|
||||||
{
|
{
|
||||||
if (playlist->current >= 0)
|
return current >= 0
|
||||||
return playlist->queue.OrderToPosition(playlist->current);
|
? queue.OrderToPosition(current)
|
||||||
|
: -1;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
playlist_get_next_song(const struct playlist *playlist)
|
playlist::GetNextPosition() const
|
||||||
{
|
{
|
||||||
if (playlist->current >= 0)
|
if (current < 0)
|
||||||
{
|
return -1;
|
||||||
if (playlist->queue.single == 1 && playlist->queue.repeat == 1)
|
|
||||||
return playlist->queue.OrderToPosition(playlist->current);
|
if (queue.single && queue.repeat)
|
||||||
else if (playlist->current + 1 < (int)playlist->queue.GetLength())
|
return queue.OrderToPosition(current);
|
||||||
return playlist->queue.OrderToPosition(playlist->current + 1);
|
else if (queue.IsValidOrder(current + 1))
|
||||||
else if (playlist->queue.repeat == 1)
|
return queue.OrderToPosition(current + 1);
|
||||||
return playlist->queue.OrderToPosition(0);
|
else if (queue.repeat)
|
||||||
}
|
return queue.OrderToPosition(0);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
|
||||||
playlist_get_version(const struct playlist *playlist)
|
|
||||||
{
|
|
||||||
return playlist->queue.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
playlist_get_length(const struct playlist *playlist)
|
|
||||||
{
|
|
||||||
return playlist->queue.GetLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned
|
|
||||||
playlist_get_song_id(const struct playlist *playlist, unsigned song)
|
|
||||||
{
|
|
||||||
return playlist->queue.PositionToId(song);
|
|
||||||
}
|
|
||||||
|
339
src/Playlist.hxx
339
src/Playlist.hxx
@@ -75,176 +75,185 @@ struct playlist {
|
|||||||
|
|
||||||
~playlist() {
|
~playlist() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t GetVersion() const {
|
||||||
|
return queue.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned GetLength() const {
|
||||||
|
return queue.GetLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PositionToId(unsigned position) const {
|
||||||
|
return queue.PositionToId(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
int GetCurrentPosition() const;
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
int GetNextPosition() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the song object which is currently queued. Returns
|
||||||
|
* none if there is none (yet?) or if MPD isn't playing.
|
||||||
|
*/
|
||||||
|
gcc_pure
|
||||||
|
const struct song *GetQueuedSong() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 SyncWithPlayer(player_control &pc);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Called by all editing methods after a modification.
|
||||||
|
* Updates the queue version and emits #IDLE_PLAYLIST.
|
||||||
|
*/
|
||||||
|
void OnModified();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 UpdateQueuedSong(player_control &pc, const song *prev);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Clear(player_control &pc);
|
||||||
|
|
||||||
|
void TagChanged();
|
||||||
|
|
||||||
|
enum playlist_result AppendSong(player_control &pc,
|
||||||
|
struct song *song,
|
||||||
|
unsigned *added_id=nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a local file (outside the music database) to the
|
||||||
|
* playlist.
|
||||||
|
*
|
||||||
|
* Note: the caller is responsible for checking permissions.
|
||||||
|
*/
|
||||||
|
enum playlist_result AppendFile(player_control &pc,
|
||||||
|
const char *path_fs,
|
||||||
|
unsigned *added_id=nullptr);
|
||||||
|
|
||||||
|
enum playlist_result AppendURI(player_control &pc,
|
||||||
|
const char *uri_utf8,
|
||||||
|
unsigned *added_id=nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void DeleteInternal(player_control &pc,
|
||||||
|
unsigned song, const struct song **queued_p);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum playlist_result DeletePosition(player_control &pc,
|
||||||
|
unsigned position);
|
||||||
|
|
||||||
|
enum playlist_result DeleteOrder(player_control &pc,
|
||||||
|
unsigned order) {
|
||||||
|
return DeletePosition(pc, queue.OrderToPosition(order));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum playlist_result DeleteId(player_control &pc, unsigned id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 DeleteRange(player_control &pc,
|
||||||
|
unsigned start, unsigned end);
|
||||||
|
|
||||||
|
void DeleteSong(player_control &pc, const song &song);
|
||||||
|
|
||||||
|
void Shuffle(player_control &pc, unsigned start, unsigned end);
|
||||||
|
|
||||||
|
enum playlist_result MoveRange(player_control &pc,
|
||||||
|
unsigned start, unsigned end, int to);
|
||||||
|
|
||||||
|
enum playlist_result MoveId(player_control &pc, unsigned id, int to);
|
||||||
|
|
||||||
|
enum playlist_result SwapPositions(player_control &pc,
|
||||||
|
unsigned song1, unsigned song2);
|
||||||
|
|
||||||
|
enum playlist_result SwapIds(player_control &pc,
|
||||||
|
unsigned id1, unsigned id2);
|
||||||
|
|
||||||
|
enum playlist_result SetPriorityRange(player_control &pc,
|
||||||
|
unsigned start_position,
|
||||||
|
unsigned end_position,
|
||||||
|
uint8_t priority);
|
||||||
|
|
||||||
|
enum playlist_result SetPriorityId(player_control &pc,
|
||||||
|
unsigned song_id, uint8_t priority);
|
||||||
|
|
||||||
|
void Stop(player_control &pc);
|
||||||
|
|
||||||
|
enum playlist_result PlayPosition(player_control &pc, int position);
|
||||||
|
|
||||||
|
void PlayOrder(player_control &pc, int order);
|
||||||
|
|
||||||
|
enum playlist_result PlayId(player_control &pc, int id);
|
||||||
|
|
||||||
|
void PlayNext(player_control &pc);
|
||||||
|
|
||||||
|
void PlayPrevious(player_control &pc);
|
||||||
|
|
||||||
|
enum playlist_result SeekSongPosition(player_control &pc,
|
||||||
|
unsigned song_position,
|
||||||
|
float seek_time);
|
||||||
|
|
||||||
|
enum playlist_result SeekSongId(player_control &pc,
|
||||||
|
unsigned song_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 SeekCurrent(player_control &pc,
|
||||||
|
float seek_time, bool relative);
|
||||||
|
|
||||||
|
bool GetRepeat() const {
|
||||||
|
return queue.repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRepeat(player_control &pc, bool new_value);
|
||||||
|
|
||||||
|
bool GetRandom() const {
|
||||||
|
return queue.random;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRandom(player_control &pc, bool new_value);
|
||||||
|
|
||||||
|
bool GetSingle() const {
|
||||||
|
return queue.single;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSingle(player_control &pc, bool new_value);
|
||||||
|
|
||||||
|
bool GetConsume() const {
|
||||||
|
return queue.consume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetConsume(bool new_value);
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_global_init();
|
playlist_global_init();
|
||||||
|
|
||||||
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
|
void
|
||||||
playlist_increment_version_all(struct playlist *playlist);
|
playlist_increment_version_all(struct playlist *playlist);
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "PlaylistInternal.hxx"
|
#include "Playlist.hxx"
|
||||||
#include "PlayerControl.hxx"
|
#include "PlayerControl.hxx"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
|
|
||||||
@@ -33,244 +33,223 @@
|
|||||||
#define G_LOG_DOMAIN "playlist"
|
#define G_LOG_DOMAIN "playlist"
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_stop(struct playlist *playlist, struct player_control *pc)
|
playlist::Stop(player_control &pc)
|
||||||
{
|
{
|
||||||
if (!playlist->playing)
|
if (!playing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(playlist->current >= 0);
|
assert(current >= 0);
|
||||||
|
|
||||||
g_debug("stop");
|
g_debug("stop");
|
||||||
pc_stop(pc);
|
pc_stop(&pc);
|
||||||
playlist->queued = -1;
|
queued = -1;
|
||||||
playlist->playing = false;
|
playing = false;
|
||||||
|
|
||||||
if (playlist->queue.random) {
|
if (queue.random) {
|
||||||
/* shuffle the playlist, so the next playback will
|
/* shuffle the playlist, so the next playback will
|
||||||
result in a new random order */
|
result in a new random order */
|
||||||
|
|
||||||
unsigned current_position =
|
unsigned current_position = queue.OrderToPosition(current);
|
||||||
playlist->queue.OrderToPosition(playlist->current);
|
|
||||||
|
|
||||||
playlist->queue.ShuffleOrder();
|
queue.ShuffleOrder();
|
||||||
|
|
||||||
/* make sure that "current" stays valid, and the next
|
/* make sure that "current" stays valid, and the next
|
||||||
"play" command plays the same song again */
|
"play" command plays the same song again */
|
||||||
playlist->current =
|
current = queue.PositionToOrder(current_position);
|
||||||
playlist->queue.PositionToOrder(current_position);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_play(struct playlist *playlist, struct player_control *pc,
|
playlist::PlayPosition(player_control &pc, int song)
|
||||||
int song)
|
|
||||||
{
|
{
|
||||||
|
pc_clear_error(&pc);
|
||||||
|
|
||||||
unsigned i = song;
|
unsigned i = song;
|
||||||
|
|
||||||
pc_clear_error(pc);
|
|
||||||
|
|
||||||
if (song == -1) {
|
if (song == -1) {
|
||||||
/* play any song ("current" song, or the first song */
|
/* play any song ("current" song, or the first song */
|
||||||
|
|
||||||
if (playlist->queue.IsEmpty())
|
if (queue.IsEmpty())
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
|
|
||||||
if (playlist->playing) {
|
if (playing) {
|
||||||
/* already playing: unpause playback, just in
|
/* already playing: unpause playback, just in
|
||||||
case it was paused, and return */
|
case it was paused, and return */
|
||||||
pc_set_pause(pc, false);
|
pc_set_pause(&pc, false);
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* select a song: "current" song, or the first one */
|
/* select a song: "current" song, or the first one */
|
||||||
i = playlist->current >= 0
|
i = current >= 0
|
||||||
? playlist->current
|
? current
|
||||||
: 0;
|
: 0;
|
||||||
} else if (!playlist->queue.IsValidPosition(song))
|
} else if (!queue.IsValidPosition(song))
|
||||||
return PLAYLIST_RESULT_BAD_RANGE;
|
return PLAYLIST_RESULT_BAD_RANGE;
|
||||||
|
|
||||||
if (playlist->queue.random) {
|
if (queue.random) {
|
||||||
if (song >= 0)
|
if (song >= 0)
|
||||||
/* "i" is currently the song position (which
|
/* "i" is currently the song position (which
|
||||||
would be equal to the order number in
|
would be equal to the order number in
|
||||||
no-random mode); convert it to a order
|
no-random mode); convert it to a order
|
||||||
number, because random mode is enabled */
|
number, because random mode is enabled */
|
||||||
i = playlist->queue.PositionToOrder(song);
|
i = queue.PositionToOrder(song);
|
||||||
|
|
||||||
if (!playlist->playing)
|
if (!playing)
|
||||||
playlist->current = 0;
|
current = 0;
|
||||||
|
|
||||||
/* swap the new song with the previous "current" one,
|
/* swap the new song with the previous "current" one,
|
||||||
so playback continues as planned */
|
so playback continues as planned */
|
||||||
playlist->queue.SwapOrders(i, playlist->current);
|
queue.SwapOrders(i, current);
|
||||||
i = playlist->current;
|
i = current;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist->stop_on_error = false;
|
stop_on_error = false;
|
||||||
playlist->error_count = 0;
|
error_count = 0;
|
||||||
|
|
||||||
playlist_play_order(playlist, pc, i);
|
PlayOrder(pc, i);
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_play_id(struct playlist *playlist, struct player_control *pc,
|
playlist::PlayId(player_control &pc, int id)
|
||||||
int id)
|
|
||||||
{
|
{
|
||||||
int song;
|
if (id == -1)
|
||||||
|
return PlayPosition(pc, id);
|
||||||
|
|
||||||
if (id == -1) {
|
int song = queue.IdToPosition(id);
|
||||||
return playlist_play(playlist, pc, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
song = playlist->queue.IdToPosition(id);
|
|
||||||
if (song < 0)
|
if (song < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_play(playlist, pc, song);
|
return PlayPosition(pc, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_next(struct playlist *playlist, struct player_control *pc)
|
playlist::PlayNext(player_control &pc)
|
||||||
{
|
{
|
||||||
int next_order;
|
if (!playing)
|
||||||
int current;
|
|
||||||
|
|
||||||
if (!playlist->playing)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(!playlist->queue.IsEmpty());
|
assert(!queue.IsEmpty());
|
||||||
assert(playlist->queue.IsValidOrder(playlist->current));
|
assert(queue.IsValidOrder(current));
|
||||||
|
|
||||||
current = playlist->current;
|
const int old_current = current;
|
||||||
playlist->stop_on_error = false;
|
stop_on_error = false;
|
||||||
|
|
||||||
/* determine the next song from the queue's order list */
|
/* determine the next song from the queue's order list */
|
||||||
|
|
||||||
next_order = playlist->queue.GetNextOrder(playlist->current);
|
const int next_order = queue.GetNextOrder(current);
|
||||||
if (next_order < 0) {
|
if (next_order < 0) {
|
||||||
/* no song after this one: stop playback */
|
/* no song after this one: stop playback */
|
||||||
playlist_stop(playlist, pc);
|
Stop(pc);
|
||||||
|
|
||||||
/* reset "current song" */
|
/* reset "current song" */
|
||||||
playlist->current = -1;
|
current = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (next_order == 0 && playlist->queue.random) {
|
if (next_order == 0 && queue.random) {
|
||||||
/* The queue told us that the next song is the first
|
/* The queue told us that the next song is the first
|
||||||
song. This means we are in repeat mode. Shuffle
|
song. This means we are in repeat mode. Shuffle
|
||||||
the queue order, so this time, the user hears the
|
the queue order, so this time, the user hears the
|
||||||
songs in a different than before */
|
songs in a different than before */
|
||||||
assert(playlist->queue.repeat);
|
assert(queue.repeat);
|
||||||
|
|
||||||
playlist->queue.ShuffleOrder();
|
queue.ShuffleOrder();
|
||||||
|
|
||||||
/* note that playlist->current and playlist->queued are
|
/* note that current and queued are
|
||||||
now invalid, but playlist_play_order() will
|
now invalid, but playlist_play_order() will
|
||||||
discard them anyway */
|
discard them anyway */
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_play_order(playlist, pc, next_order);
|
PlayOrder(pc, next_order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Consume mode removes each played songs. */
|
/* Consume mode removes each played songs. */
|
||||||
if(playlist->queue.consume)
|
if (queue.consume)
|
||||||
playlist_delete(playlist, pc,
|
DeleteOrder(pc, old_current);
|
||||||
playlist->queue.OrderToPosition(current));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_previous(struct playlist *playlist, struct player_control *pc)
|
playlist::PlayPrevious(player_control &pc)
|
||||||
{
|
{
|
||||||
if (!playlist->playing)
|
if (!playing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(playlist->queue.GetLength() > 0);
|
assert(!queue.IsEmpty());
|
||||||
|
|
||||||
if (playlist->current > 0) {
|
int order;
|
||||||
|
if (current > 0) {
|
||||||
/* play the preceding song */
|
/* play the preceding song */
|
||||||
playlist_play_order(playlist, pc,
|
order = current - 1;
|
||||||
playlist->current - 1);
|
} else if (queue.repeat) {
|
||||||
} else if (playlist->queue.repeat) {
|
|
||||||
/* play the last song in "repeat" mode */
|
/* play the last song in "repeat" mode */
|
||||||
playlist_play_order(playlist, pc,
|
order = queue.GetLength() - 1;
|
||||||
playlist->queue.GetLength() - 1);
|
|
||||||
} else {
|
} else {
|
||||||
/* re-start playing the current song if it's
|
/* re-start playing the current song if it's
|
||||||
the first one */
|
the first one */
|
||||||
playlist_play_order(playlist, pc, playlist->current);
|
order = current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayOrder(pc, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_seek_song(struct playlist *playlist, struct player_control *pc,
|
playlist::SeekSongPosition(player_control &pc, unsigned song, float seek_time)
|
||||||
unsigned song, float seek_time)
|
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
if (!queue.IsValidPosition(song))
|
||||||
unsigned i;
|
|
||||||
bool success;
|
|
||||||
|
|
||||||
if (!playlist->queue.IsValidPosition(song))
|
|
||||||
return PLAYLIST_RESULT_BAD_RANGE;
|
return PLAYLIST_RESULT_BAD_RANGE;
|
||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
const struct song *queued_song = GetQueuedSong();
|
||||||
|
|
||||||
if (playlist->queue.random)
|
unsigned i = queue.random
|
||||||
i = playlist->queue.PositionToOrder(song);
|
? queue.PositionToOrder(song)
|
||||||
else
|
: song;
|
||||||
i = song;
|
|
||||||
|
|
||||||
pc_clear_error(pc);
|
pc_clear_error(&pc);
|
||||||
playlist->stop_on_error = true;
|
stop_on_error = true;
|
||||||
playlist->error_count = 0;
|
error_count = 0;
|
||||||
|
|
||||||
if (!playlist->playing || (unsigned)playlist->current != i) {
|
if (!playing || (unsigned)current != i) {
|
||||||
/* seeking is not within the current song - prepare
|
/* seeking is not within the current song - prepare
|
||||||
song change */
|
song change */
|
||||||
|
|
||||||
playlist->playing = true;
|
playing = true;
|
||||||
playlist->current = i;
|
current = i;
|
||||||
|
|
||||||
queued = NULL;
|
queued_song = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct song *the_song =
|
struct song *the_song = song_dup_detached(queue.GetOrder(i));
|
||||||
song_dup_detached(playlist->queue.GetOrder(i));
|
if (!pc_seek(&pc, the_song, seek_time)) {
|
||||||
success = pc_seek(pc, the_song, seek_time);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
if (!success) {
|
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
|
||||||
|
|
||||||
return PLAYLIST_RESULT_NOT_PLAYING;
|
return PLAYLIST_RESULT_NOT_PLAYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist->queued = -1;
|
queued = -1;
|
||||||
playlist_update_queued_song(playlist, pc, NULL);
|
UpdateQueuedSong(pc, NULL);
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_seek_song_id(struct playlist *playlist, struct player_control *pc,
|
playlist::SeekSongId(player_control &pc, unsigned id, float seek_time)
|
||||||
unsigned id, float seek_time)
|
|
||||||
{
|
{
|
||||||
int song = playlist->queue.IdToPosition(id);
|
int song = queue.IdToPosition(id);
|
||||||
if (song < 0)
|
if (song < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_seek_song(playlist, pc, song, seek_time);
|
return SeekSongPosition(pc, song, seek_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_seek_current(struct playlist *playlist, struct player_control *pc,
|
playlist::SeekCurrent(player_control &pc, float seek_time, bool relative)
|
||||||
float seek_time, bool relative)
|
|
||||||
{
|
{
|
||||||
if (!playlist->playing)
|
if (!playing)
|
||||||
return PLAYLIST_RESULT_NOT_PLAYING;
|
return PLAYLIST_RESULT_NOT_PLAYING;
|
||||||
|
|
||||||
if (relative) {
|
if (relative) {
|
||||||
struct player_status status;
|
struct player_status status;
|
||||||
pc_get_status(pc, &status);
|
pc_get_status(&pc, &status);
|
||||||
|
|
||||||
if (status.state != PLAYER_STATE_PLAY &&
|
if (status.state != PLAYER_STATE_PLAY &&
|
||||||
status.state != PLAYER_STATE_PAUSE)
|
status.state != PLAYER_STATE_PAUSE)
|
||||||
@@ -282,5 +261,5 @@ playlist_seek_current(struct playlist *playlist, struct player_control *pc,
|
|||||||
if (seek_time < 0)
|
if (seek_time < 0)
|
||||||
seek_time = 0;
|
seek_time = 0;
|
||||||
|
|
||||||
return playlist_seek_song(playlist, pc, playlist->current, seek_time);
|
return SeekSongPosition(pc, current, seek_time);
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "PlaylistInternal.hxx"
|
#include "Playlist.hxx"
|
||||||
#include "PlayerControl.hxx"
|
#include "PlayerControl.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -38,67 +38,64 @@ extern "C" {
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static void playlist_increment_version(struct playlist *playlist)
|
void
|
||||||
|
playlist::OnModified()
|
||||||
{
|
{
|
||||||
playlist->queue.IncrementVersion();
|
queue.IncrementVersion();
|
||||||
|
|
||||||
idle_add(IDLE_PLAYLIST);
|
idle_add(IDLE_PLAYLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_clear(struct playlist *playlist, struct player_control *pc)
|
playlist::Clear(player_control &pc)
|
||||||
{
|
{
|
||||||
playlist_stop(playlist, pc);
|
Stop(pc);
|
||||||
|
|
||||||
playlist->queue.Clear();
|
queue.Clear();
|
||||||
|
current = -1;
|
||||||
|
|
||||||
playlist->current = -1;
|
OnModified();
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_file(struct playlist *playlist, struct player_control *pc,
|
playlist::AppendFile(struct player_control &pc,
|
||||||
const char *path_fs, unsigned *added_id)
|
const char *path_fs, unsigned *added_id)
|
||||||
{
|
{
|
||||||
struct song *song = song_file_load(path_fs, NULL);
|
struct song *song = song_file_load(path_fs, NULL);
|
||||||
if (song == NULL)
|
if (song == NULL)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_append_song(playlist, pc, song, added_id);
|
return AppendSong(pc, song, added_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_song(struct playlist *playlist, struct player_control *pc,
|
playlist::AppendSong(struct player_control &pc,
|
||||||
struct song *song, unsigned *added_id)
|
struct song *song, unsigned *added_id)
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
|
||||||
unsigned id;
|
unsigned id;
|
||||||
|
|
||||||
if (playlist->queue.IsFull())
|
if (queue.IsFull())
|
||||||
return PLAYLIST_RESULT_TOO_LARGE;
|
return PLAYLIST_RESULT_TOO_LARGE;
|
||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
const struct song *const queued_song = GetQueuedSong();
|
||||||
|
|
||||||
id = playlist->queue.Append(song, 0);
|
id = queue.Append(song, 0);
|
||||||
|
|
||||||
if (playlist->queue.random) {
|
if (queue.random) {
|
||||||
/* shuffle the new song into the list of remaining
|
/* shuffle the new song into the list of remaining
|
||||||
songs to play */
|
songs to play */
|
||||||
|
|
||||||
unsigned start;
|
unsigned start;
|
||||||
if (playlist->queued >= 0)
|
if (queued >= 0)
|
||||||
start = playlist->queued + 1;
|
start = queued + 1;
|
||||||
else
|
else
|
||||||
start = playlist->current + 1;
|
start = current + 1;
|
||||||
if (start < playlist->queue.GetLength())
|
if (start < queue.GetLength())
|
||||||
playlist->queue.ShuffleOrderLast(start,
|
queue.ShuffleOrderLast(start, queue.GetLength());
|
||||||
playlist->queue.GetLength());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
|
OnModified();
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
|
||||||
|
|
||||||
if (added_id)
|
if (added_id)
|
||||||
*added_id = id;
|
*added_id = id;
|
||||||
@@ -107,7 +104,7 @@ playlist_append_song(struct playlist *playlist, struct player_control *pc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_append_uri(struct playlist *playlist, struct player_control *pc,
|
playlist::AppendURI(struct player_control &pc,
|
||||||
const char *uri, unsigned *added_id)
|
const char *uri, unsigned *added_id)
|
||||||
{
|
{
|
||||||
g_debug("add to playlist: %s", uri);
|
g_debug("add to playlist: %s", uri);
|
||||||
@@ -126,8 +123,7 @@ playlist_append_uri(struct playlist *playlist, struct player_control *pc,
|
|||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result result =
|
enum playlist_result result = AppendSong(pc, song, added_id);
|
||||||
playlist_append_song(playlist, pc, song, added_id);
|
|
||||||
if (db != nullptr)
|
if (db != nullptr)
|
||||||
db->ReturnSong(song);
|
db->ReturnSong(song);
|
||||||
|
|
||||||
@@ -135,335 +131,293 @@ playlist_append_uri(struct playlist *playlist, struct player_control *pc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
|
playlist::SwapPositions(player_control &pc, unsigned song1, unsigned song2)
|
||||||
unsigned song1, unsigned song2)
|
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
if (!queue.IsValidPosition(song1) || !queue.IsValidPosition(song2))
|
||||||
|
|
||||||
if (!playlist->queue.IsValidPosition(song1) ||
|
|
||||||
!playlist->queue.IsValidPosition(song2))
|
|
||||||
return PLAYLIST_RESULT_BAD_RANGE;
|
return PLAYLIST_RESULT_BAD_RANGE;
|
||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
const struct song *const queued_song = GetQueuedSong();
|
||||||
|
|
||||||
playlist->queue.SwapPositions(song1, song2);
|
queue.SwapPositions(song1, song2);
|
||||||
|
|
||||||
if (playlist->queue.random) {
|
if (queue.random) {
|
||||||
/* update the queue order, so that playlist->current
|
/* update the queue order, so that current
|
||||||
still points to the current song order */
|
still points to the current song order */
|
||||||
|
|
||||||
playlist->queue.SwapOrders(playlist->queue.PositionToOrder(song1),
|
queue.SwapOrders(queue.PositionToOrder(song1),
|
||||||
playlist->queue.PositionToOrder(song2));
|
queue.PositionToOrder(song2));
|
||||||
} else {
|
} else {
|
||||||
/* correct the "current" song order */
|
/* correct the "current" song order */
|
||||||
|
|
||||||
if (playlist->current == (int)song1)
|
if (current == (int)song1)
|
||||||
playlist->current = song2;
|
current = song2;
|
||||||
else if (playlist->current == (int)song2)
|
else if (current == (int)song2)
|
||||||
playlist->current = song1;
|
current = song1;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
|
OnModified();
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc,
|
playlist::SwapIds(player_control &pc, unsigned id1, unsigned id2)
|
||||||
unsigned id1, unsigned id2)
|
|
||||||
{
|
{
|
||||||
int song1 = playlist->queue.IdToPosition(id1);
|
int song1 = queue.IdToPosition(id1);
|
||||||
int song2 = playlist->queue.IdToPosition(id2);
|
int song2 = queue.IdToPosition(id2);
|
||||||
|
|
||||||
if (song1 < 0 || song2 < 0)
|
if (song1 < 0 || song2 < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_swap_songs(playlist, pc, song1, song2);
|
return SwapPositions(pc, song1, song2);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_set_priority(struct playlist *playlist, struct player_control *pc,
|
playlist::SetPriorityRange(player_control &pc,
|
||||||
unsigned start, unsigned end,
|
unsigned start, unsigned end,
|
||||||
uint8_t priority)
|
uint8_t priority)
|
||||||
{
|
{
|
||||||
if (start >= playlist->queue.GetLength())
|
if (start >= GetLength())
|
||||||
return PLAYLIST_RESULT_BAD_RANGE;
|
return PLAYLIST_RESULT_BAD_RANGE;
|
||||||
|
|
||||||
if (end > playlist->queue.GetLength())
|
if (end > GetLength())
|
||||||
end = playlist->queue.GetLength();
|
end = GetLength();
|
||||||
|
|
||||||
if (start >= end)
|
if (start >= end)
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
|
|
||||||
/* remember "current" and "queued" */
|
/* remember "current" and "queued" */
|
||||||
|
|
||||||
int current_position = playlist->current >= 0
|
const int current_position = GetCurrentPosition();
|
||||||
? (int)playlist->queue.OrderToPosition(playlist->current)
|
const struct song *const queued_song = GetQueuedSong();
|
||||||
: -1;
|
|
||||||
|
|
||||||
const struct song *queued = playlist_get_queued_song(playlist);
|
|
||||||
|
|
||||||
/* apply the priority changes */
|
/* apply the priority changes */
|
||||||
|
|
||||||
playlist->queue.SetPriorityRange(start, end, priority,
|
queue.SetPriorityRange(start, end, priority, current);
|
||||||
playlist->current);
|
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
|
||||||
|
|
||||||
/* restore "current" and choose a new "queued" */
|
/* restore "current" and choose a new "queued" */
|
||||||
|
|
||||||
if (current_position >= 0)
|
if (current_position >= 0)
|
||||||
playlist->current = playlist->queue.PositionToOrder(current_position);
|
current = queue.PositionToOrder(current_position);
|
||||||
|
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
|
OnModified();
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_set_priority_id(struct playlist *playlist, struct player_control *pc,
|
playlist::SetPriorityId(struct player_control &pc,
|
||||||
unsigned song_id, uint8_t priority)
|
unsigned song_id, uint8_t priority)
|
||||||
{
|
{
|
||||||
int song_position = playlist->queue.IdToPosition(song_id);
|
int song_position = queue.IdToPosition(song_id);
|
||||||
if (song_position < 0)
|
if (song_position < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_set_priority(playlist, pc,
|
return SetPriorityRange(pc, song_position, song_position + 1,
|
||||||
song_position, song_position + 1,
|
priority);
|
||||||
priority);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
playlist_delete_internal(struct playlist *playlist, struct player_control *pc,
|
playlist::DeleteInternal(player_control &pc,
|
||||||
unsigned song, const struct song **queued_p)
|
unsigned song, const struct song **queued_p)
|
||||||
{
|
{
|
||||||
unsigned songOrder;
|
assert(song < GetLength());
|
||||||
|
|
||||||
assert(song < playlist->queue.GetLength());
|
unsigned songOrder = queue.PositionToOrder(song);
|
||||||
|
|
||||||
songOrder = playlist->queue.PositionToOrder(song);
|
if (playing && current == (int)songOrder) {
|
||||||
|
bool paused = pc_get_state(&pc) == PLAYER_STATE_PAUSE;
|
||||||
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 */
|
/* the current song is going to be deleted: stop the player */
|
||||||
|
|
||||||
pc_stop(pc);
|
pc_stop(&pc);
|
||||||
playlist->playing = false;
|
playing = false;
|
||||||
|
|
||||||
/* see which song is going to be played instead */
|
/* see which song is going to be played instead */
|
||||||
|
|
||||||
playlist->current = playlist->queue.GetNextOrder(playlist->current);
|
current = queue.GetNextOrder(current);
|
||||||
if (playlist->current == (int)songOrder)
|
if (current == (int)songOrder)
|
||||||
playlist->current = -1;
|
current = -1;
|
||||||
|
|
||||||
if (playlist->current >= 0 && !paused)
|
if (current >= 0 && !paused)
|
||||||
/* play the song after the deleted one */
|
/* play the song after the deleted one */
|
||||||
playlist_play_order(playlist, pc, playlist->current);
|
PlayOrder(pc, current);
|
||||||
else
|
else
|
||||||
/* no songs left to play, stop playback
|
/* no songs left to play, stop playback
|
||||||
completely */
|
completely */
|
||||||
playlist_stop(playlist, pc);
|
Stop(pc);
|
||||||
|
|
||||||
*queued_p = NULL;
|
*queued_p = NULL;
|
||||||
} else if (playlist->current == (int)songOrder)
|
} else if (current == (int)songOrder)
|
||||||
/* there's a "current song" but we're not playing
|
/* there's a "current song" but we're not playing
|
||||||
currently - clear "current" */
|
currently - clear "current" */
|
||||||
playlist->current = -1;
|
current = -1;
|
||||||
|
|
||||||
/* now do it: remove the song */
|
/* now do it: remove the song */
|
||||||
|
|
||||||
playlist->queue.DeletePosition(song);
|
queue.DeletePosition(song);
|
||||||
|
|
||||||
/* update the "current" and "queued" variables */
|
/* update the "current" and "queued" variables */
|
||||||
|
|
||||||
if (playlist->current > (int)songOrder) {
|
if (current > (int)songOrder)
|
||||||
playlist->current--;
|
current--;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete(struct playlist *playlist, struct player_control *pc,
|
playlist::DeletePosition(struct player_control &pc, unsigned song)
|
||||||
unsigned song)
|
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
if (song >= queue.GetLength())
|
||||||
|
|
||||||
if (song >= playlist->queue.GetLength())
|
|
||||||
return PLAYLIST_RESULT_BAD_RANGE;
|
return PLAYLIST_RESULT_BAD_RANGE;
|
||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
const struct song *queued_song = GetQueuedSong();
|
||||||
|
|
||||||
playlist_delete_internal(playlist, pc, song, &queued);
|
DeleteInternal(pc, song, &queued_song);
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
OnModified();
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete_range(struct playlist *playlist, struct player_control *pc,
|
playlist::DeleteRange(struct player_control &pc, unsigned start, unsigned end)
|
||||||
unsigned start, unsigned end)
|
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
if (start >= queue.GetLength())
|
||||||
|
|
||||||
if (start >= playlist->queue.GetLength())
|
|
||||||
return PLAYLIST_RESULT_BAD_RANGE;
|
return PLAYLIST_RESULT_BAD_RANGE;
|
||||||
|
|
||||||
if (end > playlist->queue.GetLength())
|
if (end > queue.GetLength())
|
||||||
end = playlist->queue.GetLength();
|
end = queue.GetLength();
|
||||||
|
|
||||||
if (start >= end)
|
if (start >= end)
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
const struct song *queued_song = GetQueuedSong();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
playlist_delete_internal(playlist, pc, --end, &queued);
|
DeleteInternal(pc, --end, &queued_song);
|
||||||
} while (end != start);
|
} while (end != start);
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
OnModified();
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_delete_id(struct playlist *playlist, struct player_control *pc,
|
playlist::DeleteId(struct player_control &pc, unsigned id)
|
||||||
unsigned id)
|
|
||||||
{
|
{
|
||||||
int song = playlist->queue.IdToPosition(id);
|
int song = queue.IdToPosition(id);
|
||||||
if (song < 0)
|
if (song < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_delete(playlist, pc, song);
|
return DeletePosition(pc, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_delete_song(struct playlist *playlist, struct player_control *pc,
|
playlist::DeleteSong(struct player_control &pc, const struct song &song)
|
||||||
const struct song *song)
|
|
||||||
{
|
{
|
||||||
for (int i = playlist->queue.GetLength() - 1; i >= 0; --i)
|
for (int i = queue.GetLength() - 1; i >= 0; --i)
|
||||||
if (song == playlist->queue.Get(i))
|
// TODO: compare URI instead of pointer
|
||||||
playlist_delete(playlist, pc, i);
|
if (&song == queue.Get(i))
|
||||||
|
DeletePosition(pc, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_move_range(struct playlist *playlist, struct player_control *pc,
|
playlist::MoveRange(player_control &pc, unsigned start, unsigned end, int to)
|
||||||
unsigned start, unsigned end, int to)
|
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
if (!queue.IsValidPosition(start) || !queue.IsValidPosition(end - 1))
|
||||||
int currentSong;
|
|
||||||
|
|
||||||
if (!playlist->queue.IsValidPosition(start) ||
|
|
||||||
!playlist->queue.IsValidPosition(end - 1))
|
|
||||||
return PLAYLIST_RESULT_BAD_RANGE;
|
return PLAYLIST_RESULT_BAD_RANGE;
|
||||||
|
|
||||||
if ((to >= 0 && to + end - start - 1 >= playlist->queue.GetLength()) ||
|
if ((to >= 0 && to + end - start - 1 >= GetLength()) ||
|
||||||
(to < 0 && abs(to) > (int)playlist->queue.GetLength()))
|
(to < 0 && unsigned(abs(to)) > GetLength()))
|
||||||
return PLAYLIST_RESULT_BAD_RANGE;
|
return PLAYLIST_RESULT_BAD_RANGE;
|
||||||
|
|
||||||
if ((int)start == to)
|
if ((int)start == to)
|
||||||
/* nothing happens */
|
/* nothing happens */
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
const struct song *const queued_song = GetQueuedSong();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (to < 0) => move to offset from current song
|
* (to < 0) => move to offset from current song
|
||||||
* (-playlist.length == to) => move to position BEFORE current song
|
* (-playlist.length == to) => move to position BEFORE current song
|
||||||
*/
|
*/
|
||||||
currentSong = playlist->current >= 0
|
const int currentSong = GetCurrentPosition();
|
||||||
? (int)playlist->queue.OrderToPosition(playlist->current)
|
if (to < 0 && currentSong >= 0) {
|
||||||
: -1;
|
|
||||||
if (to < 0 && playlist->current >= 0) {
|
|
||||||
if (start <= (unsigned)currentSong && (unsigned)currentSong < end)
|
if (start <= (unsigned)currentSong && (unsigned)currentSong < end)
|
||||||
/* no-op, can't be moved to offset of itself */
|
/* no-op, can't be moved to offset of itself */
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
to = (currentSong + abs(to)) % playlist->queue.GetLength();
|
to = (currentSong + abs(to)) % GetLength();
|
||||||
if (start < (unsigned)to)
|
if (start < (unsigned)to)
|
||||||
to--;
|
to--;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist->queue.MoveRange(start, end, to);
|
queue.MoveRange(start, end, to);
|
||||||
|
|
||||||
if (!playlist->queue.random) {
|
if (!queue.random) {
|
||||||
/* update current/queued */
|
/* update current/queued */
|
||||||
if ((int)start <= playlist->current &&
|
if ((int)start <= current && (unsigned)current < end)
|
||||||
(unsigned)playlist->current < end)
|
current += to - start;
|
||||||
playlist->current += to - start;
|
else if (current >= (int)end && current <= to)
|
||||||
else if (playlist->current >= (int)end &&
|
current -= end - start;
|
||||||
playlist->current <= to) {
|
else if (current >= to && current < (int)start)
|
||||||
playlist->current -= end - start;
|
current += end - start;
|
||||||
} else if (playlist->current >= to &&
|
|
||||||
playlist->current < (int)start) {
|
|
||||||
playlist->current += end - start;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
|
OnModified();
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
|
||||||
|
|
||||||
return PLAYLIST_RESULT_SUCCESS;
|
return PLAYLIST_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum playlist_result
|
enum playlist_result
|
||||||
playlist_move_id(struct playlist *playlist, struct player_control *pc,
|
playlist::MoveId(player_control &pc, unsigned id1, int to)
|
||||||
unsigned id1, int to)
|
|
||||||
{
|
{
|
||||||
int song = playlist->queue.IdToPosition(id1);
|
int song = queue.IdToPosition(id1);
|
||||||
if (song < 0)
|
if (song < 0)
|
||||||
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
||||||
|
|
||||||
return playlist_move_range(playlist, pc, song, song+1, to);
|
return MoveRange(pc, song, song + 1, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_shuffle(struct playlist *playlist, struct player_control *pc,
|
playlist::Shuffle(player_control &pc, unsigned start, unsigned end)
|
||||||
unsigned start, unsigned end)
|
|
||||||
{
|
{
|
||||||
const struct song *queued;
|
if (end > GetLength())
|
||||||
|
|
||||||
if (end > playlist->queue.GetLength())
|
|
||||||
/* correct the "end" offset */
|
/* correct the "end" offset */
|
||||||
end = playlist->queue.GetLength();
|
end = GetLength();
|
||||||
|
|
||||||
if ((start+1) >= end)
|
if (start + 1 >= end)
|
||||||
/* needs at least two entries. */
|
/* needs at least two entries. */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
const struct song *const queued_song = GetQueuedSong();
|
||||||
if (playlist->playing && playlist->current >= 0) {
|
if (playing && current >= 0) {
|
||||||
unsigned current_position;
|
unsigned current_position = queue.OrderToPosition(current);
|
||||||
current_position = playlist->queue.OrderToPosition(playlist->current);
|
|
||||||
|
|
||||||
if (current_position >= start && current_position < end)
|
if (current_position >= start && current_position < end) {
|
||||||
{
|
|
||||||
/* put current playing song first */
|
/* put current playing song first */
|
||||||
playlist->queue.SwapPositions(start, current_position);
|
queue.SwapPositions(start, current_position);
|
||||||
|
|
||||||
if (playlist->queue.random) {
|
if (queue.random) {
|
||||||
playlist->current =
|
current = queue.PositionToOrder(start);
|
||||||
playlist->queue.PositionToOrder(start);
|
|
||||||
} else
|
} else
|
||||||
playlist->current = start;
|
current = start;
|
||||||
|
|
||||||
/* start shuffle after the current song */
|
/* start shuffle after the current song */
|
||||||
start++;
|
start++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* no playback currently: reset playlist->current */
|
/* no playback currently: reset current */
|
||||||
|
|
||||||
playlist->current = -1;
|
current = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist->queue.ShuffleRange(start, end);
|
queue.ShuffleRange(start, end);
|
||||||
|
|
||||||
playlist_increment_version(playlist);
|
UpdateQueuedSong(pc, queued_song);
|
||||||
|
OnModified();
|
||||||
playlist_update_queued_song(playlist, pc, queued);
|
|
||||||
}
|
}
|
||||||
|
@@ -34,14 +34,13 @@ extern "C" {
|
|||||||
static void
|
static void
|
||||||
playlist_tag_event(void)
|
playlist_tag_event(void)
|
||||||
{
|
{
|
||||||
playlist_tag_changed(&global_partition->playlist);
|
global_partition->playlist.TagChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
playlist_event(void)
|
playlist_event(void)
|
||||||
{
|
{
|
||||||
playlist_sync(&global_partition->playlist,
|
global_partition->playlist.SyncWithPlayer(global_partition->pc);
|
||||||
&global_partition->pc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Internal header for the components of the playlist code.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MPD_PLAYLIST_INTERNAL_HXX
|
|
||||||
#define MPD_PLAYLIST_INTERNAL_HXX
|
|
||||||
|
|
||||||
#include "Playlist.hxx"
|
|
||||||
|
|
||||||
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
|
|
@@ -80,8 +80,7 @@ playlist_print_id(Client *client, const struct playlist *playlist,
|
|||||||
bool
|
bool
|
||||||
playlist_print_current(Client *client, const struct playlist *playlist)
|
playlist_print_current(Client *client, const struct playlist *playlist)
|
||||||
{
|
{
|
||||||
int current_position = playlist_get_current_song(playlist);
|
int current_position = playlist->GetCurrentPosition();
|
||||||
|
|
||||||
if (current_position < 0)
|
if (current_position < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source,
|
|||||||
if (song == NULL)
|
if (song == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result = playlist_append_song(dest, pc, song, NULL);
|
result = dest->AppendSong(*pc, song);
|
||||||
song_free(song);
|
song_free(song);
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS) {
|
if (result != PLAYLIST_RESULT_SUCCESS) {
|
||||||
g_free(base_uri);
|
g_free(base_uri);
|
||||||
|
@@ -132,8 +132,7 @@ playlist_load_spl(struct playlist *playlist, struct player_control *pc,
|
|||||||
for (unsigned i = start_index; i < end_index; ++i) {
|
for (unsigned i = start_index; i < end_index; ++i) {
|
||||||
const auto &uri_utf8 = contents[i];
|
const auto &uri_utf8 = contents[i];
|
||||||
|
|
||||||
if ((playlist_append_uri(playlist, pc, uri_utf8.c_str(),
|
if ((playlist->AppendURI(*pc, uri_utf8.c_str())) != PLAYLIST_RESULT_SUCCESS) {
|
||||||
nullptr)) != PLAYLIST_RESULT_SUCCESS) {
|
|
||||||
/* for windows compatibility, convert slashes */
|
/* for windows compatibility, convert slashes */
|
||||||
char *temp2 = g_strdup(uri_utf8.c_str());
|
char *temp2 = g_strdup(uri_utf8.c_str());
|
||||||
char *p = temp2;
|
char *p = temp2;
|
||||||
@@ -142,9 +141,10 @@ playlist_load_spl(struct playlist *playlist, struct player_control *pc,
|
|||||||
*p = '/';
|
*p = '/';
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
if ((playlist_append_uri(playlist, pc, temp2, NULL)) != PLAYLIST_RESULT_SUCCESS) {
|
|
||||||
|
if (playlist->AppendURI(*pc, temp2) != PLAYLIST_RESULT_SUCCESS)
|
||||||
g_warning("can't add file \"%s\"", temp2);
|
g_warning("can't add file \"%s\"", temp2);
|
||||||
}
|
|
||||||
g_free(temp2);
|
g_free(temp2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -145,26 +145,16 @@ playlist_state_restore(const char *line, TextFile &file,
|
|||||||
seek_time =
|
seek_time =
|
||||||
atoi(&(line[strlen(PLAYLIST_STATE_FILE_TIME)]));
|
atoi(&(line[strlen(PLAYLIST_STATE_FILE_TIME)]));
|
||||||
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_REPEAT)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_REPEAT)) {
|
||||||
if (strcmp
|
playlist->SetRepeat(*pc,
|
||||||
(&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
|
strcmp(&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
|
||||||
"1") == 0) {
|
"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)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) {
|
||||||
if (strcmp
|
playlist->SetSingle(*pc,
|
||||||
(&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]),
|
strcmp(&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]),
|
||||||
"1") == 0) {
|
"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)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) {
|
||||||
if (strcmp
|
playlist->SetConsume(strcmp(&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]),
|
||||||
(&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]),
|
"1") == 0);
|
||||||
"1") == 0) {
|
|
||||||
playlist_set_consume(playlist, true);
|
|
||||||
} else
|
|
||||||
playlist_set_consume(playlist, false);
|
|
||||||
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) {
|
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) {
|
||||||
pc_set_cross_fade(pc,
|
pc_set_cross_fade(pc,
|
||||||
atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE)));
|
atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE)));
|
||||||
@@ -188,7 +178,7 @@ playlist_state_restore(const char *line, TextFile &file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_set_random(playlist, pc, random_mode);
|
playlist->SetRandom(*pc, random_mode);
|
||||||
|
|
||||||
if (!playlist->queue.IsEmpty()) {
|
if (!playlist->queue.IsEmpty()) {
|
||||||
if (!playlist->queue.IsValidPosition(current))
|
if (!playlist->queue.IsValidPosition(current))
|
||||||
@@ -210,9 +200,9 @@ playlist_state_restore(const char *line, TextFile &file,
|
|||||||
if (state == PLAYER_STATE_STOP /* && config_option */)
|
if (state == PLAYER_STATE_STOP /* && config_option */)
|
||||||
playlist->current = current;
|
playlist->current = current;
|
||||||
else if (seek_time == 0)
|
else if (seek_time == 0)
|
||||||
playlist_play(playlist, pc, current);
|
playlist->PlayPosition(*pc, current);
|
||||||
else
|
else
|
||||||
playlist_seek_song(playlist, pc, current, seek_time);
|
playlist->SeekSongPosition(*pc, current, seek_time);
|
||||||
|
|
||||||
if (state == PLAYER_STATE_PAUSE)
|
if (state == PLAYER_STATE_PAUSE)
|
||||||
pc_pause(pc);
|
pc_pause(pc);
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include "PlaylistPrint.hxx"
|
#include "PlaylistPrint.hxx"
|
||||||
#include "ClientFile.hxx"
|
#include "ClientFile.hxx"
|
||||||
#include "ClientInternal.hxx"
|
#include "ClientInternal.hxx"
|
||||||
|
#include "Partition.hxx"
|
||||||
#include "protocol/ArgParser.hxx"
|
#include "protocol/ArgParser.hxx"
|
||||||
#include "protocol/Result.hxx"
|
#include "protocol/Result.hxx"
|
||||||
#include "ls.hxx"
|
#include "ls.hxx"
|
||||||
@@ -50,10 +51,7 @@ handle_add(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
if (!client_allow_file(client, path, &error))
|
if (!client_allow_file(client, path, &error))
|
||||||
return print_error(client, error);
|
return print_error(client, error);
|
||||||
|
|
||||||
result = playlist_append_file(&client->playlist,
|
result = client->partition.AppendFile(path);
|
||||||
client->player_control,
|
|
||||||
path,
|
|
||||||
NULL);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,9 +62,7 @@ handle_add(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = playlist_append_uri(&client->playlist,
|
result = client->partition.AppendURI(uri);
|
||||||
client->player_control,
|
|
||||||
uri, NULL);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,10 +87,7 @@ handle_addid(Client *client, int argc, char *argv[])
|
|||||||
if (!client_allow_file(client, path, &error))
|
if (!client_allow_file(client, path, &error))
|
||||||
return print_error(client, error);
|
return print_error(client, error);
|
||||||
|
|
||||||
result = playlist_append_file(&client->playlist,
|
result = client->partition.AppendFile(path, &added_id);
|
||||||
client->player_control,
|
|
||||||
path,
|
|
||||||
&added_id);
|
|
||||||
} else {
|
} else {
|
||||||
if (uri_has_scheme(uri) && !uri_supported_scheme(uri)) {
|
if (uri_has_scheme(uri) && !uri_supported_scheme(uri)) {
|
||||||
command_error(client, ACK_ERROR_NO_EXIST,
|
command_error(client, ACK_ERROR_NO_EXIST,
|
||||||
@@ -102,9 +95,7 @@ handle_addid(Client *client, int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = playlist_append_uri(&client->playlist,
|
result = client->partition.AppendURI(uri, &added_id);
|
||||||
client->player_control,
|
|
||||||
uri, &added_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS)
|
if (result != PLAYLIST_RESULT_SUCCESS)
|
||||||
@@ -114,15 +105,11 @@ handle_addid(Client *client, int argc, char *argv[])
|
|||||||
unsigned to;
|
unsigned to;
|
||||||
if (!check_unsigned(client, &to, argv[2]))
|
if (!check_unsigned(client, &to, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_move_id(&client->playlist,
|
result = client->partition.MoveId(added_id, to);
|
||||||
client->player_control,
|
|
||||||
added_id, to);
|
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS) {
|
if (result != PLAYLIST_RESULT_SUCCESS) {
|
||||||
enum command_return ret =
|
enum command_return ret =
|
||||||
print_playlist_result(client, result);
|
print_playlist_result(client, result);
|
||||||
playlist_delete_id(&client->playlist,
|
client->partition.DeleteId(added_id);
|
||||||
client->player_control,
|
|
||||||
added_id);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,14 +122,11 @@ enum command_return
|
|||||||
handle_delete(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
handle_delete(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
||||||
{
|
{
|
||||||
unsigned start, end;
|
unsigned start, end;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (!check_range(client, &start, &end, argv[1]))
|
if (!check_range(client, &start, &end, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_delete_range(&client->playlist,
|
enum playlist_result result = client->partition.DeleteRange(start, end);
|
||||||
client->player_control,
|
|
||||||
start, end);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,13 +134,11 @@ enum command_return
|
|||||||
handle_deleteid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
handle_deleteid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
||||||
{
|
{
|
||||||
unsigned id;
|
unsigned id;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (!check_unsigned(client, &id, argv[1]))
|
if (!check_unsigned(client, &id, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
result = playlist_delete_id(&client->playlist,
|
enum playlist_result result = client->partition.DeleteId(id);
|
||||||
client->player_control, id);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,8 +158,7 @@ handle_shuffle(G_GNUC_UNUSED Client *client,
|
|||||||
if (argc == 2 && !check_range(client, &start, &end, argv[1]))
|
if (argc == 2 && !check_range(client, &start, &end, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
playlist_shuffle(&client->playlist, client->player_control,
|
client->partition.Shuffle(start, end);
|
||||||
start, end);
|
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +166,7 @@ enum command_return
|
|||||||
handle_clear(G_GNUC_UNUSED Client *client,
|
handle_clear(G_GNUC_UNUSED Client *client,
|
||||||
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
|
||||||
{
|
{
|
||||||
playlist_clear(&client->playlist, client->player_control);
|
client->partition.ClearQueue();
|
||||||
return COMMAND_RETURN_OK;
|
return COMMAND_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,10 +277,9 @@ handle_prio(Client *client, int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
enum playlist_result result =
|
enum playlist_result result =
|
||||||
playlist_set_priority(&client->playlist,
|
client->partition.SetPriorityRange(start_position,
|
||||||
client->player_control,
|
end_position,
|
||||||
start_position, end_position,
|
priority);
|
||||||
priority);
|
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS)
|
if (result != PLAYLIST_RESULT_SUCCESS)
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
@@ -327,9 +307,7 @@ handle_prioid(Client *client, int argc, char *argv[])
|
|||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
|
|
||||||
enum playlist_result result =
|
enum playlist_result result =
|
||||||
playlist_set_priority_id(&client->playlist,
|
client->partition.SetPriorityId(song_id, priority);
|
||||||
client->player_control,
|
|
||||||
song_id, priority);
|
|
||||||
if (result != PLAYLIST_RESULT_SUCCESS)
|
if (result != PLAYLIST_RESULT_SUCCESS)
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
@@ -342,14 +320,14 @@ handle_move(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
unsigned start, end;
|
unsigned start, end;
|
||||||
int to;
|
int to;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (!check_range(client, &start, &end, argv[1]))
|
if (!check_range(client, &start, &end, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_int(client, &to, argv[2]))
|
if (!check_int(client, &to, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_move_range(&client->playlist, client->player_control,
|
|
||||||
start, end, to);
|
enum playlist_result result =
|
||||||
|
client->partition.MoveRange(start, end, to);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,14 +336,12 @@ handle_moveid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
unsigned id;
|
unsigned id;
|
||||||
int to;
|
int to;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (!check_unsigned(client, &id, argv[1]))
|
if (!check_unsigned(client, &id, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_int(client, &to, argv[2]))
|
if (!check_int(client, &to, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_move_id(&client->playlist, client->player_control,
|
enum playlist_result result = client->partition.MoveId(id, to);
|
||||||
id, to);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,14 +349,14 @@ enum command_return
|
|||||||
handle_swap(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
handle_swap(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
||||||
{
|
{
|
||||||
unsigned song1, song2;
|
unsigned song1, song2;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (!check_unsigned(client, &song1, argv[1]))
|
if (!check_unsigned(client, &song1, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_unsigned(client, &song2, argv[2]))
|
if (!check_unsigned(client, &song2, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_swap_songs(&client->playlist, client->player_control,
|
|
||||||
song1, song2);
|
enum playlist_result result =
|
||||||
|
client->partition.SwapPositions(song1, song2);
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,14 +364,12 @@ enum command_return
|
|||||||
handle_swapid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
handle_swapid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
|
||||||
{
|
{
|
||||||
unsigned id1, id2;
|
unsigned id1, id2;
|
||||||
enum playlist_result result;
|
|
||||||
|
|
||||||
if (!check_unsigned(client, &id1, argv[1]))
|
if (!check_unsigned(client, &id1, argv[1]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
if (!check_unsigned(client, &id2, argv[2]))
|
if (!check_unsigned(client, &id2, argv[2]))
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
result = playlist_swap_songs_id(&client->playlist,
|
|
||||||
client->player_control,
|
enum playlist_result result = client->partition.SwapIds(id1, id2);
|
||||||
id1, id2);
|
|
||||||
return print_playlist_result(client, result);
|
return print_playlist_result(client, result);
|
||||||
}
|
}
|
||||||
|
@@ -64,9 +64,7 @@ song_remove_event(void)
|
|||||||
sticker_song_delete(removed_song);
|
sticker_song_delete(removed_song);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
playlist_delete_song(&global_partition->playlist,
|
global_partition->DeleteSong(*removed_song);
|
||||||
&global_partition->pc,
|
|
||||||
removed_song);
|
|
||||||
|
|
||||||
/* clear "removed_song" and send signal to update thread */
|
/* clear "removed_song" and send signal to update thread */
|
||||||
g_mutex_lock(remove_mutex);
|
g_mutex_lock(remove_mutex);
|
||||||
|
Reference in New Issue
Block a user