Commit 847748d5 authored by Led's avatar Led

Merge commit '0.14-beta3' into alt

parents 2b2d267d 423947a7
AC_PREREQ(2.60)
AC_INIT(mpd, 0.14~beta2, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.14~beta3, musicpd-dev-team@lists.sourceforge.net)
AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2])
AM_CONFIG_HEADER(config.h)
......@@ -335,10 +335,9 @@ fi
AM_CONDITIONAL(HAVE_CURL, test x$enable_curl = xyes)
if test x$enable_shout_ogg = xyes || test x$enable_shout_mp3 = xyes; then
enable_shout=yes
PKG_CHECK_MODULES([SHOUT], [shout],
AC_DEFINE(HAVE_SHOUT, 1, [Define to enable libshout support]),
enable_shout=no)
PKG_CHECK_MODULES([SHOUT], [shout],,
[enable_shout_ogg=no; enable_shout_mp3=no;
AC_MSG_WARN([disabling shout streaming support because libshout is not available])])
fi
if test x$enable_shout_ogg = xyes; then
......@@ -350,10 +349,6 @@ if test x$enable_shout_ogg = xyes; then
AC_MSG_WARN([disabling ogg shout streaming support because tremor does not support vorbis encoding])
enable_shout_ogg=no
fi
if test x$enable_shout = xno; then
AC_MSG_WARN([disabling ogg shout streaming support because libshout is not found])
enable_shout_ogg=no
fi
if test x$enable_shout_ogg = xyes; then
PKG_CHECK_MODULES(VORBISENC, [vorbisenc],
AC_DEFINE(HAVE_SHOUT_OGG, 1, [Define to enable ogg streaming support]),
......@@ -361,20 +356,28 @@ if test x$enable_shout_ogg = xyes; then
fi
fi
if test x$enable_lame = xyes; then
AM_PATH_LAME([MPD_LIBS="$MPD_LIBS $LAME_LIBS" MPD_CFLAGS="$MPD_CFLAGS $LAME_CFLAGS"],
[enable_lame=no; AC_MSG_WARN(You need lame -- disabling lame support)])
fi
if test x$enable_shout_mp3 = xyes; then
if test x$enable_lame = xno; then
AC_MSG_WARN([disabling mp3 shout streaming support because lame is not enabled])
enable_shout_mp3=no
fi
if test x$enable_shout = xno; then
AC_MSG_WARN([disabling mp3 shout streaming support because libshout is not found])
enable_shout_mp3=no
fi
if test x$enable_shout_mp3 = xyes; then
AC_DEFINE(HAVE_SHOUT_MP3, 1, [Define to enable mp3 streaming support])
fi
fi
if test x$enable_shout_ogg = xyes || test x$enable_shout_mp3 = xyes; then
enable_shout=yes
AC_DEFINE(HAVE_SHOUT, 1, [Define to enable libshout support])
else
enable_shout=no
fi
AM_CONDITIONAL(HAVE_SHOUT, test x$enable_shout = xyes)
AM_CONDITIONAL(HAVE_SHOUT_OGG, test x$enable_shout_ogg = xyes)
AM_CONDITIONAL(HAVE_SHOUT_MP3, test x$enable_shout_mp3 = xyes)
......@@ -462,11 +465,6 @@ fi
AM_CONDITIONAL(HAVE_MAD, test x$enable_mp3 = xyes)
if test x$enable_lame = xyes; then
AM_PATH_LAME([MPD_LIBS="$MPD_LIBS $LAME_LIBS" MPD_CFLAGS="$MPD_CFLAGS $LAME_CFLAGS"],
[enable_lame=no;AC_MSG_WARN(You need lame -- disabling lame support)])
fi
if test x$enable_mpc = xyes; then
if test "x$mpcdec_libraries" != "x" ; then
......@@ -1146,6 +1144,14 @@ else
echo " Zeroconf support ..............disabled"
fi
if test x$enable_curl != xno; then
echo " HTTP streaming (libcurl) ......enabled"
else
echo " HTTP streaming (libcurl) ......disabled"
fi
echo ""
echo "##########################################"
echo ""
......
......@@ -38,7 +38,7 @@ This specifies the directory where saved playlists are stored.
.B follow_outside_symlinks <yes or no>
Control if MPD will follow symbolic links pointing outside the music dir.
You must recreate the database after changing this option.
The default is "no".
The default is "yes".
.TP
.B follow_inside_symlinks <yes or no>
Control if MPD will follow symbolic links pointing outside the music dir, potentially
......@@ -72,6 +72,9 @@ This specifies the user that mpd will run as, if set.
This specifies which address mpd binds to and listens on. Multiple
bind_to_address parameters may be specified. The default is "any", which binds
to all available addresses.
To bind to a Unix domain socket, specify an absolute path. For a
system-wide MPD, we suggest the path "\fB/var/run/mpd/socket\fP".
.TP
.B port <port>
This specifies the port that mpd listens on. The default is 6600.
......
......@@ -7,7 +7,7 @@ playlist_directory "~/.mpd/playlists"
db_file "~/.mpd/mpd.db"
log_file "~/.mpd/mpd.log"
error_file "~/.mpd/mpd.error"
#follow_outside_symlinks "no"
#follow_outside_symlinks "yes"
#follow_inside_symlinks "yes"
################################################################
......@@ -42,6 +42,10 @@ error_file "~/.mpd/mpd.error"
#bind_to_address "any"
#port "6600"
#
# Bind to a Unix domain socket:
#
#bind_to_address "/var/run/mpd/socket"
#
# Controls the amount of information that is logged. Can be
# "default", "secure", or "verbose".
#
......
......@@ -275,7 +275,8 @@ handle_urlhandlers(struct client *client,
{
if (client_get_uid(client) > 0)
client_puts(client, "handler: file://\n");
return printRemoteUrlHandlers(client);
printRemoteUrlHandlers(client);
return COMMAND_RETURN_OK;
}
static enum command_return
......@@ -449,6 +450,12 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (isRemoteUrl(path))
return addToPlaylist(path, NULL);
if (uri_has_scheme(path)) {
command_error(client, ACK_ERROR_NO_EXIST,
"unsupported URI scheme");
return COMMAND_RETURN_ERROR;
}
result = addAllIn(path);
if (result == (enum playlist_result)-1) {
command_error(client, ACK_ERROR_NO_EXIST,
......@@ -1222,7 +1229,11 @@ handle_playlistadd(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (isRemoteUrl(path))
result = spl_append_uri(path, playlist);
else
else if (uri_has_scheme(path)) {
command_error(client, ACK_ERROR_NO_EXIST,
"unsupported URI scheme");
return COMMAND_RETURN_ERROR;
} else
result = addAllInToStoredPlaylist(path, playlist);
if (result == (enum playlist_result)-1) {
......
......@@ -208,30 +208,46 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
AVCodecContext *codec_context,
const AVRational *time_base)
{
enum decoder_command cmd = DECODE_COMMAND_NONE;
int position;
uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
int len, audio_size;
uint8_t *packet_data;
int packet_size;
position = av_rescale_q(packet->pts, *time_base,
(AVRational){1, 1});
packet_data = packet->data;
packet_size = packet->size;
audio_size = sizeof(audio_buf);
len = avcodec_decode_audio2(codec_context,
(int16_t *)audio_buf,
&audio_size,
packet->data, packet->size);
while ((packet_size > 0) && (cmd == DECODE_COMMAND_NONE)) {
audio_size = sizeof(audio_buf);
len = avcodec_decode_audio2(codec_context,
(int16_t *)audio_buf,
&audio_size,
packet_data, packet_size);
if (len < 0) {
g_message("skipping frame\n");
return decoder_get_command(decoder);
}
assert(audio_size >= 0);
position = av_rescale_q(packet->pts, *time_base,
(AVRational){1, 1});
if (len < 0) {
/* if error, we skip the frame */
g_message("decoding failed\n");
break;
}
return decoder_data(decoder, is,
audio_buf, audio_size,
position,
codec_context->bit_rate / 1000, NULL);
packet_data += len;
packet_size -= len;
if (audio_size <= 0) {
g_message("no audio frame\n");
continue;
}
cmd = decoder_data(decoder, is,
audio_buf, audio_size,
position,
codec_context->bit_rate / 1000, NULL);
}
return cmd;
}
static bool
......@@ -368,8 +384,9 @@ static struct tag *ffmpeg_tag(const char *file)
*/
static const char *const ffmpeg_suffixes[] = {
"wma", "asf", "wmv", "mpeg", "mpg", "avi", "vob", "mov", "qt", "swf", "rm", "swf",
"mp1", "mp2", "mp3", "mp4", "m4a", "flac", "ogg", "wav", "au", "aiff", "aif", "ac3", "aac", "mpc",
"wma", "asf", "wmv", "mpeg", "mpg", "avi", "vob", "mov", "qt", "swf",
"rm", "swf", "mp1", "mp2", "mp3", "mp4", "m4a", "flac", "ogg", "wav",
"au", "aiff", "aif", "ac3", "aac", "mpc", "ape",
NULL
};
......
......@@ -705,7 +705,7 @@ mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
struct lame lame;
struct mad_bitptr ptr;
int bitlen;
int ret;
enum mp3_action ret;
/* stfu gcc */
memset(&xing, 0, sizeof(struct xing));
......@@ -976,7 +976,7 @@ static bool
mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
{
struct decoder *decoder = data->decoder;
int ret;
enum mp3_action ret;
enum decoder_command cmd;
mp3_update_timer_next_frame(data);
......
......@@ -138,7 +138,7 @@ strstrSearchTag(struct song *song, enum tag_type type, char *str)
song_get_url(song, path_max_tmp);
p = g_utf8_casefold(path_max_tmp, -1);
if (strstr(path_max_tmp, str))
if (strstr(p, str))
ret = 1;
g_free(p);
if (ret == 1 || type == LOCATE_TAG_FILE_TYPE)
......
......@@ -32,7 +32,7 @@ static const char *remoteUrlPrefixes[] = {
NULL
};
int printRemoteUrlHandlers(struct client *client)
void printRemoteUrlHandlers(struct client *client)
{
const char **prefixes = remoteUrlPrefixes;
......@@ -40,77 +40,32 @@ int printRemoteUrlHandlers(struct client *client)
client_printf(client, "handler: %s\n", *prefixes);
prefixes++;
}
return 0;
}
int isValidRemoteUtf8Url(const char *utf8url)
bool uri_has_scheme(const char *uri)
{
int ret = 0;
const char *temp;
switch (isRemoteUrl(utf8url)) {
case 1:
ret = 1;
temp = utf8url;
while (*temp) {
if ((*temp >= 'a' && *temp <= 'z') ||
(*temp >= 'A' && *temp <= 'Z') ||
(*temp >= '0' && *temp <= '9') ||
*temp == '$' ||
*temp == '-' ||
*temp == '.' ||
*temp == '+' ||
*temp == '!' ||
*temp == '*' ||
*temp == '\'' ||
*temp == '(' ||
*temp == ')' ||
*temp == ',' ||
*temp == '%' ||
*temp == '/' ||
*temp == ':' ||
*temp == '?' ||
*temp == ';' || *temp == '&' || *temp == '=') {
} else {
ret = 1;
break;
}
temp++;
}
break;
}
return ret;
return strstr(uri, "://") != NULL;
}
int isRemoteUrl(const char *url)
bool isRemoteUrl(const char *url)
{
int count = 0;
const char **urlPrefixes = remoteUrlPrefixes;
while (*urlPrefixes) {
count++;
if (g_str_has_prefix(url, *urlPrefixes))
return count;
return true;
urlPrefixes++;
}
return 0;
return false;
}
/* suffixes should be ascii only characters */
const char *getSuffix(const char *utf8file)
{
const char *ret = NULL;
while (*utf8file) {
if (*utf8file == '.')
ret = utf8file + 1;
utf8file++;
}
const char *dot = strrchr(g_basename(utf8file), '.');
return ret;
return dot != NULL ? dot + 1 : NULL;
}
const struct decoder_plugin *
......
......@@ -21,20 +21,24 @@
#include "decoder_list.h"
#include <sys/time.h>
#include <stdbool.h>
struct stat;
struct client;
const char *getSuffix(const char *utf8file);
int isValidRemoteUtf8Url(const char *utf8url);
/**
* Checks whether the specified URI has a schema in the form
* "scheme://".
*/
bool uri_has_scheme(const char *uri);
int isRemoteUrl(const char *url);
bool isRemoteUrl(const char *url);
const struct decoder_plugin *
hasMusicSuffix(const char *utf8file, unsigned int next);
int printRemoteUrlHandlers(struct client *client);
void printRemoteUrlHandlers(struct client *client);
#endif
......@@ -201,6 +201,12 @@ audioOutputAo_openDevice(void *data, struct audio_format *audio_format)
audioOutputAo_closeDevice(ad);
}
/* support for 24 bit samples in libao is currently dubious,
and until we have sorted that out, resample everything to
16 bit */
if (audio_format->bits > 16)
audio_format->bits = 16;
format.bits = audio_format->bits;
format.rate = audio_format->sample_rate;
format.byte_format = AO_FMT_NATIVE;
......
......@@ -18,10 +18,14 @@
#include "../output_api.h"
#include "../utils.h"
#include "../log.h"
#include <glib.h>
#include <pthread.h>
#include <AudioUnit/AudioUnit.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "osx"
typedef struct _OsxData {
AudioUnit au;
pthread_mutex_t mutex;
......@@ -35,7 +39,7 @@ typedef struct _OsxData {
static OsxData *newOsxData(void)
{
OsxData *ret = xmalloc(sizeof(OsxData));
OsxData *ret = g_new(OsxData, 1);
pthread_mutex_init(&ret->mutex, NULL);
pthread_cond_init(&ret->condition, NULL);
......@@ -124,8 +128,8 @@ static void osx_closeDevice(void *data)
od->started = 0;
}
CloseComponent(od->au);
AudioUnitUninitialize(od->au);
CloseComponent(od->au);
}
static OSStatus
......@@ -139,6 +143,7 @@ osx_render(void *vdata,
AudioBuffer *buffer = &bufferList->mBuffers[0];
size_t bufferSize = buffer->mDataByteSize;
size_t bytesToCopy;
size_t bytes;
int curpos = 0;
/*DEBUG("osx_render: enter : %i\n", (int)bufferList->mNumberBuffers);
......@@ -177,21 +182,20 @@ osx_render(void *vdata,
}
*/
bytesToCopy = od->len < bufferSize ? od->len : bufferSize;
bytesToCopy = MIN(od->len, bufferSize);
bufferSize = bytesToCopy;
od->len -= bytesToCopy;
if (od->pos + bytesToCopy > od->bufferSize) {
size_t bytes = od->bufferSize - od->pos;
memcpy(buffer->mData + curpos, od->buffer + od->pos, bytes);
bytes = od->bufferSize - od->pos;
if (bytesToCopy > bytes) {
memcpy((unsigned char*)buffer->mData + curpos, od->buffer + od->pos, bytes);
od->pos = 0;
curpos += bytes;
bytesToCopy -= bytes;
}
memcpy(buffer->mData + curpos, od->buffer + od->pos, bytesToCopy);
memcpy((unsigned char*)buffer->mData + curpos, od->buffer + od->pos, bytesToCopy);
od->pos += bytesToCopy;
curpos += bytesToCopy;
if (od->pos >= od->bufferSize)
od->pos = 0;
......@@ -219,6 +223,9 @@ osx_openDevice(void *data, struct audio_format *audioFormat)
AURenderCallbackStruct callback;
AudioStreamBasicDescription streamDesc;
if (audioFormat->bits > 16)
audioFormat->bits = 16;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
......@@ -227,18 +234,18 @@ osx_openDevice(void *data, struct audio_format *audioFormat)
comp = FindNextComponent(NULL, &desc);
if (comp == 0) {
ERROR("Error finding OS X component\n");
g_warning("Error finding OS X component\n");
return false;
}
if (OpenAComponent(comp, &od->au) != noErr) {
ERROR("Unable to open OS X component\n");
g_warning("Unable to open OS X component\n");
return false;
}
if (AudioUnitInitialize(od->au) != 0) {
CloseComponent(od->au);
ERROR("Unable to initialize OS X audio unit\n");
g_warning("Unable to initialize OS X audio unit\n");
return false;
}
......@@ -250,7 +257,7 @@ osx_openDevice(void *data, struct audio_format *audioFormat)
&callback, sizeof(callback)) != 0) {
AudioUnitUninitialize(od->au);
CloseComponent(od->au);
ERROR("unable to set callback for OS X audio unit\n");
g_warning("unable to set callback for OS X audio unit\n");
return false;
}
......@@ -272,14 +279,14 @@ osx_openDevice(void *data, struct audio_format *audioFormat)
&streamDesc, sizeof(streamDesc)) != 0) {
AudioUnitUninitialize(od->au);
CloseComponent(od->au);
ERROR("Unable to set format on OS X device\n");
g_warning("Unable to set format on OS X device\n");
return false;
}
/* create a buffer of 1s */
od->bufferSize = (audioFormat->sample_rate) *
audio_format_frame_size(audioFormat);
od->buffer = xrealloc(od->buffer, od->bufferSize);
od->buffer = g_realloc(od->buffer, od->bufferSize);
od->pos = 0;
od->len = 0;
......@@ -292,6 +299,7 @@ osx_play(void *data, const char *playChunk, size_t size)
{
OsxData *od = data;
size_t bytesToCopy;
size_t bytes;
size_t curpos;
/* DEBUG("osx_play: enter\n"); */
......@@ -301,7 +309,7 @@ osx_play(void *data, const char *playChunk, size_t size)
od->started = 1;
err = AudioOutputUnitStart(od->au);
if (err) {
ERROR("unable to start audio output: %i\n", err);
g_warning("unable to start audio output: %i\n", err);
return false;
}
}
......@@ -314,20 +322,18 @@ osx_play(void *data, const char *playChunk, size_t size)
if (curpos >= od->bufferSize)
curpos -= od->bufferSize;
bytesToCopy = od->bufferSize < size ? od->bufferSize : size;
bytesToCopy = MIN(od->bufferSize, size);
while (od->len > od->bufferSize - bytesToCopy) {
/* DEBUG("osx_play: wait\n"); */
pthread_cond_wait(&od->condition, &od->mutex);
}
bytesToCopy = od->bufferSize - od->len;
bytesToCopy = bytesToCopy < size ? bytesToCopy : size;
size -= bytesToCopy;
od->len += bytesToCopy;
if (curpos + bytesToCopy > od->bufferSize) {
size_t bytes = od->bufferSize - curpos;
bytes = od->bufferSize - curpos;
if (bytesToCopy > bytes) {
memcpy(od->buffer + curpos, playChunk, bytes);
curpos = 0;
playChunk += bytes;
......@@ -335,7 +341,6 @@ osx_play(void *data, const char *playChunk, size_t size)
}
memcpy(od->buffer + curpos, playChunk, bytesToCopy);
curpos += bytesToCopy;
playChunk += bytesToCopy;
}
......
......@@ -461,7 +461,7 @@ size_t pcm_convert_size(const struct audio_format *inFormat, size_t src_size,
assert((src_size % audio_format_frame_size(inFormat)) == 0);
dest_size /= audio_format_frame_size(inFormat);
dest_size = floor(0.5 + (double)dest_size * ratio);
dest_size = ceil((double)dest_size * ratio);
dest_size *= audio_format_frame_size(outFormat);
return dest_size;
......
......@@ -44,6 +44,13 @@ void pc_deinit(void)
notify_deinit(&pc.notify);
}
void
pc_song_deleted(const struct song *song)
{
if (pc.errored_song == song)
pc.errored_song = NULL;
}
static void player_command(enum player_command cmd)
{
pc.command = cmd;
......@@ -141,12 +148,22 @@ enum player_error getPlayerError(void)
return pc.error;
}
static const char *
pc_errored_song_uri(void)
{
char path_max_tmp[MPD_PATH_MAX];
if (pc.errored_song == NULL)
return "?";
return song_get_url(pc.errored_song, path_max_tmp);
}
char *getPlayerErrorStr(void)
{
/* static OK here, only one user in main task */
static char error[MPD_PATH_MAX + 64]; /* still too much */
static const size_t errorlen = sizeof(error);
char path_max_tmp[MPD_PATH_MAX];
*error = '\0'; /* likely */
switch (pc.error) {
......@@ -156,11 +173,11 @@ char *getPlayerErrorStr(void)
case PLAYER_ERROR_FILENOTFOUND:
snprintf(error, errorlen,
"file \"%s\" does not exist or is inaccessible",
song_get_url(pc.errored_song, path_max_tmp));
pc_errored_song_uri());
break;
case PLAYER_ERROR_FILE:
snprintf(error, errorlen, "problems decoding \"%s\"",
song_get_url(pc.errored_song, path_max_tmp));
pc_errored_song_uri());
break;
case PLAYER_ERROR_AUDIO:
strcpy(error, "problems opening audio device");
......@@ -170,7 +187,7 @@ char *getPlayerErrorStr(void)
break;
case PLAYER_ERROR_UNKTYPE:
snprintf(error, errorlen, "file type of \"%s\" is unknown",
song_get_url(pc.errored_song, path_max_tmp));
pc_errored_song_uri());
}
return *error ? error : NULL;
}
......
......@@ -84,6 +84,14 @@ void pc_init(unsigned int buffered_before_play);
void pc_deinit(void);
/**
* Call this function when the specified song pointer is about to be
* invalidated. This makes sure that player_control.errored_song does
* not point to an invalid pointer.
*/
void
pc_song_deleted(const struct song *song);
void
playerPlay(struct song *song);
......
......@@ -200,8 +200,10 @@ void clearPlaylist(void)
stopPlaylist();
for (unsigned i = 0; i < playlist.length; i++) {
if (!song_in_database(playlist.songs[i]))
if (!song_in_database(playlist.songs[i])) {
pc_song_deleted(playlist.songs[i]);
song_free(playlist.songs[i]);
}
playlist.idToPosition[playlist.positionToId[i]] = -1;
playlist.songs[i] = NULL;
......@@ -537,7 +539,7 @@ song_by_url(const char *url)
if (song != NULL)
return song;
if (isValidRemoteUtf8Url(url))
if (isRemoteUrl(url))
return song_remote_new(url);
return NULL;
......@@ -670,8 +672,10 @@ enum playlist_result deleteFromPlaylist(unsigned song)
|| playlist.order[playlist.current] == song))
clearPlayerQueue();
if (!song_in_database(playlist.songs[song]))
if (!song_in_database(playlist.songs[song])) {
pc_song_deleted(playlist.songs[song]);
song_free(playlist.songs[song]);
}
playlist.idToPosition[playlist.positionToId[song]] = -1;
......@@ -738,6 +742,8 @@ deleteASongFromPlaylist(const struct song *song)
for (unsigned i = 0; i < playlist.length; i++)
if (song == playlist.songs[i])
deleteFromPlaylist(i);
pc_song_deleted(song);
}
void stopPlaylist(void)
......
......@@ -46,7 +46,7 @@ playlist_print_uri(FILE *file, const char *uri)
char tmp[MPD_PATH_MAX];
const char *s;
if (playlist_saveAbsolutePaths && !isValidRemoteUtf8Url(uri) &&
if (playlist_saveAbsolutePaths && !isRemoteUrl(uri) &&
uri[0] != '/')
s = map_directory_child_fs(db_get_root(), uri, tmp);
else
......
......@@ -156,7 +156,7 @@ spl_load(const char *utf8path)
if (*s == PLAYLIST_COMMENT)
continue;
if (!isValidRemoteUtf8Url(s)) {
if (!isRemoteUrl(s)) {
struct song *song;
path_utf8 = map_fs_to_utf8(s, path_max_tmp);
......@@ -360,7 +360,7 @@ spl_append_uri(const char *url, const char *utf8file)
if (song)
return spl_append_song(utf8file, song);
if (!isValidRemoteUtf8Url(url))
if (!isRemoteUrl(url))
return PLAYLIST_RESULT_NO_SUCH_SONG;
song = song_remote_new(url);
......
......@@ -22,6 +22,7 @@
#include "playlist.h"
#include <glib.h>
#include <time.h>
struct song;
......
......@@ -59,7 +59,7 @@ static struct condition delete_cond;
enum {
DEFAULT_FOLLOW_INSIDE_SYMLINKS = true,
DEFAULT_FOLLOW_OUTSIDE_SYMLINKS = false,
DEFAULT_FOLLOW_OUTSIDE_SYMLINKS = true,
};
static bool follow_inside_symlinks;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment