release v0.20.11
-----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEA5IzWngIOJSkMBxDI26KWMbbRRIFAlnnDXYQHG1heEBtdXNp Y3BkLm9yZwAKCRAjbopYxttFEtPBD/4sOwd7sQr/eeJr5gqVpil+CaVkHN1GpVmF H72uYnp5eKREywLMAqrY86hxvykeflroHyNyBF7CV5hIZV8kPl1ApN6WvjG3oFeX ZnM6PQjeqgqczSVUZOd92nATJw6g/Vk0qbC+h6VwhpSoq5716dAKriSO25JzDg0L KOwEztVsLeziKrk/sHSKjgRrYpuNS8bFVxAY8Pk9MnUhEeHB3Rb7Spd2zMUfMDLF 1pncFliIX5bOUKzDavIo4flAWc3jj514VhS7rVaU2OYpAdsQV18Z5Ze5B+46FUan 2gsn3oCOVbC3QV7X0do5MtD9p1tyX0HREokY3ttgut+iRz9zym2m0uC6t1DXwyVI cugOF70JbBYxd/ChO4rFYPHZo6A1XE7hb89AcVf6EgZyXROK077EzptprW9et0Ge kIUbHs01lHfA7gFefEC+8iVGSXQmEmQQp5tBnZkdUaJdpxVULdMkhhHCNU8RIIVP ot8guH2/9oKkCj+ytHj37SUpk7bKjbzID9XIW5a+4rQPb1oRmQMvIeKgWZ6sjHP1 5cS7l51q0onPmulfdQti0jTuaRcwQZcyKOxBU+eKYNHGNgLsdk1QDxyDhqbCCqWv 0seA7h+lNBGqZL7/F6s0IxsTWIwaInkZWPE1EGSRe0wvZohDtBbNhXWQDPBlgl8O R42Jdx6PIg== =8U+o -----END PGP SIGNATURE----- Merge tag 'v0.20.11' release v0.20.11
This commit is contained in:
commit
b4b468eb27
6
NEWS
6
NEWS
@ -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 {
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 {
|
|||||||
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)
|
|||||||
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:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
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)
|
|||||||
/* 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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
void MoveOrder(unsigned from_order, unsigned to_order) noexcept;
|
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
|
||||||
|
*/
|
||||||
|
unsigned MoveOrderAfter(unsigned from_order,
|
||||||
|
unsigned to_order) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves a song to a new position.
|
* Moves a song to a new position.
|
||||||
|
Loading…
Reference in New Issue
Block a user