Commit b4b468eb authored by Max Kellermann's avatar Max Kellermann

Merge tag 'v0.20.11'

release v0.20.11
parents bd50a0d2 a7fdfa08
...@@ -13,12 +13,16 @@ ver 0.21 (not yet released) ...@@ -13,12 +13,16 @@ ver 0.21 (not yet released)
* mixer * mixer
- sndio: new mixer plugin - sndio: new mixer plugin
ver 0.20.11 (not yet released) ver 0.20.11 (2017/10/18)
* storage * storage
- curl: support Content-Type application/xml - curl: support Content-Type application/xml
* decoder * decoder
- ffmpeg: more reliable song duration - ffmpeg: more reliable song duration
- gme: fix track numbering
* improve random song order when switching songs manually
* fix case insensitive search without libicu * fix case insensitive search without libicu
* fix Unicode file names in playlists on Windows
* fix endless loop when accessing malformed file names in ZIP files
ver 0.20.10 (2017/08/24) ver 0.20.10 (2017/08/24)
* decoder * decoder
......
...@@ -207,13 +207,12 @@ try { ...@@ -207,13 +207,12 @@ try {
continue; continue;
#ifdef _UNICODE #ifdef _UNICODE
wchar_t buffer[MAX_PATH]; /* on Windows, playlists always contain UTF-8, because
auto result = MultiByteToWideChar(CP_ACP, 0, s, -1, its "narrow" charset (i.e. CP_ACP) is incapable of
buffer, ARRAY_SIZE(buffer)); storing all Unicode paths */
if (result <= 0) const auto path = AllocatedPath::FromUTF8(s);
if (path.IsNull())
continue; continue;
const Path path = Path::FromFS(buffer);
#else #else
const Path path = Path::FromFS(s); const Path path = Path::FromFS(s);
#endif #endif
......
...@@ -28,13 +28,25 @@ ...@@ -28,13 +28,25 @@
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
#include "fs/FileSystem.hxx" #include "fs/FileSystem.hxx"
#include "fs/NarrowPath.hxx"
#include "fs/io/FileOutputStream.hxx" #include "fs/io/FileOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx" #include "fs/io/BufferedOutputStream.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include <stdexcept> #include <stdexcept>
static void
playlist_print_path(BufferedOutputStream &os, const Path path)
{
#ifdef _UNICODE
/* on Windows, playlists always contain UTF-8, because its
"narrow" charset (i.e. CP_ACP) is incapable of storing all
Unicode paths */
os.Format("%s\n", path.ToUTF8().c_str());
#else
os.Format("%s\n", path.c_str());
#endif
}
void void
playlist_print_song(BufferedOutputStream &os, const DetachedSong &song) playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
{ {
...@@ -44,7 +56,7 @@ playlist_print_song(BufferedOutputStream &os, const DetachedSong &song) ...@@ -44,7 +56,7 @@ playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
try { try {
const auto uri_fs = AllocatedPath::FromUTF8Throw(uri_utf8); const auto uri_fs = AllocatedPath::FromUTF8Throw(uri_utf8);
os.Format("%s\n", NarrowPath(uri_fs).c_str()); playlist_print_path(os, uri_fs);
} catch (const std::runtime_error &) { } catch (const std::runtime_error &) {
} }
} }
...@@ -63,7 +75,7 @@ playlist_print_uri(BufferedOutputStream &os, const char *uri) ...@@ -63,7 +75,7 @@ playlist_print_uri(BufferedOutputStream &os, const char *uri)
AllocatedPath::FromUTF8Throw(uri); AllocatedPath::FromUTF8Throw(uri);
if (!path.IsNull()) if (!path.IsNull())
os.Format("%s\n", NarrowPath(path).c_str()); playlist_print_path(os, path);
} catch (const std::runtime_error &) { } catch (const std::runtime_error &) {
} }
} }
......
...@@ -508,6 +508,7 @@ try { ...@@ -508,6 +508,7 @@ try {
decoder_run_song(dc, song, uri_utf8, path_fs); decoder_run_song(dc, song, uri_utf8, path_fs);
} catch (...) { } catch (...) {
dc.state = DecoderState::ERROR; dc.state = DecoderState::ERROR;
dc.command = DecoderCommand::NONE;
dc.error = std::current_exception(); dc.error = std::current_exception();
dc.client_cond.signal(); dc.client_cond.signal();
} }
......
...@@ -310,8 +310,7 @@ playlist::SetRandom(PlayerControl &pc, bool status) ...@@ -310,8 +310,7 @@ playlist::SetRandom(PlayerControl &pc, bool status)
playlist is played after that */ playlist is played after that */
unsigned current_order = unsigned current_order =
queue.PositionToOrder(current_position); queue.PositionToOrder(current_position);
queue.MoveOrder(current_order, 0); current = queue.MoveOrder(current_order, 0);
current = 0;
} else } else
current = -1; current = -1;
} else } else
......
...@@ -356,6 +356,18 @@ public: ...@@ -356,6 +356,18 @@ public:
} }
void SetConsume(bool new_value); void SetConsume(bool new_value);
private:
/**
* Prepare a manual song change: move the given song to the
* current playback order. This is done to avoid skipping
* upcoming songs in the order list. The newly selected song
* shall be inserted in the order list, and the rest shall be
* played after that as previously planned.
*
* @return the new order number of the given song
*/
unsigned MoveOrderToCurrent(unsigned old_order);
}; };
#endif #endif
...@@ -56,6 +56,30 @@ playlist::Stop(PlayerControl &pc) ...@@ -56,6 +56,30 @@ playlist::Stop(PlayerControl &pc)
} }
} }
unsigned
playlist::MoveOrderToCurrent(unsigned old_order)
{
if (!queue.random)
/* no-op because there is no order list */
return old_order;
if (playing) {
/* already playing: move the specified song after the
current one (because the current one has already
been playing and shall not be played again) */
return queue.MoveOrderAfter(old_order, current);
} else if (current >= 0) {
/* not playing: move the specified song before the
current one, so it will be played eventually */
return queue.MoveOrderBefore(old_order, current);
} else {
/* not playing anything: move the specified song to
the front */
queue.SwapOrders(old_order, 0);
return 0;
}
}
void void
playlist::PlayPosition(PlayerControl &pc, int song) playlist::PlayPosition(PlayerControl &pc, int song)
{ {
...@@ -90,13 +114,7 @@ playlist::PlayPosition(PlayerControl &pc, int song) ...@@ -90,13 +114,7 @@ playlist::PlayPosition(PlayerControl &pc, int song)
number, because random mode is enabled */ number, because random mode is enabled */
i = queue.PositionToOrder(song); i = queue.PositionToOrder(song);
if (!playing) i = MoveOrderToCurrent(i);
current = 0;
/* swap the new song with the previous "current" one,
so playback continues as planned */
queue.SwapOrders(i, current);
i = current;
} }
stop_on_error = false; stop_on_error = false;
...@@ -205,6 +223,8 @@ playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time) ...@@ -205,6 +223,8 @@ playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time)
/* seeking is not within the current song - prepare /* seeking is not within the current song - prepare
song change */ song change */
i = MoveOrderToCurrent(i);
playing = true; playing = true;
current = i; current = i;
......
...@@ -195,7 +195,7 @@ Queue::MoveRange(unsigned start, unsigned end, unsigned to) noexcept ...@@ -195,7 +195,7 @@ Queue::MoveRange(unsigned start, unsigned end, unsigned to) noexcept
} }
} }
void unsigned
Queue::MoveOrder(unsigned from_order, unsigned to_order) noexcept Queue::MoveOrder(unsigned from_order, unsigned to_order) noexcept
{ {
assert(from_order < length); assert(from_order < length);
...@@ -212,6 +212,25 @@ Queue::MoveOrder(unsigned from_order, unsigned to_order) noexcept ...@@ -212,6 +212,25 @@ Queue::MoveOrder(unsigned from_order, unsigned to_order) noexcept
} }
order[to_order] = from_position; order[to_order] = from_position;
return to_order;
}
unsigned
Queue::MoveOrderBefore(unsigned from_order, unsigned to_order) noexcept
{
/* if "from_order" comes before "to_order", then the new
position is "to_order-1"; otherwise the "to_order" song is
moved one ahead */
return MoveOrder(from_order, to_order - (from_order < to_order));
}
unsigned
Queue::MoveOrderAfter(unsigned from_order, unsigned to_order) noexcept
{
/* if "from_order" comes after "to_order", then the new
position is "to_order+1"; otherwise the "to_order" song is
moved one back */
return MoveOrder(from_order, to_order + (from_order > to_order));
} }
void void
......
...@@ -284,8 +284,28 @@ struct Queue { ...@@ -284,8 +284,28 @@ struct Queue {
/** /**
* Moves a song to a new position in the "order" list. * Moves a song to a new position in the "order" list.
*
* @return to_order
*/
unsigned MoveOrder(unsigned from_order, unsigned to_order) noexcept;
/**
* Moves a song to a new position in the "order" list before
* the given one.
*
* @return the new order number of the given "from" song
*/
unsigned MoveOrderBefore(unsigned from_order,
unsigned to_order) noexcept;
/**
* Moves a song to a new position in the "order" list after
* the given one.
*
* @return the new order number of the given "from" song
*/ */
void MoveOrder(unsigned from_order, unsigned to_order) noexcept; unsigned MoveOrderAfter(unsigned from_order,
unsigned to_order) noexcept;
/** /**
* Moves a song to a new position. * Moves a song to a new position.
......
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