2004-02-24 00:41:20 +01:00
|
|
|
/* the Music Player Daemon (MPD)
|
2007-04-05 05:22:33 +02:00
|
|
|
* Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
|
2004-02-24 00:41:20 +01:00
|
|
|
* This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "playlist.h"
|
2008-08-26 08:44:38 +02:00
|
|
|
#include "player_control.h"
|
2004-02-24 00:41:20 +01:00
|
|
|
#include "command.h"
|
|
|
|
#include "ls.h"
|
|
|
|
#include "tag.h"
|
2008-10-08 10:49:11 +02:00
|
|
|
#include "song.h"
|
2008-09-07 13:35:01 +02:00
|
|
|
#include "song_print.h"
|
2008-09-07 13:53:55 +02:00
|
|
|
#include "client.h"
|
2004-02-24 00:41:20 +01:00
|
|
|
#include "conf.h"
|
|
|
|
#include "directory.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "path.h"
|
|
|
|
#include "utils.h"
|
2006-07-31 01:32:47 +02:00
|
|
|
#include "state_file.h"
|
2007-05-16 14:02:10 +02:00
|
|
|
#include "storedPlaylist.h"
|
2008-04-12 06:19:26 +02:00
|
|
|
#include "ack.h"
|
2008-01-03 08:29:49 +01:00
|
|
|
#include "os_compat.h"
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
#define PLAYLIST_STATE_STOP 0
|
|
|
|
#define PLAYLIST_STATE_PLAY 1
|
|
|
|
|
|
|
|
#define PLAYLIST_PREV_UNLESS_ELAPSED 10
|
|
|
|
|
|
|
|
#define PLAYLIST_STATE_FILE_STATE "state: "
|
|
|
|
#define PLAYLIST_STATE_FILE_RANDOM "random: "
|
|
|
|
#define PLAYLIST_STATE_FILE_REPEAT "repeat: "
|
|
|
|
#define PLAYLIST_STATE_FILE_CURRENT "current: "
|
|
|
|
#define PLAYLIST_STATE_FILE_TIME "time: "
|
|
|
|
#define PLAYLIST_STATE_FILE_CROSSFADE "crossfade: "
|
|
|
|
#define PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "playlist_begin"
|
|
|
|
#define PLAYLIST_STATE_FILE_PLAYLIST_END "playlist_end"
|
|
|
|
|
|
|
|
#define PLAYLIST_STATE_FILE_STATE_PLAY "play"
|
|
|
|
#define PLAYLIST_STATE_FILE_STATE_PAUSE "pause"
|
|
|
|
#define PLAYLIST_STATE_FILE_STATE_STOP "stop"
|
|
|
|
|
2007-12-28 03:56:25 +01:00
|
|
|
#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2004-06-09 02:18:31 +02:00
|
|
|
#define PLAYLIST_HASH_MULT 4
|
|
|
|
|
2004-10-28 07:14:55 +02:00
|
|
|
#define DEFAULT_PLAYLIST_MAX_LENGTH (1024*16)
|
2008-10-08 11:03:39 +02:00
|
|
|
#define DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS false
|
2004-10-28 07:14:55 +02:00
|
|
|
|
2004-06-02 22:40:30 +02:00
|
|
|
static Playlist playlist;
|
|
|
|
static int playlist_state = PLAYLIST_STATE_STOP;
|
2008-01-26 21:20:59 +01:00
|
|
|
int playlist_max_length = DEFAULT_PLAYLIST_MAX_LENGTH;
|
2004-06-02 22:40:30 +02:00
|
|
|
static int playlist_stopOnError;
|
2007-01-14 04:07:53 +01:00
|
|
|
static int playlist_errorCount;
|
|
|
|
static int playlist_noGoToNext;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-10-08 11:03:39 +02:00
|
|
|
bool playlist_saveAbsolutePaths = DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2004-06-02 22:40:30 +02:00
|
|
|
static void swapOrder(int a, int b);
|
2008-08-26 08:27:16 +02:00
|
|
|
static void playPlaylistOrderNumber(int orderNum);
|
2004-06-02 22:40:30 +02:00
|
|
|
static void randomizeOrder(int start, int end);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
static void incrPlaylistVersion(void)
|
|
|
|
{
|
2008-09-29 15:49:29 +02:00
|
|
|
static unsigned long max = ((uint32_t) 1 << 31) - 1;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.version++;
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.version >= max) {
|
2004-06-05 03:14:37 +02:00
|
|
|
int i;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
2004-06-05 03:14:37 +02:00
|
|
|
playlist.songMod[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
playlist.version = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void playlistVersionChange(void)
|
|
|
|
{
|
2008-03-26 11:37:36 +01:00
|
|
|
int i;
|
2004-06-05 03:14:37 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
2004-06-05 03:14:37 +02:00
|
|
|
playlist.songMod[i] = playlist.version;
|
|
|
|
}
|
|
|
|
|
|
|
|
incrPlaylistVersion();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
static void incrPlaylistCurrent(void)
|
|
|
|
{
|
|
|
|
if (playlist.current < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (playlist.current >= playlist.length - 1) {
|
|
|
|
if (playlist.repeat)
|
|
|
|
playlist.current = 0;
|
|
|
|
else
|
|
|
|
playlist.current = -1;
|
|
|
|
} else
|
|
|
|
playlist.current++;
|
2004-06-02 22:40:30 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void initPlaylist(void)
|
|
|
|
{
|
|
|
|
char *test;
|
2004-06-09 02:18:31 +02:00
|
|
|
int i;
|
2006-07-20 18:02:40 +02:00
|
|
|
ConfigParam *param;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
playlist.length = 0;
|
2008-10-08 11:03:39 +02:00
|
|
|
playlist.repeat = false;
|
2004-06-05 03:14:37 +02:00
|
|
|
playlist.version = 1;
|
2008-10-08 11:03:39 +02:00
|
|
|
playlist.random = false;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.queued = -1;
|
2006-07-20 18:02:40 +02:00
|
|
|
playlist.current = -1;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2004-10-28 07:14:55 +02:00
|
|
|
param = getConfigParam(CONF_MAX_PLAYLIST_LENGTH);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (param) {
|
2004-10-28 07:14:55 +02:00
|
|
|
playlist_max_length = strtol(param->value, &test, 10);
|
2006-07-20 18:02:40 +02:00
|
|
|
if (*test != '\0') {
|
2007-05-26 20:15:54 +02:00
|
|
|
FATAL("max playlist length \"%s\" is not an integer, "
|
2006-07-20 18:02:40 +02:00
|
|
|
"line %i\n", param->value, param->line);
|
2004-10-28 07:14:55 +02:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2004-10-28 07:14:55 +02:00
|
|
|
|
2007-09-06 01:59:33 +02:00
|
|
|
playlist_saveAbsolutePaths = getBoolConfigParam(
|
|
|
|
CONF_SAVE_ABSOLUTE_PATHS, 1);
|
|
|
|
if (playlist_saveAbsolutePaths == CONF_BOOL_UNSET)
|
|
|
|
playlist_saveAbsolutePaths =
|
|
|
|
DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-10-08 10:49:11 +02:00
|
|
|
playlist.songs = xmalloc(sizeof(struct song *) * playlist_max_length);
|
2008-09-29 15:49:29 +02:00
|
|
|
playlist.songMod = xmalloc(sizeof(uint32_t) * playlist_max_length);
|
2006-08-26 08:25:57 +02:00
|
|
|
playlist.order = xmalloc(sizeof(int) * playlist_max_length);
|
|
|
|
playlist.idToPosition = xmalloc(sizeof(int) * playlist_max_length *
|
2006-07-20 18:02:40 +02:00
|
|
|
PLAYLIST_HASH_MULT);
|
2006-08-26 08:25:57 +02:00
|
|
|
playlist.positionToId = xmalloc(sizeof(int) * playlist_max_length);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
memset(playlist.songs, 0, sizeof(char *) * playlist_max_length);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2004-10-30 16:33:19 +02:00
|
|
|
srandom(time(NULL));
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist_max_length * PLAYLIST_HASH_MULT; i++) {
|
2004-06-30 04:12:49 +02:00
|
|
|
playlist.idToPosition[i] = -1;
|
2004-06-09 02:18:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
static int getNextId(void)
|
|
|
|
{
|
2006-05-08 10:15:24 +02:00
|
|
|
static int cur = -1;
|
2004-06-09 02:18:31 +02:00
|
|
|
|
2006-05-08 10:15:24 +02:00
|
|
|
do {
|
2004-06-09 02:18:31 +02:00
|
|
|
cur++;
|
2006-07-20 18:02:40 +02:00
|
|
|
if (cur >= playlist_max_length * PLAYLIST_HASH_MULT) {
|
2004-06-09 02:18:31 +02:00
|
|
|
cur = 0;
|
|
|
|
}
|
2006-07-20 18:02:40 +02:00
|
|
|
} while (playlist.idToPosition[cur] != -1);
|
2004-06-09 02:18:31 +02:00
|
|
|
|
|
|
|
return cur;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void finishPlaylist(void)
|
|
|
|
{
|
2006-07-14 23:01:19 +02:00
|
|
|
int i;
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
2008-10-06 18:52:13 +02:00
|
|
|
if (!song_is_file(playlist.songs[i])) {
|
2008-10-08 11:05:34 +02:00
|
|
|
song_free(playlist.songs[i]);
|
2004-05-19 07:07:31 +02:00
|
|
|
}
|
2006-07-14 23:01:19 +02:00
|
|
|
}
|
2004-06-05 03:14:37 +02:00
|
|
|
|
|
|
|
playlist.length = 0;
|
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
free(playlist.songs);
|
2004-04-11 03:53:25 +02:00
|
|
|
playlist.songs = NULL;
|
2004-06-05 03:14:37 +02:00
|
|
|
free(playlist.songMod);
|
|
|
|
playlist.songMod = NULL;
|
2004-02-24 00:41:20 +01:00
|
|
|
free(playlist.order);
|
2004-04-11 03:53:25 +02:00
|
|
|
playlist.order = NULL;
|
2004-06-30 04:12:49 +02:00
|
|
|
free(playlist.idToPosition);
|
|
|
|
playlist.idToPosition = NULL;
|
|
|
|
free(playlist.positionToId);
|
|
|
|
playlist.positionToId = NULL;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
void clearPlaylist(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
stopPlaylist();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
2008-10-06 18:52:13 +02:00
|
|
|
if (!song_is_file(playlist.songs[i])) {
|
2008-10-08 11:05:34 +02:00
|
|
|
song_free(playlist.songs[i]);
|
2004-05-13 20:46:38 +02:00
|
|
|
}
|
2004-06-30 04:12:49 +02:00
|
|
|
playlist.idToPosition[playlist.positionToId[i]] = -1;
|
2004-05-13 20:46:38 +02:00
|
|
|
playlist.songs[i] = NULL;
|
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.length = 0;
|
2006-07-14 23:01:19 +02:00
|
|
|
playlist.current = -1;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
incrPlaylistVersion();
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:44:12 +02:00
|
|
|
int clearStoredPlaylist(const char *utf8file)
|
2006-11-20 16:37:58 +01:00
|
|
|
{
|
2008-09-07 13:44:12 +02:00
|
|
|
return removeAllFromStoredPlaylistByPath(utf8file);
|
2006-11-20 16:37:58 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 14:02:52 +02:00
|
|
|
void showPlaylist(struct client *client)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
2007-12-28 03:56:25 +01:00
|
|
|
char path_max_tmp[MPD_PATH_MAX];
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
2008-09-07 14:02:52 +02:00
|
|
|
client_printf(client, "%i:%s\n", i,
|
2008-10-08 11:05:34 +02:00
|
|
|
song_get_url(playlist.songs[i], path_max_tmp));
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-07 14:02:43 +02:00
|
|
|
static void playlist_save(FILE *fp)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char path_max_tmp[MPD_PATH_MAX];
|
|
|
|
|
|
|
|
for (i = 0; i < playlist.length; i++)
|
|
|
|
fprintf(fp, "%i:%s\n", i,
|
2008-10-08 11:05:34 +02:00
|
|
|
song_get_url(playlist.songs[i], path_max_tmp));
|
2008-09-07 14:02:43 +02:00
|
|
|
}
|
|
|
|
|
2006-07-31 01:32:47 +02:00
|
|
|
void savePlaylistState(FILE *fp)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2006-07-31 01:32:47 +02:00
|
|
|
fprintf(fp, "%s", PLAYLIST_STATE_FILE_STATE);
|
|
|
|
switch (playlist_state) {
|
|
|
|
case PLAYLIST_STATE_PLAY:
|
|
|
|
switch (getPlayerState()) {
|
|
|
|
case PLAYER_STATE_PAUSE:
|
|
|
|
fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_PAUSE);
|
2004-02-24 00:41:20 +01:00
|
|
|
break;
|
|
|
|
default:
|
2006-07-31 01:32:47 +02:00
|
|
|
fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_PLAY);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2006-07-31 01:32:47 +02:00
|
|
|
fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CURRENT,
|
|
|
|
playlist.order[playlist.current]);
|
|
|
|
fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_TIME,
|
|
|
|
getPlayerElapsedTime());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_STOP);
|
|
|
|
break;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2006-07-31 01:32:47 +02:00
|
|
|
fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_RANDOM, playlist.random);
|
|
|
|
fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_REPEAT, playlist.repeat);
|
|
|
|
fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CROSSFADE,
|
|
|
|
(int)(getPlayerCrossFade()));
|
|
|
|
fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_PLAYLIST_BEGIN);
|
2008-09-07 14:02:43 +02:00
|
|
|
playlist_save(fp);
|
2006-07-31 01:32:47 +02:00
|
|
|
fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_PLAYLIST_END);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-07-31 01:32:47 +02:00
|
|
|
static void loadPlaylistFromStateFile(FILE *fp, char *buffer,
|
2008-01-26 13:46:21 +01:00
|
|
|
int state, int current, int seek_time)
|
2004-02-24 00:41:20 +01:00
|
|
|
{
|
2006-07-20 18:02:40 +02:00
|
|
|
char *temp;
|
2004-02-24 00:41:20 +01:00
|
|
|
int song;
|
|
|
|
|
2006-07-31 01:32:47 +02:00
|
|
|
if (!myFgets(buffer, PLAYLIST_BUFFER_SIZE, fp))
|
|
|
|
state_file_fatal();
|
2006-07-20 18:02:40 +02:00
|
|
|
while (strcmp(buffer, PLAYLIST_STATE_FILE_PLAYLIST_END)) {
|
2008-03-26 11:37:40 +01:00
|
|
|
temp = strtok(buffer, ":");
|
|
|
|
if (temp == NULL)
|
|
|
|
state_file_fatal();
|
|
|
|
song = atoi(temp);
|
2006-07-31 01:32:47 +02:00
|
|
|
if (!(temp = strtok(NULL, "")))
|
|
|
|
state_file_fatal();
|
2008-09-07 13:39:31 +02:00
|
|
|
if (addToPlaylist(temp, NULL) == PLAYLIST_RESULT_SUCCESS
|
2008-01-26 13:46:49 +01:00
|
|
|
&& current == song) {
|
2006-07-20 18:02:40 +02:00
|
|
|
if (state != PLAYER_STATE_STOP) {
|
2008-09-07 13:39:31 +02:00
|
|
|
playPlaylist(playlist.length - 1, 0);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2006-07-20 18:02:40 +02:00
|
|
|
if (state == PLAYER_STATE_PAUSE) {
|
2008-08-26 08:27:16 +02:00
|
|
|
playerPause();
|
2004-03-17 21:58:09 +01:00
|
|
|
}
|
2006-07-20 18:02:40 +02:00
|
|
|
if (state != PLAYER_STATE_STOP) {
|
2008-09-07 13:39:31 +02:00
|
|
|
seekSongInPlaylist(playlist.length - 1,
|
2008-01-26 13:46:21 +01:00
|
|
|
seek_time);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
2006-07-31 01:32:47 +02:00
|
|
|
if (!myFgets(buffer, PLAYLIST_BUFFER_SIZE, fp))
|
|
|
|
state_file_fatal();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-31 01:32:47 +02:00
|
|
|
void readPlaylistState(FILE *fp)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2006-07-31 01:32:47 +02:00
|
|
|
int current = -1;
|
2008-01-26 13:46:21 +01:00
|
|
|
int seek_time = 0;
|
2006-07-31 01:32:47 +02:00
|
|
|
int state = PLAYER_STATE_STOP;
|
|
|
|
char buffer[PLAYLIST_BUFFER_SIZE];
|
|
|
|
|
|
|
|
while (myFgets(buffer, PLAYLIST_BUFFER_SIZE, fp)) {
|
2008-09-23 20:48:12 +02:00
|
|
|
if (!prefixcmp(buffer, PLAYLIST_STATE_FILE_STATE)) {
|
2006-07-31 01:32:47 +02:00
|
|
|
if (strcmp(&(buffer[strlen(PLAYLIST_STATE_FILE_STATE)]),
|
|
|
|
PLAYLIST_STATE_FILE_STATE_PLAY) == 0) {
|
|
|
|
state = PLAYER_STATE_PLAY;
|
2006-07-20 18:02:40 +02:00
|
|
|
} else
|
2006-07-31 01:32:47 +02:00
|
|
|
if (strcmp
|
|
|
|
(&(buffer[strlen(PLAYLIST_STATE_FILE_STATE)]),
|
|
|
|
PLAYLIST_STATE_FILE_STATE_PAUSE)
|
|
|
|
== 0) {
|
|
|
|
state = PLAYER_STATE_PAUSE;
|
|
|
|
}
|
2008-09-23 20:48:12 +02:00
|
|
|
} else if (!prefixcmp(buffer, PLAYLIST_STATE_FILE_TIME)) {
|
2008-01-26 13:46:21 +01:00
|
|
|
seek_time =
|
2006-07-31 01:32:47 +02:00
|
|
|
atoi(&(buffer[strlen(PLAYLIST_STATE_FILE_TIME)]));
|
|
|
|
} else
|
2008-09-23 20:48:12 +02:00
|
|
|
if (!prefixcmp(buffer, PLAYLIST_STATE_FILE_REPEAT)) {
|
2006-07-31 01:32:47 +02:00
|
|
|
if (strcmp
|
|
|
|
(&(buffer[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
|
|
|
|
"1") == 0) {
|
2008-10-08 11:03:39 +02:00
|
|
|
setPlaylistRepeatStatus(true);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else
|
2008-10-08 11:03:39 +02:00
|
|
|
setPlaylistRepeatStatus(false);
|
2008-09-23 20:48:12 +02:00
|
|
|
} else if (!prefixcmp(buffer, PLAYLIST_STATE_FILE_CROSSFADE)) {
|
2006-07-31 01:32:47 +02:00
|
|
|
setPlayerCrossFade(atoi
|
|
|
|
(&
|
|
|
|
(buffer
|
|
|
|
[strlen
|
|
|
|
(PLAYLIST_STATE_FILE_CROSSFADE)])));
|
2008-09-23 20:48:12 +02:00
|
|
|
} else if (!prefixcmp(buffer, PLAYLIST_STATE_FILE_RANDOM)) {
|
2006-07-31 01:32:47 +02:00
|
|
|
if (strcmp
|
|
|
|
(&
|
|
|
|
(buffer
|
|
|
|
[strlen(PLAYLIST_STATE_FILE_RANDOM)]),
|
|
|
|
"1") == 0) {
|
2008-10-08 11:03:39 +02:00
|
|
|
setPlaylistRandomStatus(true);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else
|
2008-10-08 11:03:39 +02:00
|
|
|
setPlaylistRandomStatus(false);
|
2008-09-23 20:48:12 +02:00
|
|
|
} else if (!prefixcmp(buffer, PLAYLIST_STATE_FILE_CURRENT)) {
|
2006-07-31 01:32:47 +02:00
|
|
|
if (strlen(buffer) ==
|
|
|
|
strlen(PLAYLIST_STATE_FILE_CURRENT))
|
|
|
|
state_file_fatal();
|
|
|
|
current = atoi(&(buffer
|
|
|
|
[strlen
|
|
|
|
(PLAYLIST_STATE_FILE_CURRENT)]));
|
2008-09-23 20:48:12 +02:00
|
|
|
} else if (!prefixcmp(buffer,
|
|
|
|
PLAYLIST_STATE_FILE_PLAYLIST_BEGIN)) {
|
2006-07-31 01:32:47 +02:00
|
|
|
if (state == PLAYER_STATE_STOP)
|
|
|
|
current = -1;
|
|
|
|
loadPlaylistFromStateFile(fp, buffer, state,
|
2008-01-26 13:46:21 +01:00
|
|
|
current, seek_time);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:53:55 +02:00
|
|
|
static void printPlaylistSongInfo(struct client *client, int song)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-07 22:06:59 +02:00
|
|
|
song_print_info(client, playlist.songs[song]);
|
2008-09-07 13:53:55 +02:00
|
|
|
client_printf(client, "Pos: %i\nId: %i\n", song, playlist.positionToId[song]);
|
2004-06-05 03:14:37 +02:00
|
|
|
}
|
|
|
|
|
2008-09-29 15:49:29 +02:00
|
|
|
int playlistChanges(struct client *client, uint32_t version)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-06-05 03:14:37 +02:00
|
|
|
int i;
|
2006-07-14 23:01:19 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
|
|
|
if (version > playlist.version ||
|
|
|
|
playlist.songMod[i] >= version ||
|
|
|
|
playlist.songMod[i] == 0) {
|
2008-09-07 13:53:55 +02:00
|
|
|
printPlaylistSongInfo(client, i);
|
2004-06-05 03:14:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-29 15:49:29 +02:00
|
|
|
int playlistChangesPosId(struct client *client, uint32_t version)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2006-04-23 13:10:41 +02:00
|
|
|
int i;
|
2006-07-14 23:01:19 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
|
|
|
if (version > playlist.version ||
|
|
|
|
playlist.songMod[i] >= version ||
|
|
|
|
playlist.songMod[i] == 0) {
|
2008-09-07 14:02:52 +02:00
|
|
|
client_printf(client, "cpos: %i\nId: %i\n",
|
|
|
|
i, playlist.positionToId[i]);
|
2006-04-23 13:10:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:53:55 +02:00
|
|
|
enum playlist_result playlistInfo(struct client *client, int song)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
|
|
|
int begin = 0;
|
|
|
|
int end = playlist.length;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (song >= 0) {
|
2004-02-24 00:41:20 +01:00
|
|
|
begin = song;
|
2006-07-20 18:02:40 +02:00
|
|
|
end = song + 1;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2008-09-07 13:39:31 +02:00
|
|
|
if (song >= playlist.length)
|
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = begin; i < end; i++)
|
2008-09-07 13:53:55 +02:00
|
|
|
printPlaylistSongInfo(client, i);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 19:19:41 +02:00
|
|
|
static int song_id_to_position(int id)
|
2008-09-07 13:39:31 +02:00
|
|
|
{
|
2008-09-07 19:19:41 +02:00
|
|
|
if (id < 0 || id >= PLAYLIST_HASH_MULT*playlist_max_length)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
assert(playlist.idToPosition[id] >= -1);
|
|
|
|
assert(playlist.idToPosition[id] < playlist.length);
|
|
|
|
|
|
|
|
return playlist.idToPosition[id];
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:53:55 +02:00
|
|
|
enum playlist_result playlistId(struct client *client, int id)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-06-09 03:30:51 +02:00
|
|
|
int i;
|
|
|
|
int begin = 0;
|
|
|
|
int end = playlist.length;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (id >= 0) {
|
2008-09-07 19:19:41 +02:00
|
|
|
begin = song_id_to_position(id);
|
|
|
|
if (begin < 0)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
end = begin + 1;
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = begin; i < end; i++)
|
2008-09-07 13:53:55 +02:00
|
|
|
printPlaylistSongInfo(client, i);
|
2004-06-09 03:30:51 +02:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2006-08-20 02:50:44 +02:00
|
|
|
static void swapSongs(int song1, int song2)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-08 10:49:11 +02:00
|
|
|
struct song *sTemp;
|
2004-06-09 02:18:31 +02:00
|
|
|
int iTemp;
|
2006-07-20 18:02:40 +02:00
|
|
|
|
2004-06-09 02:18:31 +02:00
|
|
|
sTemp = playlist.songs[song1];
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.songs[song1] = playlist.songs[song2];
|
2004-06-09 02:18:31 +02:00
|
|
|
playlist.songs[song2] = sTemp;
|
|
|
|
|
2004-06-05 03:14:37 +02:00
|
|
|
playlist.songMod[song1] = playlist.version;
|
|
|
|
playlist.songMod[song2] = playlist.version;
|
2004-06-09 02:18:31 +02:00
|
|
|
|
2004-06-30 04:12:49 +02:00
|
|
|
playlist.idToPosition[playlist.positionToId[song1]] = song2;
|
|
|
|
playlist.idToPosition[playlist.positionToId[song2]] = song1;
|
2004-06-09 02:18:31 +02:00
|
|
|
|
2004-06-30 04:12:49 +02:00
|
|
|
iTemp = playlist.positionToId[song1];
|
|
|
|
playlist.positionToId[song1] = playlist.positionToId[song2];
|
|
|
|
playlist.positionToId[song2] = iTemp;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-08-20 02:50:44 +02:00
|
|
|
static void queueNextSongInPlaylist(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2007-12-28 03:56:25 +01:00
|
|
|
char path_max_tmp[MPD_PATH_MAX];
|
|
|
|
|
Revert the queue implementation and commands
It's too ugly and broken (both technically and usability-wise)
to be worth supporting in any stable release.
In one sentence: The queue is a very crippled version of the
playlist that takes precedence over the normal playlist.
How is it crippled?
* The "queueid" command only allows the queuing of songs
ALREADY IN THE PLAYLIST! This promotes having the entire mpd
database of songs in the playlist, which is a stupid practice
to begin with.
* It doesn't allow for meaningful rearranging and movement
of songs within the queue. To move a song, you'd need to
dequeue and requeue it (and other songs on the list).
Why? The playlist already allows _all_ these features
and shows everything a client needs to know about the ordering
of songs in a _single_ command!
* Random was a stupid idea to begin with and unfortunately
we're stuck supporting it since we've always had it. Users
should learn to use "shuffle" instead and not look at their
playlists. Implementing queue because we have the problem of
random is just a bandage fix and digging ourselves a new hole.
This protocol addition was never in a stable release of mpd, so
reverting it will only break things for people following trunk;
which I'm not too worried about. I am however worried about
long-term support of this misfeature, so I'm removing it.
Additionally, there are other points:
* It's trivially DoS-able:
(while true; do echo queueid $song_id; done) | nc $MPD_HOST $MPD_PORT
The above commands would cause the queue to become infinitely
expanding, taking up all available memory in the system. The
mpd playlist was implemented as an array with a fixed (but
configurable) size limit for this reason.
* It's not backwards-compatible. All clients would require
upgrades (and additional complexity) to even know what the
next song in the playlist is. mpd is a shared architecture,
and we should not violate the principle of least astonishment
here.
This removes the following commands:
queueid, dequeue, queueinfo
Additionally, the status field of "playlistqueue: " is removed
from the status command.
While this DoS is trivial to fix, the design is simply too
broken to ever support in a real release.
The overloading of the "addid" command and the allowing of
negative numbers to be used as offsets is far more flexible.
This improved "addid" is completely backwards-compatible with
all clients, and does not require clients to have UI changes or
run additional commands to display the queue.
git-svn-id: https://svn.musicpd.org/mpd/trunk@7155 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2008-01-26 21:21:07 +01:00
|
|
|
if (playlist.current < playlist.length - 1) {
|
2006-07-20 18:02:40 +02:00
|
|
|
playlist.queued = playlist.current + 1;
|
2004-02-24 00:41:20 +01:00
|
|
|
DEBUG("playlist: queue song %i:\"%s\"\n",
|
2006-07-20 18:02:40 +02:00
|
|
|
playlist.queued,
|
2008-10-08 11:05:34 +02:00
|
|
|
song_get_url(playlist.
|
|
|
|
songs[playlist.order[playlist.queued]],
|
|
|
|
path_max_tmp));
|
2008-08-26 08:27:17 +02:00
|
|
|
queueSong(playlist.songs[playlist.order[playlist.queued]]);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else if (playlist.length && playlist.repeat) {
|
|
|
|
if (playlist.length > 1 && playlist.random) {
|
|
|
|
randomizeOrder(0, playlist.length - 1);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
playlist.queued = 0;
|
|
|
|
DEBUG("playlist: queue song %i:\"%s\"\n",
|
2006-07-20 18:02:40 +02:00
|
|
|
playlist.queued,
|
2008-10-08 11:05:34 +02:00
|
|
|
song_get_url(playlist.
|
|
|
|
songs[playlist.order[playlist.queued]],
|
|
|
|
path_max_tmp));
|
2008-08-26 08:27:17 +02:00
|
|
|
queueSong(playlist.songs[playlist.order[playlist.queued]]);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:18 +02:00
|
|
|
static void syncPlaylistWithQueue(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-08-26 08:27:17 +02:00
|
|
|
switch (getPlayerQueueState()) {
|
|
|
|
case PLAYER_QUEUE_EMPTY:
|
2004-02-24 00:41:20 +01:00
|
|
|
setQueueState(PLAYER_QUEUE_BLANK);
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.queued >= 0) {
|
2004-02-24 00:41:20 +01:00
|
|
|
DEBUG("playlist: now playing queued song\n");
|
|
|
|
playlist.current = playlist.queued;
|
|
|
|
}
|
|
|
|
playlist.queued = -1;
|
2008-08-26 08:27:17 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PLAYER_QUEUE_DECODE:
|
|
|
|
if (playlist.queued != -1)
|
|
|
|
setQueueState(PLAYER_QUEUE_PLAY);
|
|
|
|
else
|
|
|
|
setQueueState(PLAYER_QUEUE_STOP);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLAYER_QUEUE_FULL:
|
|
|
|
case PLAYER_QUEUE_PLAY:
|
|
|
|
case PLAYER_QUEUE_STOP:
|
2008-08-26 08:27:18 +02:00
|
|
|
case PLAYER_QUEUE_BLANK:
|
2008-08-26 08:27:17 +02:00
|
|
|
break;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:17 +02:00
|
|
|
static void clearPlayerQueue(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
|
|
|
if (getPlayerQueueState() == PLAYER_QUEUE_PLAY ||
|
|
|
|
getPlayerQueueState() == PLAYER_QUEUE_FULL) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playerQueueLock();
|
2008-08-26 08:27:18 +02:00
|
|
|
syncPlaylistWithQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
playlist.queued = -1;
|
2006-07-20 18:02:40 +02:00
|
|
|
switch (getPlayerQueueState()) {
|
2008-08-26 08:27:16 +02:00
|
|
|
case PLAYER_QUEUE_BLANK:
|
|
|
|
case PLAYER_QUEUE_DECODE:
|
|
|
|
case PLAYER_QUEUE_STOP:
|
|
|
|
case PLAYER_QUEUE_EMPTY:
|
|
|
|
break;
|
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
case PLAYER_QUEUE_FULL:
|
|
|
|
DEBUG("playlist: dequeue song\n");
|
|
|
|
setQueueState(PLAYER_QUEUE_BLANK);
|
|
|
|
break;
|
|
|
|
case PLAYER_QUEUE_PLAY:
|
|
|
|
DEBUG("playlist: stop decoding queued song\n");
|
|
|
|
setQueueState(PLAYER_QUEUE_STOP);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:17 +02:00
|
|
|
playerQueueUnlock();
|
2008-04-12 06:11:56 +02:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result addToPlaylist(const char *url, int *added_id)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-08 10:49:11 +02:00
|
|
|
struct song *song;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
DEBUG("add to playlist: %s\n", url);
|
|
|
|
|
|
|
|
if ((song = getSongFromDB(url))) {
|
|
|
|
} else if (!(isValidRemoteUtf8Url(url) &&
|
2008-10-08 11:05:25 +02:00
|
|
|
(song = song_remote_new(url)))) {
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return addSongToPlaylist(song, added_id);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:44:12 +02:00
|
|
|
int addToStoredPlaylist(const char *url, const char *utf8file)
|
2006-11-20 16:37:58 +01:00
|
|
|
{
|
2008-10-08 10:49:11 +02:00
|
|
|
struct song *song;
|
2006-11-20 16:37:58 +01:00
|
|
|
|
|
|
|
DEBUG("add to stored playlist: %s\n", url);
|
|
|
|
|
2007-05-26 17:00:38 +02:00
|
|
|
song = getSongFromDB(url);
|
2008-09-07 13:44:12 +02:00
|
|
|
if (song)
|
|
|
|
return appendSongToStoredPlaylistByPath(utf8file, song);
|
2006-11-20 16:37:58 +01:00
|
|
|
|
2007-05-26 17:00:38 +02:00
|
|
|
if (!isValidRemoteUtf8Url(url))
|
2008-09-07 13:44:12 +02:00
|
|
|
return ACK_ERROR_NO_EXIST;
|
2007-05-26 17:00:38 +02:00
|
|
|
|
2008-10-08 11:05:25 +02:00
|
|
|
song = song_remote_new(url);
|
2007-05-26 17:00:38 +02:00
|
|
|
if (song) {
|
2008-09-07 13:44:12 +02:00
|
|
|
int ret = appendSongToStoredPlaylistByPath(utf8file, song);
|
2008-10-08 11:05:34 +02:00
|
|
|
song_free(song);
|
2008-09-07 13:44:12 +02:00
|
|
|
return ret;
|
2007-05-26 17:00:38 +02:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:44:12 +02:00
|
|
|
return ACK_ERROR_NO_EXIST;
|
2006-11-20 16:37:58 +01:00
|
|
|
}
|
|
|
|
|
2008-10-08 10:49:11 +02:00
|
|
|
enum playlist_result
|
|
|
|
addSongToPlaylist(struct song *song, int *added_id)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-11-03 00:44:33 +01:00
|
|
|
int id;
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (playlist.length == playlist_max_length)
|
|
|
|
return PLAYLIST_RESULT_TOO_LARGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
|
|
|
if (playlist.queued >= 0
|
2008-04-12 06:11:56 +02:00
|
|
|
&& playlist.current == playlist.length - 1)
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2004-11-03 00:44:33 +01:00
|
|
|
id = getNextId();
|
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.songs[playlist.length] = song;
|
2004-06-05 03:14:37 +02:00
|
|
|
playlist.songMod[playlist.length] = playlist.version;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.order[playlist.length] = playlist.length;
|
2004-11-03 00:44:33 +01:00
|
|
|
playlist.positionToId[playlist.length] = id;
|
2006-07-20 18:02:40 +02:00
|
|
|
playlist.idToPosition[playlist.positionToId[playlist.length]] =
|
|
|
|
playlist.length;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.length++;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.random) {
|
2004-02-24 00:41:20 +01:00
|
|
|
int swap;
|
|
|
|
int start;
|
2004-05-23 16:12:05 +02:00
|
|
|
/*if(playlist_state==PLAYLIST_STATE_STOP) start = 0;
|
2006-07-20 18:02:40 +02:00
|
|
|
else */ if (playlist.queued >= 0)
|
|
|
|
start = playlist.queued + 1;
|
|
|
|
else
|
|
|
|
start = playlist.current + 1;
|
|
|
|
if (start < playlist.length) {
|
|
|
|
swap = random() % (playlist.length - start);
|
|
|
|
swap += start;
|
|
|
|
swapOrder(playlist.length - 1, swap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
incrPlaylistVersion();
|
|
|
|
|
2008-01-26 13:46:49 +01:00
|
|
|
if (added_id)
|
|
|
|
*added_id = id;
|
2004-11-03 00:44:33 +01:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result swapSongsInPlaylist(int song1, int song2)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int queuedSong = -1;
|
2008-03-26 11:37:36 +01:00
|
|
|
int currentSong;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (song1 < 0 || song1 >= playlist.length ||
|
|
|
|
song2 < 0 || song2 >= playlist.length)
|
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2006-07-20 18:02:40 +02:00
|
|
|
|
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
|
|
|
if (playlist.queued >= 0) {
|
2004-02-24 00:41:20 +01:00
|
|
|
queuedSong = playlist.order[playlist.queued];
|
|
|
|
}
|
|
|
|
currentSong = playlist.order[playlist.current];
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (queuedSong == song1 || queuedSong == song2
|
2008-04-12 06:11:56 +02:00
|
|
|
|| currentSong == song1 || currentSong == song2)
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
swapSongs(song1, song2);
|
|
|
|
if (playlist.random) {
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
|
|
|
int k;
|
|
|
|
int j = -1;
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; playlist.order[i] != song1; i++) {
|
|
|
|
if (playlist.order[i] == song2)
|
|
|
|
j = i;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
k = i;
|
2006-07-20 18:02:40 +02:00
|
|
|
for (; j == -1; i++)
|
|
|
|
if (playlist.order[i] == song2)
|
|
|
|
j = i;
|
|
|
|
swapOrder(k, j);
|
|
|
|
} else {
|
|
|
|
if (playlist.current == song1)
|
|
|
|
playlist.current = song2;
|
|
|
|
else if (playlist.current == song2)
|
|
|
|
playlist.current = song1;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
incrPlaylistVersion();
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result swapSongsInPlaylistById(int id1, int id2)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-09-07 19:19:41 +02:00
|
|
|
int song1 = song_id_to_position(id1);
|
|
|
|
int song2 = song_id_to_position(id2);
|
|
|
|
|
|
|
|
if (song1 < 0 || song2 < 0)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
2004-06-09 03:30:51 +02:00
|
|
|
|
2008-09-07 19:19:41 +02:00
|
|
|
return swapSongsInPlaylist(song1, song2);
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2004-06-09 02:18:31 +02:00
|
|
|
#define moveSongFromTo(from, to) { \
|
2004-06-30 04:12:49 +02:00
|
|
|
playlist.idToPosition[playlist.positionToId[from]] = to; \
|
|
|
|
playlist.positionToId[to] = playlist.positionToId[from]; \
|
2004-06-09 02:18:31 +02:00
|
|
|
playlist.songs[to] = playlist.songs[from]; \
|
|
|
|
playlist.songMod[to] = playlist.version; \
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result deleteFromPlaylist(int song)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
|
|
|
int songOrder;
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (song < 0 || song >= playlist.length)
|
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
|
|
|
if (playlist.queued >= 0
|
|
|
|
&& (playlist.order[playlist.queued] == song
|
2008-04-12 06:11:56 +02:00
|
|
|
|| playlist.order[playlist.current] == song))
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-10-06 18:52:13 +02:00
|
|
|
if (!song_is_file(playlist.songs[song])) {
|
2008-10-08 11:05:34 +02:00
|
|
|
song_free(playlist.songs[song]);
|
2004-05-19 07:07:31 +02:00
|
|
|
}
|
|
|
|
|
2004-06-30 04:12:49 +02:00
|
|
|
playlist.idToPosition[playlist.positionToId[song]] = -1;
|
2004-06-09 02:18:31 +02:00
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
/* delete song from songs array */
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = song; i < playlist.length - 1; i++) {
|
|
|
|
moveSongFromTo(i + 1, i);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
/* now find it in the order array */
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length - 1; i++) {
|
|
|
|
if (playlist.order[i] == song)
|
|
|
|
break;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
songOrder = i;
|
|
|
|
/* delete the entry from the order array */
|
2006-07-20 18:02:40 +02:00
|
|
|
for (; i < playlist.length - 1; i++)
|
|
|
|
playlist.order[i] = playlist.order[i + 1];
|
2004-02-24 00:41:20 +01:00
|
|
|
/* readjust values in the order array */
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length - 1; i++) {
|
|
|
|
if (playlist.order[i] > song)
|
|
|
|
playlist.order[i]--;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
/* now take care of other misc stuff */
|
2006-07-20 18:02:40 +02:00
|
|
|
playlist.songs[playlist.length - 1] = NULL;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.length--;
|
|
|
|
|
|
|
|
incrPlaylistVersion();
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state != PLAYLIST_STATE_STOP
|
|
|
|
&& playlist.current == songOrder) {
|
2006-07-30 05:43:38 +02:00
|
|
|
/*if(playlist.current>=playlist.length) return playerStop(fd);
|
|
|
|
else return playPlaylistOrderNumber(fd,playlist.current); */
|
2008-08-26 08:27:16 +02:00
|
|
|
playerWait();
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist_noGoToNext = 1;
|
|
|
|
}
|
2004-06-02 22:40:30 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.current > songOrder) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.current--;
|
2006-07-20 18:02:40 +02:00
|
|
|
} else if (playlist.current >= playlist.length) {
|
2004-06-14 17:29:55 +02:00
|
|
|
incrPlaylistCurrent();
|
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.queued > songOrder) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.queued--;
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result deleteFromPlaylistById(int id)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-09-07 19:19:41 +02:00
|
|
|
int song = song_id_to_position(id);
|
|
|
|
if (song < 0)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
2004-06-09 03:30:51 +02:00
|
|
|
|
2008-09-07 19:19:41 +02:00
|
|
|
return deleteFromPlaylist(song);
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2008-10-08 10:49:11 +02:00
|
|
|
void
|
|
|
|
deleteASongFromPlaylist(const struct song *song)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
2004-04-11 03:53:25 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (NULL == playlist.songs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < playlist.length; i++) {
|
|
|
|
if (song == playlist.songs[i]) {
|
2008-09-07 13:39:31 +02:00
|
|
|
deleteFromPlaylist(i);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
void stopPlaylist(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
DEBUG("playlist: stop\n");
|
2008-08-26 08:27:16 +02:00
|
|
|
playerWait();
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.queued = -1;
|
|
|
|
playlist_state = PLAYLIST_STATE_STOP;
|
|
|
|
playlist_noGoToNext = 0;
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.random)
|
|
|
|
randomizeOrder(0, playlist.length - 1);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
static void playPlaylistOrderNumber(int orderNum)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2007-12-28 03:56:25 +01:00
|
|
|
char path_max_tmp[MPD_PATH_MAX];
|
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist_state = PLAYLIST_STATE_PLAY;
|
|
|
|
playlist_noGoToNext = 0;
|
|
|
|
playlist.queued = -1;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
DEBUG("playlist: play %i:\"%s\"\n", orderNum,
|
2008-10-08 11:05:34 +02:00
|
|
|
song_get_url(playlist.songs[playlist.order[orderNum]],
|
|
|
|
path_max_tmp));
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
playerPlay(playlist.songs[playlist.order[orderNum]]);
|
2004-06-01 16:16:17 +02:00
|
|
|
playlist.current = orderNum;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result playPlaylist(int song, int stopOnError)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i = song;
|
|
|
|
|
|
|
|
clearPlayerError();
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (song == -1) {
|
|
|
|
if (playlist.length == 0)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-06-04 05:10:54 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
2008-08-26 08:27:16 +02:00
|
|
|
playerSetPause(0);
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2006-07-14 23:01:19 +02:00
|
|
|
}
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.current >= 0 && playlist.current < playlist.length) {
|
2006-07-14 23:01:19 +02:00
|
|
|
i = playlist.current;
|
2006-07-20 18:02:40 +02:00
|
|
|
} else {
|
2006-07-14 23:01:19 +02:00
|
|
|
i = 0;
|
|
|
|
}
|
2006-07-20 18:02:40 +02:00
|
|
|
} else if (song < 0 || song >= playlist.length) {
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.random) {
|
|
|
|
if (song == -1 && playlist_state == PLAYLIST_STATE_PLAY) {
|
|
|
|
randomizeOrder(0, playlist.length - 1);
|
|
|
|
} else {
|
|
|
|
if (song >= 0)
|
|
|
|
for (i = 0; song != playlist.order[i]; i++) ;
|
|
|
|
if (playlist_state == PLAYLIST_STATE_STOP) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.current = 0;
|
|
|
|
}
|
2006-07-20 18:02:40 +02:00
|
|
|
swapOrder(i, playlist.current);
|
2004-02-24 00:41:20 +01:00
|
|
|
i = playlist.current;
|
2004-05-23 16:12:05 +02:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
playlist_stopOnError = stopOnError;
|
|
|
|
playlist_errorCount = 0;
|
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(i);
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result playPlaylistById(int id, int stopOnError)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-09-07 19:19:41 +02:00
|
|
|
int song;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (id == -1) {
|
2008-09-07 13:39:31 +02:00
|
|
|
return playPlaylist(id, stopOnError);
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2008-09-07 19:19:41 +02:00
|
|
|
song = song_id_to_position(id);
|
|
|
|
if (song < 0)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
2004-06-09 03:30:51 +02:00
|
|
|
|
2008-09-07 19:19:41 +02:00
|
|
|
return playPlaylist(song, stopOnError);
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2006-08-20 02:50:44 +02:00
|
|
|
static void syncCurrentPlayerDecodeMetadata(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-08 10:49:11 +02:00
|
|
|
struct song *songPlayer = playerCurrentDecodeSong();
|
|
|
|
struct song *song;
|
2004-06-05 03:14:37 +02:00
|
|
|
int songNum;
|
2007-12-28 03:56:25 +01:00
|
|
|
char path_max_tmp[MPD_PATH_MAX];
|
2004-05-31 13:42:46 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (!songPlayer)
|
|
|
|
return;
|
2004-05-31 13:42:46 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state != PLAYLIST_STATE_PLAY)
|
|
|
|
return;
|
2004-05-31 13:42:46 +02:00
|
|
|
|
2004-06-05 03:14:37 +02:00
|
|
|
songNum = playlist.order[playlist.current];
|
2006-07-14 23:01:19 +02:00
|
|
|
song = playlist.songs[songNum];
|
|
|
|
|
2008-10-06 18:52:13 +02:00
|
|
|
if (!song_is_file(song) &&
|
2008-10-08 11:05:34 +02:00
|
|
|
0 == strcmp(song_get_url(song, path_max_tmp), songPlayer->url) &&
|
2008-08-29 09:38:21 +02:00
|
|
|
!tag_equal(song->tag, songPlayer->tag)) {
|
2006-07-20 18:02:40 +02:00
|
|
|
if (song->tag)
|
2008-08-29 09:38:21 +02:00
|
|
|
tag_free(song->tag);
|
|
|
|
song->tag = tag_dup(songPlayer->tag);
|
2004-06-05 03:14:37 +02:00
|
|
|
playlist.songMod[songNum] = playlist.version;
|
2006-07-14 23:01:19 +02:00
|
|
|
incrPlaylistVersion();
|
|
|
|
}
|
2004-05-31 13:42:46 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void syncPlayerAndPlaylist(void)
|
|
|
|
{
|
|
|
|
if (playlist_state != PLAYLIST_STATE_PLAY)
|
|
|
|
return;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (getPlayerState() == PLAYER_STATE_STOP)
|
|
|
|
playPlaylistIfPlayerStopped();
|
2008-08-26 08:27:18 +02:00
|
|
|
else {
|
|
|
|
syncPlaylistWithQueue();
|
|
|
|
if (getPlayerQueueState() == PLAYER_QUEUE_BLANK)
|
|
|
|
queueNextSongInPlaylist();
|
|
|
|
}
|
2004-05-31 13:42:46 +02:00
|
|
|
|
2006-07-14 23:01:19 +02:00
|
|
|
syncCurrentPlayerDecodeMetadata();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
static void currentSongInPlaylist(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
|
|
|
if (playlist_state != PLAYLIST_STATE_PLAY)
|
2008-08-26 08:27:16 +02:00
|
|
|
return;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
playlist_stopOnError = 0;
|
|
|
|
|
2008-08-26 08:27:18 +02:00
|
|
|
syncPlaylistWithQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
if (playlist.current >= 0 && playlist.current < playlist.length)
|
|
|
|
playPlaylistOrderNumber(playlist.current);
|
|
|
|
else
|
|
|
|
stopPlaylist();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
void nextSongInPlaylist(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
|
|
|
if (playlist_state != PLAYLIST_STATE_PLAY)
|
2008-08-26 08:27:16 +02:00
|
|
|
return;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-08-26 08:27:18 +02:00
|
|
|
syncPlaylistWithQueue();
|
2006-07-20 18:02:40 +02:00
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist_stopOnError = 0;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.current < playlist.length - 1) {
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(playlist.current + 1);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else if (playlist.length && playlist.repeat) {
|
|
|
|
if (playlist.random)
|
|
|
|
randomizeOrder(0, playlist.length - 1);
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(0);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else {
|
2006-07-14 23:01:19 +02:00
|
|
|
incrPlaylistCurrent();
|
2008-08-26 08:27:16 +02:00
|
|
|
stopPlaylist();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void playPlaylistIfPlayerStopped(void)
|
|
|
|
{
|
|
|
|
if (getPlayerState() == PLAYER_STATE_STOP) {
|
2004-02-24 00:41:20 +01:00
|
|
|
int error = getPlayerError();
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (error == PLAYER_ERROR_NOERROR)
|
|
|
|
playlist_errorCount = 0;
|
|
|
|
else
|
|
|
|
playlist_errorCount++;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 20:53:56 +02:00
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY
|
|
|
|
&& ((playlist_stopOnError && error != PLAYER_ERROR_NOERROR)
|
|
|
|
|| error == PLAYER_ERROR_AUDIO
|
|
|
|
|| error == PLAYER_ERROR_SYSTEM
|
|
|
|
|| playlist_errorCount >= playlist.length)) {
|
2008-08-26 08:27:16 +02:00
|
|
|
stopPlaylist();
|
2006-07-20 18:02:40 +02:00
|
|
|
} else if (playlist_noGoToNext)
|
2008-08-26 08:27:16 +02:00
|
|
|
currentSongInPlaylist();
|
2006-07-20 18:02:40 +02:00
|
|
|
else
|
2008-08-26 08:27:16 +02:00
|
|
|
nextSongInPlaylist();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-08 11:03:39 +02:00
|
|
|
bool getPlaylistRepeatStatus(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
return playlist.repeat;
|
|
|
|
}
|
|
|
|
|
2008-10-08 11:03:39 +02:00
|
|
|
bool getPlaylistRandomStatus(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
return playlist.random;
|
|
|
|
}
|
|
|
|
|
2008-10-08 11:03:39 +02:00
|
|
|
void setPlaylistRepeatStatus(bool status)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
2008-04-12 06:11:56 +02:00
|
|
|
if (playlist.repeat && !status && playlist.queued == 0)
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
playlist.repeat = status;
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result moveSongInPlaylist(int from, int to)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
2008-10-08 10:49:11 +02:00
|
|
|
struct song *tmpSong;
|
2004-06-09 02:18:31 +02:00
|
|
|
int tmpId;
|
2008-01-26 13:47:04 +01:00
|
|
|
int currentSong;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (from < 0 || from >= playlist.length)
|
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-01-26 13:47:00 +01:00
|
|
|
if ((to >= 0 && to >= playlist.length) ||
|
2008-09-07 13:39:31 +02:00
|
|
|
(to < 0 && abs(to) > playlist.length))
|
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-01-26 13:47:04 +01:00
|
|
|
if (from == to) /* no-op */
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2008-01-26 13:47:04 +01:00
|
|
|
|
2008-01-26 13:47:00 +01:00
|
|
|
/*
|
|
|
|
* (to < 0) => move to offset from current song
|
|
|
|
* (-playlist.length == to) => move to position BEFORE current song
|
|
|
|
*/
|
2008-01-26 13:47:04 +01:00
|
|
|
currentSong = playlist.order[playlist.current];
|
|
|
|
if (to < 0 && playlist.current >= 0) {
|
|
|
|
if (currentSong == from)
|
|
|
|
/* no-op, can't be moved to offset of itself */
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2008-01-26 13:47:04 +01:00
|
|
|
to = (currentSong + abs(to)) % playlist.length;
|
|
|
|
}
|
2008-01-26 13:47:00 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
2008-01-26 13:47:04 +01:00
|
|
|
int queuedSong = -1;
|
|
|
|
|
|
|
|
if (playlist.queued >= 0)
|
2004-02-24 00:41:20 +01:00
|
|
|
queuedSong = playlist.order[playlist.queued];
|
2006-07-20 18:02:40 +02:00
|
|
|
if (queuedSong == from || queuedSong == to
|
2008-04-12 06:11:56 +02:00
|
|
|
|| currentSong == from || currentSong == to)
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
tmpSong = playlist.songs[from];
|
2004-06-30 04:12:49 +02:00
|
|
|
tmpId = playlist.positionToId[from];
|
2004-02-24 00:41:20 +01:00
|
|
|
/* move songs to one less in from->to */
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = from; i < to; i++) {
|
|
|
|
moveSongFromTo(i + 1, i);
|
2004-06-05 03:14:37 +02:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
/* move songs to one more in to->from */
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = from; i > to; i--) {
|
|
|
|
moveSongFromTo(i - 1, i);
|
2004-06-05 03:14:37 +02:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
/* put song at _to_ */
|
2004-06-30 04:12:49 +02:00
|
|
|
playlist.idToPosition[tmpId] = to;
|
|
|
|
playlist.positionToId[to] = tmpId;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.songs[to] = tmpSong;
|
2004-06-05 03:14:37 +02:00
|
|
|
playlist.songMod[to] = playlist.version;
|
2004-02-24 00:41:20 +01:00
|
|
|
/* now deal with order */
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.random) {
|
|
|
|
for (i = 0; i < playlist.length; i++) {
|
|
|
|
if (playlist.order[i] > from && playlist.order[i] <= to) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.order[i]--;
|
2006-07-20 18:02:40 +02:00
|
|
|
} else if (playlist.order[i] < from &&
|
|
|
|
playlist.order[i] >= to) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.order[i]++;
|
2006-07-20 18:02:40 +02:00
|
|
|
} else if (from == playlist.order[i]) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.order[i] = to;
|
|
|
|
}
|
|
|
|
}
|
2007-02-18 01:06:20 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (playlist.current == from)
|
|
|
|
playlist.current = to;
|
|
|
|
else if (playlist.current > from && playlist.current <= to) {
|
|
|
|
playlist.current--;
|
|
|
|
} else if (playlist.current >= to && playlist.current < from) {
|
|
|
|
playlist.current++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this first if statement isn't necessary since the queue
|
|
|
|
* would have been cleared out if queued == from */
|
|
|
|
if (playlist.queued == from)
|
|
|
|
playlist.queued = to;
|
|
|
|
else if (playlist.queued > from && playlist.queued <= to) {
|
|
|
|
playlist.queued--;
|
|
|
|
} else if (playlist.queued>= to && playlist.queued < from) {
|
|
|
|
playlist.queued++;
|
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
incrPlaylistVersion();
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result moveSongInPlaylistById(int id1, int to)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-09-07 19:19:41 +02:00
|
|
|
int song = song_id_to_position(id1);
|
|
|
|
if (song < 0)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
2004-06-09 03:30:51 +02:00
|
|
|
|
2008-09-07 19:19:41 +02:00
|
|
|
return moveSongInPlaylist(song, to);
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
static void orderPlaylist(void)
|
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.current >= 0 && playlist.current < playlist.length) {
|
2004-06-26 06:34:28 +02:00
|
|
|
playlist.current = playlist.order[playlist.current];
|
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
2008-04-12 06:11:56 +02:00
|
|
|
if (playlist.queued >= 0)
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.order[i] = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
static void swapOrder(int a, int b)
|
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int bak = playlist.order[a];
|
|
|
|
playlist.order[a] = playlist.order[b];
|
|
|
|
playlist.order[b] = bak;
|
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
static void randomizeOrder(int start, int end)
|
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
|
|
|
int ri;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
DEBUG("playlist: randomize from %i to %i\n", start, end);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
2008-04-12 06:11:56 +02:00
|
|
|
if (playlist.queued >= start && playlist.queued <= end)
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
for (i = start; i <= end; i++) {
|
|
|
|
ri = random() % (end - start + 1) + start;
|
|
|
|
if (ri == playlist.current)
|
|
|
|
playlist.current = i;
|
|
|
|
else if (i == playlist.current)
|
|
|
|
playlist.current = ri;
|
|
|
|
swapOrder(i, ri);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-08 11:03:39 +02:00
|
|
|
void setPlaylistRandomStatus(bool status)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-08 11:05:02 +02:00
|
|
|
if (status == playlist.random)
|
|
|
|
return;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
playlist.random = status;
|
|
|
|
|
2008-10-08 11:05:02 +02:00
|
|
|
if (playlist.random) {
|
|
|
|
/*if(playlist_state==PLAYLIST_STATE_PLAY) {
|
|
|
|
randomizeOrder(playlist.current+1,
|
|
|
|
playlist.length-1);
|
|
|
|
}
|
|
|
|
else */ randomizeOrder(0, playlist.length - 1);
|
|
|
|
if (playlist.current >= 0 &&
|
|
|
|
playlist.current < playlist.length) {
|
|
|
|
swapOrder(playlist.current, 0);
|
|
|
|
playlist.current = 0;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
orderPlaylist();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
void previousSongInPlaylist(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2007-01-14 04:07:53 +01:00
|
|
|
static time_t lastTime;
|
2004-06-10 23:42:20 +02:00
|
|
|
time_t diff = time(NULL) - lastTime;
|
|
|
|
|
|
|
|
lastTime += diff;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state != PLAYLIST_STATE_PLAY)
|
2008-08-26 08:27:16 +02:00
|
|
|
return;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-08-26 08:27:18 +02:00
|
|
|
syncPlaylistWithQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-14 23:01:19 +02:00
|
|
|
if (diff && getPlayerElapsedTime() > PLAYLIST_PREV_UNLESS_ELAPSED) {
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(playlist.current);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else {
|
|
|
|
if (playlist.current > 0) {
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(playlist.current - 1);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else if (playlist.repeat) {
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(playlist.length - 1);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else {
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(playlist.current);
|
2006-07-14 23:01:19 +02:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
void shufflePlaylist(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2004-02-24 00:41:20 +01:00
|
|
|
int i;
|
|
|
|
int ri;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.length > 1) {
|
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
/* put current playing song first */
|
2006-07-20 18:02:40 +02:00
|
|
|
swapSongs(0, playlist.order[playlist.current]);
|
|
|
|
if (playlist.random) {
|
2004-02-24 00:41:20 +01:00
|
|
|
int j;
|
2006-07-20 18:02:40 +02:00
|
|
|
for (j = 0; 0 != playlist.order[j]; j++) ;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.current = j;
|
2006-07-20 18:02:40 +02:00
|
|
|
} else
|
|
|
|
playlist.current = 0;
|
2004-02-24 00:41:20 +01:00
|
|
|
i = 1;
|
2006-07-20 18:02:40 +02:00
|
|
|
} else {
|
|
|
|
i = 0;
|
|
|
|
playlist.current = -1;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
/* shuffle the rest of the list */
|
2006-07-20 18:02:40 +02:00
|
|
|
for (; i < playlist.length; i++) {
|
|
|
|
ri = random() % (playlist.length - 1) + 1;
|
|
|
|
swapSongs(i, ri);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
incrPlaylistVersion();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result deletePlaylist(const char *utf8file)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2007-12-28 03:56:25 +01:00
|
|
|
char path_max_tmp[MPD_PATH_MAX];
|
2008-01-01 11:09:23 +01:00
|
|
|
|
|
|
|
utf8_to_fs_playlist_path(path_max_tmp, utf8file);
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (!isPlaylist(path_max_tmp))
|
|
|
|
return PLAYLIST_RESULT_NO_SUCH_LIST;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (unlink(path_max_tmp) < 0)
|
|
|
|
return PLAYLIST_RESULT_ERRNO;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result savePlaylist(const char *utf8file)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-01-01 11:09:18 +01:00
|
|
|
FILE *fp;
|
|
|
|
int i;
|
|
|
|
struct stat sb;
|
|
|
|
char path_max_tmp[MPD_PATH_MAX];
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (!is_valid_playlist_name(utf8file))
|
|
|
|
return PLAYLIST_RESULT_BAD_NAME;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-01-01 11:09:18 +01:00
|
|
|
utf8_to_fs_playlist_path(path_max_tmp, utf8file);
|
2008-09-07 13:39:31 +02:00
|
|
|
if (!stat(path_max_tmp, &sb))
|
|
|
|
return PLAYLIST_RESULT_LIST_EXISTS;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-01-01 11:09:18 +01:00
|
|
|
while (!(fp = fopen(path_max_tmp, "w")) && errno == EINTR);
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (fp == NULL)
|
|
|
|
return PLAYLIST_RESULT_ERRNO;
|
2008-03-26 11:37:10 +01:00
|
|
|
|
2008-01-01 11:09:18 +01:00
|
|
|
for (i = 0; i < playlist.length; i++) {
|
|
|
|
char tmp[MPD_PATH_MAX];
|
|
|
|
|
2008-10-08 11:05:34 +02:00
|
|
|
song_get_url(playlist.songs[i], path_max_tmp);
|
2008-01-01 11:09:18 +01:00
|
|
|
utf8_to_fs_charset(tmp, path_max_tmp);
|
|
|
|
|
|
|
|
if (playlist_saveAbsolutePaths &&
|
2008-10-06 18:52:13 +02:00
|
|
|
song_is_file(playlist.songs[i]))
|
2008-01-01 11:09:18 +01:00
|
|
|
fprintf(fp, "%s\n", rmp2amp_r(tmp, tmp));
|
|
|
|
else
|
|
|
|
fprintf(fp, "%s\n", tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fclose(fp) && errno == EINTR) ;
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
int getPlaylistCurrentSong(void)
|
|
|
|
{
|
|
|
|
if (playlist.current >= 0 && playlist.current < playlist.length) {
|
|
|
|
return playlist.order[playlist.current];
|
|
|
|
}
|
2006-07-14 23:01:19 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
return -1;
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
unsigned long getPlaylistVersion(void)
|
|
|
|
{
|
2006-03-26 15:46:05 +02:00
|
|
|
return playlist.version;
|
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
int getPlaylistLength(void)
|
|
|
|
{
|
2006-03-26 15:46:05 +02:00
|
|
|
return playlist.length;
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result seekSongInPlaylist(int song, float seek_time)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-08-26 08:44:34 +02:00
|
|
|
int i, ret;
|
2006-03-26 15:46:05 +02:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (song < 0 || song >= playlist.length)
|
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2006-03-26 15:46:05 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.random)
|
|
|
|
for (i = 0; song != playlist.order[i]; i++) ;
|
2008-08-26 08:44:33 +02:00
|
|
|
else
|
|
|
|
i = song;
|
2006-03-26 15:46:05 +02:00
|
|
|
|
|
|
|
clearPlayerError();
|
|
|
|
playlist_stopOnError = 1;
|
|
|
|
playlist_errorCount = 0;
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist_state == PLAYLIST_STATE_PLAY) {
|
2008-04-12 06:11:56 +02:00
|
|
|
if (playlist.queued >= 0)
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2008-08-26 08:27:16 +02:00
|
|
|
} else
|
|
|
|
playPlaylistOrderNumber(i);
|
2006-03-26 15:46:05 +02:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (playlist.current != i) {
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(i);
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
|
|
|
|
2008-08-26 08:44:34 +02:00
|
|
|
ret = playerSeek(playlist.songs[playlist.order[i]], seek_time);
|
|
|
|
if (ret < 0)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_NOT_PLAYING;
|
|
|
|
|
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
enum playlist_result seekSongInPlaylistById(int id, float seek_time)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-09-07 19:19:41 +02:00
|
|
|
int song = song_id_to_position(id);
|
|
|
|
if (song < 0)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
2006-03-26 15:46:05 +02:00
|
|
|
|
2008-09-07 19:19:41 +02:00
|
|
|
return seekSongInPlaylist(song, seek_time);
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
int getPlaylistSongId(int song)
|
|
|
|
{
|
2006-03-26 15:46:05 +02:00
|
|
|
return playlist.positionToId[song];
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:53:55 +02:00
|
|
|
int PlaylistInfo(struct client *client, const char *utf8file, int detail)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2007-05-16 14:02:10 +02:00
|
|
|
ListNode *node;
|
2008-01-01 11:09:36 +01:00
|
|
|
List *list;
|
2008-01-01 11:09:31 +01:00
|
|
|
|
2008-09-07 13:44:20 +02:00
|
|
|
if (!(list = loadStoredPlaylist(utf8file)))
|
2004-02-24 00:41:20 +01:00
|
|
|
return -1;
|
|
|
|
|
2008-01-01 11:09:36 +01:00
|
|
|
node = list->firstNode;
|
2007-05-16 14:02:10 +02:00
|
|
|
while (node != NULL) {
|
|
|
|
char *temp = node->data;
|
|
|
|
int wrote = 0;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2007-05-16 14:02:10 +02:00
|
|
|
if (detail) {
|
2008-10-08 10:49:11 +02:00
|
|
|
struct song *song = getSongFromDB(temp);
|
2007-05-16 14:02:10 +02:00
|
|
|
if (song) {
|
2008-10-07 22:06:59 +02:00
|
|
|
song_print_info(client, song);
|
2007-05-16 14:02:10 +02:00
|
|
|
wrote = 1;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2007-05-16 14:02:10 +02:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2007-05-16 14:02:10 +02:00
|
|
|
if (!wrote) {
|
2008-09-07 13:53:55 +02:00
|
|
|
client_printf(client, SONG_FILE "%s\n", temp);
|
2007-05-16 14:02:10 +02:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2007-05-16 14:02:10 +02:00
|
|
|
node = node->nextNode;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-01-01 11:09:36 +01:00
|
|
|
freeList(list);
|
2004-02-24 00:41:20 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:57:26 +02:00
|
|
|
enum playlist_result loadPlaylist(struct client *client, const char *utf8file)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2007-05-16 14:02:10 +02:00
|
|
|
ListNode *node;
|
2008-01-01 11:09:36 +01:00
|
|
|
List *list;
|
2008-01-01 11:09:31 +01:00
|
|
|
|
2008-09-07 13:44:12 +02:00
|
|
|
if (!(list = loadStoredPlaylist(utf8file)))
|
|
|
|
return PLAYLIST_RESULT_NO_SUCH_LIST;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-01-01 11:09:36 +01:00
|
|
|
node = list->firstNode;
|
2007-05-16 14:02:10 +02:00
|
|
|
while (node != NULL) {
|
|
|
|
char *temp = node->data;
|
2008-09-07 13:39:31 +02:00
|
|
|
if ((addToPlaylist(temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
|
2007-05-16 14:02:10 +02:00
|
|
|
/* for windows compatibility, convert slashes */
|
|
|
|
char *temp2 = xstrdup(temp);
|
|
|
|
char *p = temp2;
|
|
|
|
while (*p) {
|
|
|
|
if (*p == '\\')
|
|
|
|
*p = '/';
|
|
|
|
p++;
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
2008-09-07 13:39:31 +02:00
|
|
|
if ((addToPlaylist(temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
|
2008-09-07 13:57:26 +02:00
|
|
|
command_error(client, ACK_ERROR_PLAYLIST_LOAD,
|
|
|
|
"can't add file \"%s\"", temp2);
|
2007-05-16 14:02:10 +02:00
|
|
|
}
|
|
|
|
free(temp2);
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
2004-06-09 03:30:51 +02:00
|
|
|
|
2007-05-16 14:02:10 +02:00
|
|
|
node = node->nextNode;
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
2004-06-09 04:50:44 +02:00
|
|
|
|
2008-01-01 11:09:36 +01:00
|
|
|
freeList(list);
|
2008-09-07 13:44:12 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-06-09 04:50:44 +02:00
|
|
|
}
|
2007-02-24 03:00:03 +01:00
|
|
|
|
2008-09-07 13:53:55 +02:00
|
|
|
void searchForSongsInPlaylist(struct client *client,
|
|
|
|
int numItems, LocateTagItem * items)
|
2007-02-24 03:00:03 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char **originalNeedles = xmalloc(numItems * sizeof(char *));
|
|
|
|
|
|
|
|
for (i = 0; i < numItems; i++) {
|
|
|
|
originalNeedles[i] = items[i].needle;
|
|
|
|
items[i].needle = strDupToUpper(originalNeedles[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < playlist.length; i++) {
|
|
|
|
if (strstrSearchTags(playlist.songs[i], numItems, items))
|
2008-09-07 13:53:55 +02:00
|
|
|
printPlaylistSongInfo(client, i);
|
2007-02-24 03:00:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < numItems; i++) {
|
|
|
|
free(items[i].needle);
|
|
|
|
items[i].needle = originalNeedles[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
free(originalNeedles);
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:53:55 +02:00
|
|
|
void findSongsInPlaylist(struct client *client,
|
|
|
|
int numItems, LocateTagItem * items)
|
2007-02-24 03:00:03 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < playlist.length; i++) {
|
|
|
|
if (tagItemsFoundAndMatches(playlist.songs[i], numItems, items))
|
2008-09-07 13:53:55 +02:00
|
|
|
printPlaylistSongInfo(client, i);
|
2007-02-24 03:00:03 +01:00
|
|
|
}
|
|
|
|
}
|
2007-09-26 10:25:35 +02:00
|
|
|
|
2008-01-01 11:09:18 +01:00
|
|
|
/*
|
|
|
|
* Not supporting '/' was done out of laziness, and we should really
|
|
|
|
* strive to support it in the future.
|
|
|
|
*
|
|
|
|
* Not supporting '\r' and '\n' is done out of protocol limitations (and
|
|
|
|
* arguably laziness), but bending over head over heels to modify the
|
|
|
|
* protocol (and compatibility with all clients) to support idiots who
|
|
|
|
* put '\r' and '\n' in filenames isn't going to happen, either.
|
|
|
|
*/
|
2008-09-07 13:37:04 +02:00
|
|
|
int is_valid_playlist_name(const char *utf8path)
|
|
|
|
{
|
|
|
|
return strchr(utf8path, '/') == NULL &&
|
|
|
|
strchr(utf8path, '\n') == NULL &&
|
|
|
|
strchr(utf8path, '\r') == NULL;
|
|
|
|
}
|