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-10-14 11:10:47 +02:00
|
|
|
#include "playlist_save.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"
|
2008-10-08 11:07:35 +02:00
|
|
|
#include "database.h"
|
2008-10-14 11:10:49 +02:00
|
|
|
#include "mapper.h"
|
2004-02-24 00:41:20 +01:00
|
|
|
#include "path.h"
|
2008-10-22 17:21:57 +02:00
|
|
|
#include "stored_playlist.h"
|
2008-04-12 06:19:26 +02:00
|
|
|
#include "ack.h"
|
2008-10-14 22:38:14 +02:00
|
|
|
#include "idle.h"
|
2009-01-20 22:49:19 +01:00
|
|
|
#include "event_pipe.h"
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-10-15 19:36:37 +02:00
|
|
|
#include <glib.h>
|
|
|
|
|
2008-12-29 17:28:32 +01:00
|
|
|
#include <assert.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
2009-01-02 17:22:47 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
2008-12-29 17:28:32 +01:00
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
#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
|
|
|
|
2008-12-30 16:34:32 +01:00
|
|
|
static GRand *g_rand;
|
2004-06-02 22:40:30 +02:00
|
|
|
static Playlist playlist;
|
2009-01-21 08:48:02 +01:00
|
|
|
unsigned playlist_max_length;
|
2004-06-02 22:40:30 +02:00
|
|
|
static int playlist_stopOnError;
|
2008-10-23 07:19:46 +02:00
|
|
|
static unsigned playlist_errorCount;
|
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
|
|
|
|
2008-08-26 08:27:16 +02:00
|
|
|
static void playPlaylistOrderNumber(int orderNum);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
static void incrPlaylistVersion(void)
|
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_increment_version(&playlist.queue);
|
2008-10-14 22:38:14 +02:00
|
|
|
|
|
|
|
idle_add(IDLE_PLAYLIST);
|
2004-06-05 03:14:37 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void playlistVersionChange(void)
|
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_modify_all(&playlist.queue);
|
|
|
|
idle_add(IDLE_PLAYLIST);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2009-01-20 22:49:19 +01:00
|
|
|
static void
|
|
|
|
playlist_tag_event(void)
|
|
|
|
{
|
2009-01-23 00:09:26 +01:00
|
|
|
if (!playlist.playing)
|
2009-01-20 22:49:19 +01:00
|
|
|
return;
|
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
assert(playlist.current >= 0);
|
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_modify(&playlist.queue, playlist.current);
|
|
|
|
idle_add(IDLE_PLAYLIST);
|
2009-01-20 22:49:19 +01:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void initPlaylist(void)
|
|
|
|
{
|
2008-12-30 16:34:32 +01:00
|
|
|
g_rand = g_rand_new();
|
|
|
|
|
2009-01-21 08:48:02 +01:00
|
|
|
playlist_max_length = config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
|
|
|
|
DEFAULT_PLAYLIST_MAX_LENGTH);
|
2004-10-28 07:14:55 +02:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_init(&playlist.queue, playlist_max_length);
|
|
|
|
|
|
|
|
playlist.queued = -1;
|
|
|
|
playlist.current = -1;
|
|
|
|
|
2009-01-17 20:23:33 +01:00
|
|
|
playlist_saveAbsolutePaths =
|
|
|
|
config_get_bool(CONF_SAVE_ABSOLUTE_PATHS,
|
|
|
|
DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-20 22:49:19 +01:00
|
|
|
event_pipe_register(PIPE_EVENT_TAG, playlist_tag_event);
|
2004-06-09 02:18:31 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void finishPlaylist(void)
|
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_finish(&playlist.queue);
|
2008-12-30 16:34:32 +01:00
|
|
|
|
|
|
|
g_rand_free(g_rand);
|
|
|
|
g_rand = 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
|
|
|
{
|
2008-08-26 08:27:16 +02:00
|
|
|
stopPlaylist();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
for (unsigned i = 0; i < queue_length(&playlist.queue); i++) {
|
|
|
|
const struct song *song = queue_get(&playlist.queue, i);
|
|
|
|
if (!song_in_database(song))
|
|
|
|
pc_song_deleted(song);
|
2004-05-13 20:46:38 +02:00
|
|
|
}
|
2009-01-22 23:40:11 +01:00
|
|
|
|
|
|
|
queue_clear(&playlist.queue);
|
|
|
|
|
2006-07-14 23:01:19 +02:00
|
|
|
playlist.current = -1;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
incrPlaylistVersion();
|
|
|
|
}
|
|
|
|
|
2008-09-07 14:02:52 +02:00
|
|
|
void showPlaylist(struct client *client)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
for (unsigned i = 0; i < queue_length(&playlist.queue); i++) {
|
|
|
|
const struct song *song = queue_get(&playlist.queue, i);
|
|
|
|
char *uri = song_get_uri(song);
|
2009-01-04 19:09:34 +01:00
|
|
|
client_printf(client, "%i:%s\n", i, uri);
|
|
|
|
g_free(uri);
|
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-09-07 14:02:43 +02:00
|
|
|
static void playlist_save(FILE *fp)
|
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
for (unsigned i = 0; i < queue_length(&playlist.queue); i++) {
|
|
|
|
const struct song *song = queue_get(&playlist.queue, i);
|
|
|
|
char *uri = song_get_uri(song);
|
2009-01-04 19:09:34 +01:00
|
|
|
fprintf(fp, "%i:%s\n", i, uri);
|
|
|
|
g_free(uri);
|
|
|
|
}
|
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);
|
2009-01-23 00:09:26 +01:00
|
|
|
|
|
|
|
if (playlist.playing) {
|
2006-07-31 01:32:47 +02:00
|
|
|
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,
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.current));
|
2006-07-31 01:32:47 +02:00
|
|
|
fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_TIME,
|
|
|
|
getPlayerElapsedTime());
|
2009-01-23 00:09:26 +01:00
|
|
|
} else
|
2006-07-31 01:32:47 +02:00
|
|
|
fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_STOP);
|
2009-01-23 00:09:26 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_RANDOM,
|
|
|
|
playlist.queue.random);
|
|
|
|
fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_REPEAT,
|
|
|
|
playlist.queue.repeat);
|
2006-07-31 01:32:47 +02:00
|
|
|
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;
|
|
|
|
|
2009-01-03 14:53:23 +01:00
|
|
|
if (!fgets(buffer, PLAYLIST_BUFFER_SIZE, fp)) {
|
|
|
|
g_warning("No playlist in state file");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-12-28 19:54:49 +01:00
|
|
|
while (!g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_PLAYLIST_END)) {
|
|
|
|
g_strchomp(buffer);
|
|
|
|
|
2008-03-26 11:37:40 +01:00
|
|
|
temp = strtok(buffer, ":");
|
2009-01-03 14:53:23 +01:00
|
|
|
if (temp == NULL) {
|
|
|
|
g_warning("Malformed playlist line in state file");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-03-26 11:37:40 +01:00
|
|
|
song = atoi(temp);
|
2009-01-03 14:53:23 +01:00
|
|
|
if (!(temp = strtok(NULL, ""))) {
|
|
|
|
g_warning("Malformed playlist line in state file");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
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) {
|
2009-01-23 00:10:50 +01:00
|
|
|
playPlaylist(queue_length(&playlist.queue) - 1);
|
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) {
|
2009-01-22 23:40:11 +01:00
|
|
|
seekSongInPlaylist(queue_length(&playlist.queue) - 1,
|
2008-01-26 13:46:21 +01:00
|
|
|
seek_time);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
}
|
2008-12-28 19:54:49 +01:00
|
|
|
|
2009-01-03 14:53:23 +01:00
|
|
|
if (!fgets(buffer, PLAYLIST_BUFFER_SIZE, fp)) {
|
|
|
|
g_warning("'%s' not found in state file",
|
|
|
|
PLAYLIST_STATE_FILE_PLAYLIST_END);
|
|
|
|
break;
|
|
|
|
}
|
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];
|
|
|
|
|
2008-12-28 19:54:49 +01:00
|
|
|
while (fgets(buffer, sizeof(buffer), fp)) {
|
|
|
|
g_strchomp(buffer);
|
|
|
|
|
2008-10-28 20:33:56 +01:00
|
|
|
if (g_str_has_prefix(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-10-28 20:33:56 +01:00
|
|
|
} else if (g_str_has_prefix(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-10-28 20:33:56 +01:00
|
|
|
if (g_str_has_prefix(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-10-28 20:33:56 +01:00
|
|
|
} else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_CROSSFADE)) {
|
2006-07-31 01:32:47 +02:00
|
|
|
setPlayerCrossFade(atoi
|
|
|
|
(&
|
|
|
|
(buffer
|
|
|
|
[strlen
|
|
|
|
(PLAYLIST_STATE_FILE_CROSSFADE)])));
|
2008-10-28 20:33:56 +01:00
|
|
|
} else if (g_str_has_prefix(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-10-28 20:33:56 +01:00
|
|
|
} else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_CURRENT)) {
|
2006-07-31 01:32:47 +02:00
|
|
|
current = atoi(&(buffer
|
|
|
|
[strlen
|
|
|
|
(PLAYLIST_STATE_FILE_CURRENT)]));
|
2008-10-28 20:33:56 +01:00
|
|
|
} else if (g_str_has_prefix(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-10-23 07:19:46 +02:00
|
|
|
static void printPlaylistSongInfo(struct client *client, unsigned song)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
song_print_info(client, queue_get(&playlist.queue, song));
|
2008-10-23 07:19:46 +02:00
|
|
|
client_printf(client, "Pos: %u\nId: %u\n",
|
2009-01-22 23:40:11 +01:00
|
|
|
song, queue_position_to_id(&playlist.queue, 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
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
for (unsigned i = 0; i < queue_length(&playlist.queue); i++) {
|
|
|
|
if (queue_song_newer(&playlist.queue, i, version))
|
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
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
for (unsigned i = 0; i < queue_length(&playlist.queue); i++) {
|
|
|
|
if (queue_song_newer(&playlist.queue, i, version))
|
2008-09-07 14:02:52 +02:00
|
|
|
client_printf(client, "cpos: %i\nId: %i\n",
|
2009-01-22 23:40:11 +01:00
|
|
|
i, queue_position_to_id(&playlist.queue, i));
|
2006-04-23 13:10:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-10 17:39:49 +01:00
|
|
|
enum playlist_result
|
|
|
|
playlistInfo(struct client *client, unsigned start, unsigned end)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
if (end > queue_length(&playlist.queue))
|
|
|
|
end = queue_length(&playlist.queue);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-10 17:39:49 +01:00
|
|
|
if (start > end)
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-10 17:39:49 +01:00
|
|
|
for (unsigned i = start; 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-10-23 07:19:46 +02:00
|
|
|
static int song_id_to_position(unsigned id)
|
2008-09-07 13:39:31 +02:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
return queue_id_to_position(&playlist.queue, 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 begin = 0;
|
2009-01-22 23:40:11 +01:00
|
|
|
unsigned end = queue_length(&playlist.queue);
|
2004-06-09 03:30:51 +02:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
for (unsigned 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
|
|
|
}
|
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
static void swapSongs(unsigned song1, unsigned song2)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_swap(&playlist.queue, song1, song2);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2009-01-23 00:06:54 +01:00
|
|
|
static void
|
|
|
|
playlist_queue_song_order(unsigned order)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-23 00:06:54 +01:00
|
|
|
struct song *song;
|
|
|
|
char *uri;
|
2009-01-04 19:09:34 +01:00
|
|
|
|
2009-01-23 00:06:54 +01:00
|
|
|
assert(queue_valid_order(&playlist.queue, order));
|
2009-01-04 19:09:34 +01:00
|
|
|
|
2009-01-23 00:06:54 +01:00
|
|
|
playlist.queued = order;
|
2009-01-04 19:09:34 +01:00
|
|
|
|
2009-01-23 00:06:54 +01:00
|
|
|
song = queue_get_order(&playlist.queue, order);
|
|
|
|
uri = song_get_uri(song);
|
|
|
|
g_debug("playlist: queue song %i:\"%s\"",
|
|
|
|
playlist.queued, uri);
|
|
|
|
g_free(uri);
|
|
|
|
|
|
|
|
queueSong(song);
|
|
|
|
}
|
2009-01-04 19:09:34 +01:00
|
|
|
|
2009-01-23 00:06:54 +01:00
|
|
|
static void queueNextSongInPlaylist(void)
|
|
|
|
{
|
2009-01-23 00:08:40 +01:00
|
|
|
assert(playlist.queued < 0);
|
|
|
|
|
2009-01-23 00:06:54 +01:00
|
|
|
if (playlist.current + 1 < (int)queue_length(&playlist.queue)) {
|
|
|
|
playlist_queue_song_order(playlist.current + 1);
|
|
|
|
} else if (!queue_is_empty(&playlist.queue) && playlist.queue.repeat) {
|
2009-01-23 00:08:40 +01:00
|
|
|
if (playlist.queue.random) {
|
|
|
|
unsigned current_position =
|
|
|
|
queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.current);
|
|
|
|
queue_shuffle_order(&playlist.queue);
|
|
|
|
playlist.current =
|
|
|
|
queue_position_to_order(&playlist.queue,
|
|
|
|
current_position);
|
|
|
|
}
|
2009-01-22 23:40:11 +01:00
|
|
|
|
2009-01-23 00:06:54 +01:00
|
|
|
playlist_queue_song_order(0);
|
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-10-12 00:07:54 +02:00
|
|
|
if (pc.next_song == NULL && playlist.queued != -1) {
|
|
|
|
playlist.current = playlist.queued;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.queued = -1;
|
2008-10-14 22:38:14 +02:00
|
|
|
|
|
|
|
idle_add(IDLE_PLAYER);
|
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
|
|
|
{
|
2008-10-12 00:03:27 +02:00
|
|
|
assert(playlist.queued >= 0);
|
|
|
|
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.queued = -1;
|
|
|
|
|
2008-10-12 00:07:54 +02:00
|
|
|
pc_cancel();
|
2008-04-12 06:11:56 +02:00
|
|
|
}
|
|
|
|
|
2008-12-30 19:14:13 +01:00
|
|
|
#ifndef WIN32
|
2008-10-15 22:35:13 +02:00
|
|
|
enum playlist_result
|
2008-10-23 07:19:46 +02:00
|
|
|
playlist_append_file(const char *path, int uid, unsigned *added_id)
|
2008-10-15 22:35:13 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct stat st;
|
|
|
|
struct song *song;
|
|
|
|
|
|
|
|
if (uid <= 0)
|
|
|
|
/* unauthenticated client */
|
|
|
|
return PLAYLIST_RESULT_DENIED;
|
|
|
|
|
|
|
|
ret = stat(path, &st);
|
|
|
|
if (ret < 0)
|
|
|
|
return PLAYLIST_RESULT_ERRNO;
|
|
|
|
|
2008-10-15 23:10:05 +02:00
|
|
|
if (st.st_uid != (uid_t)uid && (st.st_mode & 0444) != 0444)
|
2008-10-15 22:35:13 +02:00
|
|
|
/* client is not owner */
|
|
|
|
return PLAYLIST_RESULT_DENIED;
|
|
|
|
|
|
|
|
song = song_file_load(path, NULL);
|
|
|
|
if (song == NULL)
|
|
|
|
return PLAYLIST_RESULT_NO_SUCH_SONG;
|
|
|
|
|
|
|
|
return addSongToPlaylist(song, added_id);
|
|
|
|
}
|
2008-12-30 19:14:13 +01:00
|
|
|
#endif
|
2008-10-15 22:35:13 +02:00
|
|
|
|
2008-10-15 22:35:00 +02:00
|
|
|
static struct song *
|
|
|
|
song_by_url(const char *url)
|
|
|
|
{
|
|
|
|
struct song *song;
|
|
|
|
|
|
|
|
song = db_get_song(url);
|
|
|
|
if (song != NULL)
|
|
|
|
return song;
|
|
|
|
|
2009-01-04 16:23:33 +01:00
|
|
|
if (uri_has_scheme(url))
|
2008-10-15 22:35:00 +02:00
|
|
|
return song_remote_new(url);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
enum playlist_result addToPlaylist(const char *url, unsigned *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
|
|
|
|
2009-01-04 18:17:37 +01:00
|
|
|
g_debug("add to playlist: %s", url);
|
2006-07-20 18:02:40 +02:00
|
|
|
|
2008-10-15 22:35:00 +02:00
|
|
|
song = song_by_url(url);
|
|
|
|
if (song == NULL)
|
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-10-08 10:49:11 +02:00
|
|
|
enum playlist_result
|
2008-10-23 07:19:46 +02:00
|
|
|
addSongToPlaylist(struct song *song, unsigned *added_id)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned id;
|
2004-11-03 00:44:33 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (queue_is_full(&playlist.queue))
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_TOO_LARGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing && playlist.queued >= 0 &&
|
2009-01-22 23:40:11 +01:00
|
|
|
playlist.current == (int)queue_length(&playlist.queue) - 1)
|
2008-10-12 00:03:27 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
id = queue_append(&playlist.queue, song);
|
2004-11-03 00:44:33 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (playlist.queue.random) {
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned 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;
|
2009-01-22 23:40:11 +01:00
|
|
|
if (start < queue_length(&playlist.queue)) {
|
2008-12-30 16:34:32 +01:00
|
|
|
unsigned swap = g_rand_int_range(g_rand, start,
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_length(&playlist.queue));
|
|
|
|
queue_swap_order(&playlist.queue,
|
|
|
|
queue_length(&playlist.queue) - 1, swap);
|
2006-07-20 18:02:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-10-23 07:19:46 +02:00
|
|
|
enum playlist_result swapSongsInPlaylist(unsigned song1, unsigned song2)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
if (!queue_valid_position(&playlist.queue, song1) ||
|
|
|
|
!queue_valid_position(&playlist.queue, song2))
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2006-07-20 18:02:40 +02:00
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing && playlist.queued >= 0) {
|
2009-01-22 23:40:11 +01:00
|
|
|
unsigned queuedSong = queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.queued);
|
|
|
|
unsigned currentSong = queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.current);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
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);
|
2009-01-22 23:40:11 +01:00
|
|
|
if (playlist.queue.random) {
|
|
|
|
queue_swap_order(&playlist.queue,
|
|
|
|
queue_position_to_order(&playlist.queue,
|
|
|
|
song1),
|
|
|
|
queue_position_to_order(&playlist.queue,
|
|
|
|
song2));
|
2006-07-20 18:02:40 +02:00
|
|
|
} else {
|
2008-10-23 07:19:46 +02:00
|
|
|
if (playlist.current == (int)song1)
|
2006-07-20 18:02:40 +02:00
|
|
|
playlist.current = song2;
|
2008-10-23 07:19:46 +02:00
|
|
|
else if (playlist.current == (int)song2)
|
2006-07-20 18:02:40 +02:00
|
|
|
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-10-23 07:19:46 +02:00
|
|
|
enum playlist_result swapSongsInPlaylistById(unsigned id1, unsigned 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
|
|
|
}
|
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
enum playlist_result deleteFromPlaylist(unsigned song)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned songOrder;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (song >= queue_length(&playlist.queue))
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
songOrder = queue_position_to_order(&playlist.queue, song);
|
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing && playlist.queued >= 0
|
2009-01-22 23:40:11 +01:00
|
|
|
&& (playlist.queued == (int)songOrder ||
|
|
|
|
playlist.current == (int)songOrder))
|
2008-10-12 00:03:27 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing && playlist.current == (int)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();
|
2009-01-23 00:10:33 +01:00
|
|
|
|
|
|
|
playlist.current = queue_next_order(&playlist.queue,
|
|
|
|
playlist.current);
|
|
|
|
if (playlist.current == (int)songOrder)
|
|
|
|
playlist.current = -1;
|
2009-01-23 00:10:38 +01:00
|
|
|
|
|
|
|
if (playlist.current >= 0)
|
|
|
|
/* play the song after the deleted one */
|
|
|
|
playPlaylistOrderNumber(playlist.current);
|
|
|
|
else
|
|
|
|
/* no songs left to play, stop playback
|
|
|
|
completely */
|
|
|
|
stopPlaylist();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2004-06-02 22:40:30 +02:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (!song_in_database(queue_get(&playlist.queue, song)))
|
|
|
|
pc_song_deleted(queue_get(&playlist.queue, song));
|
|
|
|
|
|
|
|
queue_delete(&playlist.queue, song);
|
|
|
|
|
|
|
|
incrPlaylistVersion();
|
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
if (playlist.current > (int)songOrder) {
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.current--;
|
2004-06-14 17:29:55 +02:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
if (playlist.queued > (int)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-10-23 07:19:46 +02:00
|
|
|
enum playlist_result deleteFromPlaylistById(unsigned 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
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
for (int i = queue_length(&playlist.queue) - 1; i >= 0; --i)
|
|
|
|
if (song == queue_get(&playlist.queue, i))
|
2008-09-07 13:39:31 +02:00
|
|
|
deleteFromPlaylist(i);
|
2008-12-17 16:45:49 +01:00
|
|
|
|
|
|
|
pc_song_deleted(song);
|
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
|
|
|
{
|
2009-01-04 18:17:37 +01:00
|
|
|
g_debug("playlist: stop");
|
2008-08-26 08:27:16 +02:00
|
|
|
playerWait();
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.queued = -1;
|
2009-01-23 00:09:26 +01:00
|
|
|
playlist.playing = false;
|
2009-01-23 00:08:40 +01:00
|
|
|
|
|
|
|
if (playlist.queue.random) {
|
|
|
|
unsigned current_position =
|
|
|
|
queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.current);
|
|
|
|
queue_shuffle_order(&playlist.queue);
|
|
|
|
playlist.current =
|
|
|
|
queue_position_to_order(&playlist.queue,
|
|
|
|
current_position);
|
|
|
|
}
|
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
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
struct song *song;
|
2009-01-04 19:09:34 +01:00
|
|
|
char *uri;
|
2007-12-28 03:56:25 +01:00
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
playlist.playing = true;
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.queued = -1;
|
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
song = queue_get_order(&playlist.queue, orderNum);
|
|
|
|
|
|
|
|
uri = song_get_uri(song);
|
2009-01-04 19:09:34 +01:00
|
|
|
g_debug("playlist: play %i:\"%s\"", orderNum, uri);
|
|
|
|
g_free(uri);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
playerPlay(song);
|
2004-06-01 16:16:17 +02:00
|
|
|
playlist.current = orderNum;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2009-01-23 00:10:50 +01:00
|
|
|
enum playlist_result playPlaylist(int song)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned i = song;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
|
|
|
clearPlayerError();
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
if (song == -1) {
|
2009-01-22 23:40:11 +01:00
|
|
|
if (queue_is_empty(&playlist.queue))
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2004-06-04 05:10:54 +02:00
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing) {
|
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
|
|
|
}
|
2009-01-22 23:40:11 +01:00
|
|
|
|
|
|
|
i = playlist.current >= 0
|
|
|
|
? playlist.current
|
|
|
|
: 0;
|
|
|
|
} else if (!queue_valid_position(&playlist.queue, song))
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (playlist.queue.random) {
|
2009-01-23 00:09:26 +01:00
|
|
|
if (song == -1 && playlist.playing) {
|
2009-01-23 00:08:40 +01:00
|
|
|
queue_shuffle_order(&playlist.queue);
|
2006-07-20 18:02:40 +02:00
|
|
|
} else {
|
|
|
|
if (song >= 0)
|
2009-01-22 23:40:11 +01:00
|
|
|
i = queue_position_to_order(&playlist.queue, song);
|
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (!playlist.playing)
|
2004-02-24 00:41:20 +01:00
|
|
|
playlist.current = 0;
|
2009-01-22 23:40:11 +01:00
|
|
|
|
|
|
|
queue_swap_order(&playlist.queue,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2009-01-23 00:10:50 +01:00
|
|
|
playlist_stopOnError = false;
|
2004-02-24 00:41:20 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2009-01-23 00:10:50 +01:00
|
|
|
enum playlist_result playPlaylistById(int id)
|
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) {
|
2009-01-23 00:10:50 +01:00
|
|
|
return playPlaylist(id);
|
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
|
|
|
|
2009-01-23 00:10:50 +01:00
|
|
|
return playPlaylist(song);
|
2004-06-09 03:30:51 +02:00
|
|
|
}
|
|
|
|
|
2009-01-21 16:17:57 +01:00
|
|
|
static void playPlaylistIfPlayerStopped(void);
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
void syncPlayerAndPlaylist(void)
|
|
|
|
{
|
2009-01-23 00:09:26 +01:00
|
|
|
if (!playlist.playing)
|
2006-07-20 18:02:40 +02:00
|
|
|
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();
|
2008-10-12 00:07:54 +02:00
|
|
|
if (pc.next_song == NULL)
|
2008-08-26 08:27:18 +02:00
|
|
|
queueNextSongInPlaylist();
|
|
|
|
}
|
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
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
int next_order;
|
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (!playlist.playing)
|
2008-08-26 08:27:16 +02:00
|
|
|
return;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
assert(!queue_is_empty(&playlist.queue));
|
|
|
|
assert(queue_valid_order(&playlist.queue, playlist.current));
|
|
|
|
|
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;
|
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
next_order = queue_next_order(&playlist.queue, playlist.current);
|
|
|
|
if (next_order < 0) {
|
2008-08-26 08:27:16 +02:00
|
|
|
stopPlaylist();
|
2009-01-22 23:40:11 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (next_order == 0) {
|
|
|
|
assert(playlist.queue.repeat);
|
|
|
|
|
2009-01-23 00:08:40 +01:00
|
|
|
queue_shuffle_order(&playlist.queue);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2009-01-22 23:40:11 +01:00
|
|
|
|
|
|
|
playPlaylistOrderNumber(next_order);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2009-01-21 16:17:57 +01:00
|
|
|
static void playPlaylistIfPlayerStopped(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
|
|
|
if (getPlayerState() == PLAYER_STATE_STOP) {
|
2009-01-21 16:17:57 +01:00
|
|
|
enum player_error error = getPlayerError();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
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
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing
|
2006-07-20 20:53:56 +02:00
|
|
|
&& ((playlist_stopOnError && error != PLAYER_ERROR_NOERROR)
|
|
|
|
|| error == PLAYER_ERROR_AUDIO
|
|
|
|
|| error == PLAYER_ERROR_SYSTEM
|
2009-01-22 23:40:11 +01:00
|
|
|
|| playlist_errorCount >= queue_length(&playlist.queue))) {
|
2008-08-26 08:27:16 +02:00
|
|
|
stopPlaylist();
|
2009-01-23 00:10:38 +01: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
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
return playlist.queue.repeat;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-10-08 11:03:39 +02:00
|
|
|
bool getPlaylistRandomStatus(void)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
return playlist.queue.random;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-10-08 11:03:39 +02:00
|
|
|
void setPlaylistRepeatStatus(bool status)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-23 00:07:20 +01:00
|
|
|
if (status == playlist.queue.repeat)
|
|
|
|
return;
|
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing &&
|
2009-01-23 00:07:20 +01:00
|
|
|
playlist.queue.repeat && playlist.queued == 0)
|
2008-10-12 00:03:27 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
playlist.queue.repeat = status;
|
2008-10-14 22:38:14 +02:00
|
|
|
|
|
|
|
idle_add(IDLE_OPTIONS);
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
enum playlist_result moveSongInPlaylist(unsigned from, int to)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-22 16:14:34 +01:00
|
|
|
int currentSong;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (!queue_valid_position(&playlist.queue, from))
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if ((to >= 0 && to >= (int)queue_length(&playlist.queue)) ||
|
|
|
|
(to < 0 && abs(to) > (int)queue_length(&playlist.queue)))
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
if ((int)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
|
|
|
|
*/
|
2009-01-22 16:14:34 +01:00
|
|
|
currentSong = playlist.current >= 0
|
2009-01-22 23:40:11 +01:00
|
|
|
? (int)queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.current)
|
|
|
|
: -1;
|
2008-01-26 13:47:04 +01:00
|
|
|
if (to < 0 && playlist.current >= 0) {
|
2009-01-22 16:14:34 +01:00
|
|
|
if ((unsigned)currentSong == from)
|
2008-01-26 13:47:04 +01:00
|
|
|
/* no-op, can't be moved to offset of itself */
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_SUCCESS;
|
2009-01-22 23:40:11 +01:00
|
|
|
to = (currentSong + abs(to)) % queue_length(&playlist.queue);
|
2008-01-26 13:47:04 +01:00
|
|
|
}
|
2008-01-26 13:47:00 +01:00
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing && playlist.queued >= 0) {
|
2009-01-22 23:40:11 +01:00
|
|
|
int queuedSong = queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.queued);
|
2008-10-23 07:19:46 +02:00
|
|
|
if (queuedSong == (int)from || queuedSong == to
|
2009-01-22 16:14:34 +01:00
|
|
|
|| currentSong == (int)from || currentSong == to)
|
2008-08-26 08:27:17 +02:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_move(&playlist.queue, from, to);
|
|
|
|
|
|
|
|
if (!playlist.queue.random) {
|
|
|
|
/* update current/queued */
|
2008-10-23 07:19:46 +02:00
|
|
|
if (playlist.current == (int)from)
|
2007-02-18 01:06:20 +01:00
|
|
|
playlist.current = to;
|
2008-10-23 07:19:46 +02:00
|
|
|
else if (playlist.current > (int)from &&
|
|
|
|
playlist.current <= to) {
|
2007-02-18 01:06:20 +01:00
|
|
|
playlist.current--;
|
2008-10-23 07:19:46 +02:00
|
|
|
} else if (playlist.current >= to &&
|
|
|
|
playlist.current < (int)from) {
|
2007-02-18 01:06:20 +01:00
|
|
|
playlist.current++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this first if statement isn't necessary since the queue
|
|
|
|
* would have been cleared out if queued == from */
|
2008-10-23 07:19:46 +02:00
|
|
|
if (playlist.queued == (int)from)
|
2007-02-18 01:06:20 +01:00
|
|
|
playlist.queued = to;
|
2008-10-23 07:19:46 +02:00
|
|
|
else if (playlist.queued > (int)from && playlist.queued <= to) {
|
2007-02-18 01:06:20 +01:00
|
|
|
playlist.queued--;
|
2008-10-23 07:19:46 +02:00
|
|
|
} else if (playlist.queued>= to && playlist.queued < (int)from) {
|
2007-02-18 01:06:20 +01:00
|
|
|
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-10-23 07:19:46 +02:00
|
|
|
enum playlist_result moveSongInPlaylistById(unsigned 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)
|
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
if (playlist.current >= 0)
|
|
|
|
playlist.current = queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.current);
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing && playlist.queued >= 0)
|
2008-11-12 21:55:13 +01:00
|
|
|
clearPlayerQueue();
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
queue_restore_order(&playlist.queue);
|
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
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
if (status == playlist.queue.random)
|
2008-10-08 11:05:02 +02:00
|
|
|
return;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-23 00:07:10 +01:00
|
|
|
if (playlist.queued >= 0)
|
|
|
|
clearPlayerQueue();
|
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
playlist.queue.random = status;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (playlist.queue.random) {
|
2009-01-23 00:08:40 +01:00
|
|
|
int current_position = playlist.current >= 0
|
|
|
|
? (int)queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.current)
|
|
|
|
: -1;
|
|
|
|
|
|
|
|
queue_shuffle_order(&playlist.queue);
|
|
|
|
|
|
|
|
if (current_position >= 0) {
|
|
|
|
unsigned current_order =
|
|
|
|
queue_position_to_order(&playlist.queue,
|
|
|
|
current_position);
|
|
|
|
queue_swap_order(&playlist.queue, 0, current_order);
|
2008-10-08 11:05:02 +02:00
|
|
|
playlist.current = 0;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
orderPlaylist();
|
2008-10-14 22:38:14 +02:00
|
|
|
|
|
|
|
idle_add(IDLE_OPTIONS);
|
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;
|
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (!playlist.playing)
|
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);
|
2009-01-22 23:40:11 +01:00
|
|
|
} else if (playlist.queue.repeat) {
|
|
|
|
playPlaylistOrderNumber(queue_length(&playlist.queue) - 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
|
|
|
{
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned i;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-23 00:09:29 +01:00
|
|
|
if (queue_length(&playlist.queue) <= 1)
|
|
|
|
return;
|
2009-01-22 16:14:34 +01:00
|
|
|
|
2009-01-23 00:09:29 +01:00
|
|
|
if (playlist.playing) {
|
|
|
|
if (playlist.queued >= 0)
|
|
|
|
clearPlayerQueue();
|
2009-01-22 23:40:11 +01:00
|
|
|
|
2009-01-23 00:09:29 +01:00
|
|
|
if (playlist.current >= 0)
|
|
|
|
/* put current playing song first */
|
|
|
|
swapSongs(0, queue_order_to_position(&playlist.queue,
|
|
|
|
playlist.current));
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2009-01-23 00:09:29 +01:00
|
|
|
if (playlist.queue.random) {
|
|
|
|
playlist.current =
|
|
|
|
queue_position_to_order(&playlist.queue, 0);
|
|
|
|
} else
|
|
|
|
playlist.current = 0;
|
|
|
|
i = 1;
|
|
|
|
} else {
|
|
|
|
i = 0;
|
|
|
|
playlist.current = -1;
|
2004-02-24 00:41:20 +01:00
|
|
|
}
|
2009-01-23 00:09:29 +01:00
|
|
|
|
|
|
|
/* shuffle the rest of the list */
|
|
|
|
queue_shuffle_range(&playlist.queue, i,
|
|
|
|
queue_length(&playlist.queue));
|
|
|
|
|
|
|
|
incrPlaylistVersion();
|
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;
|
2009-01-01 19:17:44 +01:00
|
|
|
char *path;
|
2008-01-01 11:09:18 +01:00
|
|
|
|
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
|
|
|
|
2009-01-01 19:17:44 +01:00
|
|
|
path = map_spl_utf8_to_fs(utf8file);
|
2009-01-18 16:15:45 +01:00
|
|
|
if (path == NULL)
|
|
|
|
return PLAYLIST_RESULT_DISABLED;
|
|
|
|
|
2009-01-01 19:22:07 +01:00
|
|
|
if (g_file_test(path, G_FILE_TEST_EXISTS)) {
|
2009-01-01 19:17:44 +01:00
|
|
|
g_free(path);
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_LIST_EXISTS;
|
2009-01-01 19:17:44 +01:00
|
|
|
}
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-10-31 16:47:14 +01:00
|
|
|
while (!(fp = fopen(path, "w")) && errno == EINTR);
|
2009-01-01 19:17:44 +01:00
|
|
|
g_free(path);
|
2008-01-01 11:09:18 +01:00
|
|
|
|
2008-09-07 13:39:31 +02:00
|
|
|
if (fp == NULL)
|
|
|
|
return PLAYLIST_RESULT_ERRNO;
|
2008-03-26 11:37:10 +01:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
for (unsigned i = 0; i < queue_length(&playlist.queue); i++)
|
|
|
|
playlist_print_song(fp, queue_get(&playlist.queue, i));
|
2008-01-01 11:09:18 +01:00
|
|
|
|
|
|
|
while (fclose(fp) && errno == EINTR) ;
|
|
|
|
|
2008-10-14 22:38:14 +02:00
|
|
|
idle_add(IDLE_STORED_PLAYLIST);
|
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)
|
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
if (playlist.current >= 0)
|
|
|
|
return queue_order_to_position(&playlist.queue,
|
|
|
|
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)
|
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
return playlist.queue.version;
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
|
|
|
|
2006-07-20 18:02:40 +02:00
|
|
|
int getPlaylistLength(void)
|
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
return queue_length(&playlist.queue);
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
enum playlist_result seekSongInPlaylist(unsigned song, float seek_time)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned i;
|
|
|
|
int ret;
|
2006-03-26 15:46:05 +02:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (!queue_valid_position(&playlist.queue, song))
|
2008-09-07 13:39:31 +02:00
|
|
|
return PLAYLIST_RESULT_BAD_RANGE;
|
2006-03-26 15:46:05 +02:00
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
if (playlist.queue.random)
|
|
|
|
i = queue_position_to_order(&playlist.queue, song);
|
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;
|
|
|
|
|
2009-01-23 00:09:26 +01:00
|
|
|
if (playlist.playing) {
|
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
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
if (playlist.current != (int)i) {
|
2008-08-26 08:27:16 +02:00
|
|
|
playPlaylistOrderNumber(i);
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
ret = playerSeek(queue_get_order(&playlist.queue, i), seek_time);
|
2008-08-26 08:44:34 +02:00
|
|
|
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-10-23 07:19:46 +02:00
|
|
|
enum playlist_result seekSongInPlaylistById(unsigned 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
|
|
|
}
|
|
|
|
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned getPlaylistSongId(unsigned song)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
return queue_position_to_id(&playlist.queue, song);
|
2006-03-26 15:46:05 +02:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2008-10-23 09:54:28 +02:00
|
|
|
GPtrArray *list;
|
2008-01-01 11:09:31 +01:00
|
|
|
|
2008-10-22 17:21:59 +02:00
|
|
|
if (!(list = spl_load(utf8file)))
|
2004-02-24 00:41:20 +01:00
|
|
|
return -1;
|
|
|
|
|
2008-10-23 09:54:28 +02:00
|
|
|
for (unsigned i = 0; i < list->len; ++i) {
|
|
|
|
const char *temp = g_ptr_array_index(list, i);
|
2007-05-16 14:02:10 +02:00
|
|
|
int wrote = 0;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2007-05-16 14:02:10 +02:00
|
|
|
if (detail) {
|
2008-10-09 16:26:09 +02:00
|
|
|
struct song *song = db_get_song(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
|
|
|
}
|
|
|
|
|
2008-10-23 09:54:28 +02:00
|
|
|
spl_free(list);
|
2004-02-24 00:41:20 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-04 18:59:32 +01:00
|
|
|
enum playlist_result loadPlaylist(const char *utf8file)
|
2006-07-20 18:02:40 +02:00
|
|
|
{
|
2008-10-23 09:54:28 +02:00
|
|
|
GPtrArray *list;
|
2008-01-01 11:09:31 +01:00
|
|
|
|
2008-10-22 17:21:59 +02:00
|
|
|
if (!(list = spl_load(utf8file)))
|
2008-09-07 13:44:12 +02:00
|
|
|
return PLAYLIST_RESULT_NO_SUCH_LIST;
|
2004-02-24 00:41:20 +01:00
|
|
|
|
2008-10-23 09:54:28 +02:00
|
|
|
for (unsigned i = 0; i < list->len; ++i) {
|
|
|
|
const char *temp = g_ptr_array_index(list, i);
|
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 */
|
2009-01-02 17:22:47 +01:00
|
|
|
char *temp2 = g_strdup(temp);
|
2007-05-16 14:02:10 +02:00
|
|
|
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) {
|
2009-01-04 18:59:32 +01:00
|
|
|
g_warning("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 04:50:44 +02:00
|
|
|
|
2008-10-23 09:54:28 +02:00
|
|
|
spl_free(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,
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned numItems, LocateTagItem * items)
|
2007-02-24 03:00:03 +01:00
|
|
|
{
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned i;
|
2009-01-02 17:22:47 +01:00
|
|
|
char **originalNeedles = g_malloc(numItems * sizeof(char *));
|
2007-02-24 03:00:03 +01:00
|
|
|
|
|
|
|
for (i = 0; i < numItems; i++) {
|
|
|
|
originalNeedles[i] = items[i].needle;
|
2008-10-15 19:36:37 +02:00
|
|
|
items[i].needle = g_utf8_casefold(originalNeedles[i], -1);
|
2007-02-24 03:00:03 +01:00
|
|
|
}
|
|
|
|
|
2009-01-22 23:40:11 +01:00
|
|
|
for (i = 0; i < queue_length(&playlist.queue); i++) {
|
|
|
|
const struct song *song = queue_get(&playlist.queue, i);
|
|
|
|
|
|
|
|
if (strstrSearchTags(song, 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++) {
|
2008-10-15 19:36:37 +02:00
|
|
|
g_free(items[i].needle);
|
2007-02-24 03:00:03 +01:00
|
|
|
items[i].needle = originalNeedles[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
free(originalNeedles);
|
|
|
|
}
|
|
|
|
|
2008-09-07 13:53:55 +02:00
|
|
|
void findSongsInPlaylist(struct client *client,
|
2008-10-23 07:19:46 +02:00
|
|
|
unsigned numItems, LocateTagItem * items)
|
2007-02-24 03:00:03 +01:00
|
|
|
{
|
2009-01-22 23:40:11 +01:00
|
|
|
for (unsigned i = 0; i < queue_length(&playlist.queue); i++) {
|
|
|
|
const struct song *song = queue_get(&playlist.queue, i);
|
|
|
|
|
|
|
|
if (tagItemsFoundAndMatches(song, 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;
|
|
|
|
}
|