Commit 3832f02c authored by Florian Schlichting's avatar Florian Schlichting

Imported Upstream version 0.18.12

parent 41073716
......@@ -181,6 +181,7 @@ src_mpd_SOURCES = \
src/PlaylistInfo.hxx \
src/PlaylistDatabase.cxx src/PlaylistDatabase.hxx \
src/PlaylistUpdate.cxx \
src/BulkEdit.hxx \
src/IdTable.hxx \
src/Queue.cxx src/Queue.hxx \
src/QueuePrint.cxx src/QueuePrint.hxx \
......@@ -1218,6 +1219,7 @@ test_dump_playlist_LDADD = \
libpcm.a \
$(GLIB_LIBS)
test_dump_playlist_SOURCES = test/dump_playlist.cxx \
test/FakeDecoderAPI.cxx \
$(DECODER_SRC) \
src/Log.cxx \
src/IOThread.cxx \
......@@ -1271,6 +1273,7 @@ test_read_tags_LDADD = \
libutil.a \
$(GLIB_LIBS)
test_read_tags_SOURCES = test/read_tags.cxx \
test/FakeDecoderAPI.cxx \
src/Log.cxx \
src/IOThread.cxx \
src/ReplayGainInfo.cxx \
......
......@@ -1021,21 +1021,22 @@ am__src_mpd_SOURCES_DIST = src/check.h src/gerror.h \
src/PlaylistVector.cxx src/PlaylistVector.hxx \
src/PlaylistInfo.hxx src/PlaylistDatabase.cxx \
src/PlaylistDatabase.hxx src/PlaylistUpdate.cxx \
src/IdTable.hxx src/Queue.cxx src/Queue.hxx src/QueuePrint.cxx \
src/QueuePrint.hxx src/QueueSave.cxx src/QueueSave.hxx \
src/ReplayGainConfig.cxx src/ReplayGainConfig.hxx \
src/ReplayGainInfo.cxx src/ReplayGainInfo.hxx \
src/SignalHandlers.cxx src/SignalHandlers.hxx src/Song.cxx \
src/Song.hxx src/SongUpdate.cxx src/SongPrint.cxx \
src/SongPrint.hxx src/SongSave.cxx src/SongSave.hxx \
src/SongSort.cxx src/SongSort.hxx src/StateFile.cxx \
src/StateFile.hxx src/Stats.cxx src/Stats.hxx src/TagPrint.cxx \
src/TagPrint.hxx src/TagSave.cxx src/TagSave.hxx \
src/TagFile.cxx src/TagFile.hxx src/TextFile.cxx \
src/TextFile.hxx src/TextInputStream.cxx src/Volume.cxx \
src/Volume.hxx src/SongFilter.cxx src/SongFilter.hxx \
src/SongPointer.hxx src/PlaylistFile.cxx src/PlaylistFile.hxx \
src/Timer.cxx src/DespotifyUtils.cxx src/DespotifyUtils.hxx \
src/BulkEdit.hxx src/IdTable.hxx src/Queue.cxx src/Queue.hxx \
src/QueuePrint.cxx src/QueuePrint.hxx src/QueueSave.cxx \
src/QueueSave.hxx src/ReplayGainConfig.cxx \
src/ReplayGainConfig.hxx src/ReplayGainInfo.cxx \
src/ReplayGainInfo.hxx src/SignalHandlers.cxx \
src/SignalHandlers.hxx src/Song.cxx src/Song.hxx \
src/SongUpdate.cxx src/SongPrint.cxx src/SongPrint.hxx \
src/SongSave.cxx src/SongSave.hxx src/SongSort.cxx \
src/SongSort.hxx src/StateFile.cxx src/StateFile.hxx \
src/Stats.cxx src/Stats.hxx src/TagPrint.cxx src/TagPrint.hxx \
src/TagSave.cxx src/TagSave.hxx src/TagFile.cxx \
src/TagFile.hxx src/TextFile.cxx src/TextFile.hxx \
src/TextInputStream.cxx src/Volume.cxx src/Volume.hxx \
src/SongFilter.cxx src/SongFilter.hxx src/SongPointer.hxx \
src/PlaylistFile.cxx src/PlaylistFile.hxx src/Timer.cxx \
src/DespotifyUtils.cxx src/DespotifyUtils.hxx \
src/InotifyDomain.cxx src/InotifyDomain.hxx \
src/InotifySource.cxx src/InotifySource.hxx \
src/InotifyQueue.cxx src/InotifyQueue.hxx \
......@@ -1275,16 +1276,18 @@ test_DumpDatabase_OBJECTS = $(am_test_DumpDatabase_OBJECTS)
@ENABLE_TEST_TRUE@ libconf.a libutil.a libsystem.a libfs.a \
@ENABLE_TEST_TRUE@ $(am__DEPENDENCIES_1)
am__test_dump_playlist_SOURCES_DIST = test/dump_playlist.cxx \
src/Log.cxx src/IOThread.cxx src/Song.cxx src/TagSave.cxx \
src/TagFile.cxx src/CheckAudioFormat.cxx \
src/TextInputStream.cxx src/cue/CueParser.cxx \
src/cue/CueParser.hxx src/ReplayGainInfo.cxx \
src/decoder/FlacMetadata.cxx src/DespotifyUtils.cxx
test/FakeDecoderAPI.cxx src/Log.cxx src/IOThread.cxx \
src/Song.cxx src/TagSave.cxx src/TagFile.cxx \
src/CheckAudioFormat.cxx src/TextInputStream.cxx \
src/cue/CueParser.cxx src/cue/CueParser.hxx \
src/ReplayGainInfo.cxx src/decoder/FlacMetadata.cxx \
src/DespotifyUtils.cxx
@ENABLE_TEST_TRUE@@HAVE_FLAC_TRUE@am__objects_70 = src/ReplayGainInfo.$(OBJEXT) \
@ENABLE_TEST_TRUE@@HAVE_FLAC_TRUE@ src/decoder/FlacMetadata.$(OBJEXT)
@ENABLE_DESPOTIFY_TRUE@@ENABLE_TEST_TRUE@am__objects_71 = src/DespotifyUtils.$(OBJEXT)
@ENABLE_TEST_TRUE@am_test_dump_playlist_OBJECTS = \
@ENABLE_TEST_TRUE@ test/dump_playlist.$(OBJEXT) \
@ENABLE_TEST_TRUE@ test/FakeDecoderAPI.$(OBJEXT) \
@ENABLE_TEST_TRUE@ $(am__objects_60) src/Log.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/IOThread.$(OBJEXT) src/Song.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/TagSave.$(OBJEXT) src/TagFile.$(OBJEXT) \
......@@ -1342,12 +1345,14 @@ test_read_mixer_OBJECTS = $(am_test_read_mixer_OBJECTS)
@ENABLE_TEST_TRUE@ libmixer_plugins.a $(am__DEPENDENCIES_10) \
@ENABLE_TEST_TRUE@ libconf.a libutil.a libevent.a libsystem.a \
@ENABLE_TEST_TRUE@ libfs.a $(am__DEPENDENCIES_1)
am__test_read_tags_SOURCES_DIST = test/read_tags.cxx src/Log.cxx \
src/IOThread.cxx src/ReplayGainInfo.cxx \
src/CheckAudioFormat.cxx src/DespotifyUtils.cxx
am__test_read_tags_SOURCES_DIST = test/read_tags.cxx \
test/FakeDecoderAPI.cxx src/Log.cxx src/IOThread.cxx \
src/ReplayGainInfo.cxx src/CheckAudioFormat.cxx \
src/DespotifyUtils.cxx
@ENABLE_TEST_TRUE@am_test_read_tags_OBJECTS = \
@ENABLE_TEST_TRUE@ test/read_tags.$(OBJEXT) src/Log.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/IOThread.$(OBJEXT) \
@ENABLE_TEST_TRUE@ test/read_tags.$(OBJEXT) \
@ENABLE_TEST_TRUE@ test/FakeDecoderAPI.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/Log.$(OBJEXT) src/IOThread.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/ReplayGainInfo.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/CheckAudioFormat.$(OBJEXT) \
@ENABLE_TEST_TRUE@ $(am__objects_60) $(am__objects_71)
......@@ -2341,21 +2346,22 @@ src_mpd_SOURCES = $(mpd_headers) $(DECODER_SRC) $(OUTPUT_API_SRC) \
src/PlaylistVector.cxx src/PlaylistVector.hxx \
src/PlaylistInfo.hxx src/PlaylistDatabase.cxx \
src/PlaylistDatabase.hxx src/PlaylistUpdate.cxx \
src/IdTable.hxx src/Queue.cxx src/Queue.hxx src/QueuePrint.cxx \
src/QueuePrint.hxx src/QueueSave.cxx src/QueueSave.hxx \
src/ReplayGainConfig.cxx src/ReplayGainConfig.hxx \
src/ReplayGainInfo.cxx src/ReplayGainInfo.hxx \
src/SignalHandlers.cxx src/SignalHandlers.hxx src/Song.cxx \
src/Song.hxx src/SongUpdate.cxx src/SongPrint.cxx \
src/SongPrint.hxx src/SongSave.cxx src/SongSave.hxx \
src/SongSort.cxx src/SongSort.hxx src/StateFile.cxx \
src/StateFile.hxx src/Stats.cxx src/Stats.hxx src/TagPrint.cxx \
src/TagPrint.hxx src/TagSave.cxx src/TagSave.hxx \
src/TagFile.cxx src/TagFile.hxx src/TextFile.cxx \
src/TextFile.hxx src/TextInputStream.cxx src/Volume.cxx \
src/Volume.hxx src/SongFilter.cxx src/SongFilter.hxx \
src/SongPointer.hxx src/PlaylistFile.cxx src/PlaylistFile.hxx \
src/Timer.cxx $(am__append_1) $(am__append_2) $(am__append_3) \
src/BulkEdit.hxx src/IdTable.hxx src/Queue.cxx src/Queue.hxx \
src/QueuePrint.cxx src/QueuePrint.hxx src/QueueSave.cxx \
src/QueueSave.hxx src/ReplayGainConfig.cxx \
src/ReplayGainConfig.hxx src/ReplayGainInfo.cxx \
src/ReplayGainInfo.hxx src/SignalHandlers.cxx \
src/SignalHandlers.hxx src/Song.cxx src/Song.hxx \
src/SongUpdate.cxx src/SongPrint.cxx src/SongPrint.hxx \
src/SongSave.cxx src/SongSave.hxx src/SongSort.cxx \
src/SongSort.hxx src/StateFile.cxx src/StateFile.hxx \
src/Stats.cxx src/Stats.hxx src/TagPrint.cxx src/TagPrint.hxx \
src/TagSave.cxx src/TagSave.hxx src/TagFile.cxx \
src/TagFile.hxx src/TextFile.cxx src/TextFile.hxx \
src/TextInputStream.cxx src/Volume.cxx src/Volume.hxx \
src/SongFilter.cxx src/SongFilter.hxx src/SongPointer.hxx \
src/PlaylistFile.cxx src/PlaylistFile.hxx src/Timer.cxx \
$(am__append_1) $(am__append_2) $(am__append_3) \
$(am__append_7) $(am__append_40) $(am__append_41) \
$(am__append_42)
@HAVE_WINDOWS_TRUE@noinst_DATA = src/win/mpd_win32_rc.rc
......@@ -2894,8 +2900,9 @@ SPARSE_SRC = $(addprefix $(top_srcdir)/,$(filter %.c,$(src_mpd_SOURCES)))
@ENABLE_TEST_TRUE@ $(GLIB_LIBS)
@ENABLE_TEST_TRUE@test_dump_playlist_SOURCES = test/dump_playlist.cxx \
@ENABLE_TEST_TRUE@ $(DECODER_SRC) src/Log.cxx src/IOThread.cxx \
@ENABLE_TEST_TRUE@ src/Song.cxx src/TagSave.cxx src/TagFile.cxx \
@ENABLE_TEST_TRUE@ test/FakeDecoderAPI.cxx $(DECODER_SRC) \
@ENABLE_TEST_TRUE@ src/Log.cxx src/IOThread.cxx src/Song.cxx \
@ENABLE_TEST_TRUE@ src/TagSave.cxx src/TagFile.cxx \
@ENABLE_TEST_TRUE@ src/CheckAudioFormat.cxx \
@ENABLE_TEST_TRUE@ src/TextInputStream.cxx \
@ENABLE_TEST_TRUE@ src/cue/CueParser.cxx src/cue/CueParser.hxx \
......@@ -2935,8 +2942,8 @@ SPARSE_SRC = $(addprefix $(top_srcdir)/,$(filter %.c,$(src_mpd_SOURCES)))
@ENABLE_TEST_TRUE@ $(GLIB_LIBS)
@ENABLE_TEST_TRUE@test_read_tags_SOURCES = test/read_tags.cxx \
@ENABLE_TEST_TRUE@ src/Log.cxx src/IOThread.cxx \
@ENABLE_TEST_TRUE@ src/ReplayGainInfo.cxx \
@ENABLE_TEST_TRUE@ test/FakeDecoderAPI.cxx src/Log.cxx \
@ENABLE_TEST_TRUE@ src/IOThread.cxx src/ReplayGainInfo.cxx \
@ENABLE_TEST_TRUE@ src/CheckAudioFormat.cxx $(DECODER_SRC) \
@ENABLE_TEST_TRUE@ $(am__append_78)
@ENABLE_TEST_TRUE@@HAVE_ID3TAG_TRUE@test_dump_rva2_LDADD = \
......@@ -4409,6 +4416,8 @@ test/DumpDatabase$(EXEEXT): $(test_DumpDatabase_OBJECTS) $(test_DumpDatabase_DEP
$(AM_V_CXXLD)$(CXXLINK) $(test_DumpDatabase_OBJECTS) $(test_DumpDatabase_LDADD) $(LIBS)
test/dump_playlist.$(OBJEXT): test/$(am__dirstamp) \
test/$(DEPDIR)/$(am__dirstamp)
test/FakeDecoderAPI.$(OBJEXT): test/$(am__dirstamp) \
test/$(DEPDIR)/$(am__dirstamp)
src/IOThread.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/TagFile.$(OBJEXT): src/$(am__dirstamp) \
......@@ -5089,6 +5098,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/util/$(DEPDIR)/growing_fifo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/util/$(DEPDIR)/list_sort.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/DumpDatabase.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/FakeDecoderAPI.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/FakeReplayGainConfig.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ShutdownHandler.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/dump_playlist.Po@am__quote@
......
ver 0.18.12 (2014/07/30)
* database
- proxy: fix build failure with libmpdclient 2.2
- proxy: fix add/search and other commands with libmpdclient < 2.9
* decoder
- audiofile: improve responsiveness
- audiofile: fix WAV stream playback
- dsdiff, dsf: fix stream playback
- dsdiff: fix metadata parser bug (uninitialized variables)
- faad: estimate song duration for remote files
- sndfile: improve responsiveness
* randomize next song when enabling "random" mode while not playing
* randomize next song when adding to single-song queue
ver 0.18.11 (2014/05/12)
* decoder
- opus: fix missing song length on high-latency files
......
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for mpd 0.18.11.
# Generated by GNU Autoconf 2.69 for mpd 0.18.12.
#
# Report bugs to <mpd-devel@musicpd.org>.
#
......@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mpd'
PACKAGE_TARNAME='mpd'
PACKAGE_VERSION='0.18.11'
PACKAGE_STRING='mpd 0.18.11'
PACKAGE_VERSION='0.18.12'
PACKAGE_STRING='mpd 0.18.12'
PACKAGE_BUGREPORT='mpd-devel@musicpd.org'
PACKAGE_URL=''
......@@ -1673,7 +1673,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures mpd 0.18.11 to adapt to many kinds of systems.
\`configure' configures mpd 0.18.12 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
......@@ -1743,7 +1743,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of mpd 0.18.11:";;
short | recursive ) echo "Configuration of mpd 0.18.12:";;
esac
cat <<\_ACEOF
......@@ -2041,7 +2041,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
mpd configure 0.18.11
mpd configure 0.18.12
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
......@@ -2494,7 +2494,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by mpd $as_me 0.18.11, which was
It was created by mpd $as_me 0.18.12, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
......@@ -3364,7 +3364,7 @@ fi
# Define the identity of the package.
PACKAGE='mpd'
VERSION='0.18.11'
VERSION='0.18.12'
cat >>confdefs.h <<_ACEOF
......@@ -18461,7 +18461,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by mpd $as_me 0.18.11, which was
This file was extended by mpd $as_me 0.18.12, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
......@@ -18527,7 +18527,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
mpd config.status 0.18.11
mpd config.status 0.18.12
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
......
AC_PREREQ(2.60)
AC_INIT(mpd, 0.18.11, mpd-devel@musicpd.org)
AC_INIT(mpd, 0.18.12, mpd-devel@musicpd.org)
VERSION_MAJOR=0
VERSION_MINOR=18
......
......@@ -31,7 +31,7 @@ PROJECT_NAME = MPD
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 0.18.11
PROJECT_NUMBER = 0.18.12
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
......
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_BULK_EDIT_HXX
#define MPD_BULK_EDIT_HXX
#include "Partition.hxx"
/**
* Begin a "bulk edit" and commit it automatically.
*/
class ScopeBulkEdit {
Partition &partition;
public:
ScopeBulkEdit(Partition &_partition):partition(_partition) {
partition.playlist.BeginBulk();
}
~ScopeBulkEdit() {
partition.playlist.CommitBulk(partition.pc);
}
};
#endif
......@@ -30,6 +30,18 @@ DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
uri = filter->GetBase();
}
bool
DatabaseSelection::IsEmpty() const
{
return uri.empty() && (filter == nullptr || filter->IsEmpty());
}
bool
DatabaseSelection::HasOtherThanBase() const
{
return filter != nullptr && filter->HasOtherThanBase();
}
bool
DatabaseSelection::Match(const Song &song) const
{
......
......@@ -44,6 +44,15 @@ struct DatabaseSelection {
DatabaseSelection(const char *_uri, bool _recursive,
const SongFilter *_filter=nullptr);
gcc_pure
bool IsEmpty() const;
/**
* Does this selection contain constraints other than "base"?
*/
gcc_pure
bool HasOtherThanBase() const;
gcc_pure
bool Match(const Song &song) const;
};
......
......@@ -292,6 +292,40 @@ decoder_read(Decoder *decoder,
return nbytes;
}
bool
decoder_read_full(Decoder *decoder, InputStream &is,
void *_buffer, size_t size)
{
uint8_t *buffer = (uint8_t *)_buffer;
while (size > 0) {
size_t nbytes = decoder_read(decoder, is, buffer, size);
if (nbytes == 0)
return false;
buffer += nbytes;
size -= nbytes;
}
return true;
}
bool
decoder_skip(Decoder *decoder, InputStream &is, size_t size)
{
while (size > 0) {
char buffer[1024];
size_t nbytes = decoder_read(decoder, is, buffer,
std::min(sizeof(buffer), size));
if (nbytes == 0)
return false;
size -= nbytes;
}
return true;
}
void
decoder_timestamp(Decoder &decoder, double t)
{
......
......@@ -112,6 +112,25 @@ decoder_read(Decoder &decoder, InputStream &is,
return decoder_read(&decoder, is, buffer, length);
}
/**
* Blocking read from the input stream. Attempts to fill the buffer
* completely; there is no partial result.
*
* @return true on success, false on error or command or not enough
* data
*/
bool
decoder_read_full(Decoder *decoder, InputStream &is,
void *buffer, size_t size);
/**
* Skip data on the #InputStream.
*
* @return true on success, false on error or command
*/
bool
decoder_skip(Decoder *decoder, InputStream &is, size_t size);
/**
* Sets the time stamp for the next data chunk [seconds]. The MPD
* core automatically counts it up, and a decoder plugin only needs to
......
......@@ -70,6 +70,12 @@ decoder_buffer_free(DecoderBuffer *buffer)
g_free(buffer);
}
const InputStream &
decoder_buffer_get_stream(const DecoderBuffer *buffer)
{
return *buffer->is;
}
bool
decoder_buffer_is_empty(const DecoderBuffer *buffer)
{
......@@ -82,6 +88,12 @@ decoder_buffer_is_full(const DecoderBuffer *buffer)
return buffer->consumed == 0 && buffer->length == buffer->size;
}
void
decoder_buffer_clear(DecoderBuffer *buffer)
{
buffer->length = buffer->consumed = 0;
}
static void
decoder_buffer_shift(DecoderBuffer *buffer)
{
......@@ -118,6 +130,12 @@ decoder_buffer_fill(DecoderBuffer *buffer)
return true;
}
size_t
decoder_buffer_available(const DecoderBuffer *buffer)
{
return buffer->length - buffer->consumed;;
}
const void *
decoder_buffer_read(const DecoderBuffer *buffer, size_t *length_r)
{
......
......@@ -20,6 +20,8 @@
#ifndef MPD_DECODER_BUFFER_HXX
#define MPD_DECODER_BUFFER_HXX
#include "Compiler.h"
#include <stddef.h>
/**
......@@ -50,12 +52,21 @@ decoder_buffer_new(Decoder *decoder, InputStream &is,
void
decoder_buffer_free(DecoderBuffer *buffer);
gcc_pure
const InputStream &
decoder_buffer_get_stream(const DecoderBuffer *buffer);
gcc_pure
bool
decoder_buffer_is_empty(const DecoderBuffer *buffer);
gcc_pure
bool
decoder_buffer_is_full(const DecoderBuffer *buffer);
void
decoder_buffer_clear(DecoderBuffer *buffer);
/**
* Read data from the input_stream and append it to the buffer.
*
......@@ -66,6 +77,13 @@ decoder_buffer_is_full(const DecoderBuffer *buffer);
bool
decoder_buffer_fill(DecoderBuffer *buffer);
/**
* How many bytes are stored in the buffer?
*/
gcc_pure
size_t
decoder_buffer_available(const DecoderBuffer *buffer);
/**
* Reads data from the buffer. This data is not yet consumed, you
* have to call decoder_buffer_consume() to do that. The returned
......
......@@ -103,6 +103,12 @@ playlist::UpdateQueuedSong(PlayerControl &pc, const Song *prev)
if (!playing)
return;
if (prev == nullptr && bulk_edit)
/* postponed until CommitBulk() to avoid always
queueing the first song that is being added (in
random mode) */
return;
assert(!queue.IsEmpty());
assert((queued < 0) == (prev == nullptr));
......@@ -294,7 +300,9 @@ playlist::SetRandom(PlayerControl &pc, bool status)
if (queue.random) {
/* shuffle the queue order, but preserve current */
const int current_position = GetCurrentPosition();
const int current_position = playing
? GetCurrentPosition()
: -1;
queue.ShuffleOrder();
......
......@@ -45,6 +45,18 @@ struct playlist {
*/
bool stop_on_error;
/**
* If true, then a bulk edit has been initiated by
* BeginBulk(), and UpdateQueuedSong() and OnModified() will
* be postponed until CommitBulk()
*/
bool bulk_edit;
/**
* Has the queue been modified during bulk edit mode?
*/
bool bulk_modified;
/**
* Number of errors since playback was started. If this
* number exceeds the length of the playlist, MPD gives up,
......@@ -69,7 +81,9 @@ struct playlist {
int queued;
playlist(unsigned max_length)
:queue(max_length), playing(false), current(-1), queued(-1) {
:queue(max_length), playing(false),
bulk_edit(false),
current(-1), queued(-1) {
}
~playlist() {
......@@ -126,6 +140,9 @@ protected:
void UpdateQueuedSong(PlayerControl &pc, const Song *prev);
public:
void BeginBulk();
void CommitBulk(PlayerControl &pc);
void Clear(PlayerControl &pc);
/**
......
......@@ -153,7 +153,7 @@ playlist::PlayNext(PlayerControl &pc)
queue.ShuffleOrder();
/* note that current and queued are
now invalid, but playlist_play_order() will
now invalid, but PlayOrder() will
discard them anyway */
}
......
......@@ -40,6 +40,12 @@
void
playlist::OnModified()
{
if (bulk_edit) {
/* postponed to CommitBulk() */
bulk_modified = true;
return;
}
queue.IncrementVersion();
idle_add(IDLE_PLAYLIST);
......@@ -56,6 +62,35 @@ playlist::Clear(PlayerControl &pc)
OnModified();
}
void
playlist::BeginBulk()
{
assert(!bulk_edit);
bulk_edit = true;
bulk_modified = false;
}
void
playlist::CommitBulk(PlayerControl &pc)
{
assert(bulk_edit);
bulk_edit = false;
if (!bulk_modified)
return;
if (queued < 0)
/* if no song was queued, UpdateQueuedSong() is being
ignored in "bulk" edit mode; now that we have
shuffled all new songs, we can pick a random one
(instead of always picking the first one that was
added) */
UpdateQueuedSong(pc, nullptr);
OnModified();
}
PlaylistResult
playlist::AppendFile(PlayerControl &pc,
const char *path_utf8, unsigned *added_id)
......
......@@ -203,6 +203,16 @@ SongFilter::Match(const Song &song) const
return true;
}
bool
SongFilter::HasOtherThanBase() const
{
for (const auto &i : items)
if (i.GetTag() != LOCATE_TAG_BASE_TYPE)
return true;
return false;
}
std::string
SongFilter::GetBase() const
{
......
......@@ -109,6 +109,11 @@ public:
return items;
}
gcc_pure
bool IsEmpty() const {
return items.empty();
}
/**
* Is there at least one item with "fold case" enabled?
*/
......@@ -121,6 +126,12 @@ public:
return false;
}
/**
* Does this filter contain constraints other than "base"?
*/
gcc_pure
bool HasOtherThanBase() const;
/**
* Returns the "base" specification (if there is one) or an
* empty string.
......
......@@ -30,6 +30,7 @@
#include "util/Error.hxx"
#include "SongFilter.hxx"
#include "protocol/Result.hxx"
#include "BulkEdit.hxx"
#include <assert.h>
#include <string.h>
......@@ -92,6 +93,8 @@ handle_match_add(Client &client, int argc, char *argv[], bool fold_case)
return CommandResult::ERROR;
}
const ScopeBulkEdit bulk_edit(client.partition);
const DatabaseSelection selection("", true, &filter);
Error error;
return AddFromDatabase(client.partition, selection, error)
......
......@@ -26,6 +26,7 @@
#include "PlaylistFile.hxx"
#include "PlaylistVector.hxx"
#include "PlaylistQueue.hxx"
#include "BulkEdit.hxx"
#include "TimePrint.hxx"
#include "Client.hxx"
#include "protocol/ArgParser.hxx"
......@@ -67,6 +68,8 @@ handle_load(Client &client, int argc, char *argv[])
} else if (!check_range(client, &start_index, &end_index, argv[2]))
return CommandResult::ERROR;
const ScopeBulkEdit bulk_edit(client.partition);
const PlaylistResult result =
playlist_open_into_queue(argv[1],
start_index, end_index,
......
......@@ -28,6 +28,7 @@
#include "ClientFile.hxx"
#include "Client.hxx"
#include "Partition.hxx"
#include "BulkEdit.hxx"
#include "protocol/ArgParser.hxx"
#include "protocol/Result.hxx"
#include "ls.hxx"
......@@ -43,7 +44,6 @@ CommandResult
handle_add(Client &client, gcc_unused int argc, char *argv[])
{
char *uri = argv[1];
PlaylistResult result;
if (memcmp(uri, "file:///", 8) == 0) {
const char *path_utf8 = uri + 7;
......@@ -59,7 +59,7 @@ handle_add(Client &client, gcc_unused int argc, char *argv[])
if (!client_allow_file(client, path_fs, error))
return print_error(client, error);
result = client.partition.AppendFile(path_utf8);
auto result = client.partition.AppendFile(path_utf8);
return print_playlist_result(client, result);
}
......@@ -70,10 +70,12 @@ handle_add(Client &client, gcc_unused int argc, char *argv[])
return CommandResult::ERROR;
}
result = client.partition.AppendURI(uri);
auto result = client.partition.AppendURI(uri);
return print_playlist_result(client, result);
}
const ScopeBulkEdit bulk_edit(client.partition);
const DatabaseSelection selection(uri, true);
Error error;
return AddFromDatabase(client.partition, selection, error)
......
......@@ -398,8 +398,13 @@ Convert(const struct mpd_song *song)
Song *s = Song::NewDetached(mpd_song_get_uri(song));